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: 2013-03-22 12:29:48 -0700 (Fri, 22 Mar 2013) $'
10
 * '$Revision: 7519 $'
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.DocumentImpl;
73
import edu.ucsb.nceas.metacat.DocumentImplWrapper;
74
import edu.ucsb.nceas.metacat.EventLog;
75
import edu.ucsb.nceas.metacat.IdentifierManager;
76
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
77
import edu.ucsb.nceas.metacat.McdbException;
78
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlException;
79
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlForSingleFile;
80
import edu.ucsb.nceas.metacat.accesscontrol.PermOrderException;
81
import edu.ucsb.nceas.metacat.admin.upgrade.RemoveInvalidReplicas;
82
import edu.ucsb.nceas.metacat.admin.upgrade.dataone.GenerateORE;
83
import edu.ucsb.nceas.metacat.admin.upgrade.dataone.GenerateSystemMetadata;
84
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
85
import edu.ucsb.nceas.metacat.database.DBConnection;
86
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
87
import edu.ucsb.nceas.metacat.database.DatabaseService;
88
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
89
import edu.ucsb.nceas.metacat.properties.PropertyService;
90
import edu.ucsb.nceas.metacat.shared.BaseService;
91
import edu.ucsb.nceas.metacat.shared.HandlerException;
92
import edu.ucsb.nceas.metacat.shared.ServiceException;
93
import edu.ucsb.nceas.metacat.util.DocumentUtil;
94
import edu.ucsb.nceas.metacat.util.MetacatUtil;
95
import edu.ucsb.nceas.metacat.util.ReplicationUtil;
96
import edu.ucsb.nceas.metacat.util.SystemUtil;
97
import edu.ucsb.nceas.utilities.FileUtil;
98
import edu.ucsb.nceas.utilities.GeneralPropertyException;
99
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
100
import edu.ucsb.nceas.utilities.access.DocInfoHandler;
101
import edu.ucsb.nceas.utilities.access.XMLAccessDAO;
102

    
103
public class ReplicationService extends BaseService {
104

    
105
	private static ReplicationService replicationService = null;
106

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
442
			pstmt = dbConn.prepareStatement("SELECT serverid, server, last_checked, replicate, datareplicate, hub FROM xml_replication");
443
			pstmt.execute();
444
			ResultSet rs = pstmt.getResultSet();
445
			boolean tablehasrows = rs.next();
446
			while (tablehasrows) {
447
				String serverId = rs.getString(1);
448
				out.write("<tr><td>" + rs.getString(2) + "</td><td>");
449
				out.write(rs.getString(3) + "</td><td>");
450
				out.write(rs.getString(4) + "</td><td>");
451
				out.write(rs.getString(5) + "</td><td>");
452
				out.write(rs.getString(6) + "</td>");
453
				if (showGenerateSystemMetadata) {
454
					// for SM
455
					out.write("<td><form action='" + request.getContextPath() + "/admin'>");
456
					out.write("<input name='serverid' type='hidden' value='" + serverId  + "'/>");
457
					out.write("<input name='configureType' type='hidden' value='replication'/>");
458
					out.write("<input name='action' type='hidden' value='servercontrol'/>");
459
					out.write("<input name='subaction' type='hidden' value='generatesystemmetadata'/>");
460
					out.write("<input type='submit' value='Generate System Metadata'/>");
461
					out.write("</form></td>");
462
					
463
					// for ORE maps
464
					out.write("<td><form action='" + request.getContextPath() + "/admin'>");
465
					out.write("<input name='serverid' type='hidden' value='" + serverId + "'/>");
466
					out.write("<input name='configureType' type='hidden' value='replication'/>");
467
					out.write("<input name='action' type='hidden' value='servercontrol'/>");
468
					out.write("<input name='subaction' type='hidden' value='generateore'/>");
469
					out.write("<input type='submit' value='Generate ORE'/>");
470
					out.write("</form></td>");
471
					
472
					// for invalid replicas
473
					out.write("<td><form action='" + request.getContextPath() + "/admin'>");
474
					out.write("<input name='serverid' type='hidden' value='" + serverId + "'/>");
475
					out.write("<input name='configureType' type='hidden' value='replication'/>");
476
					out.write("<input name='action' type='hidden' value='servercontrol'/>");
477
					out.write("<input name='subaction' type='hidden' value='removeinvalidreplicas'/>");
478
					String disabled = "";
479
					if (Integer.valueOf(serverId) == 1) {
480
						disabled = "disabled='true'";
481
					}
482
					out.write("<input type='submit' value='Remove Invalid Replicas' " + disabled + " />");
483
					out.write("</form></td>");
484
				}
485
				out.write("</tr>");
486

    
487
				tablehasrows = rs.next();
488
			}
489
			out.write("</table></body></html>");
490
			
491
			
492
			pstmt.close();
493
			//conn.close();
494

    
495
		} catch (Exception e) {
496
			logMetacat.error("ReplicationService.handleServerControlRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
497
			logReplication.error("ReplicationService.handleServerControlRequest - Error in "
498
					+ "MetacatReplication.handleServerControlRequest " + e.getMessage());
499
			e.printStackTrace(System.out);
500
		} finally {
501
			try {
502
				pstmt.close();
503
			}//try
504
			catch (SQLException ee) {
505
				logMetacat.error("ReplicationService.handleServerControlRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
506
				logReplication.error("ReplicationService.handleServerControlRequest - Error in MetacatReplication.handleServerControlRequest to close pstmt "
507
						+ ee.getMessage());
508
			}//catch
509
			finally {
510
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
511
			}//finally
512
			if (out != null) {
513
				try {
514
					out.close();
515
				} catch (IOException e) {
516
					logMetacat.error(e.getMessage(), e);
517
				}
518
			}
519
		}//finally
520

    
521
	}
522

    
523
	/**
524
	 * when a forcereplication request comes in, local host sends a read request
525
	 * to the requesting server (remote server) for the specified docid. Then
526
	 * store it in local database.
527
	 */
528
	protected static void handleForceReplicateRequest(
529
			Hashtable<String, String[]> params, HttpServletResponse response,
530
			HttpServletRequest request) {
531
		String server = ((String[]) params.get("server"))[0]; // the server that
532
		String docid = ((String[]) params.get("docid"))[0]; // sent the document
533
		String dbaction = "UPDATE"; // the default action is UPDATE
534
		//    boolean override = false;
535
		//    int serverCode = 1;
536
		DBConnection dbConn = null;
537
		int serialNumber = -1;
538
		String docName = null;
539

    
540
		try {
541
			//if the url contains a dbaction then the default action is overridden
542
			if (params.containsKey("dbaction")) {
543
				dbaction = ((String[]) params.get("dbaction"))[0];
544
				//serverCode = MetacatReplication.getServerCode(server);
545
				//override = true; //we are now overriding the default action
546
			}
547
			logReplication.info("ReplicationService.handleForceReplicateRequest - Force replication request from: " + server);
548
			logReplication.info("ReplicationService.handleForceReplicateRequest - Force replication docid: " + docid);
549
			logReplication.info("ReplicationService.handleForceReplicateRequest - Force replication action: " + dbaction);
550
			// sending back read request to remote server
551
			URL u = new URL("https://" + server + "?server="
552
					+ MetacatUtil.getLocalReplicationServerName() + "&action=read&docid="
553
					+ docid);
554
			String xmldoc = ReplicationService.getURLContent(u);
555

    
556
			// get the document info from server
557
			URL docinfourl = new URL("https://" + server + "?server="
558
					+ MetacatUtil.getLocalReplicationServerName()
559
					+ "&action=getdocumentinfo&docid=" + docid);
560
			
561

    
562
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
563
			// strip out the system metadata portion
564
			String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
565
			docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);
566
		   	  
567
			//dih is the parser for the docinfo xml format
568
			DocInfoHandler dih = new DocInfoHandler();
569
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
570
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
571
			//      Hashtable<String,Vector<AccessControlForSingleFile>> docinfoHash = dih.getDocInfo();
572
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
573
			
574
			// Get home server of this docid
575
			String homeServer = (String) docinfoHash.get("home_server");
576
			
577
			// process system metadata
578
			if (systemMetadataXML != null) {
579
				SystemMetadata sysMeta = 
580
					TypeMarshaller.unmarshalTypeFromStream(
581
							SystemMetadata.class,
582
							new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
583
				// need the guid-to-docid mapping
584
				boolean mappingExists = true;
585
		      	mappingExists = IdentifierManager.getInstance().mappingExists(sysMeta.getIdentifier().getValue());
586
		      	if (!mappingExists) {
587
		      		IdentifierManager.getInstance().createMapping(sysMeta.getIdentifier().getValue(), docid);
588
		      	}
589
				// save the system metadata
590
				HazelcastService.getInstance().getSystemMetadataMap().put(sysMeta.getIdentifier(), sysMeta);
591
			}
592
      
593
			// dates
594
			String createdDateString = docinfoHash.get("date_created");
595
			String updatedDateString = docinfoHash.get("date_updated");
596
			Date createdDate = DateTimeMarshaller.deserializeDateToUTC(createdDateString);
597
			Date updatedDate = DateTimeMarshaller.deserializeDateToUTC(updatedDateString);
598
		      
599
			logReplication.info("ReplicationService.handleForceReplicateRequest - homeServer: " + homeServer);
600
			// Get Document type
601
			String docType = (String) docinfoHash.get("doctype");
602
			logReplication.info("ReplicationService.handleForceReplicateRequest - docType: " + docType);
603
			String parserBase = null;
604
			// this for eml2 and we need user eml2 parser
605
			if (docType != null
606
					&& (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE)) {
607
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml200 document!");
608
				parserBase = DocumentImpl.EML200;
609
			} else if (docType != null
610
					&& (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE)) {
611
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.0.1 document!");
612
				parserBase = DocumentImpl.EML200;
613
			} else if (docType != null
614
					&& (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE)) {
615
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.0 document!");
616
				parserBase = DocumentImpl.EML210;
617
			} else if (docType != null
618
					&& (docType.trim()).equals(DocumentImpl.EML2_1_1NAMESPACE)) {
619
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.1 document!");
620
				parserBase = DocumentImpl.EML210;
621
			}
622
			logReplication.warn("ReplicationService.handleForceReplicateRequest - The parserBase is: " + parserBase);
623

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

    
637
				//process extra access rules before dealing with the write exception (doc exist already)
638
				try {
639
		        	// check if we had a guid -> docid mapping
640
		        	String docidNoRev = DocumentUtil.getDocIdFromAccessionNumber(docid);
641
		        	int rev = DocumentUtil.getRevisionFromAccessionNumber(docid);
642
		        	IdentifierManager.getInstance().getGUID(docidNoRev, rev);
643
		        	// no need to create the mapping if we have it
644
		        } catch (McdbDocNotFoundException mcdbe) {
645
		        	// create mapping if we don't
646
		        	IdentifierManager.getInstance().createMapping(docid, docid);
647
		        }
648
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
649
		        if (accessControlList != null) {
650
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
651
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
652
		        		try {
653
			        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
654
			        			acfsf.insertPermissions(xmlAccessDAO);
655
								logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
656
										+ " permissions added to DB");
657
			        		}
658
		        		} catch (PermOrderException poe) {
659
		        			// this is problematic, but should not prevent us from replicating
660
		        			// see https://redmine.dataone.org/issues/2583
661
		        			String msg = "Could not insert access control for: " + docid + " Message: " + poe.getMessage();
662
		        			logMetacat.error(msg, poe);
663
		        			logReplication.error(msg, poe);
664
		        		}
665
		            }
666
		        }
