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: 2014-01-07 13:56:58 -0800 (Tue, 07 Jan 2014) $'
10
 * '$Revision: 8464 $'
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.commons.io.IOUtils;
59
import org.apache.http.HttpResponse;
60
import org.apache.http.conn.scheme.Scheme;
61
import org.apache.http.conn.ssl.SSLSocketFactory;
62
import org.apache.log4j.Logger;
63
import org.dataone.client.RestClient;
64
import org.dataone.client.auth.CertificateManager;
65
import org.dataone.service.types.v1.SystemMetadata;
66
import org.dataone.service.util.DateTimeMarshaller;
67
import org.dataone.service.util.TypeMarshaller;
68
import org.jibx.runtime.JiBXException;
69
import org.xml.sax.InputSource;
70
import org.xml.sax.SAXException;
71
import org.xml.sax.XMLReader;
72

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

    
105
public class ReplicationService extends BaseService {
106

    
107
	private static ReplicationService replicationService = null;
108

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

    
125
	public static final String REPLICATION_LOG_FILE_NAME = "metacatreplication.log";
126

    
127
	private static String DATA_FILE_FLAG = null;
128
	public static String METACAT_REPL_ERROR_MSG = null;
129
	private static Logger logReplication = Logger.getLogger("ReplicationLogging");
130
	private static Logger logMetacat = Logger.getLogger(ReplicationService.class);
131

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

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

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

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

    
184
			logReplication.info("ReplicationService.initialize - After combine current time, the real first time is "
185
					+ firstTime.toString() + " minisec");
186

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

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

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

    
218
	public boolean refreshable() {
219
		return true;
220
	}
221

    
222
	protected void doRefresh() throws ServiceException {
223
		return;
224
	}
225
	
226
	public void stop() throws ServiceException{
227
		
228
	}
229

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

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

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

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

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

    
346
				//Get data replication value
347
				dataReplicate = ((String[]) params.get("datareplicate"))[0];
348
				
349
				//Get hub value
350
				hub = ((String[]) params.get("hub"))[0];
351

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

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

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

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

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

    
524
	}
525

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

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

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

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

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

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

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

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

    
761
		}//catch
762

    
763
	}
764

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

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

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

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

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

    
813
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
814
			
815
			// strip out the system metadata portion
816
		    String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
817
		   	docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);
818

    
819
			//dih is the parser for the docinfo xml format
820
			DocInfoHandler dih = new DocInfoHandler();
821
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
822
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
823
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
824
			
825
			String docName = (String) docinfoHash.get("docname");
826

    
827
			String docType = (String) docinfoHash.get("doctype");
828

    
829
			String docHomeServer = (String) docinfoHash.get("home_server");
830
			
831
			String createdDateString = docinfoHash.get("date_created");
832
			String updatedDateString = docinfoHash.get("date_updated");
833
			
834
			Date createdDate = DateTimeMarshaller.deserializeDateToUTC(createdDateString);
835
			Date updatedDate = DateTimeMarshaller.deserializeDateToUTC(updatedDateString);
836
			
837
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - docHomeServer of datafile: " + docHomeServer);
838

    
839
			// in case we have a write exception, we still want to track access and sysmeta
840
			Exception writeException = null;
841

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

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

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

    
923
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - datafile " + docid + " added to DB with "
924
					+ "action " + dbaction);
925
			EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER,
926
					docid, dbaction);
927

    
928
		} catch (Exception e) {
929
			e.printStackTrace();
930
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG, e);                         
931
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Datafile " + docid
932
					+ " failed to added to DB with " + "action " + dbaction + " because "
933
					+ e.getMessage());
934
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - ERROR in MetacatReplication.handleForceDataFileReplicate"
935
					+ "Request(): " + e.getMessage());
936
		}
937
	}
938

    
939
	/**
940
	 * Grants or denies a lock to a requesting host.
941
	 * The servlet parameters of interrest are:
942
	 * docid: the docid of the file the lock is being requested for
943
	 * currentdate: the timestamp of the document on the remote server
944
	 *
945
	 */
946
	protected static void handleGetLockRequest(
947
			Hashtable<String, String[]> params, HttpServletResponse response) {
948

    
949
		try {
950

    
951
			String docid = ((String[]) params.get("docid"))[0];
952
			String remoteRev = ((String[]) params.get("updaterev"))[0];
953
			DocumentImpl requestDoc = new DocumentImpl(docid);
954
			logReplication.info("ReplicationService.handleGetLockRequest - lock request for " + docid);
955
			int localRevInt = requestDoc.getRev();
956
			int remoteRevInt = Integer.parseInt(remoteRev);
957

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

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

    
1003
		try {
1004
			// get docinfo as XML string
1005
			String docinfoXML = getDocumentInfo(docid);
1006
			
1007
			// get a writer for sending back to response
1008
			response.setContentType("text/xml");
1009
			Writer out = response.getWriter();
1010
			out.write(docinfoXML);
1011
			out.close();
1012

    
1013
		} catch (Exception e) {
1014
			logMetacat.error("ReplicationService.handleGetDocumentInfoRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1015
			logReplication.error("ReplicationService.handleGetDocumentInfoRequest - error in metacatReplication.handlegetdocumentinforequest "
1016
					+ "for doc: " + docid + " : " + e.getMessage());
1017
		}
1018

    
1019
	}
1020
	
1021
	public static Hashtable<String, String> getDocumentInfoMap(String docid)
1022
			throws HandlerException, AccessControlException, JiBXException,
1023
			IOException, McdbException, SAXException {
1024
		
1025
		// Try get docid info from remote server
1026
		DocInfoHandler dih = new DocInfoHandler();
1027
		XMLReader docinfoParser = ReplicationHandler.initParser(dih);
1028

    
1029
		String docInfoStr = getDocumentInfo(docid);
1030

    
1031
		// strip out the system metadata portion
1032
		String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
1033
		docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);
1034

    
1035
		docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
1036
		Hashtable<String, String> docinfoHash = dih.getDocInfo();
1037

    
1038
		return docinfoHash;
1039
	}
1040
	
1041
	/**
1042
	 * Gets a docInfo XML snippet for the replication API
1043
	 * @param docid
1044
	 * @return
1045
	 * @throws AccessControlException
1046
	 * @throws JiBXException
1047
	 * @throws IOException
1048
	 * @throws McdbException
1049
	 */
1050
	public static String getDocumentInfo(String docid) throws AccessControlException, JiBXException, IOException, McdbException {
1051
		StringBuffer sb = new StringBuffer();
1052

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

    
1095
		sb.append("<accessControl>");
1096

    
1097
		AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid); 
1098
		sb.append(acfsf.getAccessString());
1099
		
1100
		sb.append("</accessControl>");
1101

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

    
1128
		} catch (Exception e) {
1129
			String msg = "ReplicationService.handleGetSystemMetadataRequest for guid: " + guid + " : " + e.getMessage();
1130
			logMetacat.error(msg);                         
1131
			logReplication.error(msg);
1132
		}
