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: leinfelder $'
9
 *     '$Date: 2011-05-25 11:59:00 -0700 (Wed, 25 May 2011) $'
10
 * '$Revision: 6099 $'
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.dataone.service.types.SystemMetadata;
58
import org.xml.sax.InputSource;
59
import org.xml.sax.SAXException;
60
import org.xml.sax.XMLReader;
61

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

    
88
public class ReplicationService extends BaseService {
89

    
90
	private static ReplicationService replicationService = null;
91

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

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

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

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

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

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

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

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

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

    
178
	public boolean refreshable() {
179
		return true;
180
	}
181

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
418
				out.write("<error>Unkonwn subaction</error>");
419

    
420
			}
421
			pstmt.close();
422
			//conn.close();
423

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

    
450
	}
451

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

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

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

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

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

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

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

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

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

    
552
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
553

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

    
561
			
562
			// Get home server of this docid
563
			String homeServer = (String) docinfoHash.get("home_server");
564
			String guid = (String) docinfoHash.get("guid");
565
			logReplication.debug("GUID found in docinfoHash: " + guid);
566
			
567
			logReplication.debug("Processing guid " + guid + 
568
			  " information from handleForceReplicationRequest: " + 
569
			  docinfoHash.toString());
570
			
571
			//if the guid was passed in, we have system metadata with the doc
572
			if (guid != null) {
573
				// map the guid to local identifiers
574
	        	if (dbaction.equalsIgnoreCase("UPDATE")) {
575
	        		logReplication.info("updating mapping: guid: " + guid + " localId: " + docinfoHash.get("docid"));
576
	        		IdentifierManager.getInstance().updateMapping(guid, docinfoHash.get("docid"));
577
	        	} else { // insert
578
		            logReplication.info("creating mapping: guid: " + guid + " localId: " + docinfoHash.get("docid"));
579
		            IdentifierManager.getInstance().createMapping(guid, docinfoHash.get("docid"));
580
	        	}
581
	        	// process system metadata
582
	        	logReplication.info("handleForceReplicateRequest: updating system metadata");
583
	        	Date dateUploaded = new Date(new Long(docinfoHash.get("date_uploaded")));
584
		        Date dateModified = new Date(new Long(docinfoHash.get("date_modified")));
585
	            SystemMetadata sysMeta = IdentifierManager.getInstance().asSystemMetadata(
586
	                    dateUploaded, 
587
	                    docinfoHash.get("rights_holder"),
588
	                    docinfoHash.get("checksum"), 
589
	                    docinfoHash.get("checksum_algorithm"), 
590
	                    docinfoHash.get("origin_member_node"),
591
	                    docinfoHash.get("authoritive_member_node"), 
592
	                    dateModified,
593
	                    docinfoHash.get("submitter"),
594
	                    docinfoHash.get("guid"),
595
	                    docinfoHash.get("object_format"),
596
	                    new Long(docinfoHash.get("size")).longValue());
597
	        	if (dbaction.equalsIgnoreCase("INSERT")) {
598
		            logReplication.info("Adding systemMetadata for guid: " + guid);
599
		            IdentifierManager.getInstance().createSystemMetadata(sysMeta);
600
	        	}
601
	            IdentifierManager.getInstance().updateSystemMetadata(sysMeta);
602
			}
603
      
604
        	// replicate doc contents
605
			String createdDate = (String) docinfoHash.get("date_created");
606
			String updatedDate = (String) docinfoHash.get("date_updated");
607
			logReplication.info("ReplicationService.handleForceReplicateRequest - homeServer: " + homeServer);
608
			// Get Document type
609
			String docType = (String) docinfoHash.get("doctype");
610
			logReplication.info("ReplicationService.handleForceReplicateRequest - docType: " + docType);
611
			String parserBase = null;
612
			// this for eml2 and we need user eml2 parser
613
			if (docType != null
614
					&& (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE)) {
615
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml200 document!");
616
				parserBase = DocumentImpl.EML200;
617
			} else if (docType != null
618
					&& (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE)) {
619
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.0.1 document!");
620
				parserBase = DocumentImpl.EML200;
621
			} else if (docType != null
622
					&& (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE)) {
623
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.0 document!");
624
				parserBase = DocumentImpl.EML210;
625
			} else if (docType != null
626
					&& (docType.trim()).equals(DocumentImpl.EML2_1_1NAMESPACE)) {
627
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.1 document!");
628
				parserBase = DocumentImpl.EML210;
629
			}
630
			logReplication.warn("ReplicationService.handleForceReplicateRequest - The parserBase is: " + parserBase);
631

    
632
			// Get DBConnection from pool
633
			dbConn = DBConnectionPool
634
					.getDBConnection("MetacatReplication.handleForceReplicateRequest");
635
			serialNumber = dbConn.getCheckOutSerialNumber();
636
			// write the document to local database
637
			DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false);
638
			//try this independently so we can set access even if the update action is invalid (i.e docid has not changed)
639
			try {
640
				wrapper.writeReplication(dbConn, xmldoc, null, null,
641
						dbaction, docid, null, null, homeServer, server, createdDate,
642
						updatedDate);
643
			} finally {
644

    
645
				//process extra access rules before dealing with the write exception (doc exist already)			
646
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
647
		        if (accessControlList != null) {
648
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
649
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
650
		        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
651
		        			acfsf.insertPermissions(xmlAccessDAO);
652
							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
653
									+ " permissions added to DB");
654
		        		}
655
		            }
656
		        }
657
		        
658
		        // process the real owner and updater
659
				String user = (String) docinfoHash.get("user_owner");
660
				String updated = (String) docinfoHash.get("user_updated");
661
		        updateUserOwner(dbConn, docid, user, updated);
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, dbaction);
680
			}
681
		} catch (SQLException sqle) {
682
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
683
			logReplication.error("ReplicationService.handleForceReplicateRequest - SQL error when adding doc " + docid + 
684
					" to DB with action " + dbaction + ": " + sqle.getMessage());
685
		} catch (MalformedURLException mue) {
686
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
687
			logReplication.error("ReplicationService.handleForceReplicateRequest - URL error when adding doc " + docid + 
688
					" to DB with action " + dbaction + ": " + mue.getMessage());
689
		} catch (SAXException se) {
690
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
691
			logReplication.error("ReplicationService.handleForceReplicateRequest - SAX parsing error when adding doc " + docid + 
692
					" to DB with action " + dbaction + ": " + se.getMessage());
693
		} catch (HandlerException he) {
694
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
695
			logReplication.error("ReplicationService.handleForceReplicateRequest - Handler error when adding doc " + docid + 
696
					" to DB with action " + dbaction + ": " + he.getMessage());
697
		} catch (IOException ioe) {
698
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
699
			logReplication.error("ReplicationService.handleForceReplicateRequest - I/O error when adding doc " + docid + 
700
					" to DB with action " + dbaction + ": " + ioe.getMessage());
701
		} catch (PermOrderException poe) {
702
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
703
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
704
					" to DB with action " + dbaction + ": " + poe.getMessage());
705
		} catch (AccessControlException ace) {
706
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
707
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
708
					" to DB with action " + dbaction + ": " + ace.getMessage());
709
		} catch (Exception e) {
710
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
711
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when adding doc " + docid + 
712
					" to DB with action " + dbaction + ": " + e.getMessage());
713
		} finally {
714
			// Return the checked out DBConnection
715
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
716
		}//finally
717
	}
718

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

    
759
		}//catch
760

    
761
	}
762

    
763
	/**
764
	 * when a forcereplication data file request comes in, local host sends a
765
	 * readdata request to the requesting server (remote server) for the specified
766
	 * docid. Then store it in local database and file system
767
	 */