667
		        
668
		        // process the real owner and updater
669
				String user = (String) docinfoHash.get("user_owner");
670
				String updated = (String) docinfoHash.get("user_updated");
671
		        updateUserOwner(dbConn, docid, user, updated);
672

    
673
				logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid + " added to DB with "
674
						+ "action " + dbaction);
675
				
676
				EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER, docid, dbaction);
677
			}
678
		} catch (SQLException sqle) {
679
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
680
			logReplication.error("ReplicationService.handleForceReplicateRequest - SQL error when adding doc " + docid + 
681
					" to DB with action " + dbaction + ": " + sqle.getMessage());
682
		} catch (MalformedURLException mue) {
683
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
684
			logReplication.error("ReplicationService.handleForceReplicateRequest - URL error when adding doc " + docid + 
685
					" to DB with action " + dbaction + ": " + mue.getMessage());
686
		} catch (SAXException se) {
687
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
688
			logReplication.error("ReplicationService.handleForceReplicateRequest - SAX parsing error when adding doc " + docid + 
689
					" to DB with action " + dbaction + ": " + se.getMessage());
690
		} catch (HandlerException he) {
691
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
692
			logReplication.error("ReplicationService.handleForceReplicateRequest - Handler error when adding doc " + docid + 
693
					" to DB with action " + dbaction + ": " + he.getMessage());
694
		} catch (IOException ioe) {
695
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
696
			logReplication.error("ReplicationService.handleForceReplicateRequest - I/O error when adding doc " + docid + 
697
					" to DB with action " + dbaction + ": " + ioe.getMessage());
698
		} catch (PermOrderException poe) {
699
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
700
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
701
					" to DB with action " + dbaction + ": " + poe.getMessage());
702
		} catch (AccessControlException ace) {
703
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
704
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
705
					" to DB with action " + dbaction + ": " + ace.getMessage());
706
		} catch (Exception e) {
707
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
708
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when adding doc " + docid + 
709
					" to DB with action " + dbaction + ": " + e.getMessage());
710
		} finally {
711
			// Return the checked out DBConnection
712
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
713
		}//finally
714
	}
715

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

    
756
		}//catch
757

    
758
	}
759

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

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

    
783
		// Overide or not
784
		//    boolean override = false;
785
		// dbaction - update or insert
786
		String dbaction = null;
787

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

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

    
808
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
809
			
810
			// strip out the system metadata portion
811
		    String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
812
		   	docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);
813

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

    
822
			String docType = (String) docinfoHash.get("doctype");
823

    
824
			String docHomeServer = (String) docinfoHash.get("home_server");
825
			
826
			String createdDateString = docinfoHash.get("date_created");
827
			String updatedDateString = docinfoHash.get("date_updated");
828
			
829
			Date createdDate = DateTimeMarshaller.deserializeDateToUTC(createdDateString);
830
			Date updatedDate = DateTimeMarshaller.deserializeDateToUTC(updatedDateString);
831
			
832
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - docHomeServer of datafile: " + docHomeServer);
833

    
834
			// in case we have a write exception, we still want to track access and sysmeta
835
			Exception writeException = null;
836

    
837
			// do we need the object content?
838
			if (dbaction != null && (dbaction.equals("insert") || dbaction.equals("update"))) {
839
				//Get data file and store it into local file system.
840
				// sending back readdata request to server
841
				URL url = new URL("https://" + server + "?server="
842
						+ MetacatUtil.getLocalReplicationServerName()
843
						+ "&action=readdata&docid=" + docid);
844
				String datafilePath = PropertyService
845
						.getProperty("application.datafilepath");
846

    
847
				InputStream inputStream = getURLStream(url);
848
				
849
				//register data file into xml_documents table and write data file
850
				//into file system
851
				try {
852
					DocumentImpl.writeDataFileInReplication(inputStream,
853
							datafilePath, docName, docType, docid, null, docHomeServer,
854
							server, DocumentImpl.DOCUMENTTABLE, false, createdDate,
855
							updatedDate);
856
				} catch (Exception e) {
857
					writeException = e;
858
				}
859

    
860
			}
861
			
862
			// process the real owner and updater
863
			DBConnection dbConn = DBConnectionPool.getDBConnection("ReplicationService.handleForceDataFileRequest");
864
	        int serialNumber = dbConn.getCheckOutSerialNumber();
865
	        dbConn.setAutoCommit(false);
866
			String user = (String) docinfoHash.get("user_owner");
867
			String updated = (String) docinfoHash.get("user_updated");
868
	        updateUserOwner(dbConn, docid, user, updated);
869
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
870
	        
871
			// process system metadata
872
	        if (systemMetadataXML != null) {
873
	      	  SystemMetadata sysMeta = 
874
	      		TypeMarshaller.unmarshalTypeFromStream(
875
	      				  SystemMetadata.class, 
876
	      				  new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
877
	      	  
878
	      	  // need the guid-to-docid mapping
879
	      	  boolean mappingExists = true;
880
	      	  mappingExists = IdentifierManager.getInstance().mappingExists(sysMeta.getIdentifier().getValue());
881
	      	  if (!mappingExists) {
882
	      		  IdentifierManager.getInstance().createMapping(sysMeta.getIdentifier().getValue(), docid);
883
	      	  }
884
	      	  // save the system metadata
885
	      	  HazelcastService.getInstance().getSystemMetadataMap().put(sysMeta.getIdentifier(), sysMeta);
886
	        }
887
	        
888
	        // process the access control
889
	        try {
890
	        	// check if we had a guid -> docid mapping
891
	        	String docidNoRev = DocumentUtil.getDocIdFromAccessionNumber(docid);
892
	        	int rev = DocumentUtil.getRevisionFromAccessionNumber(docid);
893
	        	IdentifierManager.getInstance().getGUID(docidNoRev, rev);
894
	        	// no need to create the mapping if we have it
895
	        } catch (McdbDocNotFoundException mcdbe) {
896
	        	// create mapping if we don't
897
	        	IdentifierManager.getInstance().createMapping(docid, docid);
898
	        }
899
	        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
900
	        if (accessControlList != null) {
901
	        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
902
	        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
903
	        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
904
	        			acfsf.insertPermissions(xmlAccessDAO);
905
						logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
906
								+ " permissions added to DB");
907
	        		}