1133

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

    
1170
		} catch (Exception e) {
1171
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG, e);                         
1172
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when processing guid: " + guid, e);
1173
		}
1174
	}
1175

    
1176
	/**
1177
	 * Sends a datafile to a remote host
1178
	 */
1179
	protected static void handleGetDataFileRequest(OutputStream outPut,
1180
			Hashtable<String, String[]> params, HttpServletResponse response)
1181

    
1182
	{
1183
		// File path for data file
1184
		String filepath;
1185
		// Request docid
1186
		String docId = ((String[]) (params.get("docid")))[0];
1187
		//check if the doicd is null
1188
		if (docId == null) {
1189
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1190
			logReplication.error("ReplicationService.handleGetDataFileRequest - Didn't specify docid for replication");
1191
			return;
1192
		}
1193

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

    
1215
		if (!filepath.endsWith("/")) {
1216
			filepath += "/";
1217
		}
1218
		// Get file aboslute file name
1219
		String filename = filepath + docId;
1220

    
1221
		//MIME type
1222
		String contentType = null;
1223
		if (filename.endsWith(".xml")) {
1224
			contentType = "text/xml";
1225
		} else if (filename.endsWith(".css")) {
1226
			contentType = "text/css";
1227
		} else if (filename.endsWith(".dtd")) {
1228
			contentType = "text/plain";
1229
		} else if (filename.endsWith(".xsd")) {
1230
			contentType = "text/xml";
1231
		} else if (filename.endsWith("/")) {
1232
			contentType = "text/html";
1233
		} else {
1234
			File f = new File(filename);
1235
			if (f.isDirectory()) {
1236
				contentType = "text/html";
1237
			} else {
1238
				contentType = "application/octet-stream";
1239
			}
1240
		}
1241

    
1242
		// Set the mime type
1243
		response.setContentType(contentType);
1244

    
1245
		// Get the content of the file
1246
		FileInputStream fin = null;
1247
		try {
1248
			// FileInputStream to metacat
1249
			fin = new FileInputStream(filename);
1250
			// 4K buffer
1251
			byte[] buf = new byte[4 * 1024];
1252
			// Read data from file input stream to byte array
1253
			int b = fin.read(buf);
1254
			// Write to outStream from byte array
1255
			while (b != -1) {
1256
				outPut.write(buf, 0, b);
1257
				b = fin.read(buf);
1258
			}
1259
			// close file input stream
1260
			fin.close();
1261

    
1262
		} catch (Exception e) {
1263
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1264
			logReplication.error("ReplicationService.handleGetDataFileRequest - error getting data file from MetacatReplication."
1265
					+ "handlGetDataFileRequest " + e.getMessage());
1266
			e.printStackTrace(System.out);
1267
		} finally {
1268
		    IOUtils.closeQuietly(fin);
1269
		}
1270

    
1271
	}
1272

    
1273
	/**
1274
	 * Sends a document to a remote host
1275
	 */
