Java tutorial
/* * Copyright (C) 2005-2007 Michael Keith, University Of Manchester * * email: mkeith@pulsarastronomy.net * www : www.pulsarastronomy.net * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package bookkeepr.managers; import bookkeepr.BackgroundTaskRunner; import bookkeepr.BookKeeprException; import bookkeepr.xml.IdAble; import bookkeepr.xmlable.BackgroundedTask; import bookkeepr.xml.XMLReader; import bookkeepr.xmlable.BookkeeprConfig; import bookkeepr.xmlable.BookkeeprHost; import bookkeepr.xmlable.DatabaseManager; import bookkeepr.xmlable.Index; import bookkeepr.xmlable.IndexIndex; import bookkeepr.xmlable.Session; import java.io.IOException; import java.io.InputStream; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.http.HttpException; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.xml.sax.SAXException; /** * * @author kei041 */ public class SyncManager { private DatabaseManager obsdb; private BookkeeprConfig config; private SessionManager sessionManager; private BackgroundTaskRunner bgrunner; private boolean run = true; public SyncManager(DatabaseManager obsdb, BookkeeprConfig config, SessionManager sessionManager, BackgroundTaskRunner bgrunner) { this.obsdb = obsdb; this.config = config; this.sessionManager = sessionManager; this.bgrunner = bgrunner; } private void delaySyncTask() { new Thread() { @Override public void run() { try { Thread.sleep(config.getSyncTime() * 1000); } catch (InterruptedException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Sync manager prodded, forcing sync now."); } insertSyncTask(); } }.start(); } private void insertSyncTask() { if (run) { BackgroundedTask task = new BackgroundedTask("Synchronise database"); task.setTarget(new Runnable() { public void run() { try { SyncManager.this.sync(); delaySyncTask(); } catch (Exception e) { Logger.getLogger(SyncManager.class.getName()).log(Level.SEVERE, "Error syncing database!", e); delaySyncTask(); throw new RuntimeException(e); } } }); if (!bgrunner.offer(task)) { delaySyncTask(); } } } public void run() { this.run = true; insertSyncTask(); } public void terminate() { this.run = false; } public void sync() { HttpClient httpclient = obsdb.getBookkeepr().checkoutHttpClient(); for (BookkeeprHost host : config.getBookkeeprHostList()) { Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Attempting to sync with " + host.getUrl()); try { HttpGet httpget = new HttpGet(host.getUrl() + "/ident/"); HttpResponse response = httpclient.execute(httpget); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { InputStream in = response.getEntity().getContent(); BookkeeprHost rhost = (BookkeeprHost) XMLReader.read(in); in.close(); Logger.getLogger(SyncManager.class.getName()).log(Level.FINE, "Managed to connect to " + host.getUrl() + "/ident/ "); host.setOriginId(rhost.getOriginId()); host.setMaxOriginId(rhost.getMaxOriginId()); host.setVersion(rhost.getVersion()); if (host.getVersion() != obsdb.getBookkeepr().getHost().getVersion()) { Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Host " + host.getUrl() + " is not of the same BookKeepr version as us! (Cannot sync)"); if (host.getVersion() > obsdb.getBookkeepr().getHost().getVersion()) { } Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "There are newer versions of the BookKeepr on the network. Please update this software!"); } } else { Logger.getLogger(SyncManager.class.getName()).log(Level.WARNING, "Host " + host.getUrl() + " could not be identified"); continue; } } catch (SAXException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.SEVERE, null, ex); continue; } catch (IOException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Host " + host.getUrl() + " was not avaiable for syncing"); continue; } catch (HttpException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Host " + host.getUrl() + " was not avaiable for syncing"); continue; } catch (URISyntaxException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.SEVERE, null, ex); continue; } ArrayList<Session> sessions = new ArrayList<Session>(); for (int originId = 0; originId <= host.getMaxOriginId(); originId++) { long maxRequestId; try { String url = host.getUrl() + "/sync/" + originId + "/" + TypeIdManager.getTypeFromClass(Session.class); HttpGet httpget = new HttpGet(url); HttpResponse response = httpclient.execute(httpget); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { Logger.getLogger(SyncManager.class.getName()).log(Level.FINE, "Managed to connect to " + host.getUrl() + "/sync/ "); } else if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) { Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Up-to-date with host"); continue; } else { Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Got an unexpected " + response.getStatusLine().getStatusCode() + " response from " + host.getUrl()); continue; } InputStream in = response.getEntity().getContent(); Session topSession = (Session) XMLReader.read(in); in.close(); maxRequestId = topSession.getId(); } catch (ClassCastException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.WARNING, "Server " + host.getUrl() + " returned something that was not as session when asked for the latest session.", ex); continue; } catch (HttpException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Host " + host.getUrl() + " could not be contacted"); continue; } catch (URISyntaxException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.WARNING, "Bad url " + host.getUrl() + "/sync/" + originId + "/" + TypeIdManager.getTypeFromClass(Session.class), ex); continue; } catch (SAXException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.WARNING, "Malformed XML file received from server " + host.getOriginId(), ex); continue; } catch (IOException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Host " + host.getUrl() + " was not avaiable for syncing"); continue; } long startId = sessionManager.getNextId(originId); Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Expecting next session: " + Long.toHexString(startId)); for (long requestId = startId; requestId <= maxRequestId; requestId++) { if (originId == 0) { Logger.getLogger(SyncManager.class.getName()).log(Level.SEVERE, "Server " + host.getUrl() + " claims that there are items created by server 0, which is impossible."); break; } if (originId == obsdb.getOriginId()) { Logger.getLogger(SyncManager.class.getName()).log(Level.SEVERE, "There are more up-to-date versions of data we created than in our database!"); break; } Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Updating to session " + Long.toHexString(requestId)); try { String url = host.getUrl() + "/update/" + Long.toHexString(requestId); HttpGet httpget = new HttpGet(url); HttpResponse response = httpclient.execute(httpget); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { } else { Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Got an unexpected " + response.getStatusLine().getStatusCode() + " response from " + host.getUrl()); continue; } InputStream in = response.getEntity().getContent(); IndexIndex idxidx = (IndexIndex) XMLReader.read(in); in.close(); Session session = new Session(); session.setId(requestId); for (Index idx : idxidx.getIndexList()) { for (Object idable : idx.getIndex()) { obsdb.add((IdAble) idable, session); } } sessions.add(session); //obsdb.save(session); } catch (HttpException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "HTTP exception connecting to host " + host.getUrl()); continue; } catch (URISyntaxException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.WARNING, ex.getMessage(), ex); break; } catch (SAXException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.WARNING, ex.getMessage(), ex); break; } catch (IOException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.WARNING, ex.getMessage(), ex); break; } } } if (!sessions.isEmpty()) { try { Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Saving updates to database"); obsdb.save(sessions); Logger.getLogger(SyncManager.class.getName()).log(Level.INFO, "Database Synchronised with " + host.getUrl()); } catch (BookKeeprException ex) { Logger.getLogger(SyncManager.class.getName()).log(Level.SEVERE, "Somehow tried to modify external elements from a database sync. This should never happen!", ex); } } } this.obsdb.getBookkeepr().returnHttpClient(httpclient); } }