Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements replication for metacat
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Chad Berkley
7
 *
8
 *   '$Author: berkley $'
9
 *     '$Date: 2011-02-03 15:25:41 -0800 (Thu, 03 Feb 2011) $'
10
 * '$Revision: 5895 $'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26

    
27
package edu.ucsb.nceas.metacat.replication;
28

    
29
import java.io.BufferedInputStream;
30
import java.io.BufferedOutputStream;
31
import java.io.File;
32
import java.io.FileInputStream;
33
import java.io.FileNotFoundException;
34
import java.io.FileOutputStream;
35
import java.io.IOException;
36
import java.io.InputStream;
37
import java.io.InputStreamReader;
38
import java.io.OutputStream;
39
import java.io.StringReader;
40
import java.io.Writer;
41
import java.net.MalformedURLException;
42
import java.net.URL;
43
import java.sql.PreparedStatement;
44
import java.sql.ResultSet;
45
import java.sql.SQLException;
46
import java.text.SimpleDateFormat;
47
import java.util.Date;
48
import java.util.Enumeration;
49
import java.util.Hashtable;
50
import java.util.Timer;
51
import java.util.Vector;
52

    
53
import javax.servlet.http.HttpServletRequest;
54
import javax.servlet.http.HttpServletResponse;
55

    
56
import org.apache.log4j.Logger;
57
import org.xml.sax.InputSource;
58
import org.xml.sax.SAXException;
59
import org.xml.sax.XMLReader;
60

    
61
import edu.ucsb.nceas.metacat.DocInfoHandler;
62
import edu.ucsb.nceas.metacat.DocumentImpl;
63
import edu.ucsb.nceas.metacat.DocumentImplWrapper;
64
import edu.ucsb.nceas.metacat.EventLog;
65
import edu.ucsb.nceas.metacat.IdentifierManager;
66
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
67
import edu.ucsb.nceas.metacat.McdbException;
68
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlException;
69
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlForSingleFile;
70
import edu.ucsb.nceas.metacat.accesscontrol.PermOrderException;
71
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessDAO;
72
import edu.ucsb.nceas.metacat.database.DBConnection;
73
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
74
import edu.ucsb.nceas.metacat.database.DatabaseService;
75
import edu.ucsb.nceas.metacat.properties.PropertyService;
76
import edu.ucsb.nceas.metacat.shared.BaseService;
77
import edu.ucsb.nceas.metacat.shared.HandlerException;
78
import edu.ucsb.nceas.metacat.shared.ServiceException;
79
import edu.ucsb.nceas.metacat.util.DocumentUtil;
80
import edu.ucsb.nceas.metacat.util.MetacatUtil;
81
import edu.ucsb.nceas.metacat.util.SystemUtil;
82
import edu.ucsb.nceas.utilities.FileUtil;
83
import edu.ucsb.nceas.utilities.GeneralPropertyException;
84
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
85

    
86
public class ReplicationService extends BaseService {
87

    
88
	private static ReplicationService replicationService = null;
89

    
90
	private long timeInterval;
91
	private Date firstTime;
92
	private boolean timedReplicationIsOn = false;
93
	Timer replicationDaemon;
94
	private static Vector<String> fileLocks = new Vector<String>();
95
//	private Thread lockThread = null;
96
	public static final String FORCEREPLICATEDELETE = "forcereplicatedelete";
97
	private static String TIMEREPLICATION = "replication.timedreplication";
98
	private static String TIMEREPLICATIONINTERVAl ="replication.timedreplicationinterval";
99
	private static String FIRSTTIME = "replication.firsttimedreplication";
100
	private static final int TIMEINTERVALLIMIT = 7200000;
101
	public static final String REPLICATIONUSER = "replication";
102

    
103
	public static final String REPLICATION_LOG_FILE_NAME = "metacatreplication.log";
104
	public static String METACAT_REPL_ERROR_MSG = null;
105
	private static Logger logReplication = Logger.getLogger("ReplicationLogging");
106
	private static Logger logMetacat = Logger.getLogger(ReplicationService.class);
107

    
108
	private ReplicationService() throws ServiceException {
109
		_serviceName = "ReplicationService";
110
		
111
		initialize();
112
	}
113
	
114
	private void initialize() throws ServiceException {
115
				
116
		// initialize db connections to handle any update requests
117
		// deltaT = util.getProperty("replication.deltaT");
118
		// the default deltaT can be set from metacat.properties
119
		// create a thread to do the delta-T check but don't execute it yet
120
		replicationDaemon = new Timer(true);
121
		try {
122
			String replLogFile = PropertyService.getProperty("replication.logdir")
123
				+ FileUtil.getFS() + REPLICATION_LOG_FILE_NAME;
124
			METACAT_REPL_ERROR_MSG = "An error occurred in replication.  Please see the " +
125
				"replication log at: " + replLogFile;
126
			
127
			String timedRepIsOnStr = 
128
				PropertyService.getProperty("replication.timedreplication");
129
			timedReplicationIsOn = (new Boolean(timedRepIsOnStr)).booleanValue();
130
			logReplication.info("ReplicationService.initialize - The timed replication on is" + timedReplicationIsOn);
131

    
132
			String timeIntervalStr = 
133
				PropertyService.getProperty("replication.timedreplicationinterval");
134
			timeInterval = (new Long(timeIntervalStr)).longValue();
135
			logReplication.info("ReplicationService.initialize - The timed replication time Interval is " + timeInterval);
136

    
137
			String firstTimeStr = 
138
				PropertyService.getProperty("replication.firsttimedreplication");
139
			logReplication.info("ReplicationService.initialize - first replication time form property is " + firstTimeStr);
140
			firstTime = ReplicationHandler.combinateCurrentDateAndGivenTime(firstTimeStr);
141

    
142
			logReplication.info("ReplicationService.initialize - After combine current time, the real first time is "
143
					+ firstTime.toString() + " minisec");
144

    
145
			// set up time replication if it is on
146
			if (timedReplicationIsOn) {
147
				replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(),
148
						firstTime, timeInterval);
149
				logReplication.info("ReplicationService.initialize - deltaT handler started with rate="
150
						+ timeInterval + " mini seconds at " + firstTime.toString());
151
			}
152

    
153
		} catch (PropertyNotFoundException pnfe) {
154
			throw new ServiceException(
155
					"ReplicationService.initialize - Property error while instantiating "
156
							+ "replication service: " + pnfe.getMessage());
157
		} catch (HandlerException he) {
158
			throw new ServiceException(
159
					"ReplicationService.initialize - Handler error while instantiating "
160
							+ "replication service" + he.getMessage());
161
		} 
162
	}
163

    
164
	/**
165
	 * Get the single instance of SessionService.
166
	 * 
167
	 * @return the single instance of SessionService
168
	 */
169
	public static ReplicationService getInstance() throws ServiceException {
170
		if (replicationService == null) {
171
			replicationService = new ReplicationService();
172
		}
173
		return replicationService;
174
	}
175

    
176
	public boolean refreshable() {
177
		return true;
178
	}
179

    
180
	protected void doRefresh() throws ServiceException {
181
		return;
182
	}
183
	
184
	public void stop() throws ServiceException{
185
		
186
	}
187

    
188
	public void stopReplication() throws ServiceException {
189
	      //stop the replication server
190
	      replicationDaemon.cancel();
191
	      replicationDaemon = new Timer(true);
192
	      timedReplicationIsOn = false;
193
	      try {
194
	    	  PropertyService.setProperty("replication.timedreplication", (new Boolean(timedReplicationIsOn)).toString());
195
	      } catch (GeneralPropertyException gpe) {
196
	    	  logReplication.warn("ReplicationService.stopReplication - Could not set replication.timedreplication property: " + gpe.getMessage());
197
	      }
198

    
199
	      logReplication.info("ReplicationService.stopReplication - deltaT handler stopped");
200
		return;
201
	}
202
	
203
	protected void startReplication(Hashtable<String, String[]> params) throws ServiceException {
204

    
205
	       String firstTimeStr = "";
206
	      //start the replication server
207
	       if ( params.containsKey("rate") ) {
208
	        timeInterval = new Long(
209
	               new String(((String[])params.get("rate"))[0])).longValue();
210
	        if(timeInterval < TIMEINTERVALLIMIT) {
211
	            //deltaT<30 is a timing mess!
212
	            timeInterval = TIMEINTERVALLIMIT;
213
	            throw new ServiceException("Replication deltaT rate cannot be less than "+
214
	                    TIMEINTERVALLIMIT + " millisecs and system automatically setup the rate to "+TIMEINTERVALLIMIT);
215
	        }
216
	      } else {
217
	        timeInterval = TIMEINTERVALLIMIT ;
218
	      }
219
	      logReplication.info("ReplicationService.startReplication - New rate is: " + timeInterval + " mini seconds.");
220
	      if ( params.containsKey("firsttime"))
221
	      {
222
	         firstTimeStr = ((String[])params.get("firsttime"))[0];
223
	         try
224
	         {
225
	           firstTime = ReplicationHandler.combinateCurrentDateAndGivenTime(firstTimeStr);
226
	           logReplication.info("ReplicationService.startReplication - The first time setting is "+firstTime.toString());
227
	         }
228
	         catch (HandlerException e)
229
	         {
230
	            throw new ServiceException(e.getMessage());
231
	         }
232
	         logReplication.warn("After combine current time, the real first time is "
233
	                                  +firstTime.toString()+" minisec");
234
	      }
235
	      else
236
	      {
237
	    	  logMetacat.error("ReplicationService.startReplication - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
238
	          logReplication.error("ReplicationService.startReplication - You should specify the first time " +
239
	                                  "to start a time replication");
240
	          return;
241
	      }
242
	      
243
	      timedReplicationIsOn = true;
244
	      try {
245
	      // save settings to property file
246
	      PropertyService.setProperty(TIMEREPLICATION, (new Boolean(timedReplicationIsOn)).toString());
247
	      // note we couldn't use firstTime object because it has date info
248
	      // we only need time info such as 10:00 PM
249
	      PropertyService.setProperty(FIRSTTIME, firstTimeStr);
250
	      PropertyService.setProperty(TIMEREPLICATIONINTERVAl, (new Long(timeInterval)).toString());
251
	      } catch (GeneralPropertyException gpe) {
252
	    	  logReplication.warn("ReplicationService.startReplication - Could not set property: " + gpe.getMessage());
253
	      }
254
	      replicationDaemon.cancel();
255
	      replicationDaemon = new Timer(true);
256
	      replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(), firstTime,
257
	                                            timeInterval);
258
	      
259
	      logReplication.info("ReplicationService.startReplication - deltaT handler started with rate=" +
260
	                                    timeInterval + " milliseconds at " +firstTime.toString());
261

    
262
	}