1276
	protected static void handleGetDocumentRequest(
1277
			Hashtable<String, String[]> params, HttpServletResponse response) {
1278

    
1279
		String urlString = null;
1280
		String documentPath = null;
1281
		String errorMsg = null;
1282
		FileOutputStream fos = null;
1283
		InputStream is = null;
1284
		OutputStream outputStream = null;
1285
		try {
1286
			// try to open a https stream to test if the request server's public
1287
			// key
1288
			// in the key store, this is security issue
1289
			String server = params.get("server")[0];
1290
			urlString = "https://" + server + "?server="
1291
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test";
1292
			URL u = new URL(urlString);
1293
			String test = ReplicationService.getURLContent(u);
1294
			// couldn't pass the test
1295
			if (test.indexOf("successfully") == -1) {
1296
				response.setContentType("text/xml");
1297
				Writer out = response.getWriter();
1298
				out.write("<error>Couldn't pass the trust test " + test + " </error>");
1299
				out.close();
1300
				return;
1301
			}
1302

    
1303
			String docid = params.get("docid")[0];
1304
			logReplication.debug("ReplicationService.handleGetDocumentRequest - MetacatReplication.handleGetDocumentRequest for docid: "
1305
					+ docid);
1306
			DocumentImpl di = new DocumentImpl(docid);
1307

    
1308
			String documentDir = PropertyService
1309
					.getProperty("application.documentfilepath");
1310
			documentPath = documentDir + FileUtil.getFS() + docid;
1311

    
1312
			// if the document does not exist on disk, read it from db and write
1313
			// it to disk.
1314
			if (FileUtil.getFileStatus(documentPath) == FileUtil.DOES_NOT_EXIST
1315
					|| FileUtil.getFileSize(documentPath) == 0) {
1316
				fos = new FileOutputStream(documentPath);
1317
				is = di.toXml(fos, null, null, true);
1318
				fos.close();
1319
				is.close();
1320
			}
1321

    
1322
			// read the file from disk and send it to outputstream
1323
			outputStream = response.getOutputStream();
1324
			is = di.readFromFileSystem(outputStream, null, null, documentPath);
1325
			is.close();
1326
			outputStream.close();
1327

    
1328
			logReplication.info("ReplicationService.handleGetDocumentRequest - document " + docid + " sent");
1329

    
1330
			// return to avoid continuing to the error reporting section at the end
1331
			return;
1332
			
1333
		} catch (MalformedURLException mue) {
1334
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1335
			logReplication.error("ReplicationService.handleGetDocumentRequest - Url error when getting document from MetacatReplication."
1336
					+ "handlGetDocumentRequest for url: " + urlString + " : "
1337
					+ mue.getMessage());
1338
			// e.printStackTrace(System.out);
1339
			
1340
		} catch (IOException ioe) {
1341
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1342
			logReplication.error("ReplicationService.handleGetDocumentRequest - I/O error when getting document from MetacatReplication."
1343
					+ "handlGetDocumentRequest for file: " + documentPath + " : "
1344
					+ ioe.getMessage());
1345
			errorMsg = ioe.getMessage();
1346
		} catch (PropertyNotFoundException pnfe) {
1347
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1348
			logReplication
1349
					.error("ReplicationService.handleGetDocumentRequest - Error getting property when getting document from MetacatReplication."
1350
							+ "handlGetDocumentRequest for file: "
1351
							+ documentPath
1352
							+ " : "
1353
							+ pnfe.getMessage());
1354
			// e.printStackTrace(System.out);
1355
			errorMsg = pnfe.getMessage();
1356
		} catch (McdbException me) {
1357
			logReplication
1358
					.error("ReplicationService.handleGetDocumentRequest - Document implementation error  getting property when getting document from MetacatReplication."
1359
							+ "handlGetDocumentRequest for file: "
1360
							+ documentPath
1361
							+ " : "
1362
							+ me.getMessage());
1363
			// e.printStackTrace(System.out);
1364
			errorMsg = me.getMessage();
1365
		} finally {
1366
            IOUtils.closeQuietly(fos);
1367
            IOUtils.closeQuietly(is);
1368
            IOUtils.closeQuietly(outputStream);
1369
		}
1370
		
1371
		// report any errors if we got here
1372
		response.setContentType("text/xml");
1373
		Writer out = null;
1374
		try {
1375
			response.getWriter();
1376
			out = response.getWriter();
1377
			out.write("<error>" + errorMsg + "</error>");
1378
		} catch (Exception e) {
1379
			logMetacat.error(e.getMessage(), e);
1380
		} finally {
1381
			try {
1382
				out.close();
1383
			} catch (IOException e) {
1384
				logMetacat.error(e.getMessage(), e);
1385
			}
1386
		}
1387
		
1388

    
1389
	}
1390

    
1391
	/**
1392
	 * Sends a list of all of the documents on this sever along with their
1393
	 * revision numbers. The format is: <!ELEMENT replication (server, updates)>
1394
	 * <!ELEMENT server (#PCDATA)> <!ELEMENT updates ((updatedDocument |
1395
	 * deleteDocument | revisionDocument)*)> <!ELEMENT updatedDocument (docid,
1396
	 * rev, datafile*)> <!ELEMENT deletedDocument (docid, rev)> <!ELEMENT
1397
	 * revisionDocument (docid, rev, datafile*)> <!ELEMENT docid (#PCDATA)>
1398
	 * <!ELEMENT rev (#PCDATA)> <!ELEMENT datafile (#PCDATA)> note that the rev
1399
	 * in deletedDocument is always empty. I just left it in there to make the
1400
	 * parser implementation easier.
1401
	 */