908
	            }
909
	        }
910
	        
911
	        // throw the write exception now -- this happens when access changes on an object
912
			if (writeException != null) {
913
				throw writeException;
914
			}
915

    
916
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - datafile " + docid + " added to DB with "
917
					+ "action " + dbaction);
918
			EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER,
919
					docid, dbaction);
920

    
921
		} catch (Exception e) {
922
			e.printStackTrace();
923
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG, e);                         
924
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Datafile " + docid
925
					+ " failed to added to DB with " + "action " + dbaction + " because "
926
					+ e.getMessage());
927
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - ERROR in MetacatReplication.handleForceDataFileReplicate"
928
					+ "Request(): " + e.getMessage());
929
		}
930
	}
931

    
932
	/**
933
	 * Grants or denies a lock to a requesting host.
934
	 * The servlet parameters of interrest are:
935
	 * docid: the docid of the file the lock is being requested for
936
	 * currentdate: the timestamp of the document on the remote server
937
	 *
938
	 */
939
	protected static void handleGetLockRequest(
940
			Hashtable<String, String[]> params, HttpServletResponse response) {
941

    
942
		try {
943

    
944
			String docid = ((String[]) params.get("docid"))[0];
945
			String remoteRev = ((String[]) params.get("updaterev"))[0];
946
			DocumentImpl requestDoc = new DocumentImpl(docid);
947
			logReplication.info("ReplicationService.handleGetLockRequest - lock request for " + docid);
948
			int localRevInt = requestDoc.getRev();
949
			int remoteRevInt = Integer.parseInt(remoteRev);
950

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

    
985
	/**
986
	 * Sends all of the xml_documents information encoded in xml to a requestor
987
	 * the format is:
988
	 * <!ELEMENT documentinfo (docid, docname, doctype, doctitle, user_owner,
989
	 *                  user_updated, home_server, public_access, rev)/>
990
	 * all of the subelements of document info are #PCDATA
991
	 */
992
	protected static void handleGetDocumentInfoRequest(
993
			Hashtable<String, String[]> params, HttpServletResponse response) {
994
		String docid = ((String[]) (params.get("docid")))[0];
995

    
996
		try {
997
			// get docinfo as XML string
998
			String docinfoXML = getDocumentInfo(docid);
999
			
1000
			// get a writer for sending back to response
1001
			response.setContentType("text/xml");
1002
			Writer out = response.getWriter();
1003
			out.write(docinfoXML);
1004
			out.close();
1005

    
1006
		} catch (Exception e) {
1007
			logMetacat.error("ReplicationService.handleGetDocumentInfoRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1008
			logReplication.error("ReplicationService.handleGetDocumentInfoRequest - error in metacatReplication.handlegetdocumentinforequest "
1009
					+ "for doc: " + docid + " : " + e.getMessage());
1010
		}
1011

    
1012
	}
1013
	
1014
	public static Hashtable<String, String> getDocumentInfoMap(String docid)
1015
			throws HandlerException, AccessControlException, JiBXException,
1016
			IOException, McdbException, SAXException {
1017
		
1018
		// Try get docid info from remote server
1019
		DocInfoHandler dih = new DocInfoHandler();
1020
		XMLReader docinfoParser = ReplicationHandler.initParser(dih);
1021

    
1022
		String docInfoStr = getDocumentInfo(docid);
1023

    
1024
		// strip out the system metadata portion
1025
		String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
1026
		docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);
1027

    
1028
		docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
1029
		Hashtable<String, String> docinfoHash = dih.getDocInfo();
1030

    
1031
		return docinfoHash;
1032
	}
1033
	
1034
	/**
1035
	 * Gets a docInfo XML snippet for the replication API
1036
	 * @param docid
1037
	 * @return
1038
	 * @throws AccessControlException
1039
	 * @throws JiBXException
1040
	 * @throws IOException
1041
	 * @throws McdbException
1042
	 */
1043
	public static String getDocumentInfo(String docid) throws AccessControlException, JiBXException, IOException, McdbException {
1044
		StringBuffer sb = new StringBuffer();
1045

    
1046
		DocumentImpl doc = new DocumentImpl(docid);
1047
		sb.append("<documentinfo><docid>").append(docid);
1048
		sb.append("</docid>");
1049
		
1050
		try {
1051
			// serialize the System Metadata as XML for docinfo
1052
			String guid = IdentifierManager.getInstance().getGUID(doc.getDocID(), doc.getRev());
1053
			SystemMetadata systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
1054
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
1055
			TypeMarshaller.marshalTypeToOutputStream(systemMetadata, baos);
1056
			String systemMetadataXML = baos.toString("UTF-8");
1057
			sb.append("<systemMetadata>");
1058
			sb.append(systemMetadataXML);
1059
			sb.append("</systemMetadata>");
1060
		} catch(McdbDocNotFoundException e) {
1061
		  logMetacat.warn("No SystemMetadata found for: " + docid);
1062
		}
1063
		
1064
		Calendar created = Calendar.getInstance();
1065
		created.setTime(doc.getCreateDate());
1066
		Calendar updated = Calendar.getInstance();
1067
		updated.setTime(doc.getUpdateDate());
1068
		
1069
		sb.append("<docname><![CDATA[").append(doc.getDocname());
1070
		sb.append("]]></docname><doctype>").append(doc.getDoctype());
1071
		sb.append("</doctype>");
1072
		sb.append("<user_owner>").append(doc.getUserowner());
1073
		sb.append("</user_owner><user_updated>").append(doc.getUserupdated());
1074
		sb.append("</user_updated>");
1075
		sb.append("<date_created>");
1076
		sb.append(DateTimeMarshaller.serializeDateToUTC(doc.getCreateDate()));
1077
		sb.append("</date_created>");
1078
		sb.append("<date_updated>");
1079
		sb.append(DateTimeMarshaller.serializeDateToUTC(doc.getUpdateDate()));
1080
		sb.append("</date_updated>");
1081
		sb.append("<home_server>");
1082
		sb.append(doc.getDocHomeServer());
1083
		sb.append("</home_server>");
1084
		sb.append("<public_access>").append(doc.getPublicaccess());
1085
		sb.append("</public_access><rev>").append(doc.getRev());
1086
		sb.append("</rev>");
1087

    
1088
		sb.append("<accessControl>");
1089

    
1090
		AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid); 
1091
		sb.append(acfsf.getAccessString());
1092
		
1093
		sb.append("</accessControl>");
1094

    
1095
		sb.append("</documentinfo>");
1096
			
1097
		return sb.toString();
1098
	}
1099
	
1100
	/**
1101
	 * Sends System Metadata as XML
1102
	 */
1103
	protected static void handleGetSystemMetadataRequest(
1104
			Hashtable<String, String[]> params, HttpServletResponse response) {
1105
		String guid = ((String[]) (params.get("guid")))[0];
1106
		String systemMetadataXML = null;
1107
		try {
1108
			
1109
			// serialize the System Metadata as XML 
1110
			SystemMetadata systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
1111
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
1112
			TypeMarshaller.marshalTypeToOutputStream(systemMetadata, baos);
1113
			systemMetadataXML = baos.toString("UTF-8");
1114
				
1115
			// get a writer for sending back to response
1116
			response.setContentType("text/xml");
1117
			Writer out = response.getWriter();
1118
			out.write(systemMetadataXML);
1119
			out.close();
1120

    
1121
		} catch (Exception e) {
1122
			String msg = "ReplicationService.handleGetSystemMetadataRequest for guid: " + guid + " : " + e.getMessage();
1123
			logMetacat.error(msg);                         
1124
			logReplication.error(msg);
1125
		}
1126

    
1127
	}
1128
	
1129
	/**
1130
	 * when a forcereplication request comes in, local host sends a read request
1131
	 * to the requesting server (remote server) for the specified docid. Then
1132
	 * store it in local database.
1133
	 */
1134
	protected static void handleForceReplicateSystemMetadataRequest(
1135
			Hashtable<String, String[]> params, HttpServletResponse response,
1136
			HttpServletRequest request) {
1137
		String server = ((String[]) params.get("server"))[0]; // the server that
1138
		String guid = ((String[]) params.get("guid"))[0]; // sent the document
1139
		
1140
		try {
1141
			logReplication.info("ReplicationService.handleForceReplicateSystemMetadataRequest - Force replication system metadata request from: " + server);
1142
			// get the system metadata from server
1143
			URL docinfourl = new URL("https://" + server + "?server="
1144
					+ MetacatUtil.getLocalReplicationServerName()
1145
					+ "&action=getsystemmetadata&guid=" + guid);
1146
			
1147
			String systemMetadataXML = ReplicationService.getURLContent(docinfourl);
1148
						
1149
			// process system metadata
1150
			if (systemMetadataXML != null) {
1151
				SystemMetadata sysMeta = 
1152
					TypeMarshaller.unmarshalTypeFromStream(
1153
							SystemMetadata.class,
1154
							new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
1155
				HazelcastService.getInstance().getSystemMetadataMap().put(sysMeta.getIdentifier(), sysMeta);
1156
			}
1157
      
1158
			logReplication.info("ReplicationService.handleForceReplicateSystemMetadataRequest - processed guid: " + guid);
1159
			EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER, guid, "systemMetadata");
1160

    
1161
		} catch (Exception e) {
1162
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG, e);                         
1163
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when processing guid: " + guid, e);
1164
		}
1165
	}
