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: 2012-08-23 21:45:07 -0700 (Thu, 23 Aug 2012) $'
10
 * '$Revision: 7358 $'
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.ByteArrayInputStream;
30
import java.io.ByteArrayOutputStream;
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.security.PrivateKey;
44
import java.security.cert.X509Certificate;
45
import java.sql.PreparedStatement;
46
import java.sql.ResultSet;
47
import java.sql.SQLException;
48
import java.sql.Timestamp;
49
import java.util.Calendar;
50
import java.util.Date;
51
import java.util.Hashtable;
52
import java.util.Timer;
53
import java.util.Vector;
54

    
55
import javax.servlet.http.HttpServletRequest;
56
import javax.servlet.http.HttpServletResponse;
57

    
58
import org.apache.http.HttpResponse;
59
import org.apache.http.conn.scheme.Scheme;
60
import org.apache.http.conn.ssl.SSLSocketFactory;
61
import org.apache.log4j.Logger;
62
import org.dataone.client.RestClient;
63
import org.dataone.client.auth.CertificateManager;
64
import org.dataone.service.types.v1.SystemMetadata;
65
import org.dataone.service.util.DateTimeMarshaller;
66
import org.dataone.service.util.TypeMarshaller;
67
import org.jibx.runtime.JiBXException;
68
import org.xml.sax.InputSource;
69
import org.xml.sax.SAXException;
70
import org.xml.sax.XMLReader;
71

    
72
import edu.ucsb.nceas.metacat.DocInfoHandler;
73
import edu.ucsb.nceas.metacat.DocumentImpl;
74
import edu.ucsb.nceas.metacat.DocumentImplWrapper;
75
import edu.ucsb.nceas.metacat.EventLog;
76
import edu.ucsb.nceas.metacat.IdentifierManager;
77
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
78
import edu.ucsb.nceas.metacat.McdbException;
79
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlException;
80
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlForSingleFile;
81
import edu.ucsb.nceas.metacat.accesscontrol.PermOrderException;
82
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessDAO;
83
import edu.ucsb.nceas.metacat.admin.upgrade.dataone.GenerateORE;
84
import edu.ucsb.nceas.metacat.admin.upgrade.dataone.GenerateSystemMetadata;
85
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
86
import edu.ucsb.nceas.metacat.database.DBConnection;
87
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
88
import edu.ucsb.nceas.metacat.database.DatabaseService;
89
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
90
import edu.ucsb.nceas.metacat.properties.PropertyService;
91
import edu.ucsb.nceas.metacat.shared.BaseService;
92
import edu.ucsb.nceas.metacat.shared.HandlerException;
93
import edu.ucsb.nceas.metacat.shared.ServiceException;
94
import edu.ucsb.nceas.metacat.util.DocumentUtil;
95
import edu.ucsb.nceas.metacat.util.MetacatUtil;
96
import edu.ucsb.nceas.metacat.util.ReplicationUtil;
97
import edu.ucsb.nceas.metacat.util.SystemUtil;
98
import edu.ucsb.nceas.utilities.FileUtil;
99
import edu.ucsb.nceas.utilities.GeneralPropertyException;
100
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
101

    
102
public class ReplicationService extends BaseService {
103

    
104
	private static ReplicationService replicationService = null;
105

    
106
	private long timeInterval;
107
	private Date firstTime;
108
	private boolean timedReplicationIsOn = false;
109
	Timer replicationDaemon;
110
	private static Vector<String> fileLocks = new Vector<String>();
111
//	private Thread lockThread = null;
112
	public static final String FORCEREPLICATEDELETE = "forcereplicatedelete";
113
	private static String TIMEREPLICATION = "replication.timedreplication";
114
	private static String TIMEREPLICATIONINTERVAl ="replication.timedreplicationinterval";
115
	private static String FIRSTTIME = "replication.firsttimedreplication";
116
	private static final int TIMEINTERVALLIMIT = 7200000;
117
	public static final String REPLICATIONUSER = "replication";
118
	
119
	private static int CLIENTTIMEOUT = 30000;
120

    
121
	public static final String REPLICATION_LOG_FILE_NAME = "metacatreplication.log";
122

    
123
	private static String DATA_FILE_FLAG = null;
124
	public static String METACAT_REPL_ERROR_MSG = null;
125
	private static Logger logReplication = Logger.getLogger("ReplicationLogging");
126
	private static Logger logMetacat = Logger.getLogger(ReplicationService.class);
127

    
128
	static {
129
		// lookup the client timeout
130
		String clientTimeout = null;
131
		try {
132
			clientTimeout = PropertyService.getProperty("replication.client.timeout");
133
			CLIENTTIMEOUT = Integer.parseInt(clientTimeout);
134
		} catch (Exception e) {
135
			// just use default
136
			logReplication.warn("No custom client timeout specified in configuration, using default." + e.getMessage());
137
		}
138
		try {
139
			DATA_FILE_FLAG = PropertyService.getProperty("replication.datafileflag");
140
		} catch (PropertyNotFoundException e) {
141
			logReplication.error("No 'replication.datafileflag' specified in configuration." + e.getMessage());
142
		}
143

    
144
	}
145
	
146
	private ReplicationService() throws ServiceException {
147
		_serviceName = "ReplicationService";
148
		
149
		initialize();
150
	}
151
	
152
	private void initialize() throws ServiceException {
153
				
154
		// initialize db connections to handle any update requests
155
		// deltaT = util.getProperty("replication.deltaT");
156
		// the default deltaT can be set from metacat.properties
157
		// create a thread to do the delta-T check but don't execute it yet
158
		replicationDaemon = new Timer(true);
159
		try {
160
			String replLogFile = PropertyService.getProperty("replication.logdir")
161
				+ FileUtil.getFS() + REPLICATION_LOG_FILE_NAME;
162
			METACAT_REPL_ERROR_MSG = "An error occurred in replication.  Please see the " +
163
				"replication log at: " + replLogFile;
164
			
165
			String timedRepIsOnStr = 
166
				PropertyService.getProperty("replication.timedreplication");
167
			timedReplicationIsOn = (new Boolean(timedRepIsOnStr)).booleanValue();
168
			logReplication.info("ReplicationService.initialize - The timed replication on is" + timedReplicationIsOn);
169

    
170
			String timeIntervalStr = 
171
				PropertyService.getProperty("replication.timedreplicationinterval");
172
			timeInterval = (new Long(timeIntervalStr)).longValue();
173
			logReplication.info("ReplicationService.initialize - The timed replication time Interval is " + timeInterval);
174

    
175
			String firstTimeStr = 
176
				PropertyService.getProperty("replication.firsttimedreplication");
177
			logReplication.info("ReplicationService.initialize - first replication time form property is " + firstTimeStr);
178
			firstTime = ReplicationHandler.combinateCurrentDateAndGivenTime(firstTimeStr);
179

    
180
			logReplication.info("ReplicationService.initialize - After combine current time, the real first time is "
181
					+ firstTime.toString() + " minisec");
182

    
183
			// set up time replication if it is on
184
			if (timedReplicationIsOn) {
185
				replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(),
186
						firstTime, timeInterval);
187
				logReplication.info("ReplicationService.initialize - deltaT handler started with rate="
188
						+ timeInterval + " mini seconds at " + firstTime.toString());
189
			}
190

    
191
		} catch (PropertyNotFoundException pnfe) {
192
			throw new ServiceException(
193
					"ReplicationService.initialize - Property error while instantiating "
194
							+ "replication service: " + pnfe.getMessage());
195
		} catch (HandlerException he) {
196
			throw new ServiceException(
197
					"ReplicationService.initialize - Handler error while instantiating "
198
							+ "replication service" + he.getMessage());
199
		} 
200
	}
201

    
202
	/**
203
	 * Get the single instance of SessionService.
204
	 * 
205
	 * @return the single instance of SessionService
206
	 */
207
	public static ReplicationService getInstance() throws ServiceException {
208
		if (replicationService == null) {
209
			replicationService = new ReplicationService();
210
		}
211
		return replicationService;
212
	}
213

    
214
	public boolean refreshable() {
215
		return true;
216
	}
217

    
218
	protected void doRefresh() throws ServiceException {
219
		return;
220
	}
221
	
222
	public void stop() throws ServiceException{
223
		
224
	}
225

    
226
	public void stopReplication() throws ServiceException {
227
	      //stop the replication server
228
	      replicationDaemon.cancel();
229
	      replicationDaemon = new Timer(true);
230
	      timedReplicationIsOn = false;
231
	      try {
232
	    	  PropertyService.setProperty("replication.timedreplication", (new Boolean(timedReplicationIsOn)).toString());
233
	      } catch (GeneralPropertyException gpe) {
234
	    	  logReplication.warn("ReplicationService.stopReplication - Could not set replication.timedreplication property: " + gpe.getMessage());
235
	      }
236

    
237
	      logReplication.info("ReplicationService.stopReplication - deltaT handler stopped");
238
		return;
239
	}
240
	
241
	public void startReplication(Hashtable<String, String[]> params) throws ServiceException {
242

    
243
	       String firstTimeStr = "";
244
	      //start the replication server
245
	       if ( params.containsKey("rate") ) {
246
	        timeInterval = new Long(
247
	               new String(((String[])params.get("rate"))[0])).longValue();
248
	        if(timeInterval < TIMEINTERVALLIMIT) {
249
	            //deltaT<30 is a timing mess!
250
	            timeInterval = TIMEINTERVALLIMIT;
251
	            throw new ServiceException("Replication deltaT rate cannot be less than "+
252
	                    TIMEINTERVALLIMIT + " millisecs and system automatically setup the rate to "+TIMEINTERVALLIMIT);
253
	        }
254
	      } else {
255
	        timeInterval = TIMEINTERVALLIMIT ;
256
	      }
257
	      logReplication.info("ReplicationService.startReplication - New rate is: " + timeInterval + " mini seconds.");
258
	      if ( params.containsKey("firsttime"))
259
	      {
260
	         firstTimeStr = ((String[])params.get("firsttime"))[0];
261
	         try
262
	         {
263
	           firstTime = ReplicationHandler.combinateCurrentDateAndGivenTime(firstTimeStr);
264
	           logReplication.info("ReplicationService.startReplication - The first time setting is "+firstTime.toString());
265
	         }
266
	         catch (HandlerException e)
267
	         {
268
	            throw new ServiceException(e.getMessage());
269
	         }
270
	         logReplication.warn("After combine current time, the real first time is "
271
	                                  +firstTime.toString()+" minisec");
272
	      }
273
	      else
274
	      {
275
	    	  logMetacat.error("ReplicationService.startReplication - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
276
	          logReplication.error("ReplicationService.startReplication - You should specify the first time " +
277
	                                  "to start a time replication");
278
	          return;
279
	      }
280
	      
281
	      timedReplicationIsOn = true;
282
	      try {
283
	      // save settings to property file
284
	      PropertyService.setProperty(TIMEREPLICATION, (new Boolean(timedReplicationIsOn)).toString());
285
	      // note we couldn't use firstTime object because it has date info
286
	      // we only need time info such as 10:00 PM
287
	      PropertyService.setProperty(FIRSTTIME, firstTimeStr);
288
	      PropertyService.setProperty(TIMEREPLICATIONINTERVAl, (new Long(timeInterval)).toString());
289
	      } catch (GeneralPropertyException gpe) {
290
	    	  logReplication.warn("ReplicationService.startReplication - Could not set property: " + gpe.getMessage());
291
	      }
292
	      replicationDaemon.cancel();
293
	      replicationDaemon = new Timer(true);
294
	      replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(), firstTime,
295
	                                            timeInterval);
296
	      
297
	      logReplication.info("ReplicationService.startReplication - deltaT handler started with rate=" +
298
	                                    timeInterval + " milliseconds at " +firstTime.toString());
299

    
300
	}