263
	
264
	public void runOnce() throws ServiceException {
265
	      //updates this server exactly once
266
	      replicationDaemon.schedule(new ReplicationHandler(), 0);
267
	}
268

    
269
	/**
270
	 * This method can add, delete and list the servers currently included in
271
	 * xml_replication.
272
	 * action           subaction            other needed params
273
	 * ---------------------------------------------------------
274
	 * servercontrol    add                  server
275
	 * servercontrol    delete               server
276
	 * servercontrol    list
277
	 */
278
	protected static void handleServerControlRequest(
279
			Hashtable<String, String[]> params, HttpServletResponse response) {
280
		String subaction = ((String[]) params.get("subaction"))[0];
281
		DBConnection dbConn = null;
282
		int serialNumber = -1;
283
		PreparedStatement pstmt = null;
284
		String replicate = null;
285
		String server = null;
286
		String dataReplicate = null;
287
		String hub = null;
288
		Writer out = null;
289
		try {
290
			response.setContentType("text/xml");
291
			out = response.getWriter();
292
			
293
			//conn = util.openDBConnection();
294
			dbConn = DBConnectionPool
295
					.getDBConnection("MetacatReplication.handleServerControlRequest");
296
			serialNumber = dbConn.getCheckOutSerialNumber();
297

    
298
			// add server to server list
299
			if (subaction.equals("add")) {
300
				replicate = ((String[]) params.get("replicate"))[0];
301
				server = ((String[]) params.get("server"))[0];
302

    
303
				//Get data replication value
304
				dataReplicate = ((String[]) params.get("datareplicate"))[0];
305
				//Get hub value
306
				hub = ((String[]) params.get("hub"))[0];
307

    
308
				String toDateSql = DatabaseService.getInstance().getDBAdapter().toDate("01/01/1980","MM/DD/YYYY");
309
				String sql = "INSERT INTO xml_replication "
310
						+ "(server, last_checked, replicate, datareplicate, hub) "
311
						+ "VALUES (?," + toDateSql + ",?,?,?)";
312
				
313
				pstmt = dbConn.prepareStatement(sql);
314
						
315
				pstmt.setString(1, server);
316
				pstmt.setInt(2, Integer.parseInt(replicate));
317
				pstmt.setInt(3, Integer.parseInt(dataReplicate));
318
				pstmt.setInt(4, Integer.parseInt(hub));
319
				
320
				String sqlReport = "XMLAccessAccess.getXMLAccessForDoc - SQL: " + sql;
321
				sqlReport += " [" + server + "," + replicate + 
322
					"," + dataReplicate + "," + hub + "]";
323
				
324
				logMetacat.info(sqlReport);
325
				
326
				pstmt.execute();
327
				pstmt.close();
328
				dbConn.commit();
329
				out.write("Server " + server + " added");
330
				response.setContentType("text/html");
331
				out.write("<html><body><table border=\"1\">");
332
				out.write("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
333
				out.write("<b>replicate</b></td>");
334
				out.write("<td><b>datareplicate</b></td>");
335
				out.write("<td><b>hub</b></td></tr>");
336
				pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
337
				//increase dbconnection usage
338
				dbConn.increaseUsageCount(1);
339

    
340
				pstmt.execute();
341
				ResultSet rs = pstmt.getResultSet();
342
				boolean tablehasrows = rs.next();
343
				while (tablehasrows) {
344
					out.write("<tr><td>" + rs.getString(2) + "</td><td>");
345
					out.write(rs.getString(3) + "</td><td>");
346
					out.write(rs.getString(4) + "</td><td>");
347
					out.write(rs.getString(5) + "</td><td>");
348
					out.write(rs.getString(6) + "</td></tr>");
349

    
350
					tablehasrows = rs.next();
351
				}
352
				out.write("</table></body></html>");
353

    
354
				// download certificate with the public key on this server
355
				// and import it as a trusted certificate
356
				String certURL = ((String[]) params.get("certificate"))[0];
357
				if (certURL != null && !certURL.equals("")) {
358
					downloadCertificate(certURL);
359
				}
360

    
361
				// delete server from server list
362
			} else if (subaction.equals("delete")) {
363
				server = ((String[]) params.get("server"))[0];
364
				pstmt = dbConn.prepareStatement("DELETE FROM xml_replication "
365
						+ "WHERE server LIKE '" + server + "'");
366
				pstmt.execute();
367
				pstmt.close();
368
				dbConn.commit();
369
				out.write("Server " + server + " deleted");
370
				response.setContentType("text/html");
371
				out.write("<html><body><table border=\"1\">");
372
				out.write("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
373
				out.write("<b>replicate</b></td>");
374
				out.write("<td><b>datareplicate</b></td>");
375
				out.write("<td><b>hub</b></td></tr>");
376

    
377
				pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
378
				//increase dbconnection usage
379
				dbConn.increaseUsageCount(1);
380
				pstmt.execute();
381
				ResultSet rs = pstmt.getResultSet();
382
				boolean tablehasrows = rs.next();
383
				while (tablehasrows) {
384
					out.write("<tr><td>" + rs.getString(2) + "</td><td>");
385
					out.write(rs.getString(3) + "</td><td>");
386
					out.write(rs.getString(4) + "</td><td>");
387
					out.write(rs.getString(5) + "</td><td>");
388
					out.write(rs.getString(6) + "</td></tr>");
389
					tablehasrows = rs.next();
390
				}
391
				out.write("</table></body></html>");
392

    
393
				// list servers in server list
394
			} else if (subaction.equals("list")) {
395
				response.setContentType("text/html");
396
				out.write("<html><body><table border=\"1\">");
397
				out.write("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
398
				out.write("<b>replicate</b></td>");
399
				out.write("<td><b>datareplicate</b></td>");
400
				out.write("<td><b>hub</b></td></tr>");
401
				pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
402
				pstmt.execute();
403
				ResultSet rs = pstmt.getResultSet();
404
				boolean tablehasrows = rs.next();
405
				while (tablehasrows) {
406
					out.write("<tr><td>" + rs.getString(2) + "</td><td>");
407
					out.write(rs.getString(3) + "</td><td>");
408
					out.write(rs.getString(4) + "</td><td>");
409
					out.write(rs.getString(5) + "</td><td>");
410
					out.write(rs.getString(6) + "</td></tr>");
411
					tablehasrows = rs.next();
412
				}
413
				out.write("</table></body></html>");
414
			} else {
415

    
416
				out.write("<error>Unkonwn subaction</error>");
417

    
418
			}
419
			pstmt.close();
420
			//conn.close();
421

    
422
		} catch (Exception e) {
423
			logMetacat.error("ReplicationService.handleServerControlRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
424
			logReplication.error("ReplicationService.handleServerControlRequest - Error in "
425
					+ "MetacatReplication.handleServerControlRequest " + e.getMessage());
426
			e.printStackTrace(System.out);
427
		} finally {
428
			try {
429
				pstmt.close();
430
			}//try
431
			catch (SQLException ee) {
432
				logMetacat.error("ReplicationService.handleServerControlRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
433
				logReplication.error("ReplicationService.handleServerControlRequest - Error in MetacatReplication.handleServerControlRequest to close pstmt "
434
						+ ee.getMessage());
435
			}//catch
436
			finally {
437
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
438
			}//finally
439
			if (out != null) {
440
				try {
441
					out.close();
442
				} catch (IOException e) {
443
					logMetacat.error(e.getMessage(), e);
444
				}
445
			}
446
		}//finally
447

    
448
	}
449

    
450
	// download certificate with the public key from certURL and
451
	// upload it onto this server; it then must be imported as a
452
	// trusted certificate
453
	private static void downloadCertificate(String certURL) throws FileNotFoundException,
454
			IOException, MalformedURLException, PropertyNotFoundException {
455

    
456
		// the path to be uploaded to
457
		String certPath = SystemUtil.getContextDir();
458

    
459
		// get filename from the URL of the certificate
460
		String filename = certURL;
461
		int slash = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
462
		if (slash > -1) {
463
			filename = filename.substring(slash + 1);
464
		}
465

    
466
		// open file output strem to write the input into it
467
		File f = new File(certPath, filename);
468
		synchronized (f) {
469
			try {
470
				if (f.exists()) {
471
					throw new IOException("File already exist: " + f.getCanonicalFile());
472
					// if ( f.exists() && !f.canWrite() ) {
473
					// throw new IOException("Not writable: " +
474
					// f.getCanonicalFile());
475
				}
476
			} catch (SecurityException se) {
477
				// if a security manager exists,
478
				// its checkRead method is called for f.exist()
479
				// or checkWrite method is called for f.canWrite()
480
				throw se;
481
			}
482

    
483
			// create a buffered byte output stream
484
			// that uses a default-sized output buffer
485
			FileOutputStream fos = new FileOutputStream(f);
486
			BufferedOutputStream out = new BufferedOutputStream(fos);
487

    
488
			// this should be http url
489
			URL url = new URL(certURL);
490
			BufferedInputStream bis = null;
491
			try {
492
				bis = new BufferedInputStream(url.openStream());
493
				byte[] buf = new byte[4 * 1024]; // 4K buffer
494
				int b = bis.read(buf);
495
				while (b != -1) {
496
					out.write(buf, 0, b);
497
					b = bis.read(buf);
498
				}
499
			} finally {
500
				if (bis != null)
501
					bis.close();
502
			}
503
			// the input and the output streams must be closed
504
			bis.close();
505
			out.flush();
506
			out.close();
507
			fos.close();
508
		} // end of synchronized(f)
509
	}
510

    
511
	/**
512
	 * when a forcereplication request comes in, local host sends a read request
513
	 * to the requesting server (remote server) for the specified docid. Then
514
	 * store it in local database.
515
	 */
516
	protected static void handleForceReplicateRequest(
517
			Hashtable<String, String[]> params, HttpServletResponse response,
518
			HttpServletRequest request) {
519
		String server = ((String[]) params.get("server"))[0]; // the server that
520
		String docid = ((String[]) params.get("docid"))[0]; // sent the document
521
		String dbaction = "UPDATE"; // the default action is UPDATE
522
		//    boolean override = false;
523
		//    int serverCode = 1;
524
		DBConnection dbConn = null;
525
		int serialNumber = -1;
526
		String docName = null;
527

    
528
		try {
529
			//if the url contains a dbaction then the default action is overridden
530
			if (params.containsKey("dbaction")) {
531
				dbaction = ((String[]) params.get("dbaction"))[0];
532
				//serverCode = MetacatReplication.getServerCode(server);
533
				//override = true; //we are now overriding the default action
534
			}
535
			logReplication.info("ReplicationService.handleForceReplicateRequest - Force replication request from: " + server);
536
			logReplication.info("ReplicationService.handleForceReplicateRequest - Force replication docid: " + docid);
537
			logReplication.info("ReplicationService.handleForceReplicateRequest - Force replication action: " + dbaction);
538
			// sending back read request to remote server
539
			URL u = new URL("https://" + server + "?server="
540
					+ MetacatUtil.getLocalReplicationServerName() + "&action=read&docid="
541
					+ docid);
542
			String xmldoc = ReplicationService.getURLContent(u);
543

    
544
			// get the document info from server
545
			URL docinfourl = new URL("https://" + server + "?server="
546
					+ MetacatUtil.getLocalReplicationServerName()
547
					+ "&action=getdocumentinfo&docid=" + docid);
548
			
549

    
550
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
551

    
552
			//dih is the parser for the docinfo xml format
553
			DocInfoHandler dih = new DocInfoHandler();
554
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
555
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
556
			//      Hashtable<String,Vector<AccessControlForSingleFile>> docinfoHash = dih.getDocInfo();
557
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
558

    
559
			// Get user owner of this docid
560
			String user = (String) docinfoHash.get("user_owner");
561
			// Get home server of this docid
562
			String homeServer = (String) docinfoHash.get("home_server");
563
			String guid = (String) docinfoHash.get("guid");
564
			logReplication.info("XXXXXXXXXXXXXXXX GUID found in dociinfoHash: " + guid);
565
			
566
			logReplication.info("Processing guid " + guid + 
567
			  " information from handleForceReplicationRequest: " + 
568
			  docinfoHash.toString());
569
      IdentifierManager idman = IdentifierManager.getInstance();
570
      if(guid != null)
571
      { //if the guid was passed in, put it in the identifiers table
572
        logReplication.info("YYYYYYYYYYYYYY Creating guid/docid mapping for docid " + 
573
          docinfoHash.get("docid") + " and guid: " + guid);
574
        
575
        docName = (String) docinfoHash.get("docname");
576
        logReplication.info("ZZZZZZZZZZZZ docName: " + docName);
577
        if(docName.trim().equals("systemMetadata"))
578
        {
579
            logReplication.info("creating mapping for systemMetadata: guid: " + guid + " localId: " + docinfoHash.get("docid"));
580
            idman.createSystemMetadataMapping(guid, docinfoHash.get("docid"));
581
        }
582
        else
583
        {
584
            logReplication.info("creating mapping: guid: " + guid + " localId: " + docinfoHash.get("docid"));
585
            idman.createMapping(guid, docinfoHash.get("docid"));
586
        }
587
      }
588
      else
589
      {
590
        logReplication.debug("No guid information was included with the replicated document");
591
      }
592
      
593
			String createdDate = (String) docinfoHash.get("date_created");
594
			String updatedDate = (String) docinfoHash.get("date_updated");
595
			logReplication.info("ReplicationService.handleForceReplicateRequest - homeServer: " + homeServer);
596
			// Get Document type
597
			String docType = (String) docinfoHash.get("doctype");
598
			logReplication.info("ReplicationService.handleForceReplicateRequest - docType: " + docType);
599
			String parserBase = null;
600
			// this for eml2 and we need user eml2 parser
601
			if (docType != null
602
					&& (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE)) {
603
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml200 document!");
604
				parserBase = DocumentImpl.EML200;
605
			} else if (docType != null
606
					&& (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE)) {
607
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.0.1 document!");
608
				parserBase = DocumentImpl.EML200;
609
			} else if (docType != null
610
					&& (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE)) {
611
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.0 document!");
612
				parserBase = DocumentImpl.EML210;
613
			} else if (docType != null
614
					&& (docType.trim()).equals(DocumentImpl.EML2_1_1NAMESPACE)) {
615
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.1 document!");
616
				parserBase = DocumentImpl.EML210;
617
			}
618
			logReplication.warn("ReplicationService.handleForceReplicateRequest - The parserBase is: " + parserBase);
619

    
620
			// Get DBConnection from pool
621
			dbConn = DBConnectionPool
622
					.getDBConnection("MetacatReplication.handleForceReplicateRequest");
623
			serialNumber = dbConn.getCheckOutSerialNumber();
624
			// write the document to local database
625
			DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false);
626
			//try this independently so we can set
627
//			Exception writeException = null;
628
			try {
629
				wrapper.writeReplication(dbConn, xmldoc, null, null,
630
						dbaction, docid, user, null, homeServer, server, createdDate,
631
						updatedDate);
632
			} finally {
633
//				writeException = e;
634

    
635
				//process extra access rules before dealing with the write exception (doc exist already)			
636
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
637
		        if (accessControlList != null) {
638
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
639
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
640
		        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
641
		        			acfsf.insertPermissions(xmlAccessDAO);
642
							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
643
									+ " permissions added to DB");
644
		        		}
645
		            }
646
		        }
647
//				if (accessControlList != null) {
648
//					for (int i = 0; i < accessControlList.size(); i++) {
649
//						AccessControlForSingleFile acfsf = (AccessControlForSingleFile) accessControlList
650
//								.get(i);
651
//						if (!acfsf.accessControlExists()) {
652
//							acfsf.insertPermissions();
653
//							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
654
//									+ " permissions added to DB");
655
//						}
656
//					}
657
//				}
658

    
659
//				if (writeException != null) {
660
//					throw writeException;
661
//				}
662

    
663
				logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid + " added to DB with "
664
						+ "action " + dbaction);
665
				
666
				if(guid != null)
667
                {
668
                    if(!docName.trim().equals("systemMetadata"))
669
                    {
670
                        logReplication.info("replicate D1GUID:" + guid + ":D1SCIMETADATA:" + 
671
                                docid + ":");
672
                    }
673
                    else
674
                    {
675
                        logReplication.info("replicate D1GUID:" + guid + ":D1SYSMETADATA:" + 
676
                                docid + ":");
677
                    }
678
                }
679
				EventLog.getInstance().log(request.getRemoteAddr(), REPLICATIONUSER, docid,
680
						dbaction);
681
			}
682
		} catch (SQLException sqle) {
683
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
684
			logReplication.error("ReplicationService.handleForceReplicateRequest - SQL error when adding doc " + docid + 
685
					" to DB with action " + dbaction + ": " + sqle.getMessage());
686
		} catch (MalformedURLException mue) {
687
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
688
			logReplication.error("ReplicationService.handleForceReplicateRequest - URL error when adding doc " + docid + 
689
					" to DB with action " + dbaction + ": " + mue.getMessage());
690
		} catch (SAXException se) {
691
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
692
			logReplication.error("ReplicationService.handleForceReplicateRequest - SAX parsing error when adding doc " + docid + 
693
					" to DB with action " + dbaction + ": " + se.getMessage());
694
		} catch (HandlerException he) {
695
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
696
			logReplication.error("ReplicationService.handleForceReplicateRequest - Handler error when adding doc " + docid + 
697
					" to DB with action " + dbaction + ": " + he.getMessage());
698
		} catch (IOException ioe) {
699
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
700
			logReplication.error("ReplicationService.handleForceReplicateRequest - I/O error when adding doc " + docid + 
701
					" to DB with action " + dbaction + ": " + ioe.getMessage());
702
		} catch (PermOrderException poe) {
703
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
704
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
705
					" to DB with action " + dbaction + ": " + poe.getMessage());
706
		} catch (AccessControlException ace) {
707
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
708
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
709
					" to DB with action " + dbaction + ": " + ace.getMessage());