1166

    
1167
	/**
1168
	 * Sends a datafile to a remote host
1169
	 */
1170
	protected static void handleGetDataFileRequest(OutputStream outPut,
1171
			Hashtable<String, String[]> params, HttpServletResponse response)
1172

    
1173
	{
1174
		// File path for data file
1175
		String filepath;
1176
		// Request docid
1177
		String docId = ((String[]) (params.get("docid")))[0];
1178
		//check if the doicd is null
1179
		if (docId == null) {
1180
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1181
			logReplication.error("ReplicationService.handleGetDataFileRequest - Didn't specify docid for replication");
1182
			return;
1183
		}
1184

    
1185
		//try to open a https stream to test if the request server's public key
1186
		//in the key store, this is security issue
1187
		try {
1188
			filepath = PropertyService.getProperty("application.datafilepath");
1189
			String server = params.get("server")[0];
1190
			URL u = new URL("https://" + server + "?server="
1191
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test");
1192
			String test = ReplicationService.getURLContent(u);
1193
			//couldn't pass the test
1194
			if (test.indexOf("successfully") == -1) {
1195
				//response.setContentType("text/xml");
1196
				//outPut.println("<error>Couldn't pass the trust test</error>");
1197
				logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1198
				logReplication.error("ReplicationService.handleGetDataFileRequest - Couldn't pass the trust test");
1199
				return;
1200
			}
1201
		}//try
1202
		catch (Exception ee) {
1203
			return;
1204
		}//catch
1205

    
1206
		if (!filepath.endsWith("/")) {
1207
			filepath += "/";
1208
		}
1209
		// Get file aboslute file name
1210
		String filename = filepath + docId;
1211

    
1212
		//MIME type
1213
		String contentType = null;
1214
		if (filename.endsWith(".xml")) {
1215
			contentType = "text/xml";
1216
		} else if (filename.endsWith(".css")) {
1217
			contentType = "text/css";
1218
		} else if (filename.endsWith(".dtd")) {
1219
			contentType = "text/plain";
1220
		} else if (filename.endsWith(".xsd")) {
1221
			contentType = "text/xml";
1222
		} else if (filename.endsWith("/")) {
1223
			contentType = "text/html";
1224
		} else {
1225
			File f = new File(filename);
1226
			if (f.isDirectory()) {
1227
				contentType = "text/html";
1228
			} else {
1229
				contentType = "application/octet-stream";
1230
			}
1231
		}
1232

    
1233
		// Set the mime type
1234
		response.setContentType(contentType);
1235

    
1236
		// Get the content of the file
1237
		FileInputStream fin = null;
1238
		try {
1239
			// FileInputStream to metacat
1240
			fin = new FileInputStream(filename);
1241
			// 4K buffer
1242
			byte[] buf = new byte[4 * 1024];
1243
			// Read data from file input stream to byte array
1244
			int b = fin.read(buf);
1245
			// Write to outStream from byte array
1246
			while (b != -1) {
1247
				outPut.write(buf, 0, b);
1248
				b = fin.read(buf);
1249
			}
1250
			// close file input stream
1251
			fin.close();
1252

    
1253
		}//try
1254
		catch (Exception e) {
1255
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1256
			logReplication.error("ReplicationService.handleGetDataFileRequest - error getting data file from MetacatReplication."
1257
					+ "handlGetDataFileRequest " + e.getMessage());
1258
			e.printStackTrace(System.out);
1259
		}//catch
1260

    
1261
	}
1262

    
1263
	/**
1264
	 * Sends a document to a remote host
1265
	 */
1266
	protected static void handleGetDocumentRequest(
1267
			Hashtable<String, String[]> params, HttpServletResponse response) {
1268

    
1269
		String urlString = null;
1270
		String documentPath = null;
1271
		String errorMsg = null;
1272
		try {
1273
			// try to open a https stream to test if the request server's public
1274
			// key
1275
			// in the key store, this is security issue
1276
			String server = params.get("server")[0];
1277
			urlString = "https://" + server + "?server="
1278
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test";
1279
			URL u = new URL(urlString);
1280
			String test = ReplicationService.getURLContent(u);
1281
			// couldn't pass the test
1282
			if (test.indexOf("successfully") == -1) {
1283
				response.setContentType("text/xml");
1284
				Writer out = response.getWriter();
1285
				out.write("<error>Couldn't pass the trust test " + test + " </error>");
1286
				out.close();
1287
				return;
1288
			}
1289

    
1290
			String docid = params.get("docid")[0];
1291
			logReplication.debug("ReplicationService.handleGetDocumentRequest - MetacatReplication.handleGetDocumentRequest for docid: "
1292
					+ docid);
1293
			DocumentImpl di = new DocumentImpl(docid);
1294

    
1295
			String documentDir = PropertyService
1296
					.getProperty("application.documentfilepath");
1297
			documentPath = documentDir + FileUtil.getFS() + docid;
1298

    
1299
			// if the document does not exist on disk, read it from db and write
1300
			// it to disk.
1301
			if (FileUtil.getFileStatus(documentPath) == FileUtil.DOES_NOT_EXIST
1302
					|| FileUtil.getFileSize(documentPath) == 0) {
1303
				FileOutputStream fos = new FileOutputStream(documentPath);
1304
				di.toXml(fos, null, null, true);
1305
			}
1306

    
1307
			// read the file from disk and send it to outputstream
1308
			OutputStream outputStream = response.getOutputStream();
1309
			di.readFromFileSystem(outputStream, null, null, documentPath);
1310

    
1311
			logReplication.info("ReplicationService.handleGetDocumentRequest - document " + docid + " sent");
1312

    
1313
			// return to avoid continuing to the error reporting section at the end
1314
			return;
1315
			
1316
		} catch (MalformedURLException mue) {
1317
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1318
			logReplication.error("ReplicationService.handleGetDocumentRequest - Url error when getting document from MetacatReplication."
1319
					+ "handlGetDocumentRequest for url: " + urlString + " : "
1320
					+ mue.getMessage());
1321
			// e.printStackTrace(System.out);
1322
			
1323
		} catch (IOException ioe) {
1324
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1325
			logReplication.error("ReplicationService.handleGetDocumentRequest - I/O error when getting document from MetacatReplication."
1326
					+ "handlGetDocumentRequest for file: " + documentPath + " : "
1327
					+ ioe.getMessage());
1328
			errorMsg = ioe.getMessage();
1329
		} catch (PropertyNotFoundException pnfe) {
1330
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1331
			logReplication
1332
					.error("ReplicationService.handleGetDocumentRequest - Error getting property when getting document from MetacatReplication."
1333
							+ "handlGetDocumentRequest for file: "
1334
							+ documentPath
1335
							+ " : "
1336
							+ pnfe.getMessage());
1337
			// e.printStackTrace(System.out);
1338
			errorMsg = pnfe.getMessage();
1339
		} catch (McdbException me) {
1340
			logReplication
1341
					.error("ReplicationService.handleGetDocumentRequest - Document implementation error  getting property when getting document from MetacatReplication."
1342
							+ "handlGetDocumentRequest for file: "
1343
							+ documentPath
1344
							+ " : "
1345
							+ me.getMessage());
1346
			// e.printStackTrace(System.out);
1347
			errorMsg = me.getMessage();
1348
		}
1349
		
1350
		// report any errors if we got here
1351
		response.setContentType("text/xml");
1352
		Writer out = null;
1353
		try {
1354
			response.getWriter();
1355
			out = response.getWriter();
1356
			out.write("<error>" + errorMsg + "</error>");
1357
		} catch (Exception e) {
1358
			logMetacat.error(e.getMessage(), e);
1359
		} finally {
1360
			try {
1361
				out.close();
1362
			} catch (IOException e) {
1363
				logMetacat.error(e.getMessage(), e);
1364
			}
1365
		}
1366
		
1367

    
1368
	}
1369

    
1370
	/**
1371
	 * Sends a list of all of the documents on this sever along with their
1372
	 * revision numbers. The format is: <!ELEMENT replication (server, updates)>
1373
	 * <!ELEMENT server (#PCDATA)> <!ELEMENT updates ((updatedDocument |
1374
	 * deleteDocument | revisionDocument)*)> <!ELEMENT updatedDocument (docid,
1375
	 * rev, datafile*)> <!ELEMENT deletedDocument (docid, rev)> <!ELEMENT
1376
	 * revisionDocument (docid, rev, datafile*)> <!ELEMENT docid (#PCDATA)>
1377
	 * <!ELEMENT rev (#PCDATA)> <!ELEMENT datafile (#PCDATA)> note that the rev
1378
	 * in deletedDocument is always empty. I just left it in there to make the
1379
	 * parser implementation easier.
1380
	 */
1381
	protected static void handleUpdateRequest(Hashtable<String, String[]> params,
1382
			HttpServletResponse response) {
1383
		// Checked out DBConnection
1384
		DBConnection dbConn = null;
1385
		// DBConenction serial number when checked it out
1386
		int serialNumber = -1;
1387
		PreparedStatement pstmt = null;
1388
		// Server list to store server info of xml_replication table
1389
		ReplicationServerList serverList = null;
1390
		
1391
		// a writer for response
1392
		Writer out = null;
1393

    
1394
		try {
1395
			// get writer, TODO: encoding?
1396
			response.setContentType("text/xml");
1397
			out = response.getWriter();
1398
			
1399
			// Check out a DBConnection from pool
1400
			dbConn = DBConnectionPool
1401
					.getDBConnection("MetacatReplication.handleUpdateRequest");
1402
			serialNumber = dbConn.getCheckOutSerialNumber();
1403
			// Create a server list from xml_replication table
1404
			serverList = new ReplicationServerList();
1405

    
1406
			// Get remote server name from param
1407
			String server = ((String[]) params.get("server"))[0];
1408
			// If no servr name in param, return a error
1409
			if (server == null || server.equals("")) {
1410
				out.write("<error>Request didn't specify server name</error>");
1411
				out.close();
1412
				return;
1413
			}//if
1414

    
1415
			//try to open a https stream to test if the request server's public key
1416
			//in the key store, this is security issue
1417
			String testUrl = "https://" + server + "?server="
1418
            + MetacatUtil.getLocalReplicationServerName() + "&action=test";
1419
			logReplication.info("Running trust test: " + testUrl);
1420
			URL u = new URL(testUrl);
1421
			String test = ReplicationService.getURLContent(u);
1422
			logReplication.info("Ouput from test is '" + test + "'");
1423
			//couldn't pass the test
1424
			if (test.indexOf("successfully") == -1) {
1425
			    logReplication.error("Trust test failed.");
1426
				out.write("<error>Couldn't pass the trust test</error>");
1427
				out.close();
1428
				return;
1429
			}
1430
			logReplication.info("Trust test succeeded.");
1431

    
1432
			// Check if local host configure to replicate xml documents to remote
1433
			// server. If not send back a error message
1434
			if (!serverList.getReplicationValue(server)) {
1435
				out.write("<error>Configuration not allow to replicate document to you</error>");
1436
				out.close();
1437
				return;
1438
			}//if
1439

    
1440
			// Store the sql command
1441
			StringBuffer docsql = new StringBuffer();
1442
			StringBuffer revisionSql = new StringBuffer();
1443
			
1444
			// Store the deleted docid list
1445
			StringBuffer delsql = new StringBuffer();
1446
			// Store the data set file
1447
			Vector<Vector<String>> packageFiles = new Vector<Vector<String>>();
1448

    
1449
			// Append local server's name and replication servlet to doclist
1450
			out.append("<?xml version=\"1.0\"?><replication>");
1451
			out.append("<server>")
1452
					.append(MetacatUtil.getLocalReplicationServerName());
1453
			//doclist.append(util.getProperty("replicationpath"));
1454
			out.append("</server><updates>");
1455

    
1456
			// Get correct docid that reside on this server according the requesting
1457
			// server's replicate and data replicate value in xml_replication table
1458
			docsql.append(DatabaseService.getInstance().getDBAdapter().getReplicationDocumentListSQL());
1459
			//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)) ");
1460
			revisionSql.append("select docid, rev, doctype from xml_revisions ");
1461
			// If the localhost is not a hub to the remote server, only replicate
1462
			// the docid' which home server is local host (server_location =1)
1463
			if (!serverList.getHubValue(server)) {
1464
				String serverLocationDoc = " and a.server_location = 1";
1465
				String serverLocationRev = "where server_location = 1";
1466
				docsql.append(serverLocationDoc);
1467
				revisionSql.append(serverLocationRev);
1468
			}
1469
			logReplication.info("ReplicationService.handleUpdateRequest - Doc sql: " + docsql.toString());
1470

    
1471
			// Get any deleted documents
1472
			delsql.append("select distinct docid from ");
1473
			delsql.append("xml_revisions where docid not in (select docid from ");
1474
			delsql.append("xml_documents) ");
1475
			// If the localhost is not a hub to the remote server, only replicate
1476
			// the docid' which home server is local host (server_location =1)
1477
			if (!serverList.getHubValue(server)) {
1478
				delsql.append("and server_location = 1");
1479
			}
1480
			logReplication.info("ReplicationService.handleUpdateRequest - Deleted sql: " + delsql.toString());
1481

    
1482
			// Get docid list of local host
1483
			pstmt = dbConn.prepareStatement(docsql.toString());
1484
			pstmt.execute();
1485
			ResultSet rs = pstmt.getResultSet();
1486
			boolean tablehasrows = rs.next();
1487
			//If metacat configed to replicate data file
1488
			//if ((util.getProperty("replicationsenddata")).equals("on"))
1489
			boolean replicateData = serverList.getDataReplicationValue(server);
1490
			if (replicateData) {
1491
				while (tablehasrows) {
1492
					String recordDoctype = rs.getString(3);
1493
					Vector<String> packagedoctypes = MetacatUtil
1494
							.getOptionList(PropertyService
1495
									.getProperty("xml.packagedoctype"));
1496
					//if this is a package file, put it at the end
1497
					//because if a package file is read before all of the files it
1498
					//refers to are loaded then there is an error
1499
					if (recordDoctype != null && !packagedoctypes.contains(recordDoctype)) {
1500
						//If this is not data file
1501
						if (!recordDoctype.equals("BIN")) {
1502
							//for non-data file document
1503
							out.append("<updatedDocument>");
1504
							out.append("<docid>").append(rs.getString(1));
1505
							out.append("</docid><rev>" + rs.getInt(2));
1506
							out.append("</rev>");
1507
							out.append("</updatedDocument>");
1508
						}//if
1509
						else {
1510
							//for data file document, in datafile attributes
1511
							//we put "datafile" value there
1512
							out.append("<updatedDocument>");
1513
							out.append("<docid>").append(rs.getString(1));
1514
							out.append("</docid><rev>" + rs.getInt(2));
1515
							out.append("</rev>");
1516
							out.append("<datafile>");
1517
							out.append(DATA_FILE_FLAG);
1518
							out.append("</datafile>");
1519
							out.append("</updatedDocument>");
1520
						}//else
1521
					}//if packagedoctpes
1522
					else { //the package files are saved to be put into the xml later.
1523
						Vector<String> v = new Vector<String>();
1524
						v.add(rs.getString(1));
1525
						v.add(String.valueOf(rs.getInt(2)));
1526
						packageFiles.add(v);
1527
					}//esle
1528
					tablehasrows = rs.next();
1529
				}//while
1530
			}//if
1531
			else //metacat was configured not to send data file
1532
			{
1533
				while (tablehasrows) {
1534
					String recordDoctype = rs.getString(3);
1535
					if (!recordDoctype.equals("BIN")) { //don't replicate data files
1536
						Vector<String> packagedoctypes = MetacatUtil
1537
								.getOptionList(PropertyService
1538
										.getProperty("xml.packagedoctype"));
1539
						if (recordDoctype != null
1540
								&& !packagedoctypes.contains(recordDoctype)) { //if this is a package file, put it at the end
1541
							//because if a package file is read before all of the files it
1542
							//refers to are loaded then there is an error
1543
							out.append("<updatedDocument>");
1544
							out.append("<docid>" + rs.getString(1));
1545
							out.append("</docid><rev>" + rs.getInt(2));
1546
							out.append("</rev>");
1547
							out.append("</updatedDocument>");
1548
						} else { //the package files are saved to be put into the xml later.
1549
							Vector<String> v = new Vector<String>();
1550
							v.add(rs.getString(1));
1551
							v.add(String.valueOf(rs.getInt(2)));
1552
							packageFiles.add(v);
1553
						}
1554
					}//if
1555
					tablehasrows = rs.next();
1556
				}//while
1557
			}//else
1558

    
1559
			pstmt = dbConn.prepareStatement(delsql.toString());
1560
			//usage count should increas 1
1561
			dbConn.increaseUsageCount(1);
1562

    
1563
			pstmt.execute();
1564
			rs = pstmt.getResultSet();
1565
			tablehasrows = rs.next();
1566
			while (tablehasrows) { //handle the deleted documents
1567
				out.append("<deletedDocument><docid>").append(rs.getString(1));
1568
				out.append("</docid><rev></rev></deletedDocument>");
1569
				//note that rev is always empty for deleted docs
1570
				tablehasrows = rs.next();
1571
			}
1572

    
1573
			//now we can put the package files into the xml results
1574
			for (int i = 0; i < packageFiles.size(); i++) {
1575
				Vector<String> v = packageFiles.elementAt(i);
1576
				out.append("<updatedDocument>");
1577
				out.append("<docid>").append(v.elementAt(0));
1578
				out.append("</docid><rev>");
1579
				out.append(v.elementAt(1));
1580
				out.append("</rev>");
1581
				out.append("</updatedDocument>");
1582
			}
1583
			// add revision doc list  
1584
			out.append(prepareRevisionDoc(dbConn, revisionSql.toString(),
1585
					replicateData));
1586

    
1587
			out.append("</updates></replication>");
1588
			logReplication.info("ReplicationService.handleUpdateRequest - done writing to output stream.");
1589
			pstmt.close();
1590
			//conn.close();
1591

    
1592
		} catch (Exception e) {
1593
			logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1594
			logReplication.error("ReplicationService.handleUpdateRequest - error in MetacatReplication." + "handleupdaterequest: "
1595
					+ e.getMessage());
1596
			//e.printStackTrace(System.out);
1597
			try {
1598
				out.write("<error>" + e.getMessage() + "</error>");
1599
			} catch (IOException e1) {
1600
				logMetacat.error(e1.getMessage(), e1);
1601
			}
1602
		} finally {
1603
			try {
1604
				pstmt.close();
1605
			}//try
1606
			catch (SQLException ee) {
1607
				logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1608
				logReplication.error("ReplicationService.handleUpdateRequest - Error in MetacatReplication."
1609
						+ "handleUpdaterequest to close pstmt: " + ee.getMessage());
1610
			}//catch
1611
			finally {
1612
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1613
			}//finally
1614
			try {
1615
				out.close();
1616
			} catch (IOException e) {
1617
				logMetacat.error(e.getMessage(), e);
1618
			}
1619
		}//finally
1620

    
1621
	}//handlUpdateRequest
1622

    
1623
	/**
1624
	 * 
1625
	 * @param dbConn connection for doing the update
1626
	 * @param docid the document id to update
1627
	 * @param owner the user_owner
1628
	 * @param updater the user_updated
1629
	 * @throws SQLException
1630
	 */
1631
	public static void updateUserOwner(DBConnection dbConn, String docid, String owner, String updater) throws SQLException {
1632
	
1633
		String sql = 
1634
			"UPDATE xml_documents " +
1635
			"SET user_owner = ?, " +
1636
			"user_updated = ? " +
1637
			"WHERE docid = ?;";
1638
		PreparedStatement pstmt = dbConn.prepareStatement(sql);
1639
		//usage count should increas 1
1640
		dbConn.increaseUsageCount(1);
1641

    
1642
		docid = DocumentUtil.getSmartDocId(docid);
1643
		pstmt.setString(1, owner);
1644
		pstmt.setString(2, updater);
1645
		pstmt.setString(3, docid);
1646
		pstmt.execute();
1647
		pstmt.close();
1648
		
1649
		dbConn.commit();
1650
	}
1651
	
1652
	/*
1653
	 * This method will get the xml string for document in xml_revision
1654
	 * The schema look like <!ELEMENT revisionDocument (docid, rev, datafile*)>
1655
	 */
1656
	private static String prepareRevisionDoc(DBConnection dbConn, String revSql,
1657
			boolean replicateData) throws Exception {
1658
		logReplication.warn("ReplicationService.prepareRevisionDoc - The revision document sql is " + revSql);
1659
		StringBuffer revDocList = new StringBuffer();
1660
		PreparedStatement pstmt = dbConn.prepareStatement(revSql);
1661
		//usage count should increas 1
1662
		dbConn.increaseUsageCount(1);
1663

    
1664
		pstmt.execute();
1665
		ResultSet rs = pstmt.getResultSet();
1666
		logReplication.warn("Processing replication revision for documents");
1667
		while (rs.next()) {
1668
			String recordDoctype = rs.getString(3);
1669

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

    
1674
				// do nothing
1675
			} else {
1676
				String docid = rs.getString(1);
1677
				int rev = rs.getInt(2);
1678
				logMetacat.debug("Processing replication revision for docid: " + docid + "." + rev);
1679

    
1680
				revDocList.append("<revisionDocument>");
1681
				revDocList.append("<docid>").append(docid);
1682
				revDocList.append("</docid><rev>").append(rev);
1683
				revDocList.append("</rev>");
1684
				// data file
1685
				if (recordDoctype.equals("BIN")) {
1686
					revDocList.append("<datafile>");
1687
					revDocList.append(DATA_FILE_FLAG);
1688
					revDocList.append("</datafile>");
1689
				}
1690
				revDocList.append("</revisionDocument>");
1691

    
1692
			}//else
1693
		}
1694
		//System.out.println("The revision list is"+ revDocList.toString());
1695
		return revDocList.toString();
1696
	}
