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: jones $'
9
 *     '$Date: 2013-10-09 12:44:16 -0700 (Wed, 09 Oct 2013) $'
10
 * '$Revision: 8297 $'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26

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

    
29
import java.io.ByteArrayInputStream;
30
import java.io.ByteArrayOutputStream;
31
import java.io.File;
32
import java.io.FileInputStream;
33
import java.io.FileNotFoundException;
34
import java.io.FileOutputStream;
35
import java.io.IOException;
36
import java.io.InputStream;
37
import java.io.InputStreamReader;
38
import java.io.OutputStream;
39
import java.io.StringReader;
40
import java.io.Writer;
41
import java.net.MalformedURLException;
42
import java.net.URL;
43
import java.security.PrivateKey;
44
import java.security.cert.X509Certificate;
45
import java.sql.PreparedStatement;
46
import java.sql.ResultSet;
47
import java.sql.SQLException;
48
import java.sql.Timestamp;
49
import java.util.Calendar;
50
import java.util.Date;
51
import java.util.Hashtable;
52
import java.util.Timer;
53
import java.util.Vector;
54

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

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

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

    
103
public class ReplicationService extends BaseService {
104

    
105
	private static ReplicationService replicationService = null;
106

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
522
	}
523

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

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

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

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

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

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

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

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

    
759
		}//catch
760

    
761
	}
762

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

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

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

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

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

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

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

    
825
			String docType = (String) docinfoHash.get("doctype");
826

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

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

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

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

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

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

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

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

    
947
		try {
948

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

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

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

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

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

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

    
1027
		String docInfoStr = getDocumentInfo(docid);
1028

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

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

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

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

    
1093
		sb.append("<accessControl>");
1094

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

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

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

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

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

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

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

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

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

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

    
1240
		// Set the mime type
1241
		response.setContentType(contentType);
1242

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

    
1260
		}//try
1261
		catch (Exception e) {
1262
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1263
			logReplication.error("ReplicationService.handleGetDataFileRequest - error getting data file from MetacatReplication."
1264
					+ "handlGetDataFileRequest " + e.getMessage());
1265
			e.printStackTrace(System.out);
1266
		}//catch
1267

    
1268
	}
1269

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

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

    
1298
			String docid = params.get("docid")[0];
1299
			logReplication.debug("ReplicationService.handleGetDocumentRequest - MetacatReplication.handleGetDocumentRequest for docid: "
1300
					+ docid);
1301
			DocumentImpl di = new DocumentImpl(docid);
1302

    
1303
			String documentDir = PropertyService
1304
					.getProperty("application.documentfilepath");
1305
			documentPath = documentDir + FileUtil.getFS() + docid;
1306

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

    
1317
			// read the file from disk and send it to outputstream
1318
			OutputStream outputStream = response.getOutputStream();
1319
			di.readFromFileSystem(outputStream, null, null, documentPath);
1320

    
1321
			logReplication.info("ReplicationService.handleGetDocumentRequest - document " + docid + " sent");
1322

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

    
1386
	}
1387

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

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

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

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

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

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

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

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

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

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

    
1575
			pstmt = dbConn.prepareStatement(delsql.toString());
1576
			//usage count should increas 1
1577
			dbConn.increaseUsageCount(1);
1578

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

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

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

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

    
1637
	}//handlUpdateRequest
1638

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

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

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

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

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

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

    
1708
			}//else
1709
		}
1710
		//System.out.println("The revision list is"+ revDocList.toString());
1711
		return revDocList.toString();
1712
	}
1713

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

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

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

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

    
1814
		return null;
1815
	}
1816

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

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

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

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

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

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

    
1910
		return null;
1911
		//return null if the server does not exist
1912
	}
1913

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

    
1926
		try {
1927

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

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

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

    
1958
			}//catch
1959
			finally {
1960
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1961
			}//finally
1962
		}//finally
1963

    
1964
		return serverCode;
1965
	}
1966

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

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

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

    
2035
		}//finally
2036
		return sl;
2037
	}
2038

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

    
2051
		try {
2052

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

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

    
2083
		} finally {
2084
			try {
2085
				pstmt.close();
2086
				//conn.close();
2087

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

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

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

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

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

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

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

    
2291
}
(6-6/7)