710
		} catch (Exception e) {
711
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
712
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when adding doc " + docid + 
713
					" to DB with action " + dbaction + ": " + e.getMessage());
714
		} finally {
715
			// Return the checked out DBConnection
716
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
717
		}//finally
718
	}
719

    
720
	/*
721
	 * when a forcereplication delete request comes in, local host will delete this
722
	 * document
723
	 */
724
	protected static void handleForceReplicateDeleteRequest(
725
			Hashtable<String, String[]> params, HttpServletResponse response,
726
			HttpServletRequest request) {
727
		String server = ((String[]) params.get("server"))[0]; // the server that
728
		String docid = ((String[]) params.get("docid"))[0]; // sent the document
729
		try {
730
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - force replication delete request from " + server);
731
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - force replication delete docid " + docid);
732
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - Force replication delete request from: " + server);
733
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - Force replication delete docid: " + docid);
734
			DocumentImpl.delete(docid, null, null, server);
735
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - document " + docid + " was successfully deleted ");
736
			EventLog.getInstance().log(request.getRemoteAddr(), REPLICATIONUSER, docid,
737
					"delete");
738
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - document " + docid + " was successfully deleted ");
739
		} catch (Exception e) {
740
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
741
			logReplication.error("document " + docid
742
					+ " failed to delete because " + e.getMessage());
743
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
744

    
745
		}//catch
746

    
747
	}
748

    
749
	/**
750
	 * when a forcereplication data file request comes in, local host sends a
751
	 * readdata request to the requesting server (remote server) for the specified
752
	 * docid. Then store it in local database and file system
753
	 */