1697

    
1698
	/**
1699
	 * Returns the xml_catalog table encoded in xml
1700
	 */
1701
	public static String getCatalogXML() {
1702
		return handleGetCatalogRequest(null, null, false);
1703
	}
1704

    
1705
	/**
1706
	 * Sends the contents of the xml_catalog table encoded in xml
1707
	 * The xml format is:
1708
	 * <!ELEMENT xml_catalog (row*)>
1709
	 * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
1710
	 *                system_id)>
1711
	 * All of the sub elements of row are #PCDATA
1712

    
1713
	 * If printFlag == false then do not print to out.
1714
	 */
1715
	protected static String handleGetCatalogRequest(
1716
			Hashtable<String, String[]> params, HttpServletResponse response,
1717
			boolean printFlag) {
1718
		DBConnection dbConn = null;
1719
		int serialNumber = -1;
1720
		PreparedStatement pstmt = null;
1721
		Writer out = null;
1722
		try {
1723
			// get writer, TODO: encoding?
1724
		    if(printFlag)
1725
		    {
1726
		        response.setContentType("text/xml");
1727
		        out = response.getWriter();
1728
		    }
1729
			/*conn = MetacatReplication.getDBConnection("MetacatReplication." +
1730
			                                          "handleGetCatalogRequest");*/
1731
			dbConn = DBConnectionPool
1732
					.getDBConnection("MetacatReplication.handleGetCatalogRequest");
1733
			serialNumber = dbConn.getCheckOutSerialNumber();
1734
			pstmt = dbConn.prepareStatement("select entry_type, "
1735
					+ "source_doctype, target_doctype, public_id, "
1736
					+ "system_id from xml_catalog");
1737
			pstmt.execute();
1738
			ResultSet rs = pstmt.getResultSet();
1739
			boolean tablehasrows = rs.next();
1740
			StringBuffer sb = new StringBuffer();
1741
			sb.append("<?xml version=\"1.0\"?><xml_catalog>");
1742
			while (tablehasrows) {
1743
				sb.append("<row><entry_type>").append(rs.getString(1));
1744
				sb.append("</entry_type><source_doctype>").append(rs.getString(2));
1745
				sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
1746
				sb.append("</target_doctype><public_id>").append(rs.getString(4));
1747
				// system id may not have server url on front.  Add it if not.
1748
				String systemID = rs.getString(5);
1749
				if (!systemID.startsWith("http://")) {
1750
					systemID = SystemUtil.getContextURL() + systemID;
1751
				}
1752
				sb.append("</public_id><system_id>").append(systemID);
1753
				sb.append("</system_id></row>");
1754

    
1755
				tablehasrows = rs.next();
1756
			}
1757
			sb.append("</xml_catalog>");
1758
			//conn.close();
1759
			if (printFlag) {
1760
				response.setContentType("text/xml");
1761
				out.write(sb.toString());
1762
			}
1763
			pstmt.close();
1764
			return sb.toString();
1765
		} catch (Exception e) {
1766
			logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1767
			logReplication.error("ReplicationService.handleGetCatalogRequest - error in MetacatReplication.handleGetCatalogRequest:"
1768
					+ e.getMessage());
1769
			e.printStackTrace(System.out);
1770
			if (printFlag) {
1771
				try {
1772
					out.write("<error>" + e.getMessage() + "</error>");
1773
				} catch (IOException e1) {
1774
					logMetacat.error(e1.getMessage(), e1);
1775
				}
1776
			}
1777
		} finally {
1778
			try {
1779
				pstmt.close();
1780
			}//try
1781
			catch (SQLException ee) {
1782
				logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1783
				logReplication.error("ReplicationService.handleGetCatalogRequest - Error in MetacatReplication.handleGetCatalogRequest: "
1784
						+ ee.getMessage());
1785
			}//catch
1786
			finally {
1787
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1788
			}//finally
1789
			if (out != null) {
1790
				try {
1791
					out.close();
1792
				} catch (IOException e1) {
1793
					logMetacat.error(e1.getMessage(), e1);
1794
				}
1795
			}
1796
		}//finally
1797

    
1798
		return null;
1799
	}