1402
	protected static void handleUpdateRequest(Hashtable<String, String[]> params,
1403
			HttpServletResponse response) {
1404
		// Checked out DBConnection
1405
		DBConnection dbConn = null;
1406
		// DBConenction serial number when checked it out
1407
		int serialNumber = -1;
1408
		PreparedStatement pstmt = null;
1409
		// Server list to store server info of xml_replication table
1410
		ReplicationServerList serverList = null;
1411
		
1412
		// a writer for response
1413
		Writer out = null;
1414

    
1415
		try {
1416
			// get writer, TODO: encoding?
1417
			response.setContentType("text/xml");
1418
			out = response.getWriter();
1419
			
1420
			// Check out a DBConnection from pool
1421
			dbConn = DBConnectionPool
1422
					.getDBConnection("MetacatReplication.handleUpdateRequest");
1423
			serialNumber = dbConn.getCheckOutSerialNumber();
1424
			// Create a server list from xml_replication table
1425
			serverList = new ReplicationServerList();
1426

    
1427
			// Get remote server name from param
1428
			String server = ((String[]) params.get("server"))[0];
1429
			// If no servr name in param, return a error
1430
			if (server == null || server.equals("")) {
1431
				out.write("<error>Request didn't specify server name</error>");
1432
				out.close();
1433
				return;
1434
			}//if
1435

    
1436
			//try to open a https stream to test if the request server's public key
1437
			//in the key store, this is security issue
1438
			String testUrl = "https://" + server + "?server="
1439
            + MetacatUtil.getLocalReplicationServerName() + "&action=test";
1440
			logReplication.info("Running trust test: " + testUrl);
1441
			URL u = new URL(testUrl);
1442
			String test = ReplicationService.getURLContent(u);
1443
			logReplication.info("Ouput from test is '" + test + "'");
1444
			//couldn't pass the test
1445
			if (test.indexOf("successfully") == -1) {
1446
			    logReplication.error("Trust test failed.");
1447
				out.write("<error>Couldn't pass the trust test</error>");
1448
				out.close();
1449
				return;
1450
			}
1451
			logReplication.info("Trust test succeeded.");
1452

    
1453
			// Check if local host configure to replicate xml documents to remote
1454
			// server. If not send back a error message
1455
			if (!serverList.getReplicationValue(server)) {
1456
				out.write("<error>Configuration not allow to replicate document to you</error>");
1457
				out.close();
1458
				return;
1459
			}//if
1460

    
1461
			// Store the sql command
1462
			StringBuffer docsql = new StringBuffer();
1463
			StringBuffer revisionSql = new StringBuffer();
1464
			
1465
			// Store the data set file
1466
			Vector<Vector<String>> packageFiles = new Vector<Vector<String>>();
1467

    
1468
			// Append local server's name and replication servlet to doclist
1469
			out.append("<?xml version=\"1.0\"?><replication>");
1470
			out.append("<server>")
1471
					.append(MetacatUtil.getLocalReplicationServerName());
1472
			//doclist.append(util.getProperty("replicationpath"));
1473
			out.append("</server><updates>");
1474

    
1475
			// Get correct docid that reside on this server according the requesting
1476
			// server's replicate and data replicate value in xml_replication table
1477
			docsql.append(DatabaseService.getInstance().getDBAdapter().getReplicationDocumentListSQL());
1478
			//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)) ");
1479
			revisionSql.append("select docid, rev, doctype from xml_revisions ");
1480
			// If the localhost is not a hub to the remote server, only replicate
1481
			// the docid' which home server is local host (server_location =1)
1482
			if (!serverList.getHubValue(server)) {
1483
				String serverLocationDoc = " and a.server_location = 1";
1484
				String serverLocationRev = "where server_location = 1";
1485
				docsql.append(serverLocationDoc);
1486
				revisionSql.append(serverLocationRev);
1487
			}
1488
			logReplication.info("ReplicationService.handleUpdateRequest - Doc sql: " + docsql.toString());
1489

    
1490
			// Get any deleted documents
1491
			StringBuffer delsql = new StringBuffer();
1492
			delsql.append("SELECT t1.docid FROM xml_revisions t1 LEFT JOIN xml_documents t2 on t1.docid = t2.docid WHERE t2.docid IS NULL "); 
1493
			
1494
			// If the localhost is not a hub to the remote server, only replicate
1495
			// the docid' which home server is local host (server_location =1)
1496
			if (!serverList.getHubValue(server)) {
1497
				delsql.append("and t1.server_location = 1");
1498
			}
1499
			logReplication.info("ReplicationService.handleUpdateRequest - Deleted sql: " + delsql.toString());
1500

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

    
1578
			pstmt = dbConn.prepareStatement(delsql.toString());
1579
			//usage count should increas 1
1580
			dbConn.increaseUsageCount(1);
1581

    
1582
			pstmt.execute();
1583
			rs = pstmt.getResultSet();
1584
			tablehasrows = rs.next();
1585
			while (tablehasrows) { //handle the deleted documents
1586
				out.append("<deletedDocument><docid>").append(rs.getString(1));
1587
				out.append("</docid><rev></rev></deletedDocument>");
1588
				//note that rev is always empty for deleted docs
1589
				tablehasrows = rs.next();
1590
			}
1591

    
1592
			//now we can put the package files into the xml results
1593
			for (int i = 0; i < packageFiles.size(); i++) {
1594
				Vector<String> v = packageFiles.elementAt(i);
1595
				out.append("<updatedDocument>");
1596
				out.append("<docid>").append(v.elementAt(0));
1597
				out.append("</docid><rev>");
1598
				out.append(v.elementAt(1));
1599
				out.append("</rev>");
1600
				out.append("</updatedDocument>");
1601
			}
1602
			// add revision doc list  
1603
			out.append(prepareRevisionDoc(dbConn, revisionSql.toString(),
1604
					replicateData));
1605

    
1606
			out.append("</updates></replication>");
1607
			logReplication.info("ReplicationService.handleUpdateRequest - done writing to output stream.");
1608
			pstmt.close();
1609
			//conn.close();
1610

    
1611
		} catch (Exception e) {
1612
			logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1613
			logReplication.error("ReplicationService.handleUpdateRequest - error in MetacatReplication." + "handleupdaterequest: "
1614
					+ e.getMessage());
1615
			//e.printStackTrace(System.out);
1616
			try {
1617
				out.write("<error>" + e.getMessage() + "</error>");
1618
			} catch (IOException e1) {
1619
				logMetacat.error(e1.getMessage(), e1);
1620
			}
1621
		} finally {
1622
			try {
1623
				pstmt.close();
1624
			}//try
1625
			catch (SQLException ee) {
1626
				logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1627
				logReplication.error("ReplicationService.handleUpdateRequest - Error in MetacatReplication."
1628
						+ "handleUpdaterequest to close pstmt: " + ee.getMessage());
1629
			}//catch
1630
			finally {
1631
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1632
			}//finally
1633
			try {
1634
				out.close();
1635
			} catch (IOException e) {
1636
				logMetacat.error(e.getMessage(), e);
1637
			}
1638
		}//finally
1639

    
1640
	}//handlUpdateRequest