301
	
302
	public void runOnce() throws ServiceException {
303
	      //updates this server exactly once
304
	      replicationDaemon.schedule(new ReplicationHandler(), 0);
305
	}
306
	
307
	/**
308
	 * This method can add, delete and list the servers currently included in
309
	 * xml_replication.
310
	 * action           subaction            other needed params
311
	 * ---------------------------------------------------------
312
	 * servercontrol    add                  server
313
	 * servercontrol    delete               server
314
	 * servercontrol    list
315
	 */
316
	public static void handleServerControlRequest(
317
			Hashtable<String, String[]> params, HttpServletRequest request, HttpServletResponse response) {
318
		String subaction = ((String[]) params.get("subaction"))[0];
319
		DBConnection dbConn = null;
320
		int serialNumber = -1;
321
		PreparedStatement pstmt = null;
322
		String replicate = null;
323
		String server = null;
324
		String dataReplicate = null;
325
		String hub = null;
326
		Writer out = null;
327
		boolean showGenerateSystemMetadata = false;
328
		try {
329
			response.setContentType("text/xml");
330
			out = response.getWriter();
331
			
332
			//conn = util.openDBConnection();
333
			dbConn = DBConnectionPool
334
					.getDBConnection("MetacatReplication.handleServerControlRequest");
335
			serialNumber = dbConn.getCheckOutSerialNumber();
336

    
337
			// add server to server list
338
			if (subaction.equals("add")) {
339
				replicate = ((String[]) params.get("replicate"))[0];
340
				server = ((String[]) params.get("server"))[0];
341

    
342
				//Get data replication value
343
				dataReplicate = ((String[]) params.get("datareplicate"))[0];
344
				
345
				//Get hub value
346
				hub = ((String[]) params.get("hub"))[0];
347

    
348
				Calendar cal = Calendar.getInstance();
349
                cal.set(1980, 1, 1);
350
				String sql = "INSERT INTO xml_replication "
351
						+ "(server, last_checked, replicate, datareplicate, hub) "
352
						+ "VALUES (?,?,?,?,?)";
353
				
354
				pstmt = dbConn.prepareStatement(sql);
355
						
356
				pstmt.setString(1, server);
357
				pstmt.setTimestamp(2, new Timestamp(cal.getTimeInMillis()));
358
				pstmt.setInt(3, Integer.parseInt(replicate));
359
				pstmt.setInt(4, Integer.parseInt(dataReplicate));
360
				pstmt.setInt(5, Integer.parseInt(hub));
361
				
362
				String sqlReport = "XMLAccessAccess.getXMLAccessForDoc - SQL: " + sql;
363
				sqlReport += " [" + server + "," + replicate + 
364
					"," + dataReplicate + "," + hub + "]";
365
				
366
				logMetacat.info(sqlReport);
367
				
368
				pstmt.execute();
369
				pstmt.close();
370
				dbConn.commit();
371
				out.write("Server " + server + " added");
372
				
373
				
374
				// delete server from server list
375
			} else if (subaction.equals("delete")) {
376
				server = ((String[]) params.get("server"))[0];
377
				pstmt = dbConn.prepareStatement("DELETE FROM xml_replication "
378
						+ "WHERE server LIKE ?");
379
				pstmt.setString(1, server);
380
				pstmt.execute();
381
				pstmt.close();
382
				dbConn.commit();
383
				out.write("Server " + server + " deleted");
384
			} else if (subaction.equals("list")) {
385
				// nothing special - it's the default behavior
386

    
387
			} else if (subaction.equals("generatesystemmetadata")) {
388
				GenerateSystemMetadata gsm = new GenerateSystemMetadata();
389
				int serverLocation = -1;
390
				String serverid = ((String[]) params.get("serverid"))[0];
391
				serverLocation = Integer.parseInt(serverid);
392
				gsm.setServerLocation(serverLocation );
393
				gsm.multiThreadUpgrade();
394
				out.write("System Metadata generated for server " + serverid);
395
				
396
			} else if (subaction.equals("generateore")) {
397
				GenerateORE gore = new GenerateORE();
398
				int serverLocation = -1;
399
				String serverid = ((String[]) params.get("serverid"))[0];
400
				serverLocation = Integer.parseInt(serverid);
401
				gore.setServerLocation(serverLocation );
402
				gore.upgrade();
403
				out.write("Generated ORE maps for server " + serverid);
404
				
405
			} else {
406
			
407
				out.write("<error>Unkonwn subaction</error>");
408
				return;
409
			}
410
			
411
			// show SM generate button?
412
			String dataoneConfigured = PropertyService.getProperty("configutil.dataoneConfigured");
413
			if (dataoneConfigured != null) {
414
				showGenerateSystemMetadata = Boolean.parseBoolean(dataoneConfigured);
415
			}
416
			
417
			// always list them after processing
418
			response.setContentType("text/html");
419
			out.write("<html><body><table border=\"1\">");
420
			out.write("<tr><td><b>server</b></td>");
421
			out.write("<td><b>last_checked</b></td>");
422
			out.write("<td><b>replicate</b></td>");
423
			out.write("<td><b>datareplicate</b></td>");
424
			out.write("<td><b>hub</b></td>");
425
			if (showGenerateSystemMetadata) {
426
				out.write("<td><b>System Metadata</b></td>");
427
				out.write("<td><b>ORE Maps</b></td>");
428
			}
429
			out.write("</tr>");
430

    
431
			pstmt = dbConn.prepareStatement("SELECT serverid, server, last_checked, replicate, datareplicate, hub FROM xml_replication");
432
			pstmt.execute();
433
			ResultSet rs = pstmt.getResultSet();
434
			boolean tablehasrows = rs.next();
435
			while (tablehasrows) {
436
				out.write("<tr><td>" + rs.getString(2) + "</td><td>");
437
				out.write(rs.getString(3) + "</td><td>");
438
				out.write(rs.getString(4) + "</td><td>");
439
				out.write(rs.getString(5) + "</td><td>");
440
				out.write(rs.getString(6) + "</td>");
441
				if (showGenerateSystemMetadata) {
442
					// for SM
443
					out.write("<td><form action='" + request.getContextPath() + "/admin'>");
444
					out.write("<input name='serverid' type='hidden' value='" + rs.getString(1) + "'/>");
445
					out.write("<input name='configureType' type='hidden' value='replication'/>");
446
					out.write("<input name='action' type='hidden' value='servercontrol'/>");
447
					out.write("<input name='subaction' type='hidden' value='generatesystemmetadata'/>");
448
					out.write("<input type='submit' value='Generate System Metadata'/>");
449
					out.write("</form></td>");
450
					
451
					// for ORE maps
452
					out.write("<td><form action='" + request.getContextPath() + "/admin'>");
453
					out.write("<input name='serverid' type='hidden' value='" + rs.getString(1) + "'/>");
454
					out.write("<input name='configureType' type='hidden' value='replication'/>");
455
					out.write("<input name='action' type='hidden' value='servercontrol'/>");
456
					out.write("<input name='subaction' type='hidden' value='generateore'/>");
457
					out.write("<input type='submit' value='Generate ORE'/>");
458
					out.write("</form></td>");
459
				}
460
				out.write("</tr>");
461

    
462
				tablehasrows = rs.next();
463
			}
464
			out.write("</table></body></html>");
465
			
466
			
467
			pstmt.close();
468
			//conn.close();
469

    
470
		} catch (Exception e) {
471
			logMetacat.error("ReplicationService.handleServerControlRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
472
			logReplication.error("ReplicationService.handleServerControlRequest - Error in "
473
					+ "MetacatReplication.handleServerControlRequest " + e.getMessage());
474
			e.printStackTrace(System.out);
475
		} finally {
476
			try {
477
				pstmt.close();
478
			}//try
479
			catch (SQLException ee) {
480
				logMetacat.error("ReplicationService.handleServerControlRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
481
				logReplication.error("ReplicationService.handleServerControlRequest - Error in MetacatReplication.handleServerControlRequest to close pstmt "
482
						+ ee.getMessage());
483
			}//catch
484
			finally {
485
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
486
			}//finally
487
			if (out != null) {
488
				try {
489
					out.close();
490
				} catch (IOException e) {
491
					logMetacat.error(e.getMessage(), e);
492
				}
493
			}
494
		}//finally
495

    
496
	}
497

    
498
	/**
499
	 * when a forcereplication request comes in, local host sends a read request
500
	 * to the requesting server (remote server) for the specified docid. Then
501
	 * store it in local database.
502
	 */
503
	protected static void handleForceReplicateRequest(
504
			Hashtable<String, String[]> params, HttpServletResponse response,
505
			HttpServletRequest request) {
506
		String server = ((String[]) params.get("server"))[0]; // the server that
507
		String docid = ((String[]) params.get("docid"))[0]; // sent the document
508
		String dbaction = "UPDATE"; // the default action is UPDATE
509
		//    boolean override = false;
510
		//    int serverCode = 1;
511
		DBConnection dbConn = null;
512
		int serialNumber = -1;
513
		String docName = null;
514

    
515
		try {
516
			//if the url contains a dbaction then the default action is overridden
517
			if (params.containsKey("dbaction")) {
518
				dbaction = ((String[]) params.get("dbaction"))[0];
519
				//serverCode = MetacatReplication.getServerCode(server);
520
				//override = true; //we are now overriding the default action
521
			}
522
			logReplication.info("ReplicationService.handleForceReplicateRequest - Force replication request from: " + server);
523
			logReplication.info("ReplicationService.handleForceReplicateRequest - Force replication docid: " + docid);
524
			logReplication.info("ReplicationService.handleForceReplicateRequest - Force replication action: " + dbaction);
525
			// sending back read request to remote server
526
			URL u = new URL("https://" + server + "?server="
527
					+ MetacatUtil.getLocalReplicationServerName() + "&action=read&docid="
528
					+ docid);
529
			String xmldoc = ReplicationService.getURLContent(u);
530

    
531
			// get the document info from server
532
			URL docinfourl = new URL("https://" + server + "?server="
533
					+ MetacatUtil.getLocalReplicationServerName()
534
					+ "&action=getdocumentinfo&docid=" + docid);
535
			
536

    
537
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
538
			// strip out the system metadata portion
539
			String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
540
			docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);
541
		   	  
542
			//dih is the parser for the docinfo xml format
543
			DocInfoHandler dih = new DocInfoHandler();
544
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
545
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
546
			//      Hashtable<String,Vector<AccessControlForSingleFile>> docinfoHash = dih.getDocInfo();
547
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
548
			
549
			// Get home server of this docid
550
			String homeServer = (String) docinfoHash.get("home_server");
551
			
552
			// process system metadata
553
			if (systemMetadataXML != null) {
554
				SystemMetadata sysMeta = 
555
					TypeMarshaller.unmarshalTypeFromStream(
556
							SystemMetadata.class,
557
							new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
558
				// need the guid-to-docid mapping
559
				boolean mappingExists = true;
560
		      	mappingExists = IdentifierManager.getInstance().mappingExists(sysMeta.getIdentifier().getValue());
561
		      	if (!mappingExists) {
562
		      		IdentifierManager.getInstance().createMapping(sysMeta.getIdentifier().getValue(), docid);
563
		      	}
564
				// save the system metadata
565
				HazelcastService.getInstance().getSystemMetadataMap().put(sysMeta.getIdentifier(), sysMeta);
566
			}
567
      
568
			// dates
569
			String createdDateString = docinfoHash.get("date_created");
570
			String updatedDateString = docinfoHash.get("date_updated");
571
			Date createdDate = DateTimeMarshaller.deserializeDateToUTC(createdDateString);
572
			Date updatedDate = DateTimeMarshaller.deserializeDateToUTC(updatedDateString);
573
		      
574
			logReplication.info("ReplicationService.handleForceReplicateRequest - homeServer: " + homeServer);
575
			// Get Document type
576
			String docType = (String) docinfoHash.get("doctype");
577
			logReplication.info("ReplicationService.handleForceReplicateRequest - docType: " + docType);
578
			String parserBase = null;
579
			// this for eml2 and we need user eml2 parser
580
			if (docType != null
581
					&& (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE)) {
582
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml200 document!");
583
				parserBase = DocumentImpl.EML200;
584
			} else if (docType != null
585
					&& (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE)) {
586
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.0.1 document!");
587
				parserBase = DocumentImpl.EML200;
588
			} else if (docType != null
589
					&& (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE)) {
590
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.0 document!");
591
				parserBase = DocumentImpl.EML210;
592
			} else if (docType != null
593
					&& (docType.trim()).equals(DocumentImpl.EML2_1_1NAMESPACE)) {
594
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.1 document!");
595
				parserBase = DocumentImpl.EML210;
596
			}
597
			logReplication.warn("ReplicationService.handleForceReplicateRequest - The parserBase is: " + parserBase);
598

    
599
			// Get DBConnection from pool
600
			dbConn = DBConnectionPool
601
					.getDBConnection("MetacatReplication.handleForceReplicateRequest");
602
			serialNumber = dbConn.getCheckOutSerialNumber();
603
			// write the document to local database
604
			DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false, false);
605
			//try this independently so we can set access even if the update action is invalid (i.e docid has not changed)
606
			try {
607
				wrapper.writeReplication(dbConn, xmldoc, null, null,
608
						dbaction, docid, null, null, homeServer, server, createdDate,
609
						updatedDate);
610
			} finally {
611

    
612
				//process extra access rules before dealing with the write exception (doc exist already)
613
				try {
614
		        	// check if we had a guid -> docid mapping
615
		        	String docidNoRev = DocumentUtil.getDocIdFromAccessionNumber(docid);
616
		        	int rev = DocumentUtil.getRevisionFromAccessionNumber(docid);
617
		        	IdentifierManager.getInstance().getGUID(docid, rev);
618
		        	// no need to create the mapping if we have it
619
		        } catch (McdbDocNotFoundException mcdbe) {
620
		        	// create mapping if we don't
621
		        	IdentifierManager.getInstance().createMapping(docid, docid);
622
		        }
623
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
624
		        if (accessControlList != null) {
625
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
626
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
627
		        		try {
628
			        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
629
			        			acfsf.insertPermissions(xmlAccessDAO);
630
								logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
631
										+ " permissions added to DB");
632
			        		}
633
		        		} catch (PermOrderException poe) {
634
		        			// this is problematic, but should not prevent us from replicating
635
		        			// see https://redmine.dataone.org/issues/2583
636
		        			String msg = "Could not insert access control for: " + docid + " Message: " + poe.getMessage();
637
		        			logMetacat.error(msg, poe);
638
		        			logReplication.error(msg, poe);
639
		        		}
640
		            }
641
		        }
642
		        
643
		        // process the real owner and updater
644
				String user = (String) docinfoHash.get("user_owner");
645
				String updated = (String) docinfoHash.get("user_updated");
646
		        updateUserOwner(dbConn, docid, user, updated);
647

    
648
				logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid + " added to DB with "
649
						+ "action " + dbaction);