1800

    
1801
	/**
1802
	 * Sends the current system date to the remote server.  Using this action
1803
	 * for replication gets rid of any problems with syncronizing clocks
1804
	 * because a time specific to a document is always kept on its home server.
1805
	 */
1806
	protected static void handleGetTimeRequest(
1807
			Hashtable<String, String[]> params, HttpServletResponse response) {
1808
		
1809
		// use standard format -- the receiving end wants this too
1810
		String dateString = DateTimeMarshaller.serializeDateToUTC(Calendar.getInstance().getTime());
1811
		
1812
		// get a writer for sending back to response
1813
		response.setContentType("text/xml");
1814
		Writer out = null;
1815
		try {
1816
			out = response.getWriter();
1817
			out.write("<timestamp>" + dateString + "</timestamp>");
1818
			out.close();
1819
		} catch (IOException e) {
1820
			logMetacat.error(e.getMessage(), e);
1821
		}
1822
		
1823
	}
1824

    
1825
	/**
1826
	 * this method handles the timeout for a file lock.  when a lock is
1827
	 * granted it is granted for 30 seconds.  When this thread runs out
1828
	 * it deletes the docid from the queue, thus eliminating the lock.
1829
	 */
1830
	public void run() {
1831
		try {
1832
			logReplication.info("ReplicationService.run - thread started for docid: "
1833
					+ (String) fileLocks.elementAt(0));
1834

    
1835
			Thread.sleep(30000); //the lock will expire in 30 seconds
1836
			logReplication.info("thread for docid: "
1837
					+ (String) fileLocks.elementAt(fileLocks.size() - 1) + " exiting.");
1838

    
1839
			fileLocks.remove(fileLocks.size() - 1);
1840
			//fileLocks is treated as a FIFO queue.  If there are more than one lock
1841
			//in the vector, the first one inserted will be removed.
1842
		} catch (Exception e) {
1843
			logMetacat.error("ReplicationService.run - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1844
			logReplication.error("ReplicationService.run - error in file lock thread from "
1845
					+ "MetacatReplication.run: " + e.getMessage());
1846
		}
1847
	}
1848

    
1849
	/**
1850
	 * Returns the name of a server given a serverCode
1851
	 * @param serverCode the serverid of the server
1852
	 * @return the servername or null if the specified serverCode does not
1853
	 *         exist.
1854
	 */
1855
	public static String getServerNameForServerCode(int serverCode) {
1856
		//System.out.println("serverid: " + serverCode);
1857
		DBConnection dbConn = null;
1858
		int serialNumber = -1;
1859
		PreparedStatement pstmt = null;
1860
		try {
1861
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServer");
1862
			serialNumber = dbConn.getCheckOutSerialNumber();
1863
			String sql = new String("select server from "
1864
					+ "xml_replication where serverid = ?");
1865
			pstmt = dbConn.prepareStatement(sql);
1866
			pstmt.setInt(1, serverCode);
1867
			//System.out.println("getserver sql: " + sql);
1868
			pstmt.execute();
1869
			ResultSet rs = pstmt.getResultSet();
1870
			boolean tablehasrows = rs.next();
1871
			if (tablehasrows) {
1872
				//System.out.println("server: " + rs.getString(1));
1873
				return rs.getString(1);
1874
			}
1875

    
1876
			//conn.close();
1877
		} catch (Exception e) {
1878
			logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1879
			logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplication.getServer: " + e.getMessage());
1880
		} finally {
1881
			try {
1882
				pstmt.close();
1883
			}//try
1884
			catch (SQLException ee) {
1885
				logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1886
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacactReplication.getserver: "
1887
						+ ee.getMessage());
1888
			}//catch
1889
			finally {
1890
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1891
			}//fianlly
1892
		}//finally
1893

    
1894
		return null;
1895
		//return null if the server does not exist
1896
	}