1641

    
1642
	/**
1643
	 * 
1644
	 * @param dbConn connection for doing the update
1645
	 * @param docid the document id to update
1646
	 * @param owner the user_owner
1647
	 * @param updater the user_updated
1648
	 * @throws SQLException
1649
	 */
1650
	public static void updateUserOwner(DBConnection dbConn, String docid, String owner, String updater) throws SQLException {
1651
	
1652
		String sql = 
1653
			"UPDATE xml_documents " +
1654
			"SET user_owner = ?, " +
1655
			"user_updated = ? " +
1656
			"WHERE docid = ?;";
1657
		PreparedStatement pstmt = dbConn.prepareStatement(sql);
1658
		//usage count should increas 1
1659
		dbConn.increaseUsageCount(1);
1660

    
1661
		docid = DocumentUtil.getSmartDocId(docid);
1662
		pstmt.setString(1, owner);
1663
		pstmt.setString(2, updater);
1664
		pstmt.setString(3, docid);
1665
		pstmt.execute();
1666
		pstmt.close();
1667
		
1668
		dbConn.commit();
1669
	}
1670
	
1671
	/*
1672
	 * This method will get the xml string for document in xml_revision
1673
	 * The schema look like <!ELEMENT revisionDocument (docid, rev, datafile*)>
1674
	 */
1675
	private static String prepareRevisionDoc(DBConnection dbConn, String revSql,
1676
			boolean replicateData) throws Exception {
1677
		logReplication.warn("ReplicationService.prepareRevisionDoc - The revision document sql is " + revSql);
1678
		StringBuffer revDocList = new StringBuffer();
1679
		PreparedStatement pstmt = dbConn.prepareStatement(revSql);
1680
		//usage count should increas 1
1681
		dbConn.increaseUsageCount(1);
1682

    
1683
		pstmt.execute();
1684
		ResultSet rs = pstmt.getResultSet();
1685
		logReplication.warn("Processing replication revision for documents");
1686
		while (rs.next()) {
1687
			String recordDoctype = rs.getString(3);
1688

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

    
1693
				// do nothing
1694
			} else {
1695
				String docid = rs.getString(1);
1696
				int rev = rs.getInt(2);
1697
				logMetacat.debug("Processing replication revision for docid: " + docid + "." + rev);
1698

    
1699
				revDocList.append("<revisionDocument>");
1700
				revDocList.append("<docid>").append(docid);
1701
				revDocList.append("</docid><rev>").append(rev);
1702
				revDocList.append("</rev>");
1703
				// data file
1704
				if (recordDoctype.equals("BIN")) {
1705
					revDocList.append("<datafile>");
1706
					revDocList.append(DATA_FILE_FLAG);
1707
					revDocList.append("</datafile>");
1708
				}
1709
				revDocList.append("</revisionDocument>");
1710

    
1711
			}//else
1712
		}
1713
		//System.out.println("The revision list is"+ revDocList.toString());
1714
		return revDocList.toString();
1715
	}
1716

    
1717
	/**
1718
	 * Returns the xml_catalog table encoded in xml
1719
	 */
1720
	public static String getCatalogXML() {
1721
		return handleGetCatalogRequest(null, null, false);
1722
	}
1723

    
1724
	/**
1725
	 * Sends the contents of the xml_catalog table encoded in xml
1726
	 * The xml format is:
1727
	 * <!ELEMENT xml_catalog (row*)>
1728
	 * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
1729
	 *                system_id)>
1730
	 * All of the sub elements of row are #PCDATA
1731

    
1732
	 * If printFlag == false then do not print to out.
1733
	 */
1734
	protected static String handleGetCatalogRequest(
1735
			Hashtable<String, String[]> params, HttpServletResponse response,
1736
			boolean printFlag) {
1737
		DBConnection dbConn = null;
1738
		int serialNumber = -1;
1739
		PreparedStatement pstmt = null;
1740
		Writer out = null;
1741
		try {
1742
			// get writer, TODO: encoding?
1743
		    if(printFlag)
1744
		    {
1745
		        response.setContentType("text/xml");
1746
		        out = response.getWriter();
1747
		    }
1748
			/*conn = MetacatReplication.getDBConnection("MetacatReplication." +
1749
			                                          "handleGetCatalogRequest");*/
1750
			dbConn = DBConnectionPool
1751
					.getDBConnection("MetacatReplication.handleGetCatalogRequest");
1752
			serialNumber = dbConn.getCheckOutSerialNumber();
1753
			pstmt = dbConn.prepareStatement("select entry_type, "
1754
					+ "source_doctype, target_doctype, public_id, "
1755
					+ "system_id from xml_catalog");
1756
			pstmt.execute();
1757
			ResultSet rs = pstmt.getResultSet();
1758
			boolean tablehasrows = rs.next();
1759
			StringBuffer sb = new StringBuffer();
1760
			sb.append("<?xml version=\"1.0\"?><xml_catalog>");
1761
			while (tablehasrows) {
1762
				sb.append("<row><entry_type>").append(rs.getString(1));
1763
				sb.append("</entry_type><source_doctype>").append(rs.getString(2));
1764
				sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
1765
				sb.append("</target_doctype><public_id>").append(rs.getString(4));
1766
				// system id may not have server url on front.  Add it if not.
1767
				String systemID = rs.getString(5);
1768
				if (!systemID.startsWith("http://")) {
1769
					systemID = SystemUtil.getContextURL() + systemID;
1770
				}
1771
				sb.append("</public_id><system_id>").append(systemID);
1772
				sb.append("</system_id></row>");
1773

    
1774
				tablehasrows = rs.next();
1775
			}
1776
			sb.append("</xml_catalog>");
1777
			//conn.close();
1778
			if (printFlag) {
1779
				response.setContentType("text/xml");
1780
				out.write(sb.toString());
1781
			}
1782
			pstmt.close();
1783
			return sb.toString();
1784
		} catch (Exception e) {
1785
			logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1786
			logReplication.error("ReplicationService.handleGetCatalogRequest - error in MetacatReplication.handleGetCatalogRequest:"
1787
					+ e.getMessage());
1788
			e.printStackTrace(System.out);
1789
			if (printFlag) {
1790
				try {
1791
					out.write("<error>" + e.getMessage() + "</error>");
1792
				} catch (IOException e1) {
1793
					logMetacat.error(e1.getMessage(), e1);
1794
				}
1795
			}
1796
		} finally {
1797
			try {
1798
				pstmt.close();
1799
			}//try
1800
			catch (SQLException ee) {
1801
				logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1802
				logReplication.error("ReplicationService.handleGetCatalogRequest - Error in MetacatReplication.handleGetCatalogRequest: "
1803
						+ ee.getMessage());
1804
			}//catch
1805
			finally {
1806
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1807
			}//finally
1808
			if (out != null) {
1809
				try {
1810
					out.close();
1811
				} catch (IOException e1) {
1812
					logMetacat.error(e1.getMessage(), e1);
1813
				}
1814
			}
1815
		}//finally
1816

    
1817
		return null;
1818
	}