754
	protected static void handleForceReplicateDataFileRequest(Hashtable<String, String[]> params,
755
			HttpServletRequest request) {
756

    
757
		//make sure there is some parameters
758
		if (params.isEmpty()) {
759
			return;
760
		}
761
		// Get remote server
762
		String server = ((String[]) params.get("server"))[0];
763
		// the docid should include rev number
764
		String docid = ((String[]) params.get("docid"))[0];
765
		// Make sure there is a docid and server
766
		if (docid == null || server == null || server.equals("")) {
767
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
768
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Didn't specify docid or server for replication");
769
			return;
770
		}
771

    
772
		// Overide or not
773
		//    boolean override = false;
774
		// dbaction - update or insert
775
		String dbaction = null;
776

    
777
		try {
778
			//docid was switch to two parts uinque code and rev
779
			//String uniqueCode=MetacatUtil.getDocIdFromString(docid);
780
			//int rev=MetacatUtil.getVersionFromString(docid);
781
			if (params.containsKey("dbaction")) {
782
				dbaction = ((String[]) params.get("dbaction"))[0];
783
			} else//default value is update
784
			{
785
				dbaction = "update";
786
			}
787

    
788
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - force replication request from " + server);
789
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication request from: " + server);
790
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication docid: " + docid);
791
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication action: " + dbaction);
792
			// get the document info from server
793
			URL docinfourl = new URL("https://" + server + "?server="
794
					+ MetacatUtil.getLocalReplicationServerName()
795
					+ "&action=getdocumentinfo&docid=" + docid);
796

    
797
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
798

    
799
			//dih is the parser for the docinfo xml format
800
			DocInfoHandler dih = new DocInfoHandler();
801
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
802
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
803
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
804
			String user = (String) docinfoHash.get("user_owner");
805

    
806
			String docName = (String) docinfoHash.get("docname");
807

    
808
			String docType = (String) docinfoHash.get("doctype");
809

    
810
			String docHomeServer = (String) docinfoHash.get("home_server");
811

    
812
			String createdDate = (String) docinfoHash.get("date_created");
813

    
814
			String updatedDate = (String) docinfoHash.get("date_updated");
815
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - docHomeServer of datafile: " + docHomeServer);
816

    
817
			//if action is delete, we don't delete the data file. Just archieve
818
			//the xml_documents
819
			/*if (dbaction.equals("delete"))
820
			{
821
			  //conn = util.getConnection();
822
			  DocumentImpl.delete(docid,user,null);
823
			  //util.returnConnection(conn);
824
			}*/
825
			//To data file insert or update is same
826
			if (dbaction.equals("insert") || dbaction.equals("update")) {
827
				//Get data file and store it into local file system.
828
				// sending back readdata request to server
829
				URL url = new URL("https://" + server + "?server="
830
						+ MetacatUtil.getLocalReplicationServerName()
831
						+ "&action=readdata&docid=" + docid);
832
				String datafilePath = PropertyService
833
						.getProperty("application.datafilepath");
834

    
835
				Exception writeException = null;
836
				//register data file into xml_documents table and wite data file
837
				//into file system
838
				try {
839
					DocumentImpl.writeDataFileInReplication(url.openStream(),
840
							datafilePath, docName, docType, docid, user, docHomeServer,
841
							server, DocumentImpl.DOCUMENTTABLE, false, createdDate,
842
							updatedDate);
843
				} catch (Exception e) {
844
					writeException = e;
845
				}
846
				//process extra access rules
847
//				Vector<AccessControlForSingleFile> accessControlList = dih
848
//						.getAccessControlList();
849
//				if (accessControlList != null) {
850
//					for (int i = 0; i < accessControlList.size(); i++) {
851
//						AccessControlForSingleFile acfsf = (AccessControlForSingleFile) accessControlList
852
//								.get(i);
853
//						if (!acfsf.accessControlExists()) {
854
//							acfsf.insertPermissions();
855
//							logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - datafile " + docid
856
//									+ " permissions added to DB");
857
//						}
858
//					}
859
//				}
860
				
861
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
862
		        if (accessControlList != null) {
863
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
864
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
865
		        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
866
		        			acfsf.insertPermissions(xmlAccessDAO);
867
							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
868
									+ " permissions added to DB");
869
		        		}
870
		            }
871
		        }
872

    
873
				if (writeException != null) {
874
					throw writeException;
875
				}
876

    
877
				//false means non-timed replication
878
				logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - datafile " + docid + " added to DB with "
879
						+ "action " + dbaction);
880
				EventLog.getInstance().log(request.getRemoteAddr(), REPLICATIONUSER,
881
						docid, dbaction);
882
			}
883

    
884
		} catch (Exception e) {
885
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
886
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Datafile " + docid
887
					+ " failed to added to DB with " + "action " + dbaction + " because "
888
					+ e.getMessage());
889
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - ERROR in MetacatReplication.handleForceDataFileReplicate"
890
					+ "Request(): " + e.getMessage());
891
		}
892
	}
893

    
894
	/**
895
	 * Grants or denies a lock to a requesting host.
896
	 * The servlet parameters of interrest are:
897
	 * docid: the docid of the file the lock is being requested for
898
	 * currentdate: the timestamp of the document on the remote server
899
	 *
900
	 */