1897

    
1898
	/**
1899
	 * Returns a server code given a server name
1900
	 * @param server the name of the server
1901
	 * @return integer > 0 representing the code of the server, 0 if the server
1902
	 *  does not exist.
1903
	 */
1904
	public static int getServerCodeForServerName(String server) throws ServiceException {
1905
		DBConnection dbConn = null;
1906
		int serialNumber = -1;
1907
		PreparedStatement pstmt = null;
1908
		int serverCode = 0;
1909

    
1910
		try {
1911

    
1912
			//conn = util.openDBConnection();
1913
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServerCode");
1914
			serialNumber = dbConn.getCheckOutSerialNumber();
1915
			pstmt = dbConn.prepareStatement("SELECT serverid FROM xml_replication "
1916
					+ "WHERE server LIKE ?");
1917
			pstmt.setString(1, server);
1918
			pstmt.execute();
1919
			ResultSet rs = pstmt.getResultSet();
1920
			boolean tablehasrows = rs.next();
1921
			if (tablehasrows) {
1922
				serverCode = rs.getInt(1);
1923
				pstmt.close();
1924
				//conn.close();
1925
				return serverCode;
1926
			}
1927

    
1928
		} catch (SQLException sqle) {
1929
			throw new ServiceException("ReplicationService.getServerCodeForServerName - " 
1930
					+ "SQL error when getting server code: " + sqle.getMessage());
1931

    
1932
		} finally {
1933
			try {
1934
				pstmt.close();
1935
				//conn.close();
1936
			}//try
1937
			catch (Exception ee) {
1938
				logMetacat.error("ReplicationService.getServerCodeForServerName - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1939
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplicatio.getServerCode: "
1940
						+ ee.getMessage());
1941

    
1942
			}//catch
1943
			finally {
1944
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1945
			}//finally
1946
		}//finally
1947

    
1948
		return serverCode;
1949
	}
1950

    
1951
	/**
1952
	 * Method to get a host server information for given docid
1953
	 * @param conn a connection to the database
1954
	 */
1955
	public static Hashtable<String, String> getHomeServerInfoForDocId(String docId) {
1956
		Hashtable<String, String> sl = new Hashtable<String, String>();
1957
		DBConnection dbConn = null;
1958
		int serialNumber = -1;
1959
		docId = DocumentUtil.getDocIdFromString(docId);
1960
		PreparedStatement pstmt = null;
1961
		int serverLocation;
1962
		try {
1963
			//get conection
1964
			dbConn = DBConnectionPool.getDBConnection("ReplicationHandler.getHomeServer");
1965
			serialNumber = dbConn.getCheckOutSerialNumber();
1966
			//get a server location from xml_document table
1967
			pstmt = dbConn.prepareStatement("select server_location from xml_documents "
1968
					+ "where docid = ?");
1969
			pstmt.setString(1, docId);
1970
			pstmt.execute();
1971
			ResultSet serverName = pstmt.getResultSet();
1972
			//get a server location
1973
			if (serverName.next()) {
1974
				serverLocation = serverName.getInt(1);
1975
				pstmt.close();
1976
			} else {
1977
				pstmt.close();
1978
				//ut.returnConnection(conn);
1979
				return null;
1980
			}
1981
			pstmt = dbConn.prepareStatement("select server, last_checked, replicate "
1982
					+ "from xml_replication where serverid = ?");
1983
			//increase usage count
1984
			dbConn.increaseUsageCount(1);
1985
			pstmt.setInt(1, serverLocation);
1986
			pstmt.execute();
1987
			ResultSet rs = pstmt.getResultSet();
1988
			boolean tableHasRows = rs.next();
1989
			if (tableHasRows) {
1990

    
1991
				String server = rs.getString(1);
1992
				String last_checked = rs.getString(2);
1993
				if (!server.equals("localhost")) {
1994
					sl.put(server, last_checked);
1995
				}
1996

    
1997
			} else {
1998
				pstmt.close();
1999
				//ut.returnConnection(conn);
2000
				return null;
2001
			}
2002
			pstmt.close();
2003
		} catch (Exception e) {
2004
			logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2005
			logReplication.error("ReplicationService.getHomeServerInfoForDocId - error in replicationHandler.getHomeServer(): "
2006
					+ e.getMessage());
2007
		} finally {
2008
			try {
2009
				pstmt.close();
2010
				//ut.returnConnection(conn);
2011
			} catch (Exception ee) {
2012
				logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2013
				logReplication.error("ReplicationService.getHomeServerInfoForDocId - Eror irn rplicationHandler.getHomeServer() "
2014
						+ "to close pstmt: " + ee.getMessage());
2015
			} finally {
2016
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2017
			}
2018

    
2019
		}//finally
2020
		return sl;
2021
	}
2022

    
2023
	/**
2024
	 * Returns a home server location  given a accnum
2025
	 * @param accNum , given accNum for a document
2026
	 *
2027
	 */