1819

    
1820
	/**
1821
	 * Sends the current system date to the remote server.  Using this action
1822
	 * for replication gets rid of any problems with syncronizing clocks
1823
	 * because a time specific to a document is always kept on its home server.
1824
	 */
1825
	protected static void handleGetTimeRequest(
1826
			Hashtable<String, String[]> params, HttpServletResponse response) {
1827
		
1828
		// use standard format -- the receiving end wants this too
1829
		String dateString = DateTimeMarshaller.serializeDateToUTC(Calendar.getInstance().getTime());
1830
		
1831
		// get a writer for sending back to response
1832
		response.setContentType("text/xml");
1833
		Writer out = null;
1834
		try {
1835
			out = response.getWriter();
1836
			out.write("<timestamp>" + dateString + "</timestamp>");
1837
			out.close();
1838
		} catch (IOException e) {
1839
			logMetacat.error(e.getMessage(), e);
1840
		}
1841
		
1842
	}
1843

    
1844
	/**
1845
	 * this method handles the timeout for a file lock.  when a lock is
1846
	 * granted it is granted for 30 seconds.  When this thread runs out
1847
	 * it deletes the docid from the queue, thus eliminating the lock.
1848
	 */
1849
	public void run() {
1850
		try {
1851
			logReplication.info("ReplicationService.run - thread started for docid: "
1852
					+ (String) fileLocks.elementAt(0));
1853

    
1854
			Thread.sleep(30000); //the lock will expire in 30 seconds
1855
			logReplication.info("thread for docid: "
1856
					+ (String) fileLocks.elementAt(fileLocks.size() - 1) + " exiting.");
1857

    
1858
			fileLocks.remove(fileLocks.size() - 1);
1859
			//fileLocks is treated as a FIFO queue.  If there are more than one lock
1860
			//in the vector, the first one inserted will be removed.
1861
		} catch (Exception e) {
1862
			logMetacat.error("ReplicationService.run - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1863
			logReplication.error("ReplicationService.run - error in file lock thread from "
1864
					+ "MetacatReplication.run: " + e.getMessage());
1865
		}
1866
	}
1867

    
1868
	/**
1869
	 * Returns the name of a server given a serverCode
1870
	 * @param serverCode the serverid of the server
1871
	 * @return the servername or null if the specified serverCode does not
1872
	 *         exist.
1873
	 */
1874
	public static String getServerNameForServerCode(int serverCode) {
1875
		//System.out.println("serverid: " + serverCode);
1876
		DBConnection dbConn = null;
1877
		int serialNumber = -1;
1878
		PreparedStatement pstmt = null;
1879
		try {
1880
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServer");
1881
			serialNumber = dbConn.getCheckOutSerialNumber();
1882
			String sql = new String("select server from "
1883
					+ "xml_replication where serverid = ?");
1884
			pstmt = dbConn.prepareStatement(sql);
1885
			pstmt.setInt(1, serverCode);
1886
			//System.out.println("getserver sql: " + sql);
1887
			pstmt.execute();
1888
			ResultSet rs = pstmt.getResultSet();
1889
			boolean tablehasrows = rs.next();
1890
			if (tablehasrows) {
1891
				//System.out.println("server: " + rs.getString(1));
1892
				return rs.getString(1);
1893
			}
1894

    
1895
			//conn.close();
1896
		} catch (Exception e) {
1897
			logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1898
			logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplication.getServer: " + e.getMessage());
1899
		} finally {
1900
			try {
1901
				pstmt.close();
1902
			}//try
1903
			catch (SQLException ee) {
1904
				logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1905
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacactReplication.getserver: "
1906
						+ ee.getMessage());
1907
			}//catch
1908
			finally {
1909
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1910
			}//fianlly
1911
		}//finally
1912

    
1913
		return null;
1914
		//return null if the server does not exist
1915
	}
1916

    
1917
	/**
1918
	 * Returns a server code given a server name
1919
	 * @param server the name of the server
1920
	 * @return integer > 0 representing the code of the server, 0 if the server
1921
	 *  does not exist.
1922
	 */