650
				
651
				EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER, docid, dbaction);
652
			}
653
		} catch (SQLException sqle) {
654
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
655
			logReplication.error("ReplicationService.handleForceReplicateRequest - SQL error when adding doc " + docid + 
656
					" to DB with action " + dbaction + ": " + sqle.getMessage());
657
		} catch (MalformedURLException mue) {
658
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
659
			logReplication.error("ReplicationService.handleForceReplicateRequest - URL error when adding doc " + docid + 
660
					" to DB with action " + dbaction + ": " + mue.getMessage());
661
		} catch (SAXException se) {
662
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
663
			logReplication.error("ReplicationService.handleForceReplicateRequest - SAX parsing error when adding doc " + docid + 
664
					" to DB with action " + dbaction + ": " + se.getMessage());
665
		} catch (HandlerException he) {
666
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
667
			logReplication.error("ReplicationService.handleForceReplicateRequest - Handler error when adding doc " + docid + 
668
					" to DB with action " + dbaction + ": " + he.getMessage());
669
		} catch (IOException ioe) {
670
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
671
			logReplication.error("ReplicationService.handleForceReplicateRequest - I/O error when adding doc " + docid + 
672
					" to DB with action " + dbaction + ": " + ioe.getMessage());
673
		} catch (PermOrderException poe) {
674
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
675
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
676
					" to DB with action " + dbaction + ": " + poe.getMessage());
677
		} catch (AccessControlException ace) {
678
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
679
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
680
					" to DB with action " + dbaction + ": " + ace.getMessage());
681
		} catch (Exception e) {
682
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
683
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when adding doc " + docid + 
684
					" to DB with action " + dbaction + ": " + e.getMessage());
685
		} finally {
686
			// Return the checked out DBConnection
687
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
688
		}//finally
689
	}
690

    
691
	/*
692
	 * when a forcereplication delete request comes in, local host will delete this
693
	 * document
694
	 */
695
	protected static void handleForceReplicateDeleteRequest(
696
			Hashtable<String, String[]> params, HttpServletResponse response,
697
			HttpServletRequest request) {
698
		String server = ((String[]) params.get("server"))[0]; // the server that
699
		String docid = ((String[]) params.get("docid"))[0]; // sent the document
700
		try {
701
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - force replication delete request from " + server);
702
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - force replication delete docid " + docid);
703
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - Force replication delete request from: " + server);
704
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - Force replication delete docid: " + docid);
705
			DocumentImpl.delete(docid, null, null, server, false);
706
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - document " + docid + " was successfully deleted ");
707
			EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER, docid,
708
					"delete");
709
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - document " + docid + " was successfully deleted ");
710
		} catch (McdbDocNotFoundException e) {
711
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
712
			logReplication.error("document " + docid
713
					+ " failed to delete because " + e.getMessage());
714
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
715
		} catch (InsufficientKarmaException e) {
716
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
717
			logReplication.error("document " + docid
718
					+ " failed to delete because " + e.getMessage());
719
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
720
		} catch (SQLException e) {
721
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
722
			logReplication.error("document " + docid
723
					+ " failed to delete because " + e.getMessage());
724
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
725
		} catch (Exception e) {
726
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
727
			logReplication.error("document " + docid
728
					+ " failed to delete because " + e.getMessage());
729
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
730

    
731
		}//catch
732

    
733
	}
734

    
735
	/**
736
	 * when a forcereplication data file request comes in, local host sends a
737
	 * readdata request to the requesting server (remote server) for the specified
738
	 * docid. Then store it in local database and file system
739
	 */
740
	protected static void handleForceReplicateDataFileRequest(Hashtable<String, String[]> params,
741
			HttpServletRequest request) {
742

    
743
		//make sure there is some parameters
744
		if (params.isEmpty()) {
745
			return;
746
		}
747
		// Get remote server
748
		String server = ((String[]) params.get("server"))[0];
749
		// the docid should include rev number
750
		String docid = ((String[]) params.get("docid"))[0];
751
		// Make sure there is a docid and server
752
		if (docid == null || server == null || server.equals("")) {
753
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
754
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Didn't specify docid or server for replication");
755
			return;
756
		}
757

    
758
		// Overide or not
759
		//    boolean override = false;
760
		// dbaction - update or insert
761
		String dbaction = null;
762

    
763
		try {
764
			//docid was switch to two parts uinque code and rev
765
			//String uniqueCode=MetacatUtil.getDocIdFromString(docid);
766
			//int rev=MetacatUtil.getVersionFromString(docid);
767
			if (params.containsKey("dbaction")) {
768
				dbaction = ((String[]) params.get("dbaction"))[0];
769
			} else//default value is update
770
			{
771
//				dbaction = "update";
772
				dbaction = null;
773
			}
774

    
775
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication request from: " + server);
776
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication docid: " + docid);
777
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication action: " + dbaction);
778
			// get the document info from server
779
			URL docinfourl = new URL("https://" + server + "?server="
780
					+ MetacatUtil.getLocalReplicationServerName()
781
					+ "&action=getdocumentinfo&docid=" + docid);
782

    
783
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
784
			
785
			// strip out the system metadata portion
786
		    String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
787
		   	docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);
788

    
789
			//dih is the parser for the docinfo xml format
790
			DocInfoHandler dih = new DocInfoHandler();
791
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
792
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
793
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
794
			
795
			String docName = (String) docinfoHash.get("docname");
796

    
797
			String docType = (String) docinfoHash.get("doctype");
798

    
799
			String docHomeServer = (String) docinfoHash.get("home_server");
800
			
801
			String createdDateString = docinfoHash.get("date_created");
802
			String updatedDateString = docinfoHash.get("date_updated");
803
			
804
			Date createdDate = DateTimeMarshaller.deserializeDateToUTC(createdDateString);
805
			Date updatedDate = DateTimeMarshaller.deserializeDateToUTC(updatedDateString);
806
			
807
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - docHomeServer of datafile: " + docHomeServer);
808

    
809
			// in case we have a write exception, we still want to track access and sysmeta
810
			Exception writeException = null;
811

    
812
			// do we need the object content?
813
			if (dbaction != null && (dbaction.equals("insert") || dbaction.equals("update"))) {
814
				//Get data file and store it into local file system.
815
				// sending back readdata request to server
816
				URL url = new URL("https://" + server + "?server="
817
						+ MetacatUtil.getLocalReplicationServerName()
818
						+ "&action=readdata&docid=" + docid);
819
				String datafilePath = PropertyService
820
						.getProperty("application.datafilepath");
821

    
822
				InputStream inputStream = getURLStream(url);
823
				
824
				//register data file into xml_documents table and write data file
825
				//into file system
826
				try {
827
					DocumentImpl.writeDataFileInReplication(inputStream,
828
							datafilePath, docName, docType, docid, null, docHomeServer,
829
							server, DocumentImpl.DOCUMENTTABLE, false, createdDate,
830
							updatedDate);
831
				} catch (Exception e) {
832
					writeException = e;
833
				}
834

    
835
			}
836
			
837
			// process the real owner and updater
838
			DBConnection dbConn = DBConnectionPool.getDBConnection("ReplicationService.handleForceDataFileRequest");
839
	        int serialNumber = dbConn.getCheckOutSerialNumber();
840
	        dbConn.setAutoCommit(false);
841
			String user = (String) docinfoHash.get("user_owner");
842
			String updated = (String) docinfoHash.get("user_updated");
843
	        updateUserOwner(dbConn, docid, user, updated);
844
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
845
	        
846
			// process system metadata
847
	        if (systemMetadataXML != null) {
848
	      	  SystemMetadata sysMeta = 
849
	      		TypeMarshaller.unmarshalTypeFromStream(
850
	      				  SystemMetadata.class, 
851
	      				  new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
852
	      	  
853
	      	  // need the guid-to-docid mapping
854
	      	  boolean mappingExists = true;
855
	      	  mappingExists = IdentifierManager.getInstance().mappingExists(sysMeta.getIdentifier().getValue());
856
	      	  if (!mappingExists) {
857
	      		  IdentifierManager.getInstance().createMapping(sysMeta.getIdentifier().getValue(), docid);
858
	      	  }
859
	      	  // save the system metadata
860
	      	  HazelcastService.getInstance().getSystemMetadataMap().put(sysMeta.getIdentifier(), sysMeta);
861
	        }
862
	        
863
	        // process the access control
864
	        try {
865
	        	// check if we had a guid -> docid mapping
866
	        	String docidNoRev = DocumentUtil.getDocIdFromAccessionNumber(docid);
867
	        	int rev = DocumentUtil.getRevisionFromAccessionNumber(docidNoRev);
868
	        	IdentifierManager.getInstance().getGUID(docid, rev);
869
	        	// no need to create the mapping if we have it
870
	        } catch (McdbDocNotFoundException mcdbe) {
871
	        	// create mapping if we don't
872
	        	IdentifierManager.getInstance().createMapping(docid, docid);
873
	        }
874
	        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
875
	        if (accessControlList != null) {
876
	        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
877
	        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
878
	        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
879
	        			acfsf.insertPermissions(xmlAccessDAO);
880
						logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
881
								+ " permissions added to DB");
882
	        		}
883
	            }