2028
	public static int getHomeServerCodeForDocId(String accNum) throws ServiceException {
2029
		DBConnection dbConn = null;
2030
		int serialNumber = -1;
2031
		PreparedStatement pstmt = null;
2032
		int serverCode = 1;
2033
		String docId = DocumentUtil.getDocIdFromString(accNum);
2034

    
2035
		try {
2036

    
2037
			// Get DBConnection
2038
			dbConn = DBConnectionPool
2039
					.getDBConnection("ReplicationHandler.getServerLocation");
2040
			serialNumber = dbConn.getCheckOutSerialNumber();
2041
			pstmt = dbConn.prepareStatement("SELECT server_location FROM xml_documents "
2042
					+ "WHERE docid LIKE ? ");
2043
			pstmt.setString(1, docId);
2044
			pstmt.execute();
2045
			ResultSet rs = pstmt.getResultSet();
2046
			boolean tablehasrows = rs.next();
2047
			//If a document is find, return the server location for it
2048
			if (tablehasrows) {
2049
				serverCode = rs.getInt(1);
2050
				pstmt.close();
2051
				//conn.close();
2052
				return serverCode;
2053
			}
2054
			//if couldn't find in xml_documents table, we think server code is 1
2055
			//(this is new document)
2056
			else {
2057
				pstmt.close();
2058
				//conn.close();
2059
				return serverCode;
2060
			}
2061

    
2062
		} catch (SQLException sqle) {
2063
			throw new ServiceException("ReplicationService.getHomeServerCodeForDocId - " 
2064
					+ "SQL error when getting home server code for docid: " + docId + " : " 
2065
					+ sqle.getMessage());
2066

    
2067
		} finally {
2068
			try {
2069
				pstmt.close();
2070
				//conn.close();
2071

    
2072
			} catch (SQLException sqle) {
2073
				logMetacat.error("ReplicationService.getHomeServerCodeForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2074
				logReplication.error("ReplicationService.getHomeServerCodeForDocId - ReplicationService.getHomeServerCodeForDocId - " 
2075
						+ "SQL error when getting home server code for docid: " + docId + " : " 
2076
						+ sqle.getMessage());
2077
			} finally {
2078
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2079
			}//finally
2080
		}//finally
2081
		//return serverCode;
2082
	}
2083

    
2084
	/**
2085
	 * This method returns the content of a url
2086
	 * @param u the url to return the content from
2087
	 * @return a string representing the content of the url
2088
	 * @throws java.io.IOException
2089
	 */
2090
	public static String getURLContent(URL u) throws java.io.IOException {
2091
		char istreamChar;
2092
		int istreamInt;
2093
		// get the response content
2094
		InputStream input = getURLStream(u);
2095
		logReplication.info("ReplicationService.getURLContent - After getting response from: " + u.toString());
2096
		InputStreamReader istream = new InputStreamReader(input);
2097
		StringBuffer serverResponse = new StringBuffer();
2098
		while ((istreamInt = istream.read()) != -1) {
2099
			istreamChar = (char) istreamInt;
2100
			serverResponse.append(istreamChar);
2101
		}
2102
		istream.close();
2103
		input.close();
2104

    
2105
		return serverResponse.toString();
2106
	}
2107
	
2108
	/**
2109
	 * This method returns the InputStream after opening a url
2110
	 * @param u the url to return the content from
2111
	 * @return a InputStream representing the content of the url
2112
	 * @throws java.io.IOException
2113
	 */
2114
	public static InputStream getURLStream(URL u) throws java.io.IOException {
2115
	    logReplication.info("Getting url stream from " + u.toString());
2116
		logReplication.info("ReplicationService.getURLStream - Before sending request to: " + u.toString());
2117
		// use httpclient to set up SSL
2118
		RestClient client = getSSLClient();
2119
		HttpResponse response = client.doGetRequest(u.toString());
2120
		// get the response content
2121
		InputStream input = response.getEntity().getContent();
2122
		logReplication.info("ReplicationService.getURLStream - After getting response from: " + u.toString());
2123
		
2124
		return input;		
2125
	}
2126
	
2127
	/**
2128
	 * Sets up an HttpClient with SSL connection.
2129
	 * Sends client certificate to the server when doing the request.
2130
	 * @return
2131
	 */
2132
	private static RestClient getSSLClient() {
2133
		RestClient client = new RestClient();
2134
		
2135
		// set up this server's client identity
2136
		String subject = null;
2137
		try {
2138
			// TODO: should there be alternative ways to get the key and certificate?
2139
			String certificateFile = PropertyService.getProperty("replication.certificate.file");
2140
	    	String keyFile = PropertyService.getProperty("replication.privatekey.file");
2141
			String keyPassword = PropertyService.getProperty("replication.privatekey.password");
2142
			X509Certificate certificate = CertificateManager.getInstance().loadCertificateFromFile(certificateFile);
2143
			PrivateKey privateKey = CertificateManager.getInstance().loadPrivateKeyFromFile(keyFile, keyPassword);
2144
			subject = CertificateManager.getInstance().getSubjectDN(certificate);
2145
			CertificateManager.getInstance().registerCertificate(subject, certificate, privateKey);
2146
		} catch (Exception e) {
2147
			// this is pretty much required for replication communication
2148
			logReplication.warn("Could not find server's client certificate/private key: " + e.getMessage());
2149
		}
2150
		
2151
		// set the configured timeout
2152
		client.setTimeouts(CLIENTTIMEOUT);
2153

    
2154
		SSLSocketFactory socketFactory = null;
2155
		try {
2156
			socketFactory = CertificateManager.getInstance().getSSLSocketFactory(subject);
2157
		} catch (FileNotFoundException e) {
2158
			// these are somewhat expected for anonymous client use
2159
			logReplication.warn("Could not set up SSL connection for client - likely because the certificate could not be located: " + e.getMessage());
2160
		} catch (Exception e) {
2161
			// this is likely more severe
2162
			logReplication.warn("Funky SSL going on: " + e.getClass() + ":: " + e.getMessage());
2163
		}
2164
		try {
2165
			//443 is the default port, this value is overridden if explicitly set in the URL
2166
			Scheme sch = new Scheme("https", 443, socketFactory);
2167
			client.getHttpClient().getConnectionManager().getSchemeRegistry().register(sch);
2168
		} catch (Exception e) {
2169
			// this is likely more severe
2170
			logReplication.error("Failed to set up SSL connection for client. Continuing. " + e.getClass() + ":: " + e.getMessage(), e);
2171
		}
2172
		return client;
2173
	}
2174
	
2175

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

    
2200
//	/**
2201
//	 * Method for writing replication messages to a log file specified in
2202
//	 * metacat.properties
2203
//	 */
2204
//	public static void replErrorLog(String message) {
2205
//		try {
2206
//			FileOutputStream fos = new FileOutputStream(PropertyService
2207
//					.getProperty("replication.logdir")
2208
//					+ "/metacatreplicationerror.log", true);
2209
//			PrintWriter pw = new PrintWriter(fos);
2210
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
2211
//			java.util.Date localtime = new java.util.Date();
2212
//			String dateString = formatter.format(localtime);
2213
//			dateString += " :: " + message;
2214
//			//time stamp each entry
2215
//			pw.println(dateString);
2216
//			pw.flush();
2217
//		} catch (Exception e) {
2218
//			logReplication.error("error writing to replication error log from "
2219
//					+ "MetacatReplication.replErrorLog: " + e.getMessage());
2220
//			//e.printStackTrace(System.out);
2221
//		}
2222
//	}
2223

    
2224
	/**
2225
	 * Returns true if the replicate field for server in xml_replication is 1.
2226
	 * Returns false otherwise
2227
	 */
2228
	public static boolean replToServer(String server) {
2229
		DBConnection dbConn = null;
2230
		int serialNumber = -1;
2231
		PreparedStatement pstmt = null;
2232
		try {
2233
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.repltoServer");
2234
			serialNumber = dbConn.getCheckOutSerialNumber();
2235
			pstmt = dbConn.prepareStatement("select replicate from "
2236
					+ "xml_replication where server like ? ");
2237
			pstmt.setString(1, server);
2238
			pstmt.execute();
2239
			ResultSet rs = pstmt.getResultSet();
2240
			boolean tablehasrows = rs.next();
2241
			if (tablehasrows) {
2242
				int i = rs.getInt(1);
2243
				if (i == 1) {
2244
					pstmt.close();
2245
					//conn.close();
2246
					return true;
2247
				} else {
2248
					pstmt.close();
2249
					//conn.close();
2250
					return false;
2251
				}
2252
			}
2253
		} catch (SQLException sqle) {
2254
			logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2255
			logReplication.error("ReplicationService.replToServer - SQL error in MetacatReplication.replToServer: "
2256
					+ sqle.getMessage());
2257
		} finally {
2258
			try {
2259
				pstmt.close();
2260
				//conn.close();
2261
			}//try
2262
			catch (Exception ee) {
2263
				logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2264
				logReplication.error("ReplicationService.replToServer - Error in MetacatReplication.replToServer: "
2265
						+ ee.getMessage());
2266
			}//catch
2267
			finally {
2268
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2269
			}//finally
2270
		}//finally
2271
		return false;
2272
		//the default if this server does not exist is to not replicate to it.
2273
	}
2274

    
2275
}
(6-6/7)