1923
	public static int getServerCodeForServerName(String server) throws ServiceException {
1924
		DBConnection dbConn = null;
1925
		int serialNumber = -1;
1926
		PreparedStatement pstmt = null;
1927
		int serverCode = 0;
1928

    
1929
		try {
1930

    
1931
			//conn = util.openDBConnection();
1932
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServerCode");
1933
			serialNumber = dbConn.getCheckOutSerialNumber();
1934
			pstmt = dbConn.prepareStatement("SELECT serverid FROM xml_replication "
1935
					+ "WHERE server LIKE ?");
1936
			pstmt.setString(1, server);
1937
			pstmt.execute();
1938
			ResultSet rs = pstmt.getResultSet();
1939
			boolean tablehasrows = rs.next();
1940
			if (tablehasrows) {
1941
				serverCode = rs.getInt(1);
1942
				pstmt.close();
1943
				//conn.close();
1944
				return serverCode;
1945
			}
1946

    
1947
		} catch (SQLException sqle) {
1948
			throw new ServiceException("ReplicationService.getServerCodeForServerName - " 
1949
					+ "SQL error when getting server code: " + sqle.getMessage());
1950

    
1951
		} finally {
1952
			try {
1953
				pstmt.close();
1954
				//conn.close();
1955
			}//try
1956
			catch (Exception ee) {
1957
				logMetacat.error("ReplicationService.getServerCodeForServerName - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1958
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplicatio.getServerCode: "
1959
						+ ee.getMessage());
1960

    
1961
			}//catch
1962
			finally {
1963
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1964
			}//finally
1965
		}//finally
1966

    
1967
		return serverCode;
1968
	}
1969

    
1970
	/**
1971
	 * Method to get a host server information for given docid
1972
	 * @param conn a connection to the database
1973
	 */
1974
	public static Hashtable<String, String> getHomeServerInfoForDocId(String docId) {
1975
		Hashtable<String, String> sl = new Hashtable<String, String>();
1976
		DBConnection dbConn = null;
1977
		int serialNumber = -1;
1978
		docId = DocumentUtil.getDocIdFromString(docId);
1979
		PreparedStatement pstmt = null;
1980
		int serverLocation;
1981
		try {
1982
			//get conection
1983
			dbConn = DBConnectionPool.getDBConnection("ReplicationHandler.getHomeServer");
1984
			serialNumber = dbConn.getCheckOutSerialNumber();
1985
			//get a server location from xml_document table
1986
			pstmt = dbConn.prepareStatement("select server_location from xml_documents "
1987
					+ "where docid = ?");
1988
			pstmt.setString(1, docId);
1989
			pstmt.execute();
1990
			ResultSet serverName = pstmt.getResultSet();
1991
			//get a server location
1992
			if (serverName.next()) {
1993
				serverLocation = serverName.getInt(1);
1994
				pstmt.close();
1995
			} else {
1996
				pstmt.close();
1997
				//ut.returnConnection(conn);
1998
				return null;
1999
			}
2000
			pstmt = dbConn.prepareStatement("select server, last_checked, replicate "
2001
					+ "from xml_replication where serverid = ?");
2002
			//increase usage count
2003
			dbConn.increaseUsageCount(1);
2004
			pstmt.setInt(1, serverLocation);
2005
			pstmt.execute();
2006
			ResultSet rs = pstmt.getResultSet();
2007
			boolean tableHasRows = rs.next();
2008
			if (tableHasRows) {
2009

    
2010
				String server = rs.getString(1);
2011
				String last_checked = rs.getString(2);
2012
				if (!server.equals("localhost")) {
2013
					sl.put(server, last_checked);
2014
				}
2015

    
2016
			} else {
2017
				pstmt.close();
2018
				//ut.returnConnection(conn);
2019
				return null;
2020
			}
2021
			pstmt.close();
2022
		} catch (Exception e) {
2023
			logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2024
			logReplication.error("ReplicationService.getHomeServerInfoForDocId - error in replicationHandler.getHomeServer(): "
2025
					+ e.getMessage());
2026
		} finally {
2027
			try {
2028
				pstmt.close();
2029
				//ut.returnConnection(conn);
2030
			} catch (Exception ee) {
2031
				logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2032
				logReplication.error("ReplicationService.getHomeServerInfoForDocId - Eror irn rplicationHandler.getHomeServer() "
2033
						+ "to close pstmt: " + ee.getMessage());
2034
			} finally {
2035
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2036
			}
2037

    
2038
		}//finally
2039
		return sl;
2040
	}
2041

    
2042
	/**
2043
	 * Returns a home server location  given a accnum
2044
	 * @param accNum , given accNum for a document
2045
	 *
2046
	 */