884
	        }
885
	        
886
	        // throw the write exception now -- this happens when access changes on an object
887
			if (writeException != null) {
888
				throw writeException;
889
			}
890

    
891
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - datafile " + docid + " added to DB with "
892
					+ "action " + dbaction);
893
			EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER,
894
					docid, dbaction);
895

    
896
		} catch (Exception e) {
897
			e.printStackTrace();
898
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG, e);                         
899
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Datafile " + docid
900
					+ " failed to added to DB with " + "action " + dbaction + " because "
901
					+ e.getMessage());
902
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - ERROR in MetacatReplication.handleForceDataFileReplicate"
903
					+ "Request(): " + e.getMessage());
904
		}
905
	}
906

    
907
	/**
908
	 * Grants or denies a lock to a requesting host.
909
	 * The servlet parameters of interrest are:
910
	 * docid: the docid of the file the lock is being requested for
911
	 * currentdate: the timestamp of the document on the remote server
912
	 *
913
	 */
914
	protected static void handleGetLockRequest(
915
			Hashtable<String, String[]> params, HttpServletResponse response) {
916

    
917
		try {
918

    
919
			String docid = ((String[]) params.get("docid"))[0];
920
			String remoteRev = ((String[]) params.get("updaterev"))[0];
921
			DocumentImpl requestDoc = new DocumentImpl(docid);
922
			logReplication.info("ReplicationService.handleGetLockRequest - lock request for " + docid);
923
			int localRevInt = requestDoc.getRev();
924
			int remoteRevInt = Integer.parseInt(remoteRev);
925

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

    
960
	/**
961
	 * Sends all of the xml_documents information encoded in xml to a requestor
962
	 * the format is:
963
	 * <!ELEMENT documentinfo (docid, docname, doctype, doctitle, user_owner,
964
	 *                  user_updated, home_server, public_access, rev)/>
965
	 * all of the subelements of document info are #PCDATA
966
	 */
967
	protected static void handleGetDocumentInfoRequest(
968
			Hashtable<String, String[]> params, HttpServletResponse response) {
969
		String docid = ((String[]) (params.get("docid")))[0];
970

    
971
		try {
972
			// get docinfo as XML string
973
			String docinfoXML = getDocumentInfo(docid);
974
			
975
			// get a writer for sending back to response
976
			response.setContentType("text/xml");
977
			Writer out = response.getWriter();
978
			out.write(docinfoXML);
979
			out.close();
980

    
981
		} catch (Exception e) {
982
			logMetacat.error("ReplicationService.handleGetDocumentInfoRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
983
			logReplication.error("ReplicationService.handleGetDocumentInfoRequest - error in metacatReplication.handlegetdocumentinforequest "
984
					+ "for doc: " + docid + " : " + e.getMessage());
985
		}
986

    
987
	}
988
	
989
	public static Hashtable<String, String> getDocumentInfoMap(String docid)
990
			throws HandlerException, AccessControlException, JiBXException,
991
			IOException, McdbException, SAXException {
992
		
993
		// Try get docid info from remote server
994
		DocInfoHandler dih = new DocInfoHandler();
995
		XMLReader docinfoParser = ReplicationHandler.initParser(dih);
996

    
997
		String docInfoStr = getDocumentInfo(docid);
998

    
999
		// strip out the system metadata portion
1000
		String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
1001
		docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);
1002

    
1003
		docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
1004
		Hashtable<String, String> docinfoHash = dih.getDocInfo();
1005

    
1006
		return docinfoHash;
1007
	}
1008
	
1009
	/**
1010
	 * Gets a docInfo XML snippet for the replication API
1011
	 * @param docid
1012
	 * @return
1013
	 * @throws AccessControlException
1014
	 * @throws JiBXException
1015
	 * @throws IOException
1016
	 * @throws McdbException
1017
	 */
1018
	public static String getDocumentInfo(String docid) throws AccessControlException, JiBXException, IOException, McdbException {
1019
		StringBuffer sb = new StringBuffer();
1020

    
1021
		DocumentImpl doc = new DocumentImpl(docid);
1022
		sb.append("<documentinfo><docid>").append(docid);
1023
		sb.append("</docid>");
1024
		
1025
		try {
1026
			// serialize the System Metadata as XML for docinfo
1027
			String guid = IdentifierManager.getInstance().getGUID(doc.getDocID(), doc.getRev());
1028
			SystemMetadata systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
1029
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
1030
			TypeMarshaller.marshalTypeToOutputStream(systemMetadata, baos);
1031
			String systemMetadataXML = baos.toString("UTF-8");
1032
			sb.append("<systemMetadata>");
1033
			sb.append(systemMetadataXML);
1034
			sb.append("</systemMetadata>");
1035
		} catch(McdbDocNotFoundException e) {
1036
		  logMetacat.warn("No SystemMetadata found for: " + docid);
1037
		}
1038
		
1039
		Calendar created = Calendar.getInstance();
1040
		created.setTime(doc.getCreateDate());
1041
		Calendar updated = Calendar.getInstance();
1042
		updated.setTime(doc.getUpdateDate());
1043
		
1044
		sb.append("<docname>").append(doc.getDocname());
1045
		sb.append("</docname><doctype>").append(doc.getDoctype());
1046
		sb.append("</doctype>");
1047
		sb.append("<user_owner>").append(doc.getUserowner());
1048
		sb.append("</user_owner><user_updated>").append(doc.getUserupdated());
1049
		sb.append("</user_updated>");
1050
		sb.append("<date_created>");
1051
		sb.append(DateTimeMarshaller.serializeDateToUTC(doc.getCreateDate()));
1052
		sb.append("</date_created>");
1053
		sb.append("<date_updated>");
1054
		sb.append(DateTimeMarshaller.serializeDateToUTC(doc.getUpdateDate()));
1055
		sb.append("</date_updated>");
1056
		sb.append("<home_server>");
1057
		sb.append(doc.getDocHomeServer());
1058
		sb.append("</home_server>");
1059
		sb.append("<public_access>").append(doc.getPublicaccess());
1060
		sb.append("</public_access><rev>").append(doc.getRev());
1061
		sb.append("</rev>");
1062

    
1063
		sb.append("<accessControl>");
1064

    
1065
		AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid); 
1066
		sb.append(acfsf.getAccessString());
1067
		
1068
		sb.append("</accessControl>");
1069

    
1070
		sb.append("</documentinfo>");
1071
			
1072
		return sb.toString();
1073
	}
1074
	
1075
	/**
1076
	 * Sends System Metadata as XML
1077
	 */
1078
	protected static void handleGetSystemMetadataRequest(
1079
			Hashtable<String, String[]> params, HttpServletResponse response) {
1080
		String guid = ((String[]) (params.get("guid")))[0];
1081
		String systemMetadataXML = null;
1082
		try {
1083
			
1084
			// serialize the System Metadata as XML 
1085
			SystemMetadata systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
1086
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
1087
			TypeMarshaller.marshalTypeToOutputStream(systemMetadata, baos);
1088
			systemMetadataXML = baos.toString("UTF-8");
1089
				
1090
			// get a writer for sending back to response
1091
			response.setContentType("text/xml");
1092
			Writer out = response.getWriter();
1093
			out.write(systemMetadataXML);
1094
			out.close();
1095

    
1096
		} catch (Exception e) {
1097
			String msg = "ReplicationService.handleGetSystemMetadataRequest for guid: " + guid + " : " + e.getMessage();
1098
			logMetacat.error(msg);                         
1099
			logReplication.error(msg);
1100
		}
1101

    
1102
	}
1103
	
1104
	/**
1105
	 * when a forcereplication request comes in, local host sends a read request
1106
	 * to the requesting server (remote server) for the specified docid. Then
1107
	 * store it in local database.
1108
	 */
1109
	protected static void handleForceReplicateSystemMetadataRequest(
1110
			Hashtable<String, String[]> params, HttpServletResponse response,
1111
			HttpServletRequest request) {
1112
		String server = ((String[]) params.get("server"))[0]; // the server that
1113
		String guid = ((String[]) params.get("guid"))[0]; // sent the document
1114
		
1115
		try {
1116
			logReplication.info("ReplicationService.handleForceReplicateSystemMetadataRequest - Force replication system metadata request from: " + server);
1117
			// get the system metadata from server
1118
			URL docinfourl = new URL("https://" + server + "?server="
1119
					+ MetacatUtil.getLocalReplicationServerName()
1120
					+ "&action=getsystemmetadata&guid=" + guid);
1121
			
1122
			String systemMetadataXML = ReplicationService.getURLContent(docinfourl);
1123
						
1124
			// process system metadata
1125
			if (systemMetadataXML != null) {
1126
				SystemMetadata sysMeta = 
1127
					TypeMarshaller.unmarshalTypeFromStream(
1128
							SystemMetadata.class,
1129
							new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
1130
				HazelcastService.getInstance().getSystemMetadataMap().put(sysMeta.getIdentifier(), sysMeta);
1131
			}
1132
      
1133
			logReplication.info("ReplicationService.handleForceReplicateSystemMetadataRequest - processed guid: " + guid);
1134
			EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER, guid, "systemMetadata");
1135

    
1136
		} catch (Exception e) {
1137
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG, e);                         
1138
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when processing guid: " + guid, e);
1139
		}
1140
	}