768
	protected static void handleForceReplicateDataFileRequest(Hashtable<String, String[]> params,
769
			HttpServletRequest request) {
770

    
771
		//make sure there is some parameters
772
		if (params.isEmpty()) {
773
			return;
774
		}
775
		// Get remote server
776
		String server = ((String[]) params.get("server"))[0];
777
		// the docid should include rev number
778
		String docid = ((String[]) params.get("docid"))[0];
779
		// Make sure there is a docid and server
780
		if (docid == null || server == null || server.equals("")) {
781
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
782
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Didn't specify docid or server for replication");
783
			return;
784
		}
785

    
786
		// Overide or not
787
		//    boolean override = false;
788
		// dbaction - update or insert
789
		String dbaction = null;
790

    
791
		try {
792
			//docid was switch to two parts uinque code and rev
793
			//String uniqueCode=MetacatUtil.getDocIdFromString(docid);
794
			//int rev=MetacatUtil.getVersionFromString(docid);
795
			if (params.containsKey("dbaction")) {
796
				dbaction = ((String[]) params.get("dbaction"))[0];
797
			} else//default value is update
798
			{
799
				dbaction = "update";
800
			}
801

    
802
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication request from: " + server);
803
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication docid: " + docid);
804
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication action: " + dbaction);
805
			// get the document info from server
806
			URL docinfourl = new URL("https://" + server + "?server="
807
					+ MetacatUtil.getLocalReplicationServerName()
808
					+ "&action=getdocumentinfo&docid=" + docid);
809

    
810
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
811

    
812
			//dih is the parser for the docinfo xml format
813
			DocInfoHandler dih = new DocInfoHandler();
814
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
815
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
816
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
817
			
818
			String docName = (String) docinfoHash.get("docname");
819

    
820
			String docType = (String) docinfoHash.get("doctype");
821

    
822
			String docHomeServer = (String) docinfoHash.get("home_server");
823

    
824
			String createdDate = (String) docinfoHash.get("date_created");
825

    
826
			String updatedDate = (String) docinfoHash.get("date_updated");
827
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - docHomeServer of datafile: " + docHomeServer);
828

    
829
			if (dbaction.equals("insert") || dbaction.equals("update")) {
830
				//Get data file and store it into local file system.
831
				// sending back readdata request to server
832
				URL url = new URL("https://" + server + "?server="
833
						+ MetacatUtil.getLocalReplicationServerName()
834
						+ "&action=readdata&docid=" + docid);
835
				String datafilePath = PropertyService
836
						.getProperty("application.datafilepath");
837

    
838
				Exception writeException = null;
839
				//register data file into xml_documents table and wite data file
840
				//into file system
841
				try {
842
					DocumentImpl.writeDataFileInReplication(url.openStream(),
843
							datafilePath, docName, docType, docid, null, docHomeServer,
844
							server, DocumentImpl.DOCUMENTTABLE, false, createdDate,
845
							updatedDate);
846
				} catch (Exception e) {
847
					writeException = e;
848
				}
849
				
850
				// process the real owner and updater
851
				DBConnection dbConn = DBConnectionPool.getDBConnection("ReplicationService.handleForceDataFileRequest");
852
		        int serialNumber = dbConn.getCheckOutSerialNumber();
853
		        dbConn.setAutoCommit(false);
854
				String user = (String) docinfoHash.get("user_owner");
855
				String updated = (String) docinfoHash.get("user_updated");
856
		        updateUserOwner(dbConn, docid, user, updated);
857
		        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
858
		        
859
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
860
		        if (accessControlList != null) {
861
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
862
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
863
		        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
864
		        			acfsf.insertPermissions(xmlAccessDAO);
865
							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
866
									+ " permissions added to DB");
867
		        		}
868
		            }
869
		        }
870
		        
871
				String guid = (String) docinfoHash.get("guid");
872
				//if the guid was passed in, we have system metadata with the doc
873
				if (guid != null) {
874
					// map the guid to local identifiers
875
		        	if (dbaction.equalsIgnoreCase("UPDATE")) {
876
		        		logReplication.info("updating mapping: guid: " + guid + " localId: " + docinfoHash.get("docid"));
877
		        		IdentifierManager.getInstance().updateMapping(guid, docinfoHash.get("docid"));
878
		        	} else { // insert
879
			            logReplication.info("creating mapping: guid: " + guid + " localId: " + docinfoHash.get("docid"));
880
			            IdentifierManager.getInstance().createMapping(guid, docinfoHash.get("docid"));
881
		        	}
882
		        	// process system metadata
883
		        	logReplication.info("handleForceReplicateRequest: updating system metadata");
884
		        	Date dateUploaded = new Date(new Long(docinfoHash.get("date_uploaded")));
885
			        Date dateModified = new Date(new Long(docinfoHash.get("date_modified")));
886
		            SystemMetadata sysMeta = IdentifierManager.getInstance().asSystemMetadata(
887
		                    dateUploaded, 
888
		                    docinfoHash.get("rights_holder"),
889
		                    docinfoHash.get("checksum"), 
890
		                    docinfoHash.get("checksum_algorithm"), 
891
		                    docinfoHash.get("origin_member_node"),
892
		                    docinfoHash.get("authoritive_member_node"), 
893
		                    dateModified,
894
		                    docinfoHash.get("submitter"),
895
		                    docinfoHash.get("guid"),
896
		                    docinfoHash.get("object_format"),
897
		                    new Long(docinfoHash.get("size")).longValue());
898
		        	if (dbaction.equalsIgnoreCase("INSERT")) {
899
			            logReplication.info("Adding systemMetadata for guid: " + guid);
900
			            IdentifierManager.getInstance().createSystemMetadata(sysMeta);
901
		        	}
902
		            IdentifierManager.getInstance().updateSystemMetadata(sysMeta);
903
				}
904

    
905
				if (writeException != null) {
906
					throw writeException;
907
				}
908

    
909
				logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - datafile " + docid + " added to DB with "
910
						+ "action " + dbaction);
911
				EventLog.getInstance().log(request.getRemoteAddr(), REPLICATIONUSER,
912
						docid, dbaction);
913
			}
914

    
915
		} catch (Exception e) {
916
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
917
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Datafile " + docid
918
					+ " failed to added to DB with " + "action " + dbaction + " because "
919
					+ e.getMessage());
920
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - ERROR in MetacatReplication.handleForceDataFileReplicate"
921
					+ "Request(): " + e.getMessage());
922
		}
923
	}
924

    
925
	/**
926
	 * Grants or denies a lock to a requesting host.
927
	 * The servlet parameters of interrest are:
928
	 * docid: the docid of the file the lock is being requested for
929
	 * currentdate: the timestamp of the document on the remote server
930
	 *
931
	 */