2047
	public static int getHomeServerCodeForDocId(String accNum) throws ServiceException {
2048
		DBConnection dbConn = null;
2049
		int serialNumber = -1;
2050
		PreparedStatement pstmt = null;
2051
		int serverCode = 1;
2052
		String docId = DocumentUtil.getDocIdFromString(accNum);
2053

    
2054
		try {
2055

    
2056
			// Get DBConnection
2057
			dbConn = DBConnectionPool
2058
					.getDBConnection("ReplicationHandler.getServerLocation");
2059
			serialNumber = dbConn.getCheckOutSerialNumber();
2060
			pstmt = dbConn.prepareStatement("SELECT server_location FROM xml_documents "
2061
					+ "WHERE docid LIKE ? ");
2062
			pstmt.setString(1, docId);
2063
			pstmt.execute();
2064
			ResultSet rs = pstmt.getResultSet();
2065
			boolean tablehasrows = rs.next();
2066
			//If a document is find, return the server location for it
2067
			if (tablehasrows) {
2068
				serverCode = rs.getInt(1);
2069
				pstmt.close();
2070
				//conn.close();
2071
				return serverCode;
2072
			}
2073
			//if couldn't find in xml_documents table, we think server code is 1
2074
			//(this is new document)
2075
			else {
2076
				pstmt.close();
2077
				//conn.close();
2078
				return serverCode;
2079
			}
2080

    
2081
		} catch (SQLException sqle) {
2082
			throw new ServiceException("ReplicationService.getHomeServerCodeForDocId - " 
2083
					+ "SQL error when getting home server code for docid: " + docId + " : " 
2084
					+ sqle.getMessage());
2085

    
2086
		} finally {
2087
			try {
2088
				pstmt.close();
2089
				//conn.close();
2090

    
2091
			} catch (SQLException sqle) {
2092
				logMetacat.error("ReplicationService.getHomeServerCodeForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2093
				logReplication.error("ReplicationService.getHomeServerCodeForDocId - ReplicationService.getHomeServerCodeForDocId - " 
2094
						+ "SQL error when getting home server code for docid: " + docId + " : " 
2095
						+ sqle.getMessage());
2096
			} finally {
2097
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2098
			}//finally
2099
		}//finally
2100
		//return serverCode;
2101
	}
2102

    
2103
	/**
2104
	 * This method returns the content of a url
2105
	 * @param u the url to return the content from
2106
	 * @return a string representing the content of the url
2107
	 * @throws java.io.IOException
2108
	 */
2109
	public static String getURLContent(URL u) throws java.io.IOException {
2110
		char istreamChar;
2111
		int istreamInt;
2112
		// get the response content
2113
		InputStream input = getURLStream(u);
2114
		logReplication.info("ReplicationService.getURLContent - After getting response from: " + u.toString());
2115
		InputStreamReader istream = new InputStreamReader(input);
2116
		StringBuffer serverResponse = new StringBuffer();
2117
		while ((istreamInt = istream.read()) != -1) {
2118
			istreamChar = (char) istreamInt;
2119
			serverResponse.append(istreamChar);
2120
		}
2121
		istream.close();
2122
		input.close();
2123

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

    
2173
		SSLSocketFactory socketFactory = null;
2174
		try {
2175
			socketFactory = CertificateManager.getInstance().getSSLSocketFactory(subject);
2176
		} catch (FileNotFoundException e) {
2177
			// these are somewhat expected for anonymous client use
2178
			logReplication.warn("Could not set up SSL connection for client - likely because the certificate could not be located: " + e.getMessage());
2179
		} catch (Exception e) {
2180
			// this is likely more severe
2181
			logReplication.warn("Funky SSL going on: " + e.getClass() + ":: " + e.getMessage());
2182
		}
2183
		try {
2184
			//443 is the default port, this value is overridden if explicitly set in the URL
2185
			Scheme sch = new Scheme("https", 443, socketFactory);
2186
			client.getHttpClient().getConnectionManager().getSchemeRegistry().register(sch);
2187
		} catch (Exception e) {
2188
			// this is likely more severe
2189
			logReplication.error("Failed to set up SSL connection for client. Continuing. " + e.getClass() + ":: " + e.getMessage(), e);
2190
		}
2191
		return client;
2192
	}
2193
	
2194

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

    
2219
//	/**
2220
//	 * Method for writing replication messages to a log file specified in
2221
//	 * metacat.properties
2222
//	 */
2223
//	public static void replErrorLog(String message) {
2224
//		try {
2225
//			FileOutputStream fos = new FileOutputStream(PropertyService
2226
//					.getProperty("replication.logdir")
2227
//					+ "/metacatreplicationerror.log", true);
2228
//			PrintWriter pw = new PrintWriter(fos);
2229
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
2230
//			java.util.Date localtime = new java.util.Date();
2231
//			String dateString = formatter.format(localtime);
2232
//			dateString += " :: " + message;
2233
//			//time stamp each entry
2234
//			pw.println(dateString);
2235
//			pw.flush();
2236
//		} catch (Exception e) {
2237
//			logReplication.error("error writing to replication error log from "
2238
//					+ "MetacatReplication.replErrorLog: " + e.getMessage());
2239
//			//e.printStackTrace(System.out);
2240
//		}
2241
//	}
2242

    
2243
	/**
2244
	 * Returns true if the replicate field for server in xml_replication is 1.
2245
	 * Returns false otherwise
2246
	 */
2247
	public static boolean replToServer(String server) {
2248
		DBConnection dbConn = null;
2249
		int serialNumber = -1;
2250
		PreparedStatement pstmt = null;
2251
		try {
2252
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.repltoServer");
2253
			serialNumber = dbConn.getCheckOutSerialNumber();
2254
			pstmt = dbConn.prepareStatement("select replicate from "
2255
					+ "xml_replication where server like ? ");
2256
			pstmt.setString(1, server);
2257
			pstmt.execute();
2258
			ResultSet rs = pstmt.getResultSet();
2259
			boolean tablehasrows = rs.next();
2260
			if (tablehasrows) {
2261
				int i = rs.getInt(1);
2262
				if (i == 1) {
2263
					pstmt.close();
2264
					//conn.close();
2265
					return true;
2266
				} else {
2267
					pstmt.close();
2268
					//conn.close();
2269
					return false;
2270
				}
2271
			}
2272
		} catch (SQLException sqle) {
2273
			logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2274
			logReplication.error("ReplicationService.replToServer - SQL error in MetacatReplication.replToServer: "
2275
					+ sqle.getMessage());
2276
		} finally {
2277
			try {
2278
				pstmt.close();
2279
				//conn.close();
2280
			}//try
2281
			catch (Exception ee) {
2282
				logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2283
				logReplication.error("ReplicationService.replToServer - Error in MetacatReplication.replToServer: "
2284
						+ ee.getMessage());
2285
			}//catch
2286
			finally {
2287
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2288
			}//finally
2289
		}//finally
2290
		return false;
2291
		//the default if this server does not exist is to not replicate to it.
2292
	}
2293

    
2294
}
(6-6/7)