1141

    
1142
	/**
1143
	 * Sends a datafile to a remote host
1144
	 */
1145
	protected static void handleGetDataFileRequest(OutputStream outPut,
1146
			Hashtable<String, String[]> params, HttpServletResponse response)
1147

    
1148
	{
1149
		// File path for data file
1150
		String filepath;
1151
		// Request docid
1152
		String docId = ((String[]) (params.get("docid")))[0];
1153
		//check if the doicd is null
1154
		if (docId == null) {
1155
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1156
			logReplication.error("ReplicationService.handleGetDataFileRequest - Didn't specify docid for replication");
1157
			return;
1158
		}
1159

    
1160
		//try to open a https stream to test if the request server's public key
1161
		//in the key store, this is security issue
1162
		try {
1163
			filepath = PropertyService.getProperty("application.datafilepath");
1164
			String server = params.get("server")[0];
1165
			URL u = new URL("https://" + server + "?server="
1166
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test");
1167
			String test = ReplicationService.getURLContent(u);
1168
			//couldn't pass the test
1169
			if (test.indexOf("successfully") == -1) {
1170
				//response.setContentType("text/xml");
1171
				//outPut.println("<error>Couldn't pass the trust test</error>");
1172
				logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1173
				logReplication.error("ReplicationService.handleGetDataFileRequest - Couldn't pass the trust test");
1174
				return;
1175
			}
1176
		}//try
1177
		catch (Exception ee) {
1178
			return;
1179
		}//catch
1180

    
1181
		if (!filepath.endsWith("/")) {
1182
			filepath += "/";
1183
		}
1184
		// Get file aboslute file name
1185
		String filename = filepath + docId;
1186

    
1187
		//MIME type
1188
		String contentType = null;
1189
		if (filename.endsWith(".xml")) {
1190
			contentType = "text/xml";
1191
		} else if (filename.endsWith(".css")) {
1192
			contentType = "text/css";
1193
		} else if (filename.endsWith(".dtd")) {
1194
			contentType = "text/plain";
1195
		} else if (filename.endsWith(".xsd")) {
1196
			contentType = "text/xml";
1197
		} else if (filename.endsWith("/")) {
1198
			contentType = "text/html";
1199
		} else {
1200
			File f = new File(filename);
1201
			if (f.isDirectory()) {
1202
				contentType = "text/html";
1203
			} else {
1204
				contentType = "application/octet-stream";
1205
			}
1206
		}
1207

    
1208
		// Set the mime type
1209
		response.setContentType(contentType);
1210

    
1211
		// Get the content of the file
1212
		FileInputStream fin = null;
1213
		try {
1214
			// FileInputStream to metacat
1215
			fin = new FileInputStream(filename);
1216
			// 4K buffer
1217
			byte[] buf = new byte[4 * 1024];
1218
			// Read data from file input stream to byte array
1219
			int b = fin.read(buf);
1220
			// Write to outStream from byte array
1221
			while (b != -1) {
1222
				outPut.write(buf, 0, b);
1223
				b = fin.read(buf);
1224
			}
1225
			// close file input stream
1226
			fin.close();
1227

    
1228
		}//try
1229
		catch (Exception e) {
1230
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1231
			logReplication.error("ReplicationService.handleGetDataFileRequest - error getting data file from MetacatReplication."
1232
					+ "handlGetDataFileRequest " + e.getMessage());
1233
			e.printStackTrace(System.out);
1234
		}//catch
1235

    
1236
	}
1237

    
1238
	/**
1239
	 * Sends a document to a remote host
1240
	 */
1241
	protected static void handleGetDocumentRequest(
1242
			Hashtable<String, String[]> params, HttpServletResponse response) {
1243

    
1244
		String urlString = null;
1245
		String documentPath = null;
1246
		String errorMsg = null;
1247
		try {
1248
			// try to open a https stream to test if the request server's public
1249
			// key
1250
			// in the key store, this is security issue
1251
			String server = params.get("server")[0];
1252
			urlString = "https://" + server + "?server="
1253
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test";
1254
			URL u = new URL(urlString);
1255
			String test = ReplicationService.getURLContent(u);
1256
			// couldn't pass the test
1257
			if (test.indexOf("successfully") == -1) {
1258
				response.setContentType("text/xml");
1259
				Writer out = response.getWriter();
1260
				out.write("<error>Couldn't pass the trust test " + test + " </error>");
1261
				out.close();
1262
				return;
1263
			}
1264

    
1265
			String docid = params.get("docid")[0];
1266
			logReplication.debug("ReplicationService.handleGetDocumentRequest - MetacatReplication.handleGetDocumentRequest for docid: "
1267
					+ docid);
1268
			DocumentImpl di = new DocumentImpl(docid);
1269

    
1270
			String documentDir = PropertyService
1271
					.getProperty("application.documentfilepath");
1272
			documentPath = documentDir + FileUtil.getFS() + docid;
1273

    
1274
			// if the document does not exist on disk, read it from db and write
1275
			// it to disk.
1276
			if (FileUtil.getFileStatus(documentPath) == FileUtil.DOES_NOT_EXIST
1277
					|| FileUtil.getFileSize(documentPath) == 0) {
1278
				FileOutputStream fos = new FileOutputStream(documentPath);
1279
				di.toXml(fos, null, null, true);
1280
			}
1281

    
1282
			// read the file from disk and send it to outputstream
1283
			OutputStream outputStream = response.getOutputStream();
1284
			di.readFromFileSystem(outputStream, null, null, documentPath);
1285

    
1286
			logReplication.info("ReplicationService.handleGetDocumentRequest - document " + docid + " sent");
1287

    
1288
			// return to avoid continuing to the error reporting section at the end
1289
			return;
1290
			
1291
		} catch (MalformedURLException mue) {
1292
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1293
			logReplication.error("ReplicationService.handleGetDocumentRequest - Url error when getting document from MetacatReplication."
1294
					+ "handlGetDocumentRequest for url: " + urlString + " : "
1295
					+ mue.getMessage());
1296
			// e.printStackTrace(System.out);
1297
			
1298
		} catch (IOException ioe) {
1299
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1300
			logReplication.error("ReplicationService.handleGetDocumentRequest - I/O error when getting document from MetacatReplication."
1301
					+ "handlGetDocumentRequest for file: " + documentPath + " : "
1302
					+ ioe.getMessage());
1303
			errorMsg = ioe.getMessage();
1304
		} catch (PropertyNotFoundException pnfe) {
1305
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1306
			logReplication
1307
					.error("ReplicationService.handleGetDocumentRequest - Error getting property when getting document from MetacatReplication."
1308
							+ "handlGetDocumentRequest for file: "
1309
							+ documentPath
1310
							+ " : "
1311
							+ pnfe.getMessage());
1312
			// e.printStackTrace(System.out);
1313
			errorMsg = pnfe.getMessage();
1314
		} catch (McdbException me) {
1315
			logReplication
1316
					.error("ReplicationService.handleGetDocumentRequest - Document implementation error  getting property when getting document from MetacatReplication."
1317
							+ "handlGetDocumentRequest for file: "
1318
							+ documentPath
1319
							+ " : "
1320
							+ me.getMessage());
1321
			// e.printStackTrace(System.out);
1322
			errorMsg = me.getMessage();
1323
		}
1324
		
1325
		// report any errors if we got here
1326
		response.setContentType("text/xml");
1327
		Writer out = null;
1328
		try {
1329
			response.getWriter();
1330
			out = response.getWriter();
1331
			out.write("<error>" + errorMsg + "</error>");
1332
		} catch (Exception e) {
1333
			logMetacat.error(e.getMessage(), e);
1334
		} finally {
1335
			try {
1336
				out.close();
1337
			} catch (IOException e) {
1338
				logMetacat.error(e.getMessage(), e);
1339
			}
1340
		}
1341
		
1342

    
1343
	}
1344

    
1345
	/**
1346
	 * Sends a list of all of the documents on this sever along with their
1347
	 * revision numbers. The format is: <!ELEMENT replication (server, updates)>
1348
	 * <!ELEMENT server (#PCDATA)> <!ELEMENT updates ((updatedDocument |
1349
	 * deleteDocument | revisionDocument)*)> <!ELEMENT updatedDocument (docid,
1350
	 * rev, datafile*)> <!ELEMENT deletedDocument (docid, rev)> <!ELEMENT
1351
	 * revisionDocument (docid, rev, datafile*)> <!ELEMENT docid (#PCDATA)>
1352
	 * <!ELEMENT rev (#PCDATA)> <!ELEMENT datafile (#PCDATA)> note that the rev
1353
	 * in deletedDocument is always empty. I just left it in there to make the
1354
	 * parser implementation easier.
1355
	 */
1356
	protected static void handleUpdateRequest(Hashtable<String, String[]> params,
1357
			HttpServletResponse response) {
1358
		// Checked out DBConnection
1359
		DBConnection dbConn = null;
1360
		// DBConenction serial number when checked it out
1361
		int serialNumber = -1;
1362
		PreparedStatement pstmt = null;
1363
		// Server list to store server info of xml_replication table
1364
		ReplicationServerList serverList = null;
1365
		
1366
		// a writer for response
1367
		Writer out = null;
1368

    
1369
		try {
1370
			// get writer, TODO: encoding?
1371
			response.setContentType("text/xml");
1372
			out = response.getWriter();
1373
			
1374
			// Check out a DBConnection from pool
1375
			dbConn = DBConnectionPool
1376
					.getDBConnection("MetacatReplication.handleUpdateRequest");
1377
			serialNumber = dbConn.getCheckOutSerialNumber();
1378
			// Create a server list from xml_replication table
1379
			serverList = new ReplicationServerList();
1380

    
1381
			// Get remote server name from param
1382
			String server = ((String[]) params.get("server"))[0];
1383
			// If no servr name in param, return a error
1384
			if (server == null || server.equals("")) {
1385
				out.write("<error>Request didn't specify server name</error>");
1386
				out.close();
1387
				return;
1388
			}//if
1389

    
1390
			//try to open a https stream to test if the request server's public key
1391
			//in the key store, this is security issue
1392
			String testUrl = "https://" + server + "?server="
1393
            + MetacatUtil.getLocalReplicationServerName() + "&action=test";
1394
			logReplication.info("Running trust test: " + testUrl);
1395
			URL u = new URL(testUrl);
1396
			String test = ReplicationService.getURLContent(u);
1397
			logReplication.info("Ouput from test is '" + test + "'");
1398
			//couldn't pass the test
1399
			if (test.indexOf("successfully") == -1) {
1400
			    logReplication.error("Trust test failed.");
1401
				out.write("<error>Couldn't pass the trust test</error>");
1402
				out.close();
1403
				return;
1404
			}
1405
			logReplication.info("Trust test succeeded.");
1406

    
1407
			// Check if local host configure to replicate xml documents to remote
1408
			// server. If not send back a error message
1409
			if (!serverList.getReplicationValue(server)) {
1410
				out.write("<error>Configuration not allow to replicate document to you</error>");
1411
				out.close();
1412
				return;
1413
			}//if
1414

    
1415
			// Store the sql command
1416
			StringBuffer docsql = new StringBuffer();
1417
			StringBuffer revisionSql = new StringBuffer();
1418
			
1419
			// Store the deleted docid list
1420
			StringBuffer delsql = new StringBuffer();
1421
			// Store the data set file
1422
			Vector<Vector<String>> packageFiles = new Vector<Vector<String>>();
1423

    
1424
			// Append local server's name and replication servlet to doclist
1425
			out.append("<?xml version=\"1.0\"?><replication>");
1426
			out.append("<server>")
1427
					.append(MetacatUtil.getLocalReplicationServerName());
1428
			//doclist.append(util.getProperty("replicationpath"));
1429
			out.append("</server><updates>");
1430

    
1431
			// Get correct docid that reside on this server according the requesting
1432
			// server's replicate and data replicate value in xml_replication table
1433
			docsql.append(DatabaseService.getInstance().getDBAdapter().getReplicationDocumentListSQL());
1434
			//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)) ");
1435
			revisionSql.append("select docid, rev, doctype from xml_revisions ");
1436
			// If the localhost is not a hub to the remote server, only replicate
1437
			// the docid' which home server is local host (server_location =1)
1438
			if (!serverList.getHubValue(server)) {
1439
				String serverLocationDoc = " and a.server_location = 1";
1440
				String serverLocationRev = "where server_location = 1";
1441
				docsql.append(serverLocationDoc);
1442
				revisionSql.append(serverLocationRev);
1443
			}
1444
			logReplication.info("ReplicationService.handleUpdateRequest - Doc sql: " + docsql.toString());
1445

    
1446
			// Get any deleted documents
1447
			delsql.append("select distinct docid from ");
1448
			delsql.append("xml_revisions where docid not in (select docid from ");
1449
			delsql.append("xml_documents) ");
1450
			// If the localhost is not a hub to the remote server, only replicate
1451
			// the docid' which home server is local host (server_location =1)
1452
			if (!serverList.getHubValue(server)) {
1453
				delsql.append("and server_location = 1");
1454
			}
1455
			logReplication.info("ReplicationService.handleUpdateRequest - Deleted sql: " + delsql.toString());
1456

    
1457
			// Get docid list of local host
1458
			pstmt = dbConn.prepareStatement(docsql.toString());
1459
			pstmt.execute();
1460
			ResultSet rs = pstmt.getResultSet();
1461
			boolean tablehasrows = rs.next();
1462
			//If metacat configed to replicate data file
1463
			//if ((util.getProperty("replicationsenddata")).equals("on"))
1464
			boolean replicateData = serverList.getDataReplicationValue(server);
1465
			if (replicateData) {
1466
				while (tablehasrows) {
1467
					String recordDoctype = rs.getString(3);
1468
					Vector<String> packagedoctypes = MetacatUtil
1469
							.getOptionList(PropertyService
1470
									.getProperty("xml.packagedoctype"));
1471
					//if this is a package file, put it at the end
1472
					//because if a package file is read before all of the files it
1473
					//refers to are loaded then there is an error
1474
					if (recordDoctype != null && !packagedoctypes.contains(recordDoctype)) {
1475
						//If this is not data file
1476
						if (!recordDoctype.equals("BIN")) {
1477
							//for non-data file document
1478
							out.append("<updatedDocument>");
1479
							out.append("<docid>").append(rs.getString(1));
1480
							out.append("</docid><rev>" + rs.getInt(2));
1481
							out.append("</rev>");
1482
							out.append("</updatedDocument>");
1483
						}//if
1484
						else {
1485
							//for data file document, in datafile attributes
1486
							//we put "datafile" value there
1487
							out.append("<updatedDocument>");
1488
							out.append("<docid>").append(rs.getString(1));
1489
							out.append("</docid><rev>" + rs.getInt(2));
1490
							out.append("</rev>");
1491
							out.append("<datafile>");
1492
							out.append(DATA_FILE_FLAG);
1493
							out.append("</datafile>");
1494
							out.append("</updatedDocument>");
1495
						}//else
1496
					}//if packagedoctpes
1497
					else { //the package files are saved to be put into the xml later.
1498
						Vector<String> v = new Vector<String>();
1499
						v.add(rs.getString(1));
1500
						v.add(String.valueOf(rs.getInt(2)));
1501
						packageFiles.add(v);
1502
					}//esle
1503
					tablehasrows = rs.next();
1504
				}//while
1505
			}//if
1506
			else //metacat was configured not to send data file
1507
			{
1508
				while (tablehasrows) {
1509
					String recordDoctype = rs.getString(3);
1510
					if (!recordDoctype.equals("BIN")) { //don't replicate data files
1511
						Vector<String> packagedoctypes = MetacatUtil
1512
								.getOptionList(PropertyService
1513
										.getProperty("xml.packagedoctype"));
1514
						if (recordDoctype != null
1515
								&& !packagedoctypes.contains(recordDoctype)) { //if this is a package file, put it at the end
1516
							//because if a package file is read before all of the files it
1517
							//refers to are loaded then there is an error
1518
							out.append("<updatedDocument>");
1519
							out.append("<docid>" + rs.getString(1));
1520
							out.append("</docid><rev>" + rs.getInt(2));
1521
							out.append("</rev>");
1522
							out.append("</updatedDocument>");
1523
						} else { //the package files are saved to be put into the xml later.
1524
							Vector<String> v = new Vector<String>();
1525
							v.add(rs.getString(1));
1526
							v.add(String.valueOf(rs.getInt(2)));
1527
							packageFiles.add(v);
1528
						}
1529
					}//if
1530
					tablehasrows = rs.next();
1531
				}//while
1532
			}//else
1533

    
1534
			pstmt = dbConn.prepareStatement(delsql.toString());
1535
			//usage count should increas 1
1536
			dbConn.increaseUsageCount(1);
1537

    
1538
			pstmt.execute();
1539
			rs = pstmt.getResultSet();
1540
			tablehasrows = rs.next();
1541
			while (tablehasrows) { //handle the deleted documents
1542
				out.append("<deletedDocument><docid>").append(rs.getString(1));
1543
				out.append("</docid><rev></rev></deletedDocument>");
1544
				//note that rev is always empty for deleted docs
1545
				tablehasrows = rs.next();
1546
			}
1547

    
1548
			//now we can put the package files into the xml results
1549
			for (int i = 0; i < packageFiles.size(); i++) {
1550
				Vector<String> v = packageFiles.elementAt(i);
1551
				out.append("<updatedDocument>");
1552
				out.append("<docid>").append(v.elementAt(0));
1553
				out.append("</docid><rev>");
1554
				out.append(v.elementAt(1));
1555
				out.append("</rev>");
1556
				out.append("</updatedDocument>");
1557
			}
1558
			// add revision doc list  
1559
			out.append(prepareRevisionDoc(dbConn, revisionSql.toString(),
1560
					replicateData));
1561

    
1562
			out.append("</updates></replication>");
1563
			logReplication.info("ReplicationService.handleUpdateRequest - done writing to output stream.");
1564
			pstmt.close();
1565
			//conn.close();
1566

    
1567
		} catch (Exception e) {
1568
			logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1569
			logReplication.error("ReplicationService.handleUpdateRequest - error in MetacatReplication." + "handleupdaterequest: "
1570
					+ e.getMessage());
1571
			//e.printStackTrace(System.out);
1572
			try {
1573
				out.write("<error>" + e.getMessage() + "</error>");
1574
			} catch (IOException e1) {
1575
				logMetacat.error(e1.getMessage(), e1);
1576
			}
1577
		} finally {
1578
			try {
1579
				pstmt.close();
1580
			}//try
1581
			catch (SQLException ee) {
1582
				logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1583
				logReplication.error("ReplicationService.handleUpdateRequest - Error in MetacatReplication."
1584
						+ "handleUpdaterequest to close pstmt: " + ee.getMessage());
1585
			}//catch
1586
			finally {
1587
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1588
			}//finally
1589
			try {
1590
				out.close();
1591
			} catch (IOException e) {
1592
				logMetacat.error(e.getMessage(), e);
1593
			}
1594
		}//finally
1595

    
1596
	}//handlUpdateRequest
1597

    
1598
	/**
1599
	 * 
1600
	 * @param dbConn connection for doing the update
1601
	 * @param docid the document id to update
1602
	 * @param owner the user_owner
1603
	 * @param updater the user_updated
1604
	 * @throws SQLException
1605
	 */
1606
	public static void updateUserOwner(DBConnection dbConn, String docid, String owner, String updater) throws SQLException {
1607
	
1608
		String sql = 
1609
			"UPDATE xml_documents " +
1610
			"SET user_owner = ?, " +
1611
			"user_updated = ? " +
1612
			"WHERE docid = ?;";
1613
		PreparedStatement pstmt = dbConn.prepareStatement(sql);
1614
		//usage count should increas 1
1615
		dbConn.increaseUsageCount(1);
1616

    
1617
		docid = DocumentUtil.getSmartDocId(docid);
1618
		pstmt.setString(1, owner);
1619
		pstmt.setString(2, updater);
1620
		pstmt.setString(3, docid);
1621
		pstmt.execute();
1622
		pstmt.close();
1623
		
1624
		dbConn.commit();
1625
	}
1626
	
1627
	/*
1628
	 * This method will get the xml string for document in xml_revision
1629
	 * The schema look like <!ELEMENT revisionDocument (docid, rev, datafile*)>
1630
	 */
1631
	private static String prepareRevisionDoc(DBConnection dbConn, String revSql,
1632
			boolean replicateData) throws Exception {
1633
		logReplication.warn("ReplicationService.prepareRevisionDoc - The revision document sql is " + revSql);
1634
		StringBuffer revDocList = new StringBuffer();
1635
		PreparedStatement pstmt = dbConn.prepareStatement(revSql);
1636
		//usage count should increas 1
1637
		dbConn.increaseUsageCount(1);
1638

    
1639
		pstmt.execute();
1640
		ResultSet rs = pstmt.getResultSet();
1641
		logReplication.warn("Processing replication revision for documents");
1642
		while (rs.next()) {
1643
			String recordDoctype = rs.getString(3);
1644

    
1645
			//If this is data file and it isn't configured to replicate data
1646
			if (recordDoctype.equals("BIN") && !replicateData) {
1647
				logMetacat.debug("SKipping data file because data replication is not configured");
1648

    
1649
				// do nothing
1650
			} else {
1651
				String docid = rs.getString(1);
1652
				int rev = rs.getInt(2);
1653
				logMetacat.debug("Processing replication revision for docid: " + docid + "." + rev);
1654

    
1655
				revDocList.append("<revisionDocument>");
1656
				revDocList.append("<docid>").append(docid);
1657
				revDocList.append("</docid><rev>").append(rev);
1658
				revDocList.append("</rev>");
1659
				// data file
1660
				if (recordDoctype.equals("BIN")) {
1661
					revDocList.append("<datafile>");
1662
					revDocList.append(DATA_FILE_FLAG);
1663
					revDocList.append("</datafile>");
1664
				}
1665
				revDocList.append("</revisionDocument>");
1666

    
1667
			}//else
1668
		}
1669
		//System.out.println("The revision list is"+ revDocList.toString());
1670
		return revDocList.toString();
1671
	}
1672

    
1673
	/**
1674
	 * Returns the xml_catalog table encoded in xml
1675
	 */
1676
	public static String getCatalogXML() {
1677
		return handleGetCatalogRequest(null, null, false);
1678
	}
1679

    
1680
	/**
1681
	 * Sends the contents of the xml_catalog table encoded in xml
1682
	 * The xml format is:
1683
	 * <!ELEMENT xml_catalog (row*)>
1684
	 * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
1685
	 *                system_id)>
1686
	 * All of the sub elements of row are #PCDATA
1687

    
1688
	 * If printFlag == false then do not print to out.
1689
	 */
1690
	protected static String handleGetCatalogRequest(
1691
			Hashtable<String, String[]> params, HttpServletResponse response,
1692
			boolean printFlag) {
1693
		DBConnection dbConn = null;
1694
		int serialNumber = -1;
1695
		PreparedStatement pstmt = null;
1696
		Writer out = null;
1697
		try {
1698
			// get writer, TODO: encoding?
1699
		    if(printFlag)
1700
		    {
1701
		        response.setContentType("text/xml");
1702
		        out = response.getWriter();
1703
		    }
1704
			/*conn = MetacatReplication.getDBConnection("MetacatReplication." +
1705
			                                          "handleGetCatalogRequest");*/
1706
			dbConn = DBConnectionPool
1707
					.getDBConnection("MetacatReplication.handleGetCatalogRequest");
1708
			serialNumber = dbConn.getCheckOutSerialNumber();
1709
			pstmt = dbConn.prepareStatement("select entry_type, "
1710
					+ "source_doctype, target_doctype, public_id, "
1711
					+ "system_id from xml_catalog");
1712
			pstmt.execute();
1713
			ResultSet rs = pstmt.getResultSet();
1714
			boolean tablehasrows = rs.next();
1715
			StringBuffer sb = new StringBuffer();
1716
			sb.append("<?xml version=\"1.0\"?><xml_catalog>");
1717
			while (tablehasrows) {
1718
				sb.append("<row><entry_type>").append(rs.getString(1));
1719
				sb.append("</entry_type><source_doctype>").append(rs.getString(2));
1720
				sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
1721
				sb.append("</target_doctype><public_id>").append(rs.getString(4));
1722
				// system id may not have server url on front.  Add it if not.
1723
				String systemID = rs.getString(5);
1724
				if (!systemID.startsWith("http://")) {
1725
					systemID = SystemUtil.getContextURL() + systemID;
1726
				}
1727
				sb.append("</public_id><system_id>").append(systemID);
1728
				sb.append("</system_id></row>");
1729

    
1730
				tablehasrows = rs.next();
1731
			}
1732
			sb.append("</xml_catalog>");
1733
			//conn.close();
1734
			if (printFlag) {
1735
				response.setContentType("text/xml");
1736
				out.write(sb.toString());
1737
			}
1738
			pstmt.close();
1739
			return sb.toString();
1740
		} catch (Exception e) {
1741
			logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1742
			logReplication.error("ReplicationService.handleGetCatalogRequest - error in MetacatReplication.handleGetCatalogRequest:"
1743
					+ e.getMessage());
1744
			e.printStackTrace(System.out);
1745
			if (printFlag) {
1746
				try {
1747
					out.write("<error>" + e.getMessage() + "</error>");
1748
				} catch (IOException e1) {
1749
					logMetacat.error(e1.getMessage(), e1);
1750
				}
1751
			}
1752
		} finally {
1753
			try {
1754
				pstmt.close();
1755
			}//try
1756
			catch (SQLException ee) {
1757
				logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1758
				logReplication.error("ReplicationService.handleGetCatalogRequest - Error in MetacatReplication.handleGetCatalogRequest: "
1759
						+ ee.getMessage());
1760
			}//catch
1761
			finally {
1762
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1763
			}//finally
1764
			if (out != null) {
1765
				try {
1766
					out.close();
1767
				} catch (IOException e1) {
1768
					logMetacat.error(e1.getMessage(), e1);
1769
				}
1770
			}
1771
		}//finally
1772

    
1773
		return null;
1774
	}
1775

    
1776
	/**
1777
	 * Sends the current system date to the remote server.  Using this action
1778
	 * for replication gets rid of any problems with syncronizing clocks
1779
	 * because a time specific to a document is always kept on its home server.
1780
	 */
1781
	protected static void handleGetTimeRequest(
1782
			Hashtable<String, String[]> params, HttpServletResponse response) {
1783
		
1784
		// use standard format -- the receiving end wants this too
1785
		String dateString = DateTimeMarshaller.serializeDateToUTC(Calendar.getInstance().getTime());
1786
		
1787
		// get a writer for sending back to response
1788
		response.setContentType("text/xml");
1789
		Writer out = null;
1790
		try {
1791
			out = response.getWriter();
1792
			out.write("<timestamp>" + dateString + "</timestamp>");
1793
			out.close();
1794
		} catch (IOException e) {
1795
			logMetacat.error(e.getMessage(), e);
1796
		}
1797
		
1798
	}
1799

    
1800
	/**
1801
	 * this method handles the timeout for a file lock.  when a lock is
1802
	 * granted it is granted for 30 seconds.  When this thread runs out
1803
	 * it deletes the docid from the queue, thus eliminating the lock.
1804
	 */
1805
	public void run() {
1806
		try {
1807
			logReplication.info("ReplicationService.run - thread started for docid: "
1808
					+ (String) fileLocks.elementAt(0));
1809

    
1810
			Thread.sleep(30000); //the lock will expire in 30 seconds
1811
			logReplication.info("thread for docid: "
1812
					+ (String) fileLocks.elementAt(fileLocks.size() - 1) + " exiting.");
1813

    
1814
			fileLocks.remove(fileLocks.size() - 1);
1815
			//fileLocks is treated as a FIFO queue.  If there are more than one lock
1816
			//in the vector, the first one inserted will be removed.
1817
		} catch (Exception e) {
1818
			logMetacat.error("ReplicationService.run - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1819
			logReplication.error("ReplicationService.run - error in file lock thread from "
1820
					+ "MetacatReplication.run: " + e.getMessage());
1821
		}
1822
	}
1823

    
1824
	/**
1825
	 * Returns the name of a server given a serverCode
1826
	 * @param serverCode the serverid of the server
1827
	 * @return the servername or null if the specified serverCode does not
1828
	 *         exist.
1829
	 */
1830
	public static String getServerNameForServerCode(int serverCode) {
1831
		//System.out.println("serverid: " + serverCode);
1832
		DBConnection dbConn = null;
1833
		int serialNumber = -1;
1834
		PreparedStatement pstmt = null;
1835
		try {
1836
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServer");
1837
			serialNumber = dbConn.getCheckOutSerialNumber();
1838
			String sql = new String("select server from "
1839
					+ "xml_replication where serverid = ?");
1840
			pstmt = dbConn.prepareStatement(sql);
1841
			pstmt.setInt(1, serverCode);
1842
			//System.out.println("getserver sql: " + sql);
1843
			pstmt.execute();
1844
			ResultSet rs = pstmt.getResultSet();
1845
			boolean tablehasrows = rs.next();
1846
			if (tablehasrows) {
1847
				//System.out.println("server: " + rs.getString(1));
1848
				return rs.getString(1);
1849
			}
1850

    
1851
			//conn.close();
1852
		} catch (Exception e) {
1853
			logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1854
			logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplication.getServer: " + e.getMessage());
1855
		} finally {
1856
			try {
1857
				pstmt.close();
1858
			}//try
1859
			catch (SQLException ee) {
1860
				logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1861
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacactReplication.getserver: "
1862
						+ ee.getMessage());
1863
			}//catch
1864
			finally {
1865
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1866
			}//fianlly
1867
		}//finally
1868

    
1869
		return null;
1870
		//return null if the server does not exist
1871
	}
1872

    
1873
	/**
1874
	 * Returns a server code given a server name
1875
	 * @param server the name of the server
1876
	 * @return integer > 0 representing the code of the server, 0 if the server
1877
	 *  does not exist.
1878
	 */
1879
	public static int getServerCodeForServerName(String server) throws ServiceException {
1880
		DBConnection dbConn = null;
1881
		int serialNumber = -1;
1882
		PreparedStatement pstmt = null;
1883
		int serverCode = 0;
1884

    
1885
		try {
1886

    
1887
			//conn = util.openDBConnection();
1888
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServerCode");
1889
			serialNumber = dbConn.getCheckOutSerialNumber();
1890
			pstmt = dbConn.prepareStatement("SELECT serverid FROM xml_replication "
1891
					+ "WHERE server LIKE ?");
1892
			pstmt.setString(1, server);
1893
			pstmt.execute();
1894
			ResultSet rs = pstmt.getResultSet();
1895
			boolean tablehasrows = rs.next();
1896
			if (tablehasrows) {
1897
				serverCode = rs.getInt(1);
1898
				pstmt.close();
1899
				//conn.close();
1900
				return serverCode;
1901
			}
1902

    
1903
		} catch (SQLException sqle) {
1904
			throw new ServiceException("ReplicationService.getServerCodeForServerName - " 
1905
					+ "SQL error when getting server code: " + sqle.getMessage());
1906

    
1907
		} finally {
1908
			try {
1909
				pstmt.close();
1910
				//conn.close();
1911
			}//try
1912
			catch (Exception ee) {
1913
				logMetacat.error("ReplicationService.getServerCodeForServerName - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1914
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplicatio.getServerCode: "
1915
						+ ee.getMessage());
1916

    
1917
			}//catch
1918
			finally {
1919
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1920
			}//finally
1921
		}//finally
1922

    
1923
		return serverCode;
1924
	}
1925

    
1926
	/**
1927
	 * Method to get a host server information for given docid
1928
	 * @param conn a connection to the database
1929
	 */
1930
	public static Hashtable<String, String> getHomeServerInfoForDocId(String docId) {
1931
		Hashtable<String, String> sl = new Hashtable<String, String>();
1932
		DBConnection dbConn = null;
1933
		int serialNumber = -1;
1934
		docId = DocumentUtil.getDocIdFromString(docId);
1935
		PreparedStatement pstmt = null;
1936
		int serverLocation;
1937
		try {
1938
			//get conection
1939
			dbConn = DBConnectionPool.getDBConnection("ReplicationHandler.getHomeServer");
1940
			serialNumber = dbConn.getCheckOutSerialNumber();
1941
			//get a server location from xml_document table
1942
			pstmt = dbConn.prepareStatement("select server_location from xml_documents "
1943
					+ "where docid = ?");
1944
			pstmt.setString(1, docId);
1945
			pstmt.execute();
1946
			ResultSet serverName = pstmt.getResultSet();
1947
			//get a server location
1948
			if (serverName.next()) {
1949
				serverLocation = serverName.getInt(1);
1950
				pstmt.close();
1951
			} else {
1952
				pstmt.close();
1953
				//ut.returnConnection(conn);
1954
				return null;
1955
			}
1956
			pstmt = dbConn.prepareStatement("select server, last_checked, replicate "
1957
					+ "from xml_replication where serverid = ?");
1958
			//increase usage count
1959
			dbConn.increaseUsageCount(1);
1960
			pstmt.setInt(1, serverLocation);
1961
			pstmt.execute();
1962
			ResultSet rs = pstmt.getResultSet();
1963
			boolean tableHasRows = rs.next();
1964
			if (tableHasRows) {
1965

    
1966
				String server = rs.getString(1);
1967
				String last_checked = rs.getString(2);
1968
				if (!server.equals("localhost")) {
1969
					sl.put(server, last_checked);
1970
				}
1971

    
1972
			} else {
1973
				pstmt.close();
1974
				//ut.returnConnection(conn);
1975
				return null;
1976
			}
1977
			pstmt.close();
1978
		} catch (Exception e) {
1979
			logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1980
			logReplication.error("ReplicationService.getHomeServerInfoForDocId - error in replicationHandler.getHomeServer(): "
1981
					+ e.getMessage());
1982
		} finally {
1983
			try {
1984
				pstmt.close();
1985
				//ut.returnConnection(conn);
1986
			} catch (Exception ee) {
1987
				logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1988
				logReplication.error("ReplicationService.getHomeServerInfoForDocId - Eror irn rplicationHandler.getHomeServer() "
1989
						+ "to close pstmt: " + ee.getMessage());
1990
			} finally {
1991
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1992
			}
1993

    
1994
		}//finally
1995
		return sl;
1996
	}
1997

    
1998
	/**
1999
	 * Returns a home server location  given a accnum
2000
	 * @param accNum , given accNum for a document
2001
	 *
2002
	 */
2003
	public static int getHomeServerCodeForDocId(String accNum) throws ServiceException {
2004
		DBConnection dbConn = null;
2005
		int serialNumber = -1;
2006
		PreparedStatement pstmt = null;
2007
		int serverCode = 1;
2008
		String docId = DocumentUtil.getDocIdFromString(accNum);
2009

    
2010
		try {
2011

    
2012
			// Get DBConnection
2013
			dbConn = DBConnectionPool
2014
					.getDBConnection("ReplicationHandler.getServerLocation");
2015
			serialNumber = dbConn.getCheckOutSerialNumber();
2016
			pstmt = dbConn.prepareStatement("SELECT server_location FROM xml_documents "
2017
					+ "WHERE docid LIKE ? ");
2018
			pstmt.setString(1, docId);
2019
			pstmt.execute();
2020
			ResultSet rs = pstmt.getResultSet();
2021
			boolean tablehasrows = rs.next();
2022
			//If a document is find, return the server location for it
2023
			if (tablehasrows) {
2024
				serverCode = rs.getInt(1);
2025
				pstmt.close();
2026
				//conn.close();
2027
				return serverCode;
2028
			}
2029
			//if couldn't find in xml_documents table, we think server code is 1
2030
			//(this is new document)
2031
			else {
2032
				pstmt.close();
2033
				//conn.close();
2034
				return serverCode;
2035
			}
2036

    
2037
		} catch (SQLException sqle) {
2038
			throw new ServiceException("ReplicationService.getHomeServerCodeForDocId - " 
2039
					+ "SQL error when getting home server code for docid: " + docId + " : " 
2040
					+ sqle.getMessage());
2041

    
2042
		} finally {
2043
			try {
2044
				pstmt.close();
2045
				//conn.close();
2046

    
2047
			} catch (SQLException sqle) {
2048
				logMetacat.error("ReplicationService.getHomeServerCodeForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2049
				logReplication.error("ReplicationService.getHomeServerCodeForDocId - ReplicationService.getHomeServerCodeForDocId - " 
2050
						+ "SQL error when getting home server code for docid: " + docId + " : " 
2051
						+ sqle.getMessage());
2052
			} finally {
2053
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2054
			}//finally
2055
		}//finally
2056
		//return serverCode;
2057
	}
2058

    
2059
	/**
2060
	 * This method returns the content of a url
2061
	 * @param u the url to return the content from
2062
	 * @return a string representing the content of the url
2063
	 * @throws java.io.IOException
2064
	 */
2065
	public static String getURLContent(URL u) throws java.io.IOException {
2066
		char istreamChar;
2067
		int istreamInt;
2068
		// get the response content
2069
		InputStream input = getURLStream(u);
2070
		logReplication.info("ReplicationService.getURLContent - After getting response from: " + u.toString());
2071
		InputStreamReader istream = new InputStreamReader(input);
2072
		StringBuffer serverResponse = new StringBuffer();
2073
		while ((istreamInt = istream.read()) != -1) {
2074
			istreamChar = (char) istreamInt;
2075
			serverResponse.append(istreamChar);
2076
		}
2077
		istream.close();
2078
		input.close();
2079

    
2080
		return serverResponse.toString();
2081
	}
2082
	
2083
	/**
2084
	 * This method returns the InputStream after opening a url
2085
	 * @param u the url to return the content from
2086
	 * @return a InputStream representing the content of the url
2087
	 * @throws java.io.IOException
2088
	 */
2089
	public static InputStream getURLStream(URL u) throws java.io.IOException {
2090
	    logReplication.info("Getting url stream from " + u.toString());
2091
		logReplication.info("ReplicationService.getURLStream - Before sending request to: " + u.toString());
2092
		// use httpclient to set up SSL
2093
		RestClient client = getSSLClient();
2094
		HttpResponse response = client.doGetRequest(u.toString());
2095
		// get the response content
2096
		InputStream input = response.getEntity().getContent();
2097
		logReplication.info("ReplicationService.getURLStream - After getting response from: " + u.toString());
2098
		
2099
		return input;		
2100
	}
2101
	
2102
	/**
2103
	 * Sets up an HttpClient with SSL connection.
2104
	 * Sends client certificate to the server when doing the request.
2105
	 * @return
2106
	 */
2107
	private static RestClient getSSLClient() {
2108
		RestClient client = new RestClient();
2109
		
2110
		// set up this server's client identity
2111
		String subject = null;
2112
		try {
2113
			// TODO: should there be alternative ways to get the key and certificate?
2114
			String certificateFile = PropertyService.getProperty("replication.certificate.file");
2115
	    	String keyFile = PropertyService.getProperty("replication.privatekey.file");
2116
			String keyPassword = PropertyService.getProperty("replication.privatekey.password");
2117
			X509Certificate certificate = CertificateManager.getInstance().loadCertificateFromFile(certificateFile);
2118
			PrivateKey privateKey = CertificateManager.getInstance().loadPrivateKeyFromFile(keyFile, keyPassword);
2119
			subject = CertificateManager.getInstance().getSubjectDN(certificate);
2120
			CertificateManager.getInstance().registerCertificate(subject, certificate, privateKey);
2121
		} catch (Exception e) {
2122
			// this is pretty much required for replication communication
2123
			logReplication.warn("Could not find server's client certificate/private key: " + e.getMessage());
2124
		}
2125
		
2126
		// set the configured timeout
2127
		client.setTimeouts(CLIENTTIMEOUT);
2128

    
2129
		SSLSocketFactory socketFactory = null;
2130
		try {
2131
			socketFactory = CertificateManager.getInstance().getSSLSocketFactory(subject);
2132
		} catch (FileNotFoundException e) {
2133
			// these are somewhat expected for anonymous client use
2134
			logReplication.warn("Could not set up SSL connection for client - likely because the certificate could not be located: " + e.getMessage());
2135
		} catch (Exception e) {
2136
			// this is likely more severe
2137
			logReplication.warn("Funky SSL going on: " + e.getClass() + ":: " + e.getMessage());
2138
		}
2139
		try {
2140
			//443 is the default port, this value is overridden if explicitly set in the URL
2141
			Scheme sch = new Scheme("https", 443, socketFactory);
2142
			client.getHttpClient().getConnectionManager().getSchemeRegistry().register(sch);
2143
		} catch (Exception e) {
2144
			// this is likely more severe
2145
			logReplication.error("Failed to set up SSL connection for client. Continuing. " + e.getClass() + ":: " + e.getMessage(), e);
2146
		}
2147
		return client;
2148
	}
2149
	
2150

    
2151
//	/**
2152
//	 * Method for writing replication messages to a log file specified in
2153
//	 * metacat.properties
2154
//	 */
2155
//	public static void replLog(String message) {
2156
//		try {
2157
//			FileOutputStream fos = new FileOutputStream(PropertyService
2158
//					.getProperty("replication.logdir")
2159
//					+ "/metacatreplication.log", true);
2160
//			PrintWriter pw = new PrintWriter(fos);
2161
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
2162
//			java.util.Date localtime = new java.util.Date();
2163
//			String dateString = formatter.format(localtime);
2164
//			dateString += " :: " + message;
2165
//			// time stamp each entry
2166
//			pw.println(dateString);
2167
//			pw.flush();
2168
//		} catch (Exception e) {
2169
//			logReplication.error("error writing to replication log from "
2170
//					+ "MetacatReplication.replLog: " + e.getMessage());
2171
//			// e.printStackTrace(System.out);
2172
//		}
2173
//	}
2174

    
2175
//	/**
2176
//	 * Method for writing replication messages to a log file specified in
2177
//	 * metacat.properties
2178
//	 */
2179
//	public static void replErrorLog(String message) {
2180
//		try {
2181
//			FileOutputStream fos = new FileOutputStream(PropertyService
2182
//					.getProperty("replication.logdir")
2183
//					+ "/metacatreplicationerror.log", true);
2184
//			PrintWriter pw = new PrintWriter(fos);
2185
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
2186
//			java.util.Date localtime = new java.util.Date();
2187
//			String dateString = formatter.format(localtime);
2188
//			dateString += " :: " + message;
2189
//			//time stamp each entry
2190
//			pw.println(dateString);
2191
//			pw.flush();
2192
//		} catch (Exception e) {
2193
//			logReplication.error("error writing to replication error log from "
2194
//					+ "MetacatReplication.replErrorLog: " + e.getMessage());
2195
//			//e.printStackTrace(System.out);
2196
//		}
2197
//	}
2198

    
2199
	/**
2200
	 * Returns true if the replicate field for server in xml_replication is 1.
2201
	 * Returns false otherwise
2202
	 */
2203
	public static boolean replToServer(String server) {
2204
		DBConnection dbConn = null;
2205
		int serialNumber = -1;
2206
		PreparedStatement pstmt = null;
2207
		try {
2208
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.repltoServer");
2209
			serialNumber = dbConn.getCheckOutSerialNumber();
2210
			pstmt = dbConn.prepareStatement("select replicate from "
2211
					+ "xml_replication where server like ? ");
2212
			pstmt.setString(1, server);
2213
			pstmt.execute();
2214
			ResultSet rs = pstmt.getResultSet();
2215
			boolean tablehasrows = rs.next();
2216
			if (tablehasrows) {
2217
				int i = rs.getInt(1);
2218
				if (i == 1) {
2219
					pstmt.close();
2220
					//conn.close();
2221
					return true;
2222
				} else {
2223
					pstmt.close();
2224
					//conn.close();
2225
					return false;
2226
				}
2227
			}
2228
		} catch (SQLException sqle) {
2229
			logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2230
			logReplication.error("ReplicationService.replToServer - SQL error in MetacatReplication.replToServer: "
2231
					+ sqle.getMessage());
2232
		} finally {
2233
			try {
2234
				pstmt.close();
2235
				//conn.close();
2236
			}//try
2237
			catch (Exception ee) {
2238
				logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2239
				logReplication.error("ReplicationService.replToServer - Error in MetacatReplication.replToServer: "
2240
						+ ee.getMessage());
2241
			}//catch
2242
			finally {
2243
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2244
			}//finally
2245
		}//finally
2246
		return false;
2247
		//the default if this server does not exist is to not replicate to it.
2248
	}
2249

    
2250
}
(6-6/7)