932
	protected static void handleGetLockRequest(
933
			Hashtable<String, String[]> params, HttpServletResponse response) {
934

    
935
		try {
936

    
937
			String docid = ((String[]) params.get("docid"))[0];
938
			String remoteRev = ((String[]) params.get("updaterev"))[0];
939
			DocumentImpl requestDoc = new DocumentImpl(docid);
940
			logReplication.info("ReplicationService.handleGetLockRequest - lock request for " + docid);
941
			int localRevInt = requestDoc.getRev();
942
			int remoteRevInt = Integer.parseInt(remoteRev);
943

    
944
			// get a writer for sending back to response
945
			response.setContentType("text/xml");
946
			Writer out = response.getWriter();
947
			
948
			if (remoteRevInt >= localRevInt) {
949
				if (!fileLocks.contains(docid)) { //grant the lock if it is not already locked
950
					fileLocks.add(0, docid); //insert at the beginning of the queue Vector
951
					//send a message back to the the remote host authorizing the insert
952
					out.write("<lockgranted><docid>" + docid
953
									+ "</docid></lockgranted>");
954
					//          lockThread = new Thread(this);
955
					//          lockThread.setPriority(Thread.MIN_PRIORITY);
956
					//          lockThread.start();
957
					logReplication.info("ReplicationService.handleGetLockRequest - lock granted for " + docid);
958
				} else { //deny the lock
959
					out.write("<filelocked><docid>" + docid + "</docid></filelocked>");
960
					logReplication.info("ReplicationService.handleGetLockRequest - lock denied for " + docid
961
							+ "reason: file already locked");
962
				}
963
			} else {//deny the lock.
964
				out.write("<outdatedfile><docid>" + docid + "</docid></filelocked>");
965
				logReplication.info("ReplicationService.handleGetLockRequest - lock denied for " + docid
966
						+ "reason: client has outdated file");
967
			}
968
			out.close();
969
			//conn.close();
970
		} catch (Exception e) {
971
			logMetacat.error("ReplicationService.handleGetLockRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
972
			logReplication.error("ReplicationService.handleGetLockRequest - error requesting file lock from MetacatReplication."
973
					+ "handleGetLockRequest: " + e.getMessage());
974
			e.printStackTrace(System.out);
975
		}
976
	}
977

    
978
	/**
979
	 * Sends all of the xml_documents information encoded in xml to a requestor
980
	 * the format is:
981
	 * <!ELEMENT documentinfo (docid, docname, doctype, doctitle, user_owner,
982
	 *                  user_updated, home_server, public_access, rev)/>
983
	 * all of the subelements of document info are #PCDATA
984
	 */
985
	protected static void handleGetDocumentInfoRequest(
986
			Hashtable<String, String[]> params, HttpServletResponse response) {
987
		String docid = ((String[]) (params.get("docid")))[0];
988
		StringBuffer sb = new StringBuffer();
989

    
990
		try {
991
		  IdentifierManager idman = IdentifierManager.getInstance();
992

    
993
			DocumentImpl doc = new DocumentImpl(docid);
994
			sb.append("<documentinfo><docid>").append(docid);
995
			sb.append("</docid>");
996
			try
997
			{
998
			  String guid = idman.getGUID(doc.getDocID(), doc.getRev());
999
			  sb.append("<guid>").append(guid).append("</guid>");
1000
			  Hashtable<String, String> sysmetaInfo = idman.getSystemMetadataInfo(guid);
1001
			  
1002
			  Enumeration<String> sysmetaKeys = sysmetaInfo.keys();
1003
			  while(sysmetaKeys.hasMoreElements())
1004
			  {
1005
			      String key = sysmetaKeys.nextElement();
1006
			      sb.append("<" + key + ">" + sysmetaInfo.get(key).toString() + "</" + key + ">");
1007
			  }
1008
			  
1009
			}
1010
			catch(McdbDocNotFoundException e)
1011
			{
1012
			  //do nothing, there was no guid for this document
1013
			}
1014
			sb.append("<docname>").append(doc.getDocname());
1015
			sb.append("</docname><doctype>").append(doc.getDoctype());
1016
			sb.append("</doctype>");
1017
			sb.append("<user_owner>").append(doc.getUserowner());
1018
			sb.append("</user_owner><user_updated>").append(doc.getUserupdated());
1019
			sb.append("</user_updated>");
1020
			sb.append("<date_created>");
1021
			sb.append(doc.getCreateDate());
1022
			sb.append("</date_created>");
1023
			sb.append("<date_updated>");
1024
			sb.append(doc.getUpdateDate());
1025
			sb.append("</date_updated>");
1026
			sb.append("<home_server>");
1027
			sb.append(doc.getDocHomeServer());
1028
			sb.append("</home_server>");
1029
			sb.append("<public_access>").append(doc.getPublicaccess());
1030
			sb.append("</public_access><rev>").append(doc.getRev());
1031
			sb.append("</rev>");
1032

    
1033
			sb.append("<accessControl>");
1034

    
1035
			AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid); 
1036
			sb.append(acfsf.getAccessString());
1037
			
1038
			sb.append("</accessControl>");
1039

    
1040
			sb.append("</documentinfo>");
1041
			// get a writer for sending back to response
1042
			response.setContentType("text/xml");
1043
			Writer out = response.getWriter();
1044
			out.write(sb.toString());
1045
			out.close();
1046

    
1047
		} catch (Exception e) {
1048
			logMetacat.error("ReplicationService.handleGetDocumentInfoRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1049
			logReplication.error("ReplicationService.handleGetDocumentInfoRequest - error in metacatReplication.handlegetdocumentinforequest "
1050
					+ "for doc: " + docid + " : " + e.getMessage());
1051
		}
1052

    
1053
	}
1054

    
1055
	/**
1056
	 * Sends a datafile to a remote host
1057
	 */
1058
	protected static void handleGetDataFileRequest(OutputStream outPut,
1059
			Hashtable<String, String[]> params, HttpServletResponse response)
1060

    
1061
	{
1062
		// File path for data file
1063
		String filepath;
1064
		// Request docid
1065
		String docId = ((String[]) (params.get("docid")))[0];
1066
		//check if the doicd is null
1067
		if (docId == null) {
1068
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1069
			logReplication.error("ReplicationService.handleGetDataFileRequest - Didn't specify docid for replication");
1070
			return;
1071
		}
1072

    
1073
		//try to open a https stream to test if the request server's public key
1074
		//in the key store, this is security issue
1075
		try {
1076
			filepath = PropertyService.getProperty("application.datafilepath");
1077
			String server = params.get("server")[0];
1078
			URL u = new URL("https://" + server + "?server="
1079
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test");
1080
			String test = ReplicationService.getURLContent(u);
1081
			//couldn't pass the test
1082
			if (test.indexOf("successfully") == -1) {
1083
				//response.setContentType("text/xml");
1084
				//outPut.println("<error>Couldn't pass the trust test</error>");
1085
				logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1086
				logReplication.error("ReplicationService.handleGetDataFileRequest - Couldn't pass the trust test");
1087
				return;
1088
			}
1089
		}//try
1090
		catch (Exception ee) {
1091
			return;
1092
		}//catch
1093

    
1094
		if (!filepath.endsWith("/")) {
1095
			filepath += "/";
1096
		}
1097
		// Get file aboslute file name
1098
		String filename = filepath + docId;
1099

    
1100
		//MIME type
1101
		String contentType = null;
1102
		if (filename.endsWith(".xml")) {
1103
			contentType = "text/xml";
1104
		} else if (filename.endsWith(".css")) {
1105
			contentType = "text/css";
1106
		} else if (filename.endsWith(".dtd")) {
1107
			contentType = "text/plain";
1108
		} else if (filename.endsWith(".xsd")) {
1109
			contentType = "text/xml";
1110
		} else if (filename.endsWith("/")) {
1111
			contentType = "text/html";
1112
		} else {
1113
			File f = new File(filename);
1114
			if (f.isDirectory()) {
1115
				contentType = "text/html";
1116
			} else {
1117
				contentType = "application/octet-stream";
1118
			}
1119
		}
1120

    
1121
		// Set the mime type
1122
		response.setContentType(contentType);
1123

    
1124
		// Get the content of the file
1125
		FileInputStream fin = null;
1126
		try {
1127
			// FileInputStream to metacat
1128
			fin = new FileInputStream(filename);
1129
			// 4K buffer
1130
			byte[] buf = new byte[4 * 1024];
1131
			// Read data from file input stream to byte array
1132
			int b = fin.read(buf);
1133
			// Write to outStream from byte array
1134
			while (b != -1) {
1135
				outPut.write(buf, 0, b);
1136
				b = fin.read(buf);
1137
			}
1138
			// close file input stream
1139
			fin.close();
1140

    
1141
		}//try
1142
		catch (Exception e) {
1143
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1144
			logReplication.error("ReplicationService.handleGetDataFileRequest - error getting data file from MetacatReplication."
1145
					+ "handlGetDataFileRequest " + e.getMessage());
1146
			e.printStackTrace(System.out);
1147
		}//catch
1148

    
1149
	}
1150

    
1151
	/**
1152
	 * Sends a document to a remote host
1153
	 */
1154
	protected static void handleGetDocumentRequest(
1155
			Hashtable<String, String[]> params, HttpServletResponse response) {
1156

    
1157
		String urlString = null;
1158
		String documentPath = null;
1159
		String errorMsg = null;
1160
		try {
1161
			// try to open a https stream to test if the request server's public
1162
			// key
1163
			// in the key store, this is security issue
1164
			String server = params.get("server")[0];
1165
			urlString = "https://" + server + "?server="
1166
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test";
1167
			URL u = new URL(urlString);
1168
			String test = ReplicationService.getURLContent(u);
1169
			// couldn't pass the test
1170
			if (test.indexOf("successfully") == -1) {
1171
				response.setContentType("text/xml");
1172
				Writer out = response.getWriter();
1173
				out.write("<error>Couldn't pass the trust test " + test + " </error>");
1174
				out.close();
1175
				return;
1176
			}
1177

    
1178
			String docid = params.get("docid")[0];
1179
			logReplication.debug("ReplicationService.handleGetDocumentRequest - MetacatReplication.handleGetDocumentRequest for docid: "
1180
					+ docid);
1181
			DocumentImpl di = new DocumentImpl(docid);
1182

    
1183
			String documentDir = PropertyService
1184
					.getProperty("application.documentfilepath");
1185
			documentPath = documentDir + FileUtil.getFS() + docid;
1186

    
1187
			// if the document does not exist on disk, read it from db and write
1188
			// it to disk.
1189
			if (FileUtil.getFileStatus(documentPath) == FileUtil.DOES_NOT_EXIST
1190
					|| FileUtil.getFileSize(documentPath) == 0) {
1191
				FileOutputStream fos = new FileOutputStream(documentPath);
1192
				di.toXml(fos, null, null, true);
1193
			}
1194

    
1195
			// read the file from disk and send it to outputstream
1196
			OutputStream outputStream = response.getOutputStream();
1197
			di.readFromFileSystem(outputStream, null, null, documentPath);
1198

    
1199
			logReplication.info("ReplicationService.handleGetDocumentRequest - document " + docid + " sent");
1200

    
1201
			// return to avoid continuing to the error reporting section at the end
1202
			return;
1203
			
1204
		} catch (MalformedURLException mue) {
1205
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1206
			logReplication.error("ReplicationService.handleGetDocumentRequest - Url error when getting document from MetacatReplication."
1207
					+ "handlGetDocumentRequest for url: " + urlString + " : "
1208
					+ mue.getMessage());
1209
			// e.printStackTrace(System.out);
1210
			
1211
		} catch (IOException ioe) {
1212
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1213
			logReplication.error("ReplicationService.handleGetDocumentRequest - I/O error when getting document from MetacatReplication."
1214
					+ "handlGetDocumentRequest for file: " + documentPath + " : "
1215
					+ ioe.getMessage());
1216
			errorMsg = ioe.getMessage();
1217
		} catch (PropertyNotFoundException pnfe) {
1218
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1219
			logReplication
1220
					.error("ReplicationService.handleGetDocumentRequest - Error getting property when getting document from MetacatReplication."
1221
							+ "handlGetDocumentRequest for file: "
1222
							+ documentPath
1223
							+ " : "
1224
							+ pnfe.getMessage());
1225
			// e.printStackTrace(System.out);
1226
			errorMsg = pnfe.getMessage();
1227
		} catch (McdbException me) {
1228
			logReplication
1229
					.error("ReplicationService.handleGetDocumentRequest - Document implementation error  getting property when getting document from MetacatReplication."
1230
							+ "handlGetDocumentRequest for file: "
1231
							+ documentPath
1232
							+ " : "
1233
							+ me.getMessage());
1234
			// e.printStackTrace(System.out);
1235
			errorMsg = me.getMessage();
1236
		}
1237
		
1238
		// report any errors if we got here
1239
		response.setContentType("text/xml");
1240
		Writer out = null;
1241
		try {
1242
			response.getWriter();
1243
			out = response.getWriter();
1244
			out.write("<error>" + errorMsg + "</error>");
1245
		} catch (Exception e) {
1246
			logMetacat.error(e.getMessage(), e);
1247
		} finally {
1248
			try {
1249
				out.close();
1250
			} catch (IOException e) {
1251
				logMetacat.error(e.getMessage(), e);
1252
			}
1253
		}
1254
		
1255

    
1256
	}
1257

    
1258
	/**
1259
	 * Sends a list of all of the documents on this sever along with their
1260
	 * revision numbers. The format is: <!ELEMENT replication (server, updates)>
1261
	 * <!ELEMENT server (#PCDATA)> <!ELEMENT updates ((updatedDocument |
1262
	 * deleteDocument | revisionDocument)*)> <!ELEMENT updatedDocument (docid,
1263
	 * rev, datafile*)> <!ELEMENT deletedDocument (docid, rev)> <!ELEMENT
1264
	 * revisionDocument (docid, rev, datafile*)> <!ELEMENT docid (#PCDATA)>
1265
	 * <!ELEMENT rev (#PCDATA)> <!ELEMENT datafile (#PCDATA)> note that the rev
1266
	 * in deletedDocument is always empty. I just left it in there to make the
1267
	 * parser implementation easier.
1268
	 */
1269
	protected static void handleUpdateRequest(Hashtable<String, String[]> params,
1270
			HttpServletResponse response) {
1271
		// Checked out DBConnection
1272
		DBConnection dbConn = null;
1273
		// DBConenction serial number when checked it out
1274
		int serialNumber = -1;
1275
		PreparedStatement pstmt = null;
1276
		// Server list to store server info of xml_replication table
1277
		ReplicationServerList serverList = null;
1278
		
1279
		// a writer for response
1280
		Writer out = null;
1281

    
1282
		try {
1283
			// get writer, TODO: encoding?
1284
			response.setContentType("text/xml");
1285
			out = response.getWriter();
1286
			
1287
			// Check out a DBConnection from pool
1288
			dbConn = DBConnectionPool
1289
					.getDBConnection("MetacatReplication.handleUpdateRequest");
1290
			serialNumber = dbConn.getCheckOutSerialNumber();
1291
			// Create a server list from xml_replication table
1292
			serverList = new ReplicationServerList();
1293

    
1294
			// Get remote server name from param
1295
			String server = ((String[]) params.get("server"))[0];
1296
			// If no servr name in param, return a error
1297
			if (server == null || server.equals("")) {
1298
				out.write("<error>Request didn't specify server name</error>");
1299
				out.close();
1300
				return;
1301
			}//if
1302

    
1303
			//try to open a https stream to test if the request server's public key
1304
			//in the key store, this is security issue
1305
			String testUrl = "https://" + server + "?server="
1306
            + MetacatUtil.getLocalReplicationServerName() + "&action=test";
1307
			logReplication.info("Running trust test: " + testUrl);
1308
			URL u = new URL(testUrl);
1309
			String test = ReplicationService.getURLContent(u);
1310
			logReplication.info("Ouput from test is '" + test + "'");
1311
			//couldn't pass the test
1312
			if (test.indexOf("successfully") == -1) {
1313
			    logReplication.error("Trust test failed.");
1314
				out.write("<error>Couldn't pass the trust test</error>");
1315
				out.close();
1316
				return;
1317
			}
1318
			logReplication.info("Trust test succeeded.");
1319

    
1320
			// Check if local host configure to replicate xml documents to remote
1321
			// server. If not send back a error message
1322
			if (!serverList.getReplicationValue(server)) {
1323
				out.write("<error>Configuration not allow to replicate document to you</error>");
1324
				out.close();
1325
				return;
1326
			}//if
1327

    
1328
			// Store the sql command
1329
			StringBuffer docsql = new StringBuffer();
1330
			StringBuffer revisionSql = new StringBuffer();
1331
			// Stroe the docid list
1332
			StringBuffer doclist = new StringBuffer();
1333
			// Store the deleted docid list
1334
			StringBuffer delsql = new StringBuffer();
1335
			// Store the data set file
1336
			Vector<Vector<String>> packageFiles = new Vector<Vector<String>>();
1337

    
1338
			// Append local server's name and replication servlet to doclist
1339
			doclist.append("<?xml version=\"1.0\"?><replication>");
1340
			doclist.append("<server>")
1341
					.append(MetacatUtil.getLocalReplicationServerName());
1342
			//doclist.append(util.getProperty("replicationpath"));
1343
			doclist.append("</server><updates>");
1344

    
1345
			// Get correct docid that reside on this server according the requesting
1346
			// server's replicate and data replicate value in xml_replication table
1347
			docsql.append(DatabaseService.getInstance().getDBAdapter().getReplicationDocumentListSQL());
1348
			//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)) ");
1349
			revisionSql.append("select docid, rev, doctype from xml_revisions ");
1350
			// If the localhost is not a hub to the remote server, only replicate
1351
			// the docid' which home server is local host (server_location =1)
1352
			if (!serverList.getHubValue(server)) {
1353
				String serverLocationDoc = " and a.server_location = 1";
1354
				String serverLocationRev = "where server_location = 1";
1355
				docsql.append(serverLocationDoc);
1356
				revisionSql.append(serverLocationRev);
1357
			}
1358
			logReplication.info("ReplicationService.handleUpdateRequest - Doc sql: " + docsql.toString());
1359

    
1360
			// Get any deleted documents
1361
			delsql.append("select distinct docid from ");
1362
			delsql.append("xml_revisions where docid not in (select docid from ");
1363
			delsql.append("xml_documents) ");
1364
			// If the localhost is not a hub to the remote server, only replicate
1365
			// the docid' which home server is local host (server_location =1)
1366
			if (!serverList.getHubValue(server)) {
1367
				delsql.append("and server_location = 1");
1368
			}
1369
			logReplication.info("ReplicationService.handleUpdateRequest - Deleted sql: " + delsql.toString());
1370

    
1371
			// Get docid list of local host
1372
			pstmt = dbConn.prepareStatement(docsql.toString());
1373
			pstmt.execute();
1374
			ResultSet rs = pstmt.getResultSet();
1375
			boolean tablehasrows = rs.next();
1376
			//If metacat configed to replicate data file
1377
			//if ((util.getProperty("replicationsenddata")).equals("on"))
1378
			boolean replicateData = serverList.getDataReplicationValue(server);
1379
			if (replicateData) {
1380
				while (tablehasrows) {
1381
					String recordDoctype = rs.getString(3);
1382
					Vector<String> packagedoctypes = MetacatUtil
1383
							.getOptionList(PropertyService
1384
									.getProperty("xml.packagedoctype"));
1385
					//if this is a package file, put it at the end
1386
					//because if a package file is read before all of the files it
1387
					//refers to are loaded then there is an error
1388
					if (recordDoctype != null && !packagedoctypes.contains(recordDoctype)) {
1389
						//If this is not data file
1390
						if (!recordDoctype.equals("BIN")) {
1391
							//for non-data file document
1392
							doclist.append("<updatedDocument>");
1393
							doclist.append("<docid>").append(rs.getString(1));
1394
							doclist.append("</docid><rev>").append(rs.getInt(2));
1395
							doclist.append("</rev>");
1396
							doclist.append("</updatedDocument>");
1397
						}//if
1398
						else {
1399
							//for data file document, in datafile attributes
1400
							//we put "datafile" value there
1401
							doclist.append("<updatedDocument>");
1402
							doclist.append("<docid>").append(rs.getString(1));
1403
							doclist.append("</docid><rev>").append(rs.getInt(2));
1404
							doclist.append("</rev>");
1405
							doclist.append("<datafile>");
1406
							doclist.append(PropertyService
1407
									.getProperty("replication.datafileflag"));
1408
							doclist.append("</datafile>");
1409
							doclist.append("</updatedDocument>");
1410
						}//else
1411
					}//if packagedoctpes
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
					}//esle
1418
					tablehasrows = rs.next();
1419
				}//while
1420
			}//if
1421
			else //metacat was configured not to send data file
1422
			{
1423
				while (tablehasrows) {
1424
					String recordDoctype = rs.getString(3);
1425
					if (!recordDoctype.equals("BIN")) { //don't replicate data files
1426
						Vector<String> packagedoctypes = MetacatUtil
1427
								.getOptionList(PropertyService
1428
										.getProperty("xml.packagedoctype"));
1429
						if (recordDoctype != null
1430
								&& !packagedoctypes.contains(recordDoctype)) { //if this is a package file, put it at the end
1431
							//because if a package file is read before all of the files it
1432
							//refers to are loaded then there is an error
1433
							doclist.append("<updatedDocument>");
1434
							doclist.append("<docid>").append(rs.getString(1));
1435
							doclist.append("</docid><rev>").append(rs.getInt(2));
1436
							doclist.append("</rev>");
1437
							doclist.append("</updatedDocument>");
1438
						} else { //the package files are saved to be put into the xml later.
1439
							Vector<String> v = new Vector<String>();
1440
							v.add(rs.getString(1));
1441
							v.add(String.valueOf(rs.getInt(2)));
1442
							packageFiles.add(v);
1443
						}
1444
					}//if
1445
					tablehasrows = rs.next();
1446
				}//while
1447
			}//else
1448

    
1449
			pstmt = dbConn.prepareStatement(delsql.toString());
1450
			//usage count should increas 1
1451
			dbConn.increaseUsageCount(1);
1452

    
1453
			pstmt.execute();
1454
			rs = pstmt.getResultSet();
1455
			tablehasrows = rs.next();
1456
			while (tablehasrows) { //handle the deleted documents
1457
				doclist.append("<deletedDocument><docid>").append(rs.getString(1));
1458
				doclist.append("</docid><rev></rev></deletedDocument>");
1459
				//note that rev is always empty for deleted docs
1460
				tablehasrows = rs.next();
1461
			}
1462

    
1463
			//now we can put the package files into the xml results
1464
			for (int i = 0; i < packageFiles.size(); i++) {
1465
				Vector<String> v = packageFiles.elementAt(i);
1466
				doclist.append("<updatedDocument>");
1467
				doclist.append("<docid>").append(v.elementAt(0));
1468
				doclist.append("</docid><rev>");
1469
				doclist.append(v.elementAt(1));
1470
				doclist.append("</rev>");
1471
				doclist.append("</updatedDocument>");
1472
			}
1473
			// add revision doc list  
1474
			doclist.append(prepareRevisionDoc(dbConn, revisionSql.toString(),
1475
					replicateData));
1476

    
1477
			doclist.append("</updates></replication>");
1478
			logReplication.info("ReplicationService.handleUpdateRequest - doclist: " + doclist.toString());
1479
			pstmt.close();
1480
			//conn.close();
1481
			out.write(doclist.toString());
1482

    
1483
		} catch (Exception e) {
1484
			logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1485
			logReplication.error("ReplicationService.handleUpdateRequest - error in MetacatReplication." + "handleupdaterequest: "
1486
					+ e.getMessage());
1487
			//e.printStackTrace(System.out);
1488
			try {
1489
				out.write("<error>" + e.getMessage() + "</error>");
1490
			} catch (IOException e1) {
1491
				logMetacat.error(e1.getMessage(), e1);
1492
			}
1493
		} finally {
1494
			try {
1495
				pstmt.close();
1496
			}//try
1497
			catch (SQLException ee) {
1498
				logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1499
				logReplication.error("ReplicationService.handleUpdateRequest - Error in MetacatReplication."
1500
						+ "handleUpdaterequest to close pstmt: " + ee.getMessage());
1501
			}//catch
1502
			finally {
1503
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1504
			}//finally
1505
			try {
1506
				out.close();
1507
			} catch (IOException e) {
1508
				logMetacat.error(e.getMessage(), e);
1509
			}
1510
		}//finally
1511

    
1512
	}//handlUpdateRequest
1513

    
1514
	/**
1515
	 * 
1516
	 * @param dbConn connection for doing the update
1517
	 * @param docid the document id to update
1518
	 * @param owner the user_owner
1519
	 * @param updater the user_updated
1520
	 * @throws SQLException
1521
	 */
1522
	public static void updateUserOwner(DBConnection dbConn, String docid, String owner, String updater) throws SQLException {
1523
	
1524
		String sql = 
1525
			"UPDATE xml_documents " +
1526
			"SET user_owner = ?, " +
1527
			"user_updated = ? " +
1528
			"WHERE docid = ?;";
1529
		PreparedStatement pstmt = dbConn.prepareStatement(sql);
1530
		//usage count should increas 1
1531
		dbConn.increaseUsageCount(1);
1532

    
1533
		docid = DocumentUtil.getSmartDocId(docid);
1534
		pstmt.setString(1, owner);
1535
		pstmt.setString(2, updater);
1536
		pstmt.setString(3, docid);
1537
		pstmt.execute();
1538
		pstmt.close();
1539
		
1540
		dbConn.commit();
1541
	}
1542
	
1543
	/*
1544
	 * This method will get the xml string for document in xml_revision
1545
	 * The schema look like <!ELEMENT revisionDocument (docid, rev, datafile*)>
1546
	 */
1547
	private static String prepareRevisionDoc(DBConnection dbConn, String revSql,
1548
			boolean replicateData) throws Exception {
1549
		logReplication.warn("ReplicationService.prepareRevisionDoc - The revision document sql is " + revSql);
1550
		StringBuffer revDocList = new StringBuffer();
1551
		PreparedStatement pstmt = dbConn.prepareStatement(revSql);
1552
		//usage count should increas 1
1553
		dbConn.increaseUsageCount(1);
1554

    
1555
		pstmt.execute();
1556
		ResultSet rs = pstmt.getResultSet();
1557
		boolean tablehasrows = rs.next();
1558
		while (tablehasrows) {
1559
			String recordDoctype = rs.getString(3);
1560

    
1561
			//If this is data file and it isn't configured to replicate data
1562
			if (recordDoctype.equals("BIN") && !replicateData) {
1563
				// do nothing
1564
				continue;
1565
			} else {
1566

    
1567
				revDocList.append("<revisionDocument>");
1568
				revDocList.append("<docid>").append(rs.getString(1));
1569
				revDocList.append("</docid><rev>").append(rs.getInt(2));
1570
				revDocList.append("</rev>");
1571
				// data file
1572
				if (recordDoctype.equals("BIN")) {
1573
					revDocList.append("<datafile>");
1574
					revDocList.append(PropertyService
1575
							.getProperty("replication.datafileflag"));
1576
					revDocList.append("</datafile>");
1577
				}
1578
				revDocList.append("</revisionDocument>");
1579

    
1580
			}//else
1581
			tablehasrows = rs.next();
1582
		}
1583
		//System.out.println("The revision list is"+ revDocList.toString());
1584
		return revDocList.toString();
1585
	}
1586

    
1587
	/**
1588
	 * Returns the xml_catalog table encoded in xml
1589
	 */
1590
	public static String getCatalogXML() {
1591
		return handleGetCatalogRequest(null, null, false);
1592
	}
1593

    
1594
	/**
1595
	 * Sends the contents of the xml_catalog table encoded in xml
1596
	 * The xml format is:
1597
	 * <!ELEMENT xml_catalog (row*)>
1598
	 * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
1599
	 *                system_id)>
1600
	 * All of the sub elements of row are #PCDATA
1601

    
1602
	 * If printFlag == false then do not print to out.
1603
	 */
1604
	protected static String handleGetCatalogRequest(
1605
			Hashtable<String, String[]> params, HttpServletResponse response,
1606
			boolean printFlag) {
1607
		DBConnection dbConn = null;
1608
		int serialNumber = -1;
1609
		PreparedStatement pstmt = null;
1610
		Writer out = null;
1611
		try {
1612
			// get writer, TODO: encoding?
1613
		    if(printFlag)
1614
		    {
1615
		        response.setContentType("text/xml");
1616
		        out = response.getWriter();
1617
		    }
1618
			/*conn = MetacatReplication.getDBConnection("MetacatReplication." +
1619
			                                          "handleGetCatalogRequest");*/
1620
			dbConn = DBConnectionPool
1621
					.getDBConnection("MetacatReplication.handleGetCatalogRequest");
1622
			serialNumber = dbConn.getCheckOutSerialNumber();
1623
			pstmt = dbConn.prepareStatement("select entry_type, "
1624
					+ "source_doctype, target_doctype, public_id, "
1625
					+ "system_id from xml_catalog");
1626
			pstmt.execute();
1627
			ResultSet rs = pstmt.getResultSet();
1628
			boolean tablehasrows = rs.next();
1629
			StringBuffer sb = new StringBuffer();
1630
			sb.append("<?xml version=\"1.0\"?><xml_catalog>");
1631
			while (tablehasrows) {
1632
				sb.append("<row><entry_type>").append(rs.getString(1));
1633
				sb.append("</entry_type><source_doctype>").append(rs.getString(2));
1634
				sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
1635
				sb.append("</target_doctype><public_id>").append(rs.getString(4));
1636
				// system id may not have server url on front.  Add it if not.
1637
				String systemID = rs.getString(5);
1638
				if (!systemID.startsWith("http://")) {
1639
					systemID = SystemUtil.getContextURL() + systemID;
1640
				}
1641
				sb.append("</public_id><system_id>").append(systemID);
1642
				sb.append("</system_id></row>");
1643

    
1644
				tablehasrows = rs.next();
1645
			}
1646
			sb.append("</xml_catalog>");
1647
			//conn.close();
1648
			if (printFlag) {
1649
				response.setContentType("text/xml");
1650
				out.write(sb.toString());
1651
			}
1652
			pstmt.close();
1653
			return sb.toString();
1654
		} catch (Exception e) {
1655
			logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1656
			logReplication.error("ReplicationService.handleGetCatalogRequest - error in MetacatReplication.handleGetCatalogRequest:"
1657
					+ e.getMessage());
1658
			e.printStackTrace(System.out);
1659
			if (printFlag) {
1660
				try {
1661
					out.write("<error>" + e.getMessage() + "</error>");
1662
				} catch (IOException e1) {
1663
					logMetacat.error(e1.getMessage(), e1);
1664
				}
1665
			}
1666
		} finally {
1667
			try {
1668
				pstmt.close();
1669
			}//try
1670
			catch (SQLException ee) {
1671
				logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1672
				logReplication.error("ReplicationService.handleGetCatalogRequest - Error in MetacatReplication.handleGetCatalogRequest: "
1673
						+ ee.getMessage());
1674
			}//catch
1675
			finally {
1676
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1677
			}//finally
1678
			if (out != null) {
1679
				try {
1680
					out.close();
1681
				} catch (IOException e1) {
1682
					logMetacat.error(e1.getMessage(), e1);
1683
				}
1684
			}
1685
		}//finally
1686

    
1687
		return null;
1688
	}
1689

    
1690
	/**
1691
	 * Sends the current system date to the remote server.  Using this action
1692
	 * for replication gets rid of any problems with syncronizing clocks
1693
	 * because a time specific to a document is always kept on its home server.
1694
	 */
1695
	protected static void handleGetTimeRequest(
1696
			Hashtable<String, String[]> params, HttpServletResponse response) {
1697
		SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yy HH:mm:ss");
1698
		java.util.Date localtime = new java.util.Date();
1699
		String dateString = formatter.format(localtime);
1700
		
1701
		// get a writer for sending back to response
1702
		response.setContentType("text/xml");
1703
		Writer out = null;
1704
		try {
1705
			out = response.getWriter();
1706
			out.write("<timestamp>" + dateString + "</timestamp>");
1707
			out.close();
1708
		} catch (IOException e) {
1709
			logMetacat.error(e.getMessage(), e);
1710
		}
1711
		
1712
	}
1713

    
1714
	/**
1715
	 * this method handles the timeout for a file lock.  when a lock is
1716
	 * granted it is granted for 30 seconds.  When this thread runs out
1717
	 * it deletes the docid from the queue, thus eliminating the lock.
1718
	 */
1719
	public void run() {
1720
		try {
1721
			logReplication.info("ReplicationService.run - thread started for docid: "
1722
					+ (String) fileLocks.elementAt(0));
1723

    
1724
			Thread.sleep(30000); //the lock will expire in 30 seconds
1725
			logReplication.info("thread for docid: "
1726
					+ (String) fileLocks.elementAt(fileLocks.size() - 1) + " exiting.");
1727

    
1728
			fileLocks.remove(fileLocks.size() - 1);
1729
			//fileLocks is treated as a FIFO queue.  If there are more than one lock
1730
			//in the vector, the first one inserted will be removed.
1731
		} catch (Exception e) {
1732
			logMetacat.error("ReplicationService.run - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1733
			logReplication.error("ReplicationService.run - error in file lock thread from "
1734
					+ "MetacatReplication.run: " + e.getMessage());
1735
		}
1736
	}
1737

    
1738
	/**
1739
	 * Returns the name of a server given a serverCode
1740
	 * @param serverCode the serverid of the server
1741
	 * @return the servername or null if the specified serverCode does not
1742
	 *         exist.
1743
	 */
1744
	public static String getServerNameForServerCode(int serverCode) {
1745
		//System.out.println("serverid: " + serverCode);
1746
		DBConnection dbConn = null;
1747
		int serialNumber = -1;
1748
		PreparedStatement pstmt = null;
1749
		try {
1750
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServer");
1751
			serialNumber = dbConn.getCheckOutSerialNumber();
1752
			String sql = new String("select server from "
1753
					+ "xml_replication where serverid = " + serverCode);
1754
			pstmt = dbConn.prepareStatement(sql);
1755
			//System.out.println("getserver sql: " + sql);
1756
			pstmt.execute();
1757
			ResultSet rs = pstmt.getResultSet();
1758
			boolean tablehasrows = rs.next();
1759
			if (tablehasrows) {
1760
				//System.out.println("server: " + rs.getString(1));
1761
				return rs.getString(1);
1762
			}
1763

    
1764
			//conn.close();
1765
		} catch (Exception e) {
1766
			logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1767
			logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplication.getServer: " + e.getMessage());
1768
		} finally {
1769
			try {
1770
				pstmt.close();
1771
			}//try
1772
			catch (SQLException ee) {
1773
				logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1774
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacactReplication.getserver: "
1775
						+ ee.getMessage());
1776
			}//catch
1777
			finally {
1778
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1779
			}//fianlly
1780
		}//finally
1781

    
1782
		return null;
1783
		//return null if the server does not exist
1784
	}
1785

    
1786
	/**
1787
	 * Returns a server code given a server name
1788
	 * @param server the name of the server
1789
	 * @return integer > 0 representing the code of the server, 0 if the server
1790
	 *  does not exist.
1791
	 */
1792
	public static int getServerCodeForServerName(String server) throws ServiceException {
1793
		DBConnection dbConn = null;
1794
		int serialNumber = -1;
1795
		PreparedStatement pstmt = null;
1796
		int serverCode = 0;
1797

    
1798
		try {
1799

    
1800
			//conn = util.openDBConnection();
1801
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServerCode");
1802
			serialNumber = dbConn.getCheckOutSerialNumber();
1803
			pstmt = dbConn.prepareStatement("SELECT serverid FROM xml_replication "
1804
					+ "WHERE server LIKE '" + server + "'");
1805
			pstmt.execute();
1806
			ResultSet rs = pstmt.getResultSet();
1807
			boolean tablehasrows = rs.next();
1808
			if (tablehasrows) {
1809
				serverCode = rs.getInt(1);
1810
				pstmt.close();
1811
				//conn.close();
1812
				return serverCode;
1813
			}
1814

    
1815
		} catch (SQLException sqle) {
1816
			throw new ServiceException("ReplicationService.getServerCodeForServerName - " 
1817
					+ "SQL error when getting server code: " + sqle.getMessage());
1818

    
1819
		} finally {
1820
			try {
1821
				pstmt.close();
1822
				//conn.close();
1823
			}//try
1824
			catch (Exception ee) {
1825
				logMetacat.error("ReplicationService.getServerCodeForServerName - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1826
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplicatio.getServerCode: "
1827
						+ ee.getMessage());
1828

    
1829
			}//catch
1830
			finally {
1831
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1832
			}//finally
1833
		}//finally
1834

    
1835
		return serverCode;
1836
	}
1837

    
1838
	/**
1839
	 * Method to get a host server information for given docid
1840
	 * @param conn a connection to the database
1841
	 */
1842
	public static Hashtable<String, String> getHomeServerInfoForDocId(String docId) {
1843
		Hashtable<String, String> sl = new Hashtable<String, String>();
1844
		DBConnection dbConn = null;
1845
		int serialNumber = -1;
1846
		docId = DocumentUtil.getDocIdFromString(docId);
1847
		PreparedStatement pstmt = null;
1848
		int serverLocation;
1849
		try {
1850
			//get conection
1851
			dbConn = DBConnectionPool.getDBConnection("ReplicationHandler.getHomeServer");
1852
			serialNumber = dbConn.getCheckOutSerialNumber();
1853
			//get a server location from xml_document table
1854
			pstmt = dbConn.prepareStatement("select server_location from xml_documents "
1855
					+ "where docid = ?");
1856
			pstmt.setString(1, docId);
1857
			pstmt.execute();
1858
			ResultSet serverName = pstmt.getResultSet();
1859
			//get a server location
1860
			if (serverName.next()) {
1861
				serverLocation = serverName.getInt(1);
1862
				pstmt.close();
1863
			} else {
1864
				pstmt.close();
1865
				//ut.returnConnection(conn);
1866
				return null;
1867
			}
1868
			pstmt = dbConn.prepareStatement("select server, last_checked, replicate "
1869
					+ "from xml_replication where serverid = ?");
1870
			//increase usage count
1871
			dbConn.increaseUsageCount(1);
1872
			pstmt.setInt(1, serverLocation);
1873
			pstmt.execute();
1874
			ResultSet rs = pstmt.getResultSet();
1875
			boolean tableHasRows = rs.next();
1876
			if (tableHasRows) {
1877

    
1878
				String server = rs.getString(1);
1879
				String last_checked = rs.getString(2);
1880
				if (!server.equals("localhost")) {
1881
					sl.put(server, last_checked);
1882
				}
1883

    
1884
			} else {
1885
				pstmt.close();
1886
				//ut.returnConnection(conn);
1887
				return null;
1888
			}
1889
			pstmt.close();
1890
		} catch (Exception e) {
1891
			logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1892
			logReplication.error("ReplicationService.getHomeServerInfoForDocId - error in replicationHandler.getHomeServer(): "
1893
					+ e.getMessage());
1894
		} finally {
1895
			try {
1896
				pstmt.close();
1897
				//ut.returnConnection(conn);
1898
			} catch (Exception ee) {
1899
				logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1900
				logReplication.error("ReplicationService.getHomeServerInfoForDocId - Eror irn rplicationHandler.getHomeServer() "
1901
						+ "to close pstmt: " + ee.getMessage());
1902
			} finally {
1903
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1904
			}
1905

    
1906
		}//finally
1907
		return sl;
1908
	}
1909

    
1910
	/**
1911
	 * Returns a home server location  given a accnum
1912
	 * @param accNum , given accNum for a document
1913
	 *
1914
	 */
1915
	public static int getHomeServerCodeForDocId(String accNum) throws ServiceException {
1916
		DBConnection dbConn = null;
1917
		int serialNumber = -1;
1918
		PreparedStatement pstmt = null;
1919
		int serverCode = 1;
1920
		String docId = DocumentUtil.getDocIdFromString(accNum);
1921

    
1922
		try {
1923

    
1924
			// Get DBConnection
1925
			dbConn = DBConnectionPool
1926
					.getDBConnection("ReplicationHandler.getServerLocation");
1927
			serialNumber = dbConn.getCheckOutSerialNumber();
1928
			pstmt = dbConn.prepareStatement("SELECT server_location FROM xml_documents "
1929
					+ "WHERE docid LIKE '" + docId + "'");
1930
			pstmt.execute();
1931
			ResultSet rs = pstmt.getResultSet();
1932
			boolean tablehasrows = rs.next();
1933
			//If a document is find, return the server location for it
1934
			if (tablehasrows) {
1935
				serverCode = rs.getInt(1);
1936
				pstmt.close();
1937
				//conn.close();
1938
				return serverCode;
1939
			}
1940
			//if couldn't find in xml_documents table, we think server code is 1
1941
			//(this is new document)
1942
			else {
1943
				pstmt.close();
1944
				//conn.close();
1945
				return serverCode;
1946
			}
1947

    
1948
		} catch (SQLException sqle) {
1949
			throw new ServiceException("ReplicationService.getHomeServerCodeForDocId - " 
1950
					+ "SQL error when getting home server code for docid: " + docId + " : " 
1951
					+ sqle.getMessage());
1952

    
1953
		} finally {
1954
			try {
1955
				pstmt.close();
1956
				//conn.close();
1957

    
1958
			} catch (SQLException sqle) {
1959
				logMetacat.error("ReplicationService.getHomeServerCodeForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1960
				logReplication.error("ReplicationService.getHomeServerCodeForDocId - ReplicationService.getHomeServerCodeForDocId - " 
1961
						+ "SQL error when getting home server code for docid: " + docId + " : " 
1962
						+ sqle.getMessage());
1963
			} finally {
1964
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1965
			}//finally
1966
		}//finally
1967
		//return serverCode;
1968
	}
1969

    
1970
	/**
1971
	 * This method returns the content of a url
1972
	 * @param u the url to return the content from
1973
	 * @return a string representing the content of the url
1974
	 * @throws java.io.IOException
1975
	 */
1976
	public static String getURLContent(URL u) throws java.io.IOException {
1977
	    logReplication.info("Getting url content from " + u.toString());
1978
		char istreamChar;
1979
		int istreamInt;
1980
		logReplication.info("ReplicationService.getURLContent - Before open the stream" + u.toString());
1981
		InputStream input = u.openStream();
1982
		logReplication.info("ReplicationService.getURLContent - After open the stream" + u.toString());
1983
		InputStreamReader istream = new InputStreamReader(input);
1984
		StringBuffer serverResponse = new StringBuffer();
1985
		while ((istreamInt = istream.read()) != -1) {
1986
			istreamChar = (char) istreamInt;
1987
			serverResponse.append(istreamChar);
1988
		}
1989
		istream.close();
1990
		input.close();
1991

    
1992
		return serverResponse.toString();
1993
	}
1994

    
1995
//	/**
1996
//	 * Method for writing replication messages to a log file specified in
1997
//	 * metacat.properties
1998
//	 */
1999
//	public static void replLog(String message) {
2000
//		try {
2001
//			FileOutputStream fos = new FileOutputStream(PropertyService
2002
//					.getProperty("replication.logdir")
2003
//					+ "/metacatreplication.log", true);
2004
//			PrintWriter pw = new PrintWriter(fos);
2005
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
2006
//			java.util.Date localtime = new java.util.Date();
2007
//			String dateString = formatter.format(localtime);
2008
//			dateString += " :: " + message;
2009
//			// time stamp each entry
2010
//			pw.println(dateString);
2011
//			pw.flush();
2012
//		} catch (Exception e) {
2013
//			logReplication.error("error writing to replication log from "
2014
//					+ "MetacatReplication.replLog: " + e.getMessage());
2015
//			// e.printStackTrace(System.out);
2016
//		}
2017
//	}
2018

    
2019
//	/**
2020
//	 * Method for writing replication messages to a log file specified in
2021
//	 * metacat.properties
2022
//	 */
2023
//	public static void replErrorLog(String message) {
2024
//		try {
2025
//			FileOutputStream fos = new FileOutputStream(PropertyService
2026
//					.getProperty("replication.logdir")
2027
//					+ "/metacatreplicationerror.log", true);
2028
//			PrintWriter pw = new PrintWriter(fos);
2029
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
2030
//			java.util.Date localtime = new java.util.Date();
2031
//			String dateString = formatter.format(localtime);
2032
//			dateString += " :: " + message;
2033
//			//time stamp each entry
2034
//			pw.println(dateString);
2035
//			pw.flush();
2036
//		} catch (Exception e) {
2037
//			logReplication.error("error writing to replication error log from "
2038
//					+ "MetacatReplication.replErrorLog: " + e.getMessage());
2039
//			//e.printStackTrace(System.out);
2040
//		}
2041
//	}
2042

    
2043
	/**
2044
	 * Returns true if the replicate field for server in xml_replication is 1.
2045
	 * Returns false otherwise
2046
	 */
2047
	public static boolean replToServer(String server) {
2048
		DBConnection dbConn = null;
2049
		int serialNumber = -1;
2050
		PreparedStatement pstmt = null;
2051
		try {
2052
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.repltoServer");
2053
			serialNumber = dbConn.getCheckOutSerialNumber();
2054
			pstmt = dbConn.prepareStatement("select replicate from "
2055
					+ "xml_replication where server like '" + server + "'");
2056
			pstmt.execute();
2057
			ResultSet rs = pstmt.getResultSet();
2058
			boolean tablehasrows = rs.next();
2059
			if (tablehasrows) {
2060
				int i = rs.getInt(1);
2061
				if (i == 1) {
2062
					pstmt.close();
2063
					//conn.close();
2064
					return true;
2065
				} else {
2066
					pstmt.close();
2067
					//conn.close();
2068
					return false;
2069
				}
2070
			}
2071
		} catch (SQLException sqle) {
2072
			logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2073
			logReplication.error("ReplicationService.replToServer - SQL error in MetacatReplication.replToServer: "
2074
					+ sqle.getMessage());
2075
		} finally {
2076
			try {
2077
				pstmt.close();
2078
				//conn.close();
2079
			}//try
2080
			catch (Exception ee) {
2081
				logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2082
				logReplication.error("ReplicationService.replToServer - Error in MetacatReplication.replToServer: "
2083
						+ ee.getMessage());
2084
			}//catch
2085
			finally {
2086
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2087
			}//finally
2088
		}//finally
2089
		return false;
2090
		//the default if this server does not exist is to not replicate to it.
2091
	}
2092

    
2093
}
(6-6/7)