901
	protected static void handleGetLockRequest(
902
			Hashtable<String, String[]> params, HttpServletResponse response) {
903

    
904
		try {
905

    
906
			String docid = ((String[]) params.get("docid"))[0];
907
			String remoteRev = ((String[]) params.get("updaterev"))[0];
908
			DocumentImpl requestDoc = new DocumentImpl(docid);
909
			logReplication.info("ReplicationService.handleGetLockRequest - lock request for " + docid);
910
			int localRevInt = requestDoc.getRev();
911
			int remoteRevInt = Integer.parseInt(remoteRev);
912

    
913
			// get a writer for sending back to response
914
			response.setContentType("text/xml");
915
			Writer out = response.getWriter();
916
			
917
			if (remoteRevInt >= localRevInt) {
918
				if (!fileLocks.contains(docid)) { //grant the lock if it is not already locked
919
					fileLocks.add(0, docid); //insert at the beginning of the queue Vector
920
					//send a message back to the the remote host authorizing the insert
921
					out.write("<lockgranted><docid>" + docid
922
									+ "</docid></lockgranted>");
923
					//          lockThread = new Thread(this);
924
					//          lockThread.setPriority(Thread.MIN_PRIORITY);
925
					//          lockThread.start();
926
					logReplication.info("ReplicationService.handleGetLockRequest - lock granted for " + docid);
927
				} else { //deny the lock
928
					out.write("<filelocked><docid>" + docid + "</docid></filelocked>");
929
					logReplication.info("ReplicationService.handleGetLockRequest - lock denied for " + docid
930
							+ "reason: file already locked");
931
				}
932
			} else {//deny the lock.
933
				out.write("<outdatedfile><docid>" + docid + "</docid></filelocked>");
934
				logReplication.info("ReplicationService.handleGetLockRequest - lock denied for " + docid
935
						+ "reason: client has outdated file");
936
			}
937
			out.close();
938
			//conn.close();
939
		} catch (Exception e) {
940
			logMetacat.error("ReplicationService.handleGetLockRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
941
			logReplication.error("ReplicationService.handleGetLockRequest - error requesting file lock from MetacatReplication."
942
					+ "handleGetLockRequest: " + e.getMessage());
943
			e.printStackTrace(System.out);
944
		}
945
	}
946

    
947
	/**
948
	 * Sends all of the xml_documents information encoded in xml to a requestor
949
	 * the format is:
950
	 * <!ELEMENT documentinfo (docid, docname, doctype, doctitle, user_owner,
951
	 *                  user_updated, home_server, public_access, rev)/>
952
	 * all of the subelements of document info are #PCDATA
953
	 */
954
	protected static void handleGetDocumentInfoRequest(
955
			Hashtable<String, String[]> params, HttpServletResponse response) {
956
		String docid = ((String[]) (params.get("docid")))[0];
957
		StringBuffer sb = new StringBuffer();
958

    
959
		try {
960
		  IdentifierManager idman = IdentifierManager.getInstance();
961

    
962
			DocumentImpl doc = new DocumentImpl(docid);
963
			sb.append("<documentinfo><docid>").append(docid);
964
			sb.append("</docid>");
965
			try
966
			{
967
			  String guid = idman.getGUID(doc.getDocID(), doc.getRev());
968
			  sb.append("<guid>").append(guid).append("</guid>");
969
			  String smLocalId = idman.getSystemMetadataLocalId(guid);
970
			  Hashtable<String, String> sysmetaInfo = idman.getSystemMetadataInfo(smLocalId);
971
			  if(smLocalId != null && !smLocalId.trim().equals(""))
972
			  {
973
			      sb.append("<systemmetadatalocalid>").append(smLocalId).append("</systemmetadatalocalid>");
974
			  }
975
			  
976
			  Enumeration<String> sysmetaKeys = sysmetaInfo.keys();
977
			  while(sysmetaKeys.hasMoreElements())
978
			  {
979
			      String key = sysmetaKeys.nextElement();
980
			      sb.append("<" + key + ">" + sysmetaInfo.get(key).toString() + "</" + key + ">");
981
			  }
982
			  
983
			}
984
			catch(McdbDocNotFoundException e)
985
			{
986
			  //do nothing, there was no guid for this document
987
			}
988
			sb.append("<docname>").append(doc.getDocname());
989
			sb.append("</docname><doctype>").append(doc.getDoctype());
990
			sb.append("</doctype>");
991
			sb.append("<user_owner>").append(doc.getUserowner());
992
			sb.append("</user_owner><user_updated>").append(doc.getUserupdated());
993
			sb.append("</user_updated>");
994
			sb.append("<date_created>");
995
			sb.append(doc.getCreateDate());
996
			sb.append("</date_created>");
997
			sb.append("<date_updated>");
998
			sb.append(doc.getUpdateDate());
999
			sb.append("</date_updated>");
1000
			sb.append("<home_server>");
1001
			sb.append(doc.getDocHomeServer());
1002
			sb.append("</home_server>");
1003
			sb.append("<public_access>").append(doc.getPublicaccess());
1004
			sb.append("</public_access><rev>").append(doc.getRev());
1005
			sb.append("</rev>");
1006

    
1007
			sb.append("<accessControl>");
1008

    
1009
			AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid); 
1010
			sb.append(acfsf.getAccessString());
1011
			
1012
			sb.append("</accessControl>");
1013

    
1014
			sb.append("</documentinfo>");
1015
			// get a writer for sending back to response
1016
			response.setContentType("text/xml");
1017
			Writer out = response.getWriter();
1018
			out.write(sb.toString());
1019
			out.close();
1020

    
1021
		} catch (Exception e) {
1022
			logMetacat.error("ReplicationService.handleGetDocumentInfoRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1023
			logReplication.error("ReplicationService.handleGetDocumentInfoRequest - error in metacatReplication.handlegetdocumentinforequest "
1024
					+ "for doc: " + docid + " : " + e.getMessage());
1025
		}
1026

    
1027
	}
1028

    
1029
	/**
1030
	 * Sends a datafile to a remote host
1031
	 */
1032
	protected static void handleGetDataFileRequest(OutputStream outPut,
1033
			Hashtable<String, String[]> params, HttpServletResponse response)
1034

    
1035
	{
1036
		// File path for data file
1037
		String filepath;
1038
		// Request docid
1039
		String docId = ((String[]) (params.get("docid")))[0];
1040
		//check if the doicd is null
1041
		if (docId == null) {
1042
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1043
			logReplication.error("ReplicationService.handleGetDataFileRequest - Didn't specify docid for replication");
1044
			return;
1045
		}
1046

    
1047
		//try to open a https stream to test if the request server's public key
1048
		//in the key store, this is security issue
1049
		try {
1050
			filepath = PropertyService.getProperty("application.datafilepath");
1051
			String server = params.get("server")[0];
1052
			URL u = new URL("https://" + server + "?server="
1053
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test");
1054
			String test = ReplicationService.getURLContent(u);
1055
			//couldn't pass the test
1056
			if (test.indexOf("successfully") == -1) {
1057
				//response.setContentType("text/xml");
1058
				//outPut.println("<error>Couldn't pass the trust test</error>");
1059
				logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1060
				logReplication.error("ReplicationService.handleGetDataFileRequest - Couldn't pass the trust test");
1061
				return;
1062
			}
1063
		}//try
1064
		catch (Exception ee) {
1065
			return;
1066
		}//catch
1067

    
1068
		if (!filepath.endsWith("/")) {
1069
			filepath += "/";
1070
		}
1071
		// Get file aboslute file name
1072
		String filename = filepath + docId;
1073

    
1074
		//MIME type
1075
		String contentType = null;
1076
		if (filename.endsWith(".xml")) {
1077
			contentType = "text/xml";
1078
		} else if (filename.endsWith(".css")) {
1079
			contentType = "text/css";
1080
		} else if (filename.endsWith(".dtd")) {
1081
			contentType = "text/plain";
1082
		} else if (filename.endsWith(".xsd")) {
1083
			contentType = "text/xml";
1084
		} else if (filename.endsWith("/")) {
1085
			contentType = "text/html";
1086
		} else {
1087
			File f = new File(filename);
1088
			if (f.isDirectory()) {
1089
				contentType = "text/html";
1090
			} else {
1091
				contentType = "application/octet-stream";
1092
			}
1093
		}
1094

    
1095
		// Set the mime type
1096
		response.setContentType(contentType);
1097

    
1098
		// Get the content of the file
1099
		FileInputStream fin = null;
1100
		try {
1101
			// FileInputStream to metacat
1102
			fin = new FileInputStream(filename);
1103
			// 4K buffer
1104
			byte[] buf = new byte[4 * 1024];
1105
			// Read data from file input stream to byte array
1106
			int b = fin.read(buf);
1107
			// Write to outStream from byte array
1108
			while (b != -1) {
1109
				outPut.write(buf, 0, b);
1110
				b = fin.read(buf);
1111
			}
1112
			// close file input stream
1113
			fin.close();
1114

    
1115
		}//try
1116
		catch (Exception e) {
1117
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1118
			logReplication.error("ReplicationService.handleGetDataFileRequest - error getting data file from MetacatReplication."
1119
					+ "handlGetDataFileRequest " + e.getMessage());
1120
			e.printStackTrace(System.out);
1121
		}//catch
1122

    
1123
	}
1124

    
1125
	/**
1126
	 * Sends a document to a remote host
1127
	 */
1128
	protected static void handleGetDocumentRequest(
1129
			Hashtable<String, String[]> params, HttpServletResponse response) {
1130

    
1131
		String urlString = null;
1132
		String documentPath = null;
1133
		String errorMsg = null;
1134
		try {
1135
			// try to open a https stream to test if the request server's public
1136
			// key
1137
			// in the key store, this is security issue
1138
			String server = params.get("server")[0];
1139
			urlString = "https://" + server + "?server="
1140
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test";
1141
			URL u = new URL(urlString);
1142
			String test = ReplicationService.getURLContent(u);
1143
			// couldn't pass the test
1144
			if (test.indexOf("successfully") == -1) {
1145
				response.setContentType("text/xml");
1146
				Writer out = response.getWriter();
1147
				out.write("<error>Couldn't pass the trust test " + test + " </error>");
1148
				out.close();
1149
				return;
1150
			}
1151

    
1152
			String docid = params.get("docid")[0];
1153
			logReplication.debug("ReplicationService.handleGetDocumentRequest - MetacatReplication.handleGetDocumentRequest for docid: "
1154
					+ docid);
1155
			DocumentImpl di = new DocumentImpl(docid);
1156

    
1157
			String documentDir = PropertyService
1158
					.getProperty("application.documentfilepath");
1159
			documentPath = documentDir + FileUtil.getFS() + docid;
1160

    
1161
			// if the document does not exist on disk, read it from db and write
1162
			// it to disk.
1163
			if (FileUtil.getFileStatus(documentPath) == FileUtil.DOES_NOT_EXIST
1164
					|| FileUtil.getFileSize(documentPath) == 0) {
1165
				FileOutputStream fos = new FileOutputStream(documentPath);
1166
				di.toXml(fos, null, null, true);
1167
			}
1168

    
1169
			// read the file from disk and send it to outputstream
1170
			OutputStream outputStream = response.getOutputStream();
1171
			di.readFromFileSystem(outputStream, null, null, documentPath);
1172

    
1173
			logReplication.info("ReplicationService.handleGetDocumentRequest - document " + docid + " sent");
1174

    
1175
			// return to avoid continuing to the error reporting section at the end
1176
			return;
1177
			
1178
		} catch (MalformedURLException mue) {
1179
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1180
			logReplication.error("ReplicationService.handleGetDocumentRequest - Url error when getting document from MetacatReplication."
1181
					+ "handlGetDocumentRequest for url: " + urlString + " : "
1182
					+ mue.getMessage());
1183
			// e.printStackTrace(System.out);
1184
			
1185
		} catch (IOException ioe) {
1186
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1187
			logReplication.error("ReplicationService.handleGetDocumentRequest - I/O error when getting document from MetacatReplication."
1188
					+ "handlGetDocumentRequest for file: " + documentPath + " : "
1189
					+ ioe.getMessage());
1190
			errorMsg = ioe.getMessage();
1191
		} catch (PropertyNotFoundException pnfe) {
1192
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1193
			logReplication
1194
					.error("ReplicationService.handleGetDocumentRequest - Error getting property when getting document from MetacatReplication."
1195
							+ "handlGetDocumentRequest for file: "
1196
							+ documentPath
1197
							+ " : "
1198
							+ pnfe.getMessage());
1199
			// e.printStackTrace(System.out);
1200
			errorMsg = pnfe.getMessage();
1201
		} catch (McdbException me) {
1202
			logReplication
1203
					.error("ReplicationService.handleGetDocumentRequest - Document implementation error  getting property when getting document from MetacatReplication."
1204
							+ "handlGetDocumentRequest for file: "
1205
							+ documentPath
1206
							+ " : "
1207
							+ me.getMessage());
1208
			// e.printStackTrace(System.out);
1209
			errorMsg = me.getMessage();
1210
		}
1211
		
1212
		// report any errors if we got here
1213
		response.setContentType("text/xml");
1214
		Writer out = null;
1215
		try {
1216
			response.getWriter();
1217
			out = response.getWriter();
1218
			out.write("<error>" + errorMsg + "</error>");
1219
		} catch (Exception e) {
1220
			logMetacat.error(e.getMessage(), e);
1221
		} finally {
1222
			try {
1223
				out.close();
1224
			} catch (IOException e) {
1225
				logMetacat.error(e.getMessage(), e);
1226
			}
1227
		}
1228
		
1229

    
1230
	}
1231

    
1232
	/**
1233
	 * Sends a list of all of the documents on this sever along with their
1234
	 * revision numbers. The format is: <!ELEMENT replication (server, updates)>
1235
	 * <!ELEMENT server (#PCDATA)> <!ELEMENT updates ((updatedDocument |
1236
	 * deleteDocument | revisionDocument)*)> <!ELEMENT updatedDocument (docid,
1237
	 * rev, datafile*)> <!ELEMENT deletedDocument (docid, rev)> <!ELEMENT
1238
	 * revisionDocument (docid, rev, datafile*)> <!ELEMENT docid (#PCDATA)>
1239
	 * <!ELEMENT rev (#PCDATA)> <!ELEMENT datafile (#PCDATA)> note that the rev
1240
	 * in deletedDocument is always empty. I just left it in there to make the
1241
	 * parser implementation easier.
1242
	 */
1243
	protected static void handleUpdateRequest(Hashtable<String, String[]> params,
1244
			HttpServletResponse response) {
1245
		// Checked out DBConnection
1246
		DBConnection dbConn = null;
1247
		// DBConenction serial number when checked it out
1248
		int serialNumber = -1;
1249
		PreparedStatement pstmt = null;
1250
		// Server list to store server info of xml_replication table
1251
		ReplicationServerList serverList = null;
1252
		
1253
		// a writer for response
1254
		Writer out = null;
1255

    
1256
		try {
1257
			// get writer, TODO: encoding?
1258
			response.setContentType("text/xml");
1259
			out = response.getWriter();
1260
			
1261
			// Check out a DBConnection from pool
1262
			dbConn = DBConnectionPool
1263
					.getDBConnection("MetacatReplication.handleUpdateRequest");
1264
			serialNumber = dbConn.getCheckOutSerialNumber();
1265
			// Create a server list from xml_replication table
1266
			serverList = new ReplicationServerList();
1267

    
1268
			// Get remote server name from param
1269
			String server = ((String[]) params.get("server"))[0];
1270
			// If no servr name in param, return a error
1271
			if (server == null || server.equals("")) {
1272
				out.write("<error>Request didn't specify server name</error>");
1273
				out.close();
1274
				return;
1275
			}//if
1276

    
1277
			//try to open a https stream to test if the request server's public key
1278
			//in the key store, this is security issue
1279
			String testUrl = "https://" + server + "?server="
1280
            + MetacatUtil.getLocalReplicationServerName() + "&action=test";
1281
			logReplication.info("Running trust test: " + testUrl);
1282
			URL u = new URL(testUrl);
1283
			String test = ReplicationService.getURLContent(u);
1284
			logReplication.info("Ouput from test is '" + test + "'");
1285
			//couldn't pass the test
1286
			if (test.indexOf("successfully") == -1) {
1287
			    logReplication.error("Trust test failed.");
1288
				out.write("<error>Couldn't pass the trust test</error>");
1289
				out.close();
1290
				return;
1291
			}
1292
			logReplication.info("Trust test succeeded.");
1293

    
1294
			// Check if local host configure to replicate xml documents to remote
1295
			// server. If not send back a error message
1296
			if (!serverList.getReplicationValue(server)) {
1297
				out.write("<error>Configuration not allow to replicate document to you</error>");
1298
				out.close();
1299
				return;
1300
			}//if
1301

    
1302
			// Store the sql command
1303
			StringBuffer docsql = new StringBuffer();
1304
			StringBuffer revisionSql = new StringBuffer();
1305
			// Stroe the docid list
1306
			StringBuffer doclist = new StringBuffer();
1307
			// Store the deleted docid list
1308
			StringBuffer delsql = new StringBuffer();
1309
			// Store the data set file
1310
			Vector<Vector<String>> packageFiles = new Vector<Vector<String>>();
1311

    
1312
			// Append local server's name and replication servlet to doclist
1313
			doclist.append("<?xml version=\"1.0\"?><replication>");
1314
			doclist.append("<server>")
1315
					.append(MetacatUtil.getLocalReplicationServerName());
1316
			//doclist.append(util.getProperty("replicationpath"));
1317
			doclist.append("</server><updates>");
1318

    
1319
			// Get correct docid that reside on this server according the requesting
1320
			// server's replicate and data replicate value in xml_replication table
1321
			docsql.append(DatabaseService.getInstance().getDBAdapter().getReplicationDocumentListSQL());
1322
			//docsql.append("select docid, rev, doctype from xml_documents where (docid not in (select a.docid from xml_documents a, xml_revisions b where a.docid=b.docid and a.rev<=b.rev)) ");
1323
			revisionSql.append("select docid, rev, doctype from xml_revisions ");
1324
			// If the localhost is not a hub to the remote server, only replicate
1325
			// the docid' which home server is local host (server_location =1)
1326
			if (!serverList.getHubValue(server)) {
1327
				String serverLocationDoc = " and a.server_location = 1";
1328
				String serverLocationRev = "where server_location = 1";
1329
				docsql.append(serverLocationDoc);
1330
				revisionSql.append(serverLocationRev);
1331
			}
1332
			logReplication.info("ReplicationService.handleUpdateRequest - Doc sql: " + docsql.toString());
1333

    
1334
			// Get any deleted documents
1335
			delsql.append("select distinct docid from ");
1336
			delsql.append("xml_revisions where docid not in (select docid from ");
1337
			delsql.append("xml_documents) ");
1338
			// If the localhost is not a hub to the remote server, only replicate
1339
			// the docid' which home server is local host (server_location =1)
1340
			if (!serverList.getHubValue(server)) {
1341
				delsql.append("and server_location = 1");
1342
			}
1343
			logReplication.info("ReplicationService.handleUpdateRequest - Deleted sql: " + delsql.toString());
1344

    
1345
			// Get docid list of local host
1346
			pstmt = dbConn.prepareStatement(docsql.toString());
1347
			pstmt.execute();
1348
			ResultSet rs = pstmt.getResultSet();
1349
			boolean tablehasrows = rs.next();
1350
			//If metacat configed to replicate data file
1351
			//if ((util.getProperty("replicationsenddata")).equals("on"))
1352
			boolean replicateData = serverList.getDataReplicationValue(server);
1353
			if (replicateData) {
1354
				while (tablehasrows) {
1355
					String recordDoctype = rs.getString(3);
1356
					Vector<String> packagedoctypes = MetacatUtil
1357
							.getOptionList(PropertyService
1358
									.getProperty("xml.packagedoctype"));
1359
					//if this is a package file, put it at the end
1360
					//because if a package file is read before all of the files it
1361
					//refers to are loaded then there is an error
1362
					if (recordDoctype != null && !packagedoctypes.contains(recordDoctype)) {
1363
						//If this is not data file
1364
						if (!recordDoctype.equals("BIN")) {
1365
							//for non-data file document
1366
							doclist.append("<updatedDocument>");
1367
							doclist.append("<docid>").append(rs.getString(1));
1368
							doclist.append("</docid><rev>").append(rs.getInt(2));
1369
							doclist.append("</rev>");
1370
							doclist.append("</updatedDocument>");
1371
						}//if
1372
						else {
1373
							//for data file document, in datafile attributes
1374
							//we put "datafile" value there
1375
							doclist.append("<updatedDocument>");
1376
							doclist.append("<docid>").append(rs.getString(1));
1377
							doclist.append("</docid><rev>").append(rs.getInt(2));
1378
							doclist.append("</rev>");
1379
							doclist.append("<datafile>");
1380
							doclist.append(PropertyService
1381
									.getProperty("replication.datafileflag"));
1382
							doclist.append("</datafile>");
1383
							doclist.append("</updatedDocument>");
1384
						}//else
1385
					}//if packagedoctpes
1386
					else { //the package files are saved to be put into the xml later.
1387
						Vector<String> v = new Vector<String>();
1388
						v.add(rs.getString(1));
1389
						v.add(String.valueOf(rs.getInt(2)));
1390
						packageFiles.add(v);
1391
					}//esle
1392
					tablehasrows = rs.next();
1393
				}//while
1394
			}//if
1395
			else //metacat was configured not to send data file
1396
			{
1397
				while (tablehasrows) {
1398
					String recordDoctype = rs.getString(3);
1399
					if (!recordDoctype.equals("BIN")) { //don't replicate data files
1400
						Vector<String> packagedoctypes = MetacatUtil
1401
								.getOptionList(PropertyService
1402
										.getProperty("xml.packagedoctype"));
1403
						if (recordDoctype != null
1404
								&& !packagedoctypes.contains(recordDoctype)) { //if this is a package file, put it at the end
1405
							//because if a package file is read before all of the files it
1406
							//refers to are loaded then there is an error
1407
							doclist.append("<updatedDocument>");
1408
							doclist.append("<docid>").append(rs.getString(1));
1409
							doclist.append("</docid><rev>").append(rs.getInt(2));
1410
							doclist.append("</rev>");
1411
							doclist.append("</updatedDocument>");
1412
						} else { //the package files are saved to be put into the xml later.
1413
							Vector<String> v = new Vector<String>();
1414
							v.add(rs.getString(1));
1415
							v.add(String.valueOf(rs.getInt(2)));
1416
							packageFiles.add(v);
1417
						}
1418
					}//if
1419
					tablehasrows = rs.next();
1420
				}//while
1421
			}//else
1422

    
1423
			pstmt = dbConn.prepareStatement(delsql.toString());
1424
			//usage count should increas 1
1425
			dbConn.increaseUsageCount(1);
1426

    
1427
			pstmt.execute();
1428
			rs = pstmt.getResultSet();
1429
			tablehasrows = rs.next();
1430
			while (tablehasrows) { //handle the deleted documents
1431
				doclist.append("<deletedDocument><docid>").append(rs.getString(1));
1432
				doclist.append("</docid><rev></rev></deletedDocument>");
1433
				//note that rev is always empty for deleted docs
1434
				tablehasrows = rs.next();
1435
			}
1436

    
1437
			//now we can put the package files into the xml results
1438
			for (int i = 0; i < packageFiles.size(); i++) {
1439
				Vector<String> v = packageFiles.elementAt(i);
1440
				doclist.append("<updatedDocument>");
1441
				doclist.append("<docid>").append(v.elementAt(0));
1442
				doclist.append("</docid><rev>");
1443
				doclist.append(v.elementAt(1));
1444
				doclist.append("</rev>");
1445
				doclist.append("</updatedDocument>");
1446
			}
1447
			// add revision doc list  
1448
			doclist.append(prepareRevisionDoc(dbConn, revisionSql.toString(),
1449
					replicateData));
1450

    
1451
			doclist.append("</updates></replication>");
1452
			logReplication.info("ReplicationService.handleUpdateRequest - doclist: " + doclist.toString());
1453
			pstmt.close();
1454
			//conn.close();
1455
			out.write(doclist.toString());
1456

    
1457
		} catch (Exception e) {
1458
			logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1459
			logReplication.error("ReplicationService.handleUpdateRequest - error in MetacatReplication." + "handleupdaterequest: "
1460
					+ e.getMessage());
1461
			//e.printStackTrace(System.out);
1462
			try {
1463
				out.write("<error>" + e.getMessage() + "</error>");
1464
			} catch (IOException e1) {
1465
				logMetacat.error(e1.getMessage(), e1);
1466
			}
1467
		} finally {
1468
			try {
1469
				pstmt.close();
1470
			}//try
1471
			catch (SQLException ee) {
1472
				logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1473
				logReplication.error("ReplicationService.handleUpdateRequest - Error in MetacatReplication."
1474
						+ "handleUpdaterequest to close pstmt: " + ee.getMessage());
1475
			}//catch
1476
			finally {
1477
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1478
			}//finally
1479
			try {
1480
				out.close();
1481
			} catch (IOException e) {
1482
				logMetacat.error(e.getMessage(), e);
1483
			}
1484
		}//finally
1485

    
1486
	}//handlUpdateRequest
1487

    
1488
	/*
1489
	 * This method will get the xml string for document in xml_revision
1490
	 * The schema look like <!ELEMENT revisionDocument (docid, rev, datafile*)>
1491
	 */
1492
	private static String prepareRevisionDoc(DBConnection dbConn, String revSql,
1493
			boolean replicateData) throws Exception {
1494
		logReplication.warn("ReplicationService.prepareRevisionDoc - The revision document sql is " + revSql);
1495
		StringBuffer revDocList = new StringBuffer();
1496
		PreparedStatement pstmt = dbConn.prepareStatement(revSql);
1497
		//usage count should increas 1
1498
		dbConn.increaseUsageCount(1);
1499

    
1500
		pstmt.execute();
1501
		ResultSet rs = pstmt.getResultSet();
1502
		boolean tablehasrows = rs.next();
1503
		while (tablehasrows) {
1504
			String recordDoctype = rs.getString(3);
1505

    
1506
			//If this is data file and it isn't configured to replicate data
1507
			if (recordDoctype.equals("BIN") && !replicateData) {
1508
				// do nothing
1509
				continue;
1510
			} else {
1511

    
1512
				revDocList.append("<revisionDocument>");
1513
				revDocList.append("<docid>").append(rs.getString(1));
1514
				revDocList.append("</docid><rev>").append(rs.getInt(2));
1515
				revDocList.append("</rev>");
1516
				// data file
1517
				if (recordDoctype.equals("BIN")) {
1518
					revDocList.append("<datafile>");
1519
					revDocList.append(PropertyService
1520
							.getProperty("replication.datafileflag"));
1521
					revDocList.append("</datafile>");
1522
				}
1523
				revDocList.append("</revisionDocument>");
1524

    
1525
			}//else
1526
			tablehasrows = rs.next();
1527
		}
1528
		//System.out.println("The revision list is"+ revDocList.toString());
1529
		return revDocList.toString();
1530
	}
1531

    
1532
	/**
1533
	 * Returns the xml_catalog table encoded in xml
1534
	 */
1535
	public static String getCatalogXML() {
1536
		return handleGetCatalogRequest(null, null, false);
1537
	}
1538

    
1539
	/**
1540
	 * Sends the contents of the xml_catalog table encoded in xml
1541
	 * The xml format is:
1542
	 * <!ELEMENT xml_catalog (row*)>
1543
	 * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
1544
	 *                system_id)>
1545
	 * All of the sub elements of row are #PCDATA
1546

    
1547
	 * If printFlag == false then do not print to out.
1548
	 */
1549
	protected static String handleGetCatalogRequest(
1550
			Hashtable<String, String[]> params, HttpServletResponse response,
1551
			boolean printFlag) {
1552
		DBConnection dbConn = null;
1553
		int serialNumber = -1;
1554
		PreparedStatement pstmt = null;
1555
		Writer out = null;
1556
		try {
1557
			// get writer, TODO: encoding?
1558
			response.setContentType("text/xml");
1559
			out = response.getWriter();
1560
			
1561
			/*conn = MetacatReplication.getDBConnection("MetacatReplication." +
1562
			                                          "handleGetCatalogRequest");*/
1563
			dbConn = DBConnectionPool
1564
					.getDBConnection("MetacatReplication.handleGetCatalogRequest");
1565
			serialNumber = dbConn.getCheckOutSerialNumber();
1566
			pstmt = dbConn.prepareStatement("select entry_type, "
1567
					+ "source_doctype, target_doctype, public_id, "
1568
					+ "system_id from xml_catalog");
1569
			pstmt.execute();
1570
			ResultSet rs = pstmt.getResultSet();
1571
			boolean tablehasrows = rs.next();
1572
			StringBuffer sb = new StringBuffer();
1573
			sb.append("<?xml version=\"1.0\"?><xml_catalog>");
1574
			while (tablehasrows) {
1575
				sb.append("<row><entry_type>").append(rs.getString(1));
1576
				sb.append("</entry_type><source_doctype>").append(rs.getString(2));
1577
				sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
1578
				sb.append("</target_doctype><public_id>").append(rs.getString(4));
1579
				// system id may not have server url on front.  Add it if not.
1580
				String systemID = rs.getString(5);
1581
				if (!systemID.startsWith("http://")) {
1582
					systemID = SystemUtil.getContextURL() + systemID;
1583
				}
1584
				sb.append("</public_id><system_id>").append(systemID);
1585
				sb.append("</system_id></row>");
1586

    
1587
				tablehasrows = rs.next();
1588
			}
1589
			sb.append("</xml_catalog>");
1590
			//conn.close();
1591
			if (printFlag) {
1592
				response.setContentType("text/xml");
1593
				out.write(sb.toString());
1594
			}
1595
			pstmt.close();
1596
			return sb.toString();
1597
		} catch (Exception e) {
1598
			logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1599
			logReplication.error("ReplicationService.handleGetCatalogRequest - error in MetacatReplication.handleGetCatalogRequest:"
1600
					+ e.getMessage());
1601
			e.printStackTrace(System.out);
1602
			if (printFlag) {
1603
				try {
1604
					out.write("<error>" + e.getMessage() + "</error>");
1605
				} catch (IOException e1) {
1606
					logMetacat.error(e1.getMessage(), e1);
1607
				}
1608
			}
1609
		} finally {
1610
			try {
1611
				pstmt.close();
1612
			}//try
1613
			catch (SQLException ee) {
1614
				logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1615
				logReplication.error("ReplicationService.handleGetCatalogRequest - Error in MetacatReplication.handleGetCatalogRequest: "
1616
						+ ee.getMessage());
1617
			}//catch
1618
			finally {
1619
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1620
			}//finally
1621
			if (out != null) {
1622
				try {
1623
					out.close();
1624
				} catch (IOException e1) {
1625
					logMetacat.error(e1.getMessage(), e1);
1626
				}
1627
			}
1628
		}//finally
1629

    
1630
		return null;
1631
	}
1632

    
1633
	/**
1634
	 * Sends the current system date to the remote server.  Using this action
1635
	 * for replication gets rid of any problems with syncronizing clocks
1636
	 * because a time specific to a document is always kept on its home server.
1637
	 */
1638
	protected static void handleGetTimeRequest(
1639
			Hashtable<String, String[]> params, HttpServletResponse response) {
1640
		SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yy HH:mm:ss");
1641
		java.util.Date localtime = new java.util.Date();
1642
		String dateString = formatter.format(localtime);
1643
		
1644
		// get a writer for sending back to response
1645
		response.setContentType("text/xml");
1646
		Writer out = null;
1647
		try {
1648
			out = response.getWriter();
1649
			out.write("<timestamp>" + dateString + "</timestamp>");
1650
			out.close();
1651
		} catch (IOException e) {
1652
			logMetacat.error(e.getMessage(), e);
1653
		}
1654
		
1655
	}
1656

    
1657
	/**
1658
	 * this method handles the timeout for a file lock.  when a lock is
1659
	 * granted it is granted for 30 seconds.  When this thread runs out
1660
	 * it deletes the docid from the queue, thus eliminating the lock.
1661
	 */
1662
	public void run() {
1663
		try {
1664
			logReplication.info("ReplicationService.run - thread started for docid: "
1665
					+ (String) fileLocks.elementAt(0));
1666

    
1667
			Thread.sleep(30000); //the lock will expire in 30 seconds
1668
			logReplication.info("thread for docid: "
1669
					+ (String) fileLocks.elementAt(fileLocks.size() - 1) + " exiting.");
1670

    
1671
			fileLocks.remove(fileLocks.size() - 1);
1672
			//fileLocks is treated as a FIFO queue.  If there are more than one lock
1673
			//in the vector, the first one inserted will be removed.
1674
		} catch (Exception e) {
1675
			logMetacat.error("ReplicationService.run - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1676
			logReplication.error("ReplicationService.run - error in file lock thread from "
1677
					+ "MetacatReplication.run: " + e.getMessage());
1678
		}
1679
	}
1680

    
1681
	/**
1682
	 * Returns the name of a server given a serverCode
1683
	 * @param serverCode the serverid of the server
1684
	 * @return the servername or null if the specified serverCode does not
1685
	 *         exist.
1686
	 */
1687
	public static String getServerNameForServerCode(int serverCode) {
1688
		//System.out.println("serverid: " + serverCode);
1689
		DBConnection dbConn = null;
1690
		int serialNumber = -1;
1691
		PreparedStatement pstmt = null;
1692
		try {
1693
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServer");
1694
			serialNumber = dbConn.getCheckOutSerialNumber();
1695
			String sql = new String("select server from "
1696
					+ "xml_replication where serverid = " + serverCode);
1697
			pstmt = dbConn.prepareStatement(sql);
1698
			//System.out.println("getserver sql: " + sql);
1699
			pstmt.execute();
1700
			ResultSet rs = pstmt.getResultSet();
1701
			boolean tablehasrows = rs.next();
1702
			if (tablehasrows) {
1703
				//System.out.println("server: " + rs.getString(1));
1704
				return rs.getString(1);
1705
			}
1706

    
1707
			//conn.close();
1708
		} catch (Exception e) {
1709
			logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1710
			logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplication.getServer: " + e.getMessage());
1711
		} finally {
1712
			try {
1713
				pstmt.close();
1714
			}//try
1715
			catch (SQLException ee) {
1716
				logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1717
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacactReplication.getserver: "
1718
						+ ee.getMessage());
1719
			}//catch
1720
			finally {
1721
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1722
			}//fianlly
1723
		}//finally
1724

    
1725
		return null;
1726
		//return null if the server does not exist
1727
	}
1728

    
1729
	/**
1730
	 * Returns a server code given a server name
1731
	 * @param server the name of the server
1732
	 * @return integer > 0 representing the code of the server, 0 if the server
1733
	 *  does not exist.
1734
	 */
1735
	public static int getServerCodeForServerName(String server) throws ServiceException {
1736
		DBConnection dbConn = null;
1737
		int serialNumber = -1;
1738
		PreparedStatement pstmt = null;
1739
		int serverCode = 0;
1740

    
1741
		try {
1742

    
1743
			//conn = util.openDBConnection();
1744
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServerCode");
1745
			serialNumber = dbConn.getCheckOutSerialNumber();
1746
			pstmt = dbConn.prepareStatement("SELECT serverid FROM xml_replication "
1747
					+ "WHERE server LIKE '" + server + "'");
1748
			pstmt.execute();
1749
			ResultSet rs = pstmt.getResultSet();
1750
			boolean tablehasrows = rs.next();
1751
			if (tablehasrows) {
1752
				serverCode = rs.getInt(1);
1753
				pstmt.close();
1754
				//conn.close();
1755
				return serverCode;
1756
			}
1757

    
1758
		} catch (SQLException sqle) {
1759
			throw new ServiceException("ReplicationService.getServerCodeForServerName - " 
1760
					+ "SQL error when getting server code: " + sqle.getMessage());
1761

    
1762
		} finally {
1763
			try {
1764
				pstmt.close();
1765
				//conn.close();
1766
			}//try
1767
			catch (Exception ee) {
1768
				logMetacat.error("ReplicationService.getServerCodeForServerName - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1769
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplicatio.getServerCode: "
1770
						+ ee.getMessage());
1771

    
1772
			}//catch
1773
			finally {
1774
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1775
			}//finally
1776
		}//finally
1777

    
1778
		return serverCode;
1779
	}
1780

    
1781
	/**
1782
	 * Method to get a host server information for given docid
1783
	 * @param conn a connection to the database
1784
	 */
1785
	public static Hashtable<String, String> getHomeServerInfoForDocId(String docId) {
1786
		Hashtable<String, String> sl = new Hashtable<String, String>();
1787
		DBConnection dbConn = null;
1788
		int serialNumber = -1;
1789
		docId = DocumentUtil.getDocIdFromString(docId);
1790
		PreparedStatement pstmt = null;
1791
		int serverLocation;
1792
		try {
1793
			//get conection
1794
			dbConn = DBConnectionPool.getDBConnection("ReplicationHandler.getHomeServer");
1795
			serialNumber = dbConn.getCheckOutSerialNumber();
1796
			//get a server location from xml_document table
1797
			pstmt = dbConn.prepareStatement("select server_location from xml_documents "
1798
					+ "where docid = ?");
1799
			pstmt.setString(1, docId);
1800
			pstmt.execute();
1801
			ResultSet serverName = pstmt.getResultSet();
1802
			//get a server location
1803
			if (serverName.next()) {
1804
				serverLocation = serverName.getInt(1);
1805
				pstmt.close();
1806
			} else {
1807
				pstmt.close();
1808
				//ut.returnConnection(conn);
1809
				return null;
1810
			}
1811
			pstmt = dbConn.prepareStatement("select server, last_checked, replicate "
1812
					+ "from xml_replication where serverid = ?");
1813
			//increase usage count
1814
			dbConn.increaseUsageCount(1);
1815
			pstmt.setInt(1, serverLocation);
1816
			pstmt.execute();
1817
			ResultSet rs = pstmt.getResultSet();
1818
			boolean tableHasRows = rs.next();
1819
			if (tableHasRows) {
1820

    
1821
				String server = rs.getString(1);
1822
				String last_checked = rs.getString(2);
1823
				if (!server.equals("localhost")) {
1824
					sl.put(server, last_checked);
1825
				}
1826

    
1827
			} else {
1828
				pstmt.close();
1829
				//ut.returnConnection(conn);
1830
				return null;
1831
			}
1832
			pstmt.close();
1833
		} catch (Exception e) {
1834
			logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1835
			logReplication.error("ReplicationService.getHomeServerInfoForDocId - error in replicationHandler.getHomeServer(): "
1836
					+ e.getMessage());
1837
		} finally {
1838
			try {
1839
				pstmt.close();
1840
				//ut.returnConnection(conn);
1841
			} catch (Exception ee) {
1842
				logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1843
				logReplication.error("ReplicationService.getHomeServerInfoForDocId - Eror irn rplicationHandler.getHomeServer() "
1844
						+ "to close pstmt: " + ee.getMessage());
1845
			} finally {
1846
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1847
			}
1848

    
1849
		}//finally
1850
		return sl;
1851
	}
1852

    
1853
	/**
1854
	 * Returns a home server location  given a accnum
1855
	 * @param accNum , given accNum for a document
1856
	 *
1857
	 */
1858
	public static int getHomeServerCodeForDocId(String accNum) throws ServiceException {
1859
		DBConnection dbConn = null;
1860
		int serialNumber = -1;
1861
		PreparedStatement pstmt = null;
1862
		int serverCode = 1;
1863
		String docId = DocumentUtil.getDocIdFromString(accNum);
1864

    
1865
		try {
1866

    
1867
			// Get DBConnection
1868
			dbConn = DBConnectionPool
1869
					.getDBConnection("ReplicationHandler.getServerLocation");
1870
			serialNumber = dbConn.getCheckOutSerialNumber();
1871
			pstmt = dbConn.prepareStatement("SELECT server_location FROM xml_documents "
1872
					+ "WHERE docid LIKE '" + docId + "'");
1873
			pstmt.execute();
1874
			ResultSet rs = pstmt.getResultSet();
1875
			boolean tablehasrows = rs.next();
1876
			//If a document is find, return the server location for it
1877
			if (tablehasrows) {
1878
				serverCode = rs.getInt(1);
1879
				pstmt.close();
1880
				//conn.close();
1881
				return serverCode;
1882
			}
1883
			//if couldn't find in xml_documents table, we think server code is 1
1884
			//(this is new document)
1885
			else {
1886
				pstmt.close();
1887
				//conn.close();
1888
				return serverCode;
1889
			}
1890

    
1891
		} catch (SQLException sqle) {
1892
			throw new ServiceException("ReplicationService.getHomeServerCodeForDocId - " 
1893
					+ "SQL error when getting home server code for docid: " + docId + " : " 
1894
					+ sqle.getMessage());
1895

    
1896
		} finally {
1897
			try {
1898
				pstmt.close();
1899
				//conn.close();
1900

    
1901
			} catch (SQLException sqle) {
1902
				logMetacat.error("ReplicationService.getHomeServerCodeForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1903
				logReplication.error("ReplicationService.getHomeServerCodeForDocId - ReplicationService.getHomeServerCodeForDocId - " 
1904
						+ "SQL error when getting home server code for docid: " + docId + " : " 
1905
						+ sqle.getMessage());
1906
			} finally {
1907
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1908
			}//finally
1909
		}//finally
1910
		//return serverCode;
1911
	}
1912

    
1913
	/**
1914
	 * This method returns the content of a url
1915
	 * @param u the url to return the content from
1916
	 * @return a string representing the content of the url
1917
	 * @throws java.io.IOException
1918
	 */
1919
	public static String getURLContent(URL u) throws java.io.IOException {
1920
	    logReplication.info("Getting url content from " + u.toString());
1921
		char istreamChar;
1922
		int istreamInt;
1923
		logReplication.info("ReplicationService.getURLContent - Before open the stream" + u.toString());
1924
		InputStream input = u.openStream();
1925
		logReplication.info("ReplicationService.getURLContent - After open the stream" + u.toString());
1926
		InputStreamReader istream = new InputStreamReader(input);
1927
		StringBuffer serverResponse = new StringBuffer();
1928
		while ((istreamInt = istream.read()) != -1) {
1929
			istreamChar = (char) istreamInt;
1930
			serverResponse.append(istreamChar);
1931
		}
1932
		istream.close();
1933
		input.close();
1934

    
1935
		return serverResponse.toString();
1936
	}
1937

    
1938
//	/**
1939
//	 * Method for writing replication messages to a log file specified in
1940
//	 * metacat.properties
1941
//	 */
1942
//	public static void replLog(String message) {
1943
//		try {
1944
//			FileOutputStream fos = new FileOutputStream(PropertyService
1945
//					.getProperty("replication.logdir")
1946
//					+ "/metacatreplication.log", true);
1947
//			PrintWriter pw = new PrintWriter(fos);
1948
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
1949
//			java.util.Date localtime = new java.util.Date();
1950
//			String dateString = formatter.format(localtime);
1951
//			dateString += " :: " + message;
1952
//			// time stamp each entry
1953
//			pw.println(dateString);
1954
//			pw.flush();
1955
//		} catch (Exception e) {
1956
//			logReplication.error("error writing to replication log from "
1957
//					+ "MetacatReplication.replLog: " + e.getMessage());
1958
//			// e.printStackTrace(System.out);
1959
//		}
1960
//	}
1961

    
1962
//	/**
1963
//	 * Method for writing replication messages to a log file specified in
1964
//	 * metacat.properties
1965
//	 */
1966
//	public static void replErrorLog(String message) {
1967
//		try {
1968
//			FileOutputStream fos = new FileOutputStream(PropertyService
1969
//					.getProperty("replication.logdir")
1970
//					+ "/metacatreplicationerror.log", true);
1971
//			PrintWriter pw = new PrintWriter(fos);
1972
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
1973
//			java.util.Date localtime = new java.util.Date();
1974
//			String dateString = formatter.format(localtime);
1975
//			dateString += " :: " + message;
1976
//			//time stamp each entry
1977
//			pw.println(dateString);
1978
//			pw.flush();
1979
//		} catch (Exception e) {
1980
//			logReplication.error("error writing to replication error log from "
1981
//					+ "MetacatReplication.replErrorLog: " + e.getMessage());
1982
//			//e.printStackTrace(System.out);
1983
//		}
1984
//	}
1985

    
1986
	/**
1987
	 * Returns true if the replicate field for server in xml_replication is 1.
1988
	 * Returns false otherwise
1989
	 */
1990
	public static boolean replToServer(String server) {
1991
		DBConnection dbConn = null;
1992
		int serialNumber = -1;
1993
		PreparedStatement pstmt = null;
1994
		try {
1995
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.repltoServer");
1996
			serialNumber = dbConn.getCheckOutSerialNumber();
1997
			pstmt = dbConn.prepareStatement("select replicate from "
1998
					+ "xml_replication where server like '" + server + "'");
1999
			pstmt.execute();
2000
			ResultSet rs = pstmt.getResultSet();
2001
			boolean tablehasrows = rs.next();
2002
			if (tablehasrows) {
2003
				int i = rs.getInt(1);
2004
				if (i == 1) {
2005
					pstmt.close();
2006
					//conn.close();
2007
					return true;
2008
				} else {
2009
					pstmt.close();
2010
					//conn.close();
2011
					return false;
2012
				}
2013
			}
2014
		} catch (SQLException sqle) {
2015
			logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2016
			logReplication.error("ReplicationService.replToServer - SQL error in MetacatReplication.replToServer: "
2017
					+ sqle.getMessage());
2018
		} finally {
2019
			try {
2020
				pstmt.close();
2021
				//conn.close();
2022
			}//try
2023
			catch (Exception ee) {
2024
				logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2025
				logReplication.error("ReplicationService.replToServer - Error in MetacatReplication.replToServer: "
2026
						+ ee.getMessage());
2027
			}//catch
2028
			finally {
2029
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2030
			}//finally
2031
		}//finally
2032
		return false;
2033
		//the default if this server does not exist is to not replicate to it.
2034
	}
2035

    
2036
}
(6-6/7)