Project

General

Profile

1 522 berkley
/**
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$'
9
 *     '$Date$'
10
 * '$Revision$'
11 669 jones
 *
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 522 berkley
 */
26
27 5014 daigle
package edu.ucsb.nceas.metacat.replication;
28 522 berkley
29 6102 leinfelder
import java.io.ByteArrayInputStream;
30
import java.io.ByteArrayOutputStream;
31 5755 leinfelder
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 6582 leinfelder
import java.security.PrivateKey;
44
import java.security.cert.X509Certificate;
45 5755 leinfelder
import java.sql.PreparedStatement;
46
import java.sql.ResultSet;
47
import java.sql.SQLException;
48 6595 leinfelder
import java.sql.Timestamp;
49
import java.util.Calendar;
50 2572 tao
import java.util.Date;
51 5755 leinfelder
import java.util.Hashtable;
52
import java.util.Timer;
53
import java.util.Vector;
54 4080 daigle
55 5755 leinfelder
import javax.servlet.http.HttpServletRequest;
56
import javax.servlet.http.HttpServletResponse;
57 574 berkley
58 6582 leinfelder
import org.apache.http.HttpResponse;
59
import org.apache.http.conn.scheme.Scheme;
60
import org.apache.http.conn.ssl.SSLSocketFactory;
61 5755 leinfelder
import org.apache.log4j.Logger;
62 6582 leinfelder
import org.dataone.client.RestClient;
63
import org.dataone.client.auth.CertificateManager;
64 6366 leinfelder
import org.dataone.service.types.v1.SystemMetadata;
65 6614 leinfelder
import org.dataone.service.util.DateTimeMarshaller;
66 6367 leinfelder
import org.dataone.service.util.TypeMarshaller;
67 6708 leinfelder
import org.jibx.runtime.JiBXException;
68 5755 leinfelder
import org.xml.sax.InputSource;
69
import org.xml.sax.SAXException;
70
import org.xml.sax.XMLReader;
71
72 5014 daigle
import edu.ucsb.nceas.metacat.DocumentImpl;
73
import edu.ucsb.nceas.metacat.DocumentImplWrapper;
74
import edu.ucsb.nceas.metacat.EventLog;
75 5755 leinfelder
import edu.ucsb.nceas.metacat.IdentifierManager;
76
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
77 5014 daigle
import edu.ucsb.nceas.metacat.McdbException;
78 5195 daigle
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlException;
79 5089 daigle
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlForSingleFile;
80 5195 daigle
import edu.ucsb.nceas.metacat.accesscontrol.PermOrderException;
81 7519 leinfelder
import edu.ucsb.nceas.metacat.admin.upgrade.RemoveInvalidReplicas;
82 7175 leinfelder
import edu.ucsb.nceas.metacat.admin.upgrade.dataone.GenerateORE;
83 7170 leinfelder
import edu.ucsb.nceas.metacat.admin.upgrade.dataone.GenerateSystemMetadata;
84 6001 cjones
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
85 5014 daigle
import edu.ucsb.nceas.metacat.database.DBConnection;
86
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
87
import edu.ucsb.nceas.metacat.database.DatabaseService;
88 6447 leinfelder
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
89 5030 daigle
import edu.ucsb.nceas.metacat.properties.PropertyService;
90 5014 daigle
import edu.ucsb.nceas.metacat.shared.BaseService;
91
import edu.ucsb.nceas.metacat.shared.HandlerException;
92
import edu.ucsb.nceas.metacat.shared.ServiceException;
93 5027 daigle
import edu.ucsb.nceas.metacat.util.DocumentUtil;
94 4698 daigle
import edu.ucsb.nceas.metacat.util.MetacatUtil;
95 6531 leinfelder
import edu.ucsb.nceas.metacat.util.ReplicationUtil;
96 4080 daigle
import edu.ucsb.nceas.metacat.util.SystemUtil;
97 4488 daigle
import edu.ucsb.nceas.utilities.FileUtil;
98 4087 daigle
import edu.ucsb.nceas.utilities.GeneralPropertyException;
99 4080 daigle
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
100 7475 leinfelder
import edu.ucsb.nceas.utilities.access.DocInfoHandler;
101
import edu.ucsb.nceas.utilities.access.XMLAccessDAO;
102 4080 daigle
103 5014 daigle
public class ReplicationService extends BaseService {
104 4335 daigle
105 5014 daigle
	private static ReplicationService replicationService = null;
106 2663 sgarg
107 5014 daigle
	private long timeInterval;
108
	private Date firstTime;
109
	private boolean timedReplicationIsOn = false;
110
	Timer replicationDaemon;
111
	private static Vector<String> fileLocks = new Vector<String>();
112
//	private Thread lockThread = null;
113
	public static final String FORCEREPLICATEDELETE = "forcereplicatedelete";
114
	private static String TIMEREPLICATION = "replication.timedreplication";
115
	private static String TIMEREPLICATIONINTERVAl ="replication.timedreplicationinterval";
116
	private static String FIRSTTIME = "replication.firsttimedreplication";
117
	private static final int TIMEINTERVALLIMIT = 7200000;
118
	public static final String REPLICATIONUSER = "replication";
119 7317 leinfelder
120
	private static int CLIENTTIMEOUT = 30000;
121 2286 tao
122 5014 daigle
	public static final String REPLICATION_LOG_FILE_NAME = "metacatreplication.log";
123 7337 leinfelder
124 7356 leinfelder
	private static String DATA_FILE_FLAG = null;
125 5014 daigle
	public static String METACAT_REPL_ERROR_MSG = null;
126
	private static Logger logReplication = Logger.getLogger("ReplicationLogging");
127
	private static Logger logMetacat = Logger.getLogger(ReplicationService.class);
128 2286 tao
129 7317 leinfelder
	static {
130
		// lookup the client timeout
131
		String clientTimeout = null;
132
		try {
133
			clientTimeout = PropertyService.getProperty("replication.client.timeout");
134
			CLIENTTIMEOUT = Integer.parseInt(clientTimeout);
135
		} catch (Exception e) {
136
			// just use default
137
			logReplication.warn("No custom client timeout specified in configuration, using default." + e.getMessage());
138
		}
139 7337 leinfelder
		try {
140
			DATA_FILE_FLAG = PropertyService.getProperty("replication.datafileflag");
141
		} catch (PropertyNotFoundException e) {
142
			logReplication.error("No 'replication.datafileflag' specified in configuration." + e.getMessage());
143
		}
144
145 7317 leinfelder
	}
146
147 5014 daigle
	private ReplicationService() throws ServiceException {
148
		_serviceName = "ReplicationService";
149
150
		initialize();
151
	}
152
153
	private void initialize() throws ServiceException {
154
155
		// initialize db connections to handle any update requests
156
		// deltaT = util.getProperty("replication.deltaT");
157
		// the default deltaT can be set from metacat.properties
158
		// create a thread to do the delta-T check but don't execute it yet
159
		replicationDaemon = new Timer(true);
160
		try {
161
			String replLogFile = PropertyService.getProperty("replication.logdir")
162
				+ FileUtil.getFS() + REPLICATION_LOG_FILE_NAME;
163
			METACAT_REPL_ERROR_MSG = "An error occurred in replication.  Please see the " +
164
				"replication log at: " + replLogFile;
165
166
			String timedRepIsOnStr =
167
				PropertyService.getProperty("replication.timedreplication");
168
			timedReplicationIsOn = (new Boolean(timedRepIsOnStr)).booleanValue();
169
			logReplication.info("ReplicationService.initialize - The timed replication on is" + timedReplicationIsOn);
170 522 berkley
171 5014 daigle
			String timeIntervalStr =
172
				PropertyService.getProperty("replication.timedreplicationinterval");
173
			timeInterval = (new Long(timeIntervalStr)).longValue();
174
			logReplication.info("ReplicationService.initialize - The timed replication time Interval is " + timeInterval);
175 2286 tao
176 5014 daigle
			String firstTimeStr =
177
				PropertyService.getProperty("replication.firsttimedreplication");
178
			logReplication.info("ReplicationService.initialize - first replication time form property is " + firstTimeStr);
179
			firstTime = ReplicationHandler.combinateCurrentDateAndGivenTime(firstTimeStr);
180 2286 tao
181 5014 daigle
			logReplication.info("ReplicationService.initialize - After combine current time, the real first time is "
182
					+ firstTime.toString() + " minisec");
183 2286 tao
184 5014 daigle
			// set up time replication if it is on
185
			if (timedReplicationIsOn) {
186
				replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(),
187
						firstTime, timeInterval);
188
				logReplication.info("ReplicationService.initialize - deltaT handler started with rate="
189
						+ timeInterval + " mini seconds at " + firstTime.toString());
190
			}
191 2286 tao
192 5014 daigle
		} catch (PropertyNotFoundException pnfe) {
193
			throw new ServiceException(
194
					"ReplicationService.initialize - Property error while instantiating "
195
							+ "replication service: " + pnfe.getMessage());
196
		} catch (HandlerException he) {
197
			throw new ServiceException(
198
					"ReplicationService.initialize - Handler error while instantiating "
199
							+ "replication service" + he.getMessage());
200
		}
201
	}
202 2286 tao
203 5014 daigle
	/**
204
	 * Get the single instance of SessionService.
205
	 *
206
	 * @return the single instance of SessionService
207
	 */
208
	public static ReplicationService getInstance() throws ServiceException {
209
		if (replicationService == null) {
210
			replicationService = new ReplicationService();
211
		}
212
		return replicationService;
213
	}
214 2286 tao
215 5014 daigle
	public boolean refreshable() {
216
		return true;
217
	}
218 2286 tao
219 5014 daigle
	protected void doRefresh() throws ServiceException {
220
		return;
221
	}
222
223
	public void stop() throws ServiceException{
224
225
	}
226 840 bojilova
227 5014 daigle
	public void stopReplication() throws ServiceException {
228
	      //stop the replication server
229
	      replicationDaemon.cancel();
230
	      replicationDaemon = new Timer(true);
231
	      timedReplicationIsOn = false;
232
	      try {
233
	    	  PropertyService.setProperty("replication.timedreplication", (new Boolean(timedReplicationIsOn)).toString());
234
	      } catch (GeneralPropertyException gpe) {
235
	    	  logReplication.warn("ReplicationService.stopReplication - Could not set replication.timedreplication property: " + gpe.getMessage());
236
	      }
237 4080 daigle
238 5014 daigle
	      logReplication.info("ReplicationService.stopReplication - deltaT handler stopped");
239
		return;
240
	}
241
242 6669 leinfelder
	public void startReplication(Hashtable<String, String[]> params) throws ServiceException {
243 2286 tao
244 5014 daigle
	       String firstTimeStr = "";
245
	      //start the replication server
246
	       if ( params.containsKey("rate") ) {
247
	        timeInterval = new Long(
248
	               new String(((String[])params.get("rate"))[0])).longValue();
249
	        if(timeInterval < TIMEINTERVALLIMIT) {
250
	            //deltaT<30 is a timing mess!
251
	            timeInterval = TIMEINTERVALLIMIT;
252
	            throw new ServiceException("Replication deltaT rate cannot be less than "+
253
	                    TIMEINTERVALLIMIT + " millisecs and system automatically setup the rate to "+TIMEINTERVALLIMIT);
254
	        }
255
	      } else {
256
	        timeInterval = TIMEINTERVALLIMIT ;
257
	      }
258
	      logReplication.info("ReplicationService.startReplication - New rate is: " + timeInterval + " mini seconds.");
259
	      if ( params.containsKey("firsttime"))
260
	      {
261
	         firstTimeStr = ((String[])params.get("firsttime"))[0];
262
	         try
263
	         {
264
	           firstTime = ReplicationHandler.combinateCurrentDateAndGivenTime(firstTimeStr);
265
	           logReplication.info("ReplicationService.startReplication - The first time setting is "+firstTime.toString());
266
	         }
267
	         catch (HandlerException e)
268
	         {
269
	            throw new ServiceException(e.getMessage());
270
	         }
271
	         logReplication.warn("After combine current time, the real first time is "
272
	                                  +firstTime.toString()+" minisec");
273
	      }
274
	      else
275
	      {
276
	    	  logMetacat.error("ReplicationService.startReplication - " + ReplicationService.METACAT_REPL_ERROR_MSG);
277
	          logReplication.error("ReplicationService.startReplication - You should specify the first time " +
278
	                                  "to start a time replication");
279
	          return;
280
	      }
281
282
	      timedReplicationIsOn = true;
283
	      try {
284
	      // save settings to property file
285
	      PropertyService.setProperty(TIMEREPLICATION, (new Boolean(timedReplicationIsOn)).toString());
286
	      // note we couldn't use firstTime object because it has date info
287
	      // we only need time info such as 10:00 PM
288
	      PropertyService.setProperty(FIRSTTIME, firstTimeStr);
289
	      PropertyService.setProperty(TIMEREPLICATIONINTERVAl, (new Long(timeInterval)).toString());
290
	      } catch (GeneralPropertyException gpe) {
291
	    	  logReplication.warn("ReplicationService.startReplication - Could not set property: " + gpe.getMessage());
292
	      }
293
	      replicationDaemon.cancel();
294
	      replicationDaemon = new Timer(true);
295
	      replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(), firstTime,
296
	                                            timeInterval);
297
298
	      logReplication.info("ReplicationService.startReplication - deltaT handler started with rate=" +
299
	                                    timeInterval + " milliseconds at " +firstTime.toString());
300 837 bojilova
301 5014 daigle
	}
302
303
	public void runOnce() throws ServiceException {
304
	      //updates this server exactly once
305
	      replicationDaemon.schedule(new ReplicationHandler(), 0);
306
	}
307 7170 leinfelder
308 5014 daigle
	/**
309
	 * This method can add, delete and list the servers currently included in
310
	 * xml_replication.
311
	 * action           subaction            other needed params
312
	 * ---------------------------------------------------------
313
	 * servercontrol    add                  server
314
	 * servercontrol    delete               server
315
	 * servercontrol    list
316
	 */
317 6669 leinfelder
	public static void handleServerControlRequest(
318 7170 leinfelder
			Hashtable<String, String[]> params, HttpServletRequest request, HttpServletResponse response) {
319 5014 daigle
		String subaction = ((String[]) params.get("subaction"))[0];
320
		DBConnection dbConn = null;
321
		int serialNumber = -1;
322
		PreparedStatement pstmt = null;
323
		String replicate = null;
324
		String server = null;
325
		String dataReplicate = null;
326
		String hub = null;
327 5755 leinfelder
		Writer out = null;
328 7170 leinfelder
		boolean showGenerateSystemMetadata = false;
329 5014 daigle
		try {
330 5755 leinfelder
			response.setContentType("text/xml");
331
			out = response.getWriter();
332
333 5014 daigle
			//conn = util.openDBConnection();
334
			dbConn = DBConnectionPool
335
					.getDBConnection("MetacatReplication.handleServerControlRequest");
336
			serialNumber = dbConn.getCheckOutSerialNumber();
337 837 bojilova
338 5014 daigle
			// add server to server list
339
			if (subaction.equals("add")) {
340
				replicate = ((String[]) params.get("replicate"))[0];
341
				server = ((String[]) params.get("server"))[0];
342 2286 tao
343 5014 daigle
				//Get data replication value
344
				dataReplicate = ((String[]) params.get("datareplicate"))[0];
345 6814 leinfelder
346 5014 daigle
				//Get hub value
347
				hub = ((String[]) params.get("hub"))[0];
348 837 bojilova
349 6595 leinfelder
				Calendar cal = Calendar.getInstance();
350
                cal.set(1980, 1, 1);
351 5151 daigle
				String sql = "INSERT INTO xml_replication "
352 6814 leinfelder
						+ "(server, last_checked, replicate, datareplicate, hub) "
353
						+ "VALUES (?,?,?,?,?)";
354 5151 daigle
355
				pstmt = dbConn.prepareStatement(sql);
356
357
				pstmt.setString(1, server);
358 6595 leinfelder
				pstmt.setTimestamp(2, new Timestamp(cal.getTimeInMillis()));
359
				pstmt.setInt(3, Integer.parseInt(replicate));
360
				pstmt.setInt(4, Integer.parseInt(dataReplicate));
361 6814 leinfelder
				pstmt.setInt(5, Integer.parseInt(hub));
362 5151 daigle
363
				String sqlReport = "XMLAccessAccess.getXMLAccessForDoc - SQL: " + sql;
364
				sqlReport += " [" + server + "," + replicate +
365
					"," + dataReplicate + "," + hub + "]";
366
367
				logMetacat.info(sqlReport);
368
369 5014 daigle
				pstmt.execute();
370
				pstmt.close();
371
				dbConn.commit();
372 5755 leinfelder
				out.write("Server " + server + " added");
373 7170 leinfelder
374
375 5014 daigle
				// delete server from server list
376
			} else if (subaction.equals("delete")) {
377
				server = ((String[]) params.get("server"))[0];
378
				pstmt = dbConn.prepareStatement("DELETE FROM xml_replication "
379 6595 leinfelder
						+ "WHERE server LIKE ?");
380
				pstmt.setString(1, server);
381 5014 daigle
				pstmt.execute();
382
				pstmt.close();
383
				dbConn.commit();
384 5755 leinfelder
				out.write("Server " + server + " deleted");
385 5014 daigle
			} else if (subaction.equals("list")) {
386 7170 leinfelder
				// nothing special - it's the default behavior
387 6135 leinfelder
388 7170 leinfelder
			} else if (subaction.equals("generatesystemmetadata")) {
389
				GenerateSystemMetadata gsm = new GenerateSystemMetadata();
390
				int serverLocation = -1;
391
				String serverid = ((String[]) params.get("serverid"))[0];
392
				serverLocation = Integer.parseInt(serverid);
393
				gsm.setServerLocation(serverLocation );
394
				gsm.multiThreadUpgrade();
395
				out.write("System Metadata generated for server " + serverid);
396
397 7175 leinfelder
			} else if (subaction.equals("generateore")) {
398
				GenerateORE gore = new GenerateORE();
399
				int serverLocation = -1;
400
				String serverid = ((String[]) params.get("serverid"))[0];
401
				serverLocation = Integer.parseInt(serverid);
402
				gore.setServerLocation(serverLocation );
403
				gore.upgrade();
404
				out.write("Generated ORE maps for server " + serverid);
405
406 7519 leinfelder
			} else if (subaction.equals("removeinvalidreplicas")) {
407
				RemoveInvalidReplicas rir = new RemoveInvalidReplicas();
408
				int serverLocation = -1;
409
				String serverid = ((String[]) params.get("serverid"))[0];
410
				serverLocation = Integer.parseInt(serverid);
411
				rir.setServerLocation(serverLocation );
412
				rir.upgrade();
413
				out.write("Removed invalid replicas for server " + serverid);
414
415 5014 daigle
			} else {
416 7170 leinfelder
417 5755 leinfelder
				out.write("<error>Unkonwn subaction</error>");
418 7170 leinfelder
				return;
419
			}
420
421
			// show SM generate button?
422
			String dataoneConfigured = PropertyService.getProperty("configutil.dataoneConfigured");
423
			if (dataoneConfigured != null) {
424
				showGenerateSystemMetadata = Boolean.parseBoolean(dataoneConfigured);
425
			}
426
427
			// always list them after processing
428
			response.setContentType("text/html");
429
			out.write("<html><body><table border=\"1\">");
430
			out.write("<tr><td><b>server</b></td>");
431
			out.write("<td><b>last_checked</b></td>");
432
			out.write("<td><b>replicate</b></td>");
433
			out.write("<td><b>datareplicate</b></td>");
434
			out.write("<td><b>hub</b></td>");
435
			if (showGenerateSystemMetadata) {
436 7175 leinfelder
				out.write("<td><b>System Metadata</b></td>");
437
				out.write("<td><b>ORE Maps</b></td>");
438 7519 leinfelder
				out.write("<td><b>Invalid Replicas</b></td>");
439 7170 leinfelder
			}
440
			out.write("</tr>");
441 2286 tao
442 7170 leinfelder
			pstmt = dbConn.prepareStatement("SELECT serverid, server, last_checked, replicate, datareplicate, hub FROM xml_replication");
443
			pstmt.execute();
444
			ResultSet rs = pstmt.getResultSet();
445
			boolean tablehasrows = rs.next();
446
			while (tablehasrows) {
447 7519 leinfelder
				String serverId = rs.getString(1);
448 7170 leinfelder
				out.write("<tr><td>" + rs.getString(2) + "</td><td>");
449
				out.write(rs.getString(3) + "</td><td>");
450
				out.write(rs.getString(4) + "</td><td>");
451
				out.write(rs.getString(5) + "</td><td>");
452
				out.write(rs.getString(6) + "</td>");
453
				if (showGenerateSystemMetadata) {
454 7175 leinfelder
					// for SM
455 7170 leinfelder
					out.write("<td><form action='" + request.getContextPath() + "/admin'>");
456 7519 leinfelder
					out.write("<input name='serverid' type='hidden' value='" + serverId  + "'/>");
457 7170 leinfelder
					out.write("<input name='configureType' type='hidden' value='replication'/>");
458
					out.write("<input name='action' type='hidden' value='servercontrol'/>");
459
					out.write("<input name='subaction' type='hidden' value='generatesystemmetadata'/>");
460
					out.write("<input type='submit' value='Generate System Metadata'/>");
461
					out.write("</form></td>");
462 7175 leinfelder
463
					// for ORE maps
464
					out.write("<td><form action='" + request.getContextPath() + "/admin'>");
465 7519 leinfelder
					out.write("<input name='serverid' type='hidden' value='" + serverId + "'/>");
466 7175 leinfelder
					out.write("<input name='configureType' type='hidden' value='replication'/>");
467
					out.write("<input name='action' type='hidden' value='servercontrol'/>");
468
					out.write("<input name='subaction' type='hidden' value='generateore'/>");
469
					out.write("<input type='submit' value='Generate ORE'/>");
470
					out.write("</form></td>");
471 7519 leinfelder
472
					// for invalid replicas
473
					out.write("<td><form action='" + request.getContextPath() + "/admin'>");
474
					out.write("<input name='serverid' type='hidden' value='" + serverId + "'/>");
475
					out.write("<input name='configureType' type='hidden' value='replication'/>");
476
					out.write("<input name='action' type='hidden' value='servercontrol'/>");
477
					out.write("<input name='subaction' type='hidden' value='removeinvalidreplicas'/>");
478
					String disabled = "";
479
					if (Integer.valueOf(serverId) == 1) {
480
						disabled = "disabled='true'";
481
					}
482
					out.write("<input type='submit' value='Remove Invalid Replicas' " + disabled + " />");
483
					out.write("</form></td>");
484 7170 leinfelder
				}
485
				out.write("</tr>");
486
487
				tablehasrows = rs.next();
488 5014 daigle
			}
489 7170 leinfelder
			out.write("</table></body></html>");
490
491
492 5014 daigle
			pstmt.close();
493
			//conn.close();
494 2286 tao
495 5014 daigle
		} catch (Exception e) {
496
			logMetacat.error("ReplicationService.handleServerControlRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
497
			logReplication.error("ReplicationService.handleServerControlRequest - Error in "
498
					+ "MetacatReplication.handleServerControlRequest " + e.getMessage());
499
			e.printStackTrace(System.out);
500
		} finally {
501
			try {
502
				pstmt.close();
503
			}//try
504
			catch (SQLException ee) {
505
				logMetacat.error("ReplicationService.handleServerControlRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
506
				logReplication.error("ReplicationService.handleServerControlRequest - Error in MetacatReplication.handleServerControlRequest to close pstmt "
507
						+ ee.getMessage());
508
			}//catch
509
			finally {
510
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
511
			}//finally
512 5755 leinfelder
			if (out != null) {
513
				try {
514
					out.close();
515
				} catch (IOException e) {
516
					logMetacat.error(e.getMessage(), e);
517
				}
518
			}
519 5014 daigle
		}//finally
520 2286 tao
521 5014 daigle
	}
522 2286 tao
523 5014 daigle
	/**
524 4080 daigle
	 * when a forcereplication request comes in, local host sends a read request
525
	 * to the requesting server (remote server) for the specified docid. Then
526
	 * store it in local database.
527
	 */
528 5755 leinfelder
	protected static void handleForceReplicateRequest(
529 5014 daigle
			Hashtable<String, String[]> params, HttpServletResponse response,
530
			HttpServletRequest request) {
531
		String server = ((String[]) params.get("server"))[0]; // the server that
532
		String docid = ((String[]) params.get("docid"))[0]; // sent the document
533
		String dbaction = "UPDATE"; // the default action is UPDATE
534
		//    boolean override = false;
535
		//    int serverCode = 1;
536
		DBConnection dbConn = null;
537
		int serialNumber = -1;
538 5459 berkley
		String docName = null;
539 2286 tao
540 5014 daigle
		try {
541
			//if the url contains a dbaction then the default action is overridden
542
			if (params.containsKey("dbaction")) {
543
				dbaction = ((String[]) params.get("dbaction"))[0];
544
				//serverCode = MetacatReplication.getServerCode(server);
545
				//override = true; //we are now overriding the default action
546
			}
547
			logReplication.info("ReplicationService.handleForceReplicateRequest - Force replication request from: " + server);
548
			logReplication.info("ReplicationService.handleForceReplicateRequest - Force replication docid: " + docid);
549
			logReplication.info("ReplicationService.handleForceReplicateRequest - Force replication action: " + dbaction);
550
			// sending back read request to remote server
551
			URL u = new URL("https://" + server + "?server="
552
					+ MetacatUtil.getLocalReplicationServerName() + "&action=read&docid="
553
					+ docid);
554
			String xmldoc = ReplicationService.getURLContent(u);
555 2286 tao
556 5014 daigle
			// get the document info from server
557
			URL docinfourl = new URL("https://" + server + "?server="
558
					+ MetacatUtil.getLocalReplicationServerName()
559
					+ "&action=getdocumentinfo&docid=" + docid);
560 5440 berkley
561 2286 tao
562 5014 daigle
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
563 6531 leinfelder
			// strip out the system metadata portion
564
			String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
565
			docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);
566
567 5014 daigle
			//dih is the parser for the docinfo xml format
568
			DocInfoHandler dih = new DocInfoHandler();
569
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
570
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
571
			//      Hashtable<String,Vector<AccessControlForSingleFile>> docinfoHash = dih.getDocInfo();
572
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
573 6015 leinfelder
574 5014 daigle
			// Get home server of this docid
575
			String homeServer = (String) docinfoHash.get("home_server");
576 6531 leinfelder
577
			// process system metadata
578
			if (systemMetadataXML != null) {
579
				SystemMetadata sysMeta =
580
					TypeMarshaller.unmarshalTypeFromStream(
581
							SystemMetadata.class,
582
							new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
583
				// need the guid-to-docid mapping
584 6783 leinfelder
				boolean mappingExists = true;
585 7045 leinfelder
		      	mappingExists = IdentifierManager.getInstance().mappingExists(sysMeta.getIdentifier().getValue());
586 6783 leinfelder
		      	if (!mappingExists) {
587
		      		IdentifierManager.getInstance().createMapping(sysMeta.getIdentifier().getValue(), docid);
588
		      	}
589 6666 leinfelder
				// save the system metadata
590
				HazelcastService.getInstance().getSystemMetadataMap().put(sysMeta.getIdentifier(), sysMeta);
591 7812 leinfelder
				// submit for indexing
592
                HazelcastService.getInstance().getIndexQueue().add(sysMeta);
593 6531 leinfelder
			}
594 5324 berkley
595 6595 leinfelder
			// dates
596
			String createdDateString = docinfoHash.get("date_created");
597
			String updatedDateString = docinfoHash.get("date_updated");
598 6614 leinfelder
			Date createdDate = DateTimeMarshaller.deserializeDateToUTC(createdDateString);
599
			Date updatedDate = DateTimeMarshaller.deserializeDateToUTC(updatedDateString);
600 6595 leinfelder
601 5014 daigle
			logReplication.info("ReplicationService.handleForceReplicateRequest - homeServer: " + homeServer);
602
			// Get Document type
603
			String docType = (String) docinfoHash.get("doctype");
604
			logReplication.info("ReplicationService.handleForceReplicateRequest - docType: " + docType);
605
			String parserBase = null;
606
			// this for eml2 and we need user eml2 parser
607
			if (docType != null
608
					&& (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE)) {
609
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml200 document!");
610
				parserBase = DocumentImpl.EML200;
611
			} else if (docType != null
612
					&& (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE)) {
613
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.0.1 document!");
614
				parserBase = DocumentImpl.EML200;
615
			} else if (docType != null
616
					&& (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE)) {
617
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.0 document!");
618
				parserBase = DocumentImpl.EML210;
619 5709 leinfelder
			} else if (docType != null
620
					&& (docType.trim()).equals(DocumentImpl.EML2_1_1NAMESPACE)) {
621
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.1 document!");
622
				parserBase = DocumentImpl.EML210;
623 5014 daigle
			}
624
			logReplication.warn("ReplicationService.handleForceReplicateRequest - The parserBase is: " + parserBase);
625 2286 tao
626 5014 daigle
			// Get DBConnection from pool
627
			dbConn = DBConnectionPool
628
					.getDBConnection("MetacatReplication.handleForceReplicateRequest");
629
			serialNumber = dbConn.getCheckOutSerialNumber();
630
			// write the document to local database
631 7128 leinfelder
			DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false, false);
632 6079 leinfelder
			//try this independently so we can set access even if the update action is invalid (i.e docid has not changed)
633 5014 daigle
			try {
634 5195 daigle
				wrapper.writeReplication(dbConn, xmldoc, null, null,
635 6015 leinfelder
						dbaction, docid, null, null, homeServer, server, createdDate,
636 5014 daigle
						updatedDate);
637 5195 daigle
			} finally {
638 3230 tao
639 7358 leinfelder
				//process extra access rules before dealing with the write exception (doc exist already)
640
				try {
641
		        	// check if we had a guid -> docid mapping
642
		        	String docidNoRev = DocumentUtil.getDocIdFromAccessionNumber(docid);
643
		        	int rev = DocumentUtil.getRevisionFromAccessionNumber(docid);
644 7382 leinfelder
		        	IdentifierManager.getInstance().getGUID(docidNoRev, rev);
645 7358 leinfelder
		        	// no need to create the mapping if we have it
646
		        } catch (McdbDocNotFoundException mcdbe) {
647
		        	// create mapping if we don't
648
		        	IdentifierManager.getInstance().createMapping(docid, docid);
649
		        }
650 5195 daigle
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
651
		        if (accessControlList != null) {
652
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
653
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
654 7120 leinfelder
		        		try {
655
			        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
656
			        			acfsf.insertPermissions(xmlAccessDAO);
657
								logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
658
										+ " permissions added to DB");
659
			        		}
660
		        		} catch (PermOrderException poe) {
661
		        			// this is problematic, but should not prevent us from replicating
662
		        			// see https://redmine.dataone.org/issues/2583
663
		        			String msg = "Could not insert access control for: " + docid + " Message: " + poe.getMessage();
664
		        			logMetacat.error(msg, poe);
665
		        			logReplication.error(msg, poe);
666 5195 daigle
		        		}
667
		            }
668
		        }
669 6015 leinfelder
670
		        // process the real owner and updater
671
				String user = (String) docinfoHash.get("user_owner");
672
				String updated = (String) docinfoHash.get("user_updated");
673
		        updateUserOwner(dbConn, docid, user, updated);
674 2286 tao
675 5195 daigle
				logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid + " added to DB with "
676
						+ "action " + dbaction);
677 5458 berkley
678 6542 leinfelder
				EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER, docid, dbaction);
679 5014 daigle
			}
680 5195 daigle
		} catch (SQLException sqle) {
681 5014 daigle
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
682 5195 daigle
			logReplication.error("ReplicationService.handleForceReplicateRequest - SQL error when adding doc " + docid +
683
					" to DB with action " + dbaction + ": " + sqle.getMessage());
684
		} catch (MalformedURLException mue) {
685
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
686
			logReplication.error("ReplicationService.handleForceReplicateRequest - URL error when adding doc " + docid +
687
					" to DB with action " + dbaction + ": " + mue.getMessage());
688
		} catch (SAXException se) {
689
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
690
			logReplication.error("ReplicationService.handleForceReplicateRequest - SAX parsing error when adding doc " + docid +
691
					" to DB with action " + dbaction + ": " + se.getMessage());
692
		} catch (HandlerException he) {
693
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
694
			logReplication.error("ReplicationService.handleForceReplicateRequest - Handler error when adding doc " + docid +
695
					" to DB with action " + dbaction + ": " + he.getMessage());
696
		} catch (IOException ioe) {
697
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
698
			logReplication.error("ReplicationService.handleForceReplicateRequest - I/O error when adding doc " + docid +
699
					" to DB with action " + dbaction + ": " + ioe.getMessage());
700
		} catch (PermOrderException poe) {
701
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
702
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid +
703
					" to DB with action " + dbaction + ": " + poe.getMessage());
704
		} catch (AccessControlException ace) {
705
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
706
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid +
707
					" to DB with action " + dbaction + ": " + ace.getMessage());
708
		} catch (Exception e) {
709
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
710
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when adding doc " + docid +
711
					" to DB with action " + dbaction + ": " + e.getMessage());
712
		} finally {
713 5014 daigle
			// Return the checked out DBConnection
714
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
715
		}//finally
716
	}
717 2298 tao
718 5014 daigle
	/*
719
	 * when a forcereplication delete request comes in, local host will delete this
720
	 * document
721
	 */
722 5755 leinfelder
	protected static void handleForceReplicateDeleteRequest(
723 5014 daigle
			Hashtable<String, String[]> params, HttpServletResponse response,
724
			HttpServletRequest request) {
725
		String server = ((String[]) params.get("server"))[0]; // the server that
726
		String docid = ((String[]) params.get("docid"))[0]; // sent the document
727
		try {
728
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - force replication delete request from " + server);
729
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - force replication delete docid " + docid);
730
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - Force replication delete request from: " + server);
731
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - Force replication delete docid: " + docid);
732 7150 leinfelder
			DocumentImpl.delete(docid, null, null, server, false);
733 5014 daigle
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - document " + docid + " was successfully deleted ");
734 6542 leinfelder
			EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER, docid,
735 5014 daigle
					"delete");
736
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - document " + docid + " was successfully deleted ");
737 6001 cjones
		} catch (McdbDocNotFoundException e) {
738
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
739
			logReplication.error("document " + docid
740
					+ " failed to delete because " + e.getMessage());
741
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
742
		} catch (InsufficientKarmaException e) {
743
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
744
			logReplication.error("document " + docid
745
					+ " failed to delete because " + e.getMessage());
746
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
747
		} catch (SQLException e) {
748
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
749
			logReplication.error("document " + docid
750
					+ " failed to delete because " + e.getMessage());
751
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
752 5014 daigle
		} catch (Exception e) {
753
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
754
			logReplication.error("document " + docid
755
					+ " failed to delete because " + e.getMessage());
756
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
757 2298 tao
758 5014 daigle
		}//catch
759 2298 tao
760 5014 daigle
	}
761 2286 tao
762 5014 daigle
	/**
763
	 * when a forcereplication data file request comes in, local host sends a
764
	 * readdata request to the requesting server (remote server) for the specified
765
	 * docid. Then store it in local database and file system
766
	 */
767
	protected static void handleForceReplicateDataFileRequest(Hashtable<String, String[]> params,
768
			HttpServletRequest request) {
769 2286 tao
770 5014 daigle
		//make sure there is some parameters
771
		if (params.isEmpty()) {
772
			return;
773
		}
774
		// Get remote server
775
		String server = ((String[]) params.get("server"))[0];
776
		// the docid should include rev number
777
		String docid = ((String[]) params.get("docid"))[0];
778
		// Make sure there is a docid and server
779
		if (docid == null || server == null || server.equals("")) {
780
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
781
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Didn't specify docid or server for replication");
782
			return;
783
		}
784 2286 tao
785 5014 daigle
		// Overide or not
786
		//    boolean override = false;
787
		// dbaction - update or insert
788
		String dbaction = null;
789 2286 tao
790 5014 daigle
		try {
791
			//docid was switch to two parts uinque code and rev
792
			//String uniqueCode=MetacatUtil.getDocIdFromString(docid);
793
			//int rev=MetacatUtil.getVersionFromString(docid);
794
			if (params.containsKey("dbaction")) {
795
				dbaction = ((String[]) params.get("dbaction"))[0];
796
			} else//default value is update
797
			{
798 6782 leinfelder
//				dbaction = "update";
799
				dbaction = null;
800 5014 daigle
			}
801 2286 tao
802 5014 daigle
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication request from: " + server);
803
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication docid: " + docid);
804
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication action: " + dbaction);
805
			// get the document info from server
806
			URL docinfourl = new URL("https://" + server + "?server="
807
					+ MetacatUtil.getLocalReplicationServerName()
808
					+ "&action=getdocumentinfo&docid=" + docid);
809 1023 tao
810 5014 daigle
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
811 6102 leinfelder
812 6531 leinfelder
			// strip out the system metadata portion
813
		    String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
814
		   	docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);
815
816 5014 daigle
			//dih is the parser for the docinfo xml format
817
			DocInfoHandler dih = new DocInfoHandler();
818
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
819
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
820
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
821 6015 leinfelder
822 5014 daigle
			String docName = (String) docinfoHash.get("docname");
823 2286 tao
824 5014 daigle
			String docType = (String) docinfoHash.get("doctype");
825 2286 tao
826 5014 daigle
			String docHomeServer = (String) docinfoHash.get("home_server");
827 6595 leinfelder
828
			String createdDateString = docinfoHash.get("date_created");
829
			String updatedDateString = docinfoHash.get("date_updated");
830
831 6614 leinfelder
			Date createdDate = DateTimeMarshaller.deserializeDateToUTC(createdDateString);
832
			Date updatedDate = DateTimeMarshaller.deserializeDateToUTC(updatedDateString);
833 6595 leinfelder
834 5014 daigle
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - docHomeServer of datafile: " + docHomeServer);
835
836 6782 leinfelder
			// in case we have a write exception, we still want to track access and sysmeta
837
			Exception writeException = null;
838
839
			// do we need the object content?
840
			if (dbaction != null && (dbaction.equals("insert") || dbaction.equals("update"))) {
841 5014 daigle
				//Get data file and store it into local file system.
842
				// sending back readdata request to server
843
				URL url = new URL("https://" + server + "?server="
844
						+ MetacatUtil.getLocalReplicationServerName()
845
						+ "&action=readdata&docid=" + docid);
846
				String datafilePath = PropertyService
847
						.getProperty("application.datafilepath");
848
849 6611 leinfelder
				InputStream inputStream = getURLStream(url);
850
851 6780 leinfelder
				//register data file into xml_documents table and write data file
852 5014 daigle
				//into file system
853
				try {
854 6611 leinfelder
					DocumentImpl.writeDataFileInReplication(inputStream,
855 6015 leinfelder
							datafilePath, docName, docType, docid, null, docHomeServer,
856 5014 daigle
							server, DocumentImpl.DOCUMENTTABLE, false, createdDate,
857
							updatedDate);
858
				} catch (Exception e) {
859
					writeException = e;
860
				}
861
862
			}
863 6782 leinfelder
864
			// process the real owner and updater
865
			DBConnection dbConn = DBConnectionPool.getDBConnection("ReplicationService.handleForceDataFileRequest");
866
	        int serialNumber = dbConn.getCheckOutSerialNumber();
867
	        dbConn.setAutoCommit(false);
868
			String user = (String) docinfoHash.get("user_owner");
869
			String updated = (String) docinfoHash.get("user_updated");
870
	        updateUserOwner(dbConn, docid, user, updated);
871
	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
872
873
			// process system metadata
874
	        if (systemMetadataXML != null) {
875
	      	  SystemMetadata sysMeta =
876
	      		TypeMarshaller.unmarshalTypeFromStream(
877
	      				  SystemMetadata.class,
878
	      				  new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
879
880
	      	  // need the guid-to-docid mapping
881
	      	  boolean mappingExists = true;
882 7045 leinfelder
	      	  mappingExists = IdentifierManager.getInstance().mappingExists(sysMeta.getIdentifier().getValue());
883 6782 leinfelder
	      	  if (!mappingExists) {
884
	      		  IdentifierManager.getInstance().createMapping(sysMeta.getIdentifier().getValue(), docid);
885
	      	  }
886
	      	  // save the system metadata
887
	      	  HazelcastService.getInstance().getSystemMetadataMap().put(sysMeta.getIdentifier(), sysMeta);
888 7812 leinfelder
	      	  // submit for indexing
889
              HazelcastService.getInstance().getIndexQueue().add(sysMeta);
890 6782 leinfelder
	        }
891
892
	        // process the access control
893 7358 leinfelder
	        try {
894
	        	// check if we had a guid -> docid mapping
895
	        	String docidNoRev = DocumentUtil.getDocIdFromAccessionNumber(docid);
896 7382 leinfelder
	        	int rev = DocumentUtil.getRevisionFromAccessionNumber(docid);
897
	        	IdentifierManager.getInstance().getGUID(docidNoRev, rev);
898 7358 leinfelder
	        	// no need to create the mapping if we have it
899
	        } catch (McdbDocNotFoundException mcdbe) {
900
	        	// create mapping if we don't
901
	        	IdentifierManager.getInstance().createMapping(docid, docid);
902
	        }
903 6782 leinfelder
	        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
904
	        if (accessControlList != null) {
905
	        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
906
	        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
907
	        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
908
	        			acfsf.insertPermissions(xmlAccessDAO);
909
						logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
910
								+ " permissions added to DB");
911
	        		}
912
	            }
913
	        }
914
915
	        // throw the write exception now -- this happens when access changes on an object
916
			if (writeException != null) {
917
				throw writeException;
918
			}
919 5014 daigle
920 6782 leinfelder
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - datafile " + docid + " added to DB with "
921
					+ "action " + dbaction);
922
			EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER,
923
					docid, dbaction);
924
925 5014 daigle
		} catch (Exception e) {
926 6613 leinfelder
			e.printStackTrace();
927
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG, e);
928 5014 daigle
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Datafile " + docid
929
					+ " failed to added to DB with " + "action " + dbaction + " because "
930
					+ e.getMessage());
931
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - ERROR in MetacatReplication.handleForceDataFileReplicate"
932
					+ "Request(): " + e.getMessage());
933 4449 leinfelder
		}
934 5014 daigle
	}
935 2286 tao
936 5014 daigle
	/**
937
	 * Grants or denies a lock to a requesting host.
938
	 * The servlet parameters of interrest are:
939
	 * docid: the docid of the file the lock is being requested for
940
	 * currentdate: the timestamp of the document on the remote server
941
	 *
942
	 */
943 5755 leinfelder
	protected static void handleGetLockRequest(
944 5014 daigle
			Hashtable<String, String[]> params, HttpServletResponse response) {
945 1292 tao
946 5014 daigle
		try {
947 2286 tao
948 5014 daigle
			String docid = ((String[]) params.get("docid"))[0];
949
			String remoteRev = ((String[]) params.get("updaterev"))[0];
950
			DocumentImpl requestDoc = new DocumentImpl(docid);
951
			logReplication.info("ReplicationService.handleGetLockRequest - lock request for " + docid);
952
			int localRevInt = requestDoc.getRev();
953
			int remoteRevInt = Integer.parseInt(remoteRev);
954 2286 tao
955 5755 leinfelder
			// get a writer for sending back to response
956
			response.setContentType("text/xml");
957
			Writer out = response.getWriter();
958
959 5014 daigle
			if (remoteRevInt >= localRevInt) {
960
				if (!fileLocks.contains(docid)) { //grant the lock if it is not already locked
961
					fileLocks.add(0, docid); //insert at the beginning of the queue Vector
962
					//send a message back to the the remote host authorizing the insert
963 5755 leinfelder
					out.write("<lockgranted><docid>" + docid
964 5014 daigle
									+ "</docid></lockgranted>");
965
					//          lockThread = new Thread(this);
966
					//          lockThread.setPriority(Thread.MIN_PRIORITY);
967
					//          lockThread.start();
968
					logReplication.info("ReplicationService.handleGetLockRequest - lock granted for " + docid);
969
				} else { //deny the lock
970 5755 leinfelder
					out.write("<filelocked><docid>" + docid + "</docid></filelocked>");
971 5014 daigle
					logReplication.info("ReplicationService.handleGetLockRequest - lock denied for " + docid
972
							+ "reason: file already locked");
973
				}
974
			} else {//deny the lock.
975 5755 leinfelder
				out.write("<outdatedfile><docid>" + docid + "</docid></filelocked>");
976 5014 daigle
				logReplication.info("ReplicationService.handleGetLockRequest - lock denied for " + docid
977
						+ "reason: client has outdated file");
978
			}
979 5755 leinfelder
			out.close();
980 5014 daigle
			//conn.close();
981
		} catch (Exception e) {
982
			logMetacat.error("ReplicationService.handleGetLockRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
983
			logReplication.error("ReplicationService.handleGetLockRequest - error requesting file lock from MetacatReplication."
984
					+ "handleGetLockRequest: " + e.getMessage());
985
			e.printStackTrace(System.out);
986
		}
987
	}
988 2286 tao
989 5014 daigle
	/**
990
	 * Sends all of the xml_documents information encoded in xml to a requestor
991
	 * the format is:
992
	 * <!ELEMENT documentinfo (docid, docname, doctype, doctitle, user_owner,
993
	 *                  user_updated, home_server, public_access, rev)/>
994
	 * all of the subelements of document info are #PCDATA
995
	 */
996 5755 leinfelder
	protected static void handleGetDocumentInfoRequest(
997 5014 daigle
			Hashtable<String, String[]> params, HttpServletResponse response) {
998
		String docid = ((String[]) (params.get("docid")))[0];
999 2286 tao
1000 5014 daigle
		try {
1001 6708 leinfelder
			// get docinfo as XML string
1002
			String docinfoXML = getDocumentInfo(docid);
1003 6531 leinfelder
1004 5755 leinfelder
			// get a writer for sending back to response
1005 5014 daigle
			response.setContentType("text/xml");
1006 5755 leinfelder
			Writer out = response.getWriter();
1007 6708 leinfelder
			out.write(docinfoXML);
1008 5755 leinfelder
			out.close();
1009 2286 tao
1010 5014 daigle
		} catch (Exception e) {
1011
			logMetacat.error("ReplicationService.handleGetDocumentInfoRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1012
			logReplication.error("ReplicationService.handleGetDocumentInfoRequest - error in metacatReplication.handlegetdocumentinforequest "
1013
					+ "for doc: " + docid + " : " + e.getMessage());
1014
		}
1015 2286 tao
1016 5014 daigle
	}
1017 6118 leinfelder
1018 6708 leinfelder
	public static Hashtable<String, String> getDocumentInfoMap(String docid)
1019
			throws HandlerException, AccessControlException, JiBXException,
1020
			IOException, McdbException, SAXException {
1021
1022
		// Try get docid info from remote server
1023
		DocInfoHandler dih = new DocInfoHandler();
1024
		XMLReader docinfoParser = ReplicationHandler.initParser(dih);
1025
1026
		String docInfoStr = getDocumentInfo(docid);
1027
1028
		// strip out the system metadata portion
1029
		String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
1030
		docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);
1031
1032
		docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
1033
		Hashtable<String, String> docinfoHash = dih.getDocInfo();
1034
1035
		return docinfoHash;
1036
	}
1037
1038 6118 leinfelder
	/**
1039 6708 leinfelder
	 * Gets a docInfo XML snippet for the replication API
1040
	 * @param docid
1041
	 * @return
1042
	 * @throws AccessControlException
1043
	 * @throws JiBXException
1044
	 * @throws IOException
1045
	 * @throws McdbException
1046
	 */
1047
	public static String getDocumentInfo(String docid) throws AccessControlException, JiBXException, IOException, McdbException {
1048
		StringBuffer sb = new StringBuffer();
1049
1050
		DocumentImpl doc = new DocumentImpl(docid);
1051
		sb.append("<documentinfo><docid>").append(docid);
1052
		sb.append("</docid>");
1053
1054
		try {
1055
			// serialize the System Metadata as XML for docinfo
1056
			String guid = IdentifierManager.getInstance().getGUID(doc.getDocID(), doc.getRev());
1057
			SystemMetadata systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
1058
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
1059
			TypeMarshaller.marshalTypeToOutputStream(systemMetadata, baos);
1060
			String systemMetadataXML = baos.toString("UTF-8");
1061
			sb.append("<systemMetadata>");
1062
			sb.append(systemMetadataXML);
1063
			sb.append("</systemMetadata>");
1064
		} catch(McdbDocNotFoundException e) {
1065
		  logMetacat.warn("No SystemMetadata found for: " + docid);
1066
		}
1067
1068
		Calendar created = Calendar.getInstance();
1069
		created.setTime(doc.getCreateDate());
1070
		Calendar updated = Calendar.getInstance();
1071
		updated.setTime(doc.getUpdateDate());
1072
1073 7379 leinfelder
		sb.append("<docname><![CDATA[").append(doc.getDocname());
1074
		sb.append("]]></docname><doctype>").append(doc.getDoctype());
1075 6708 leinfelder
		sb.append("</doctype>");
1076
		sb.append("<user_owner>").append(doc.getUserowner());
1077
		sb.append("</user_owner><user_updated>").append(doc.getUserupdated());
1078
		sb.append("</user_updated>");
1079
		sb.append("<date_created>");
1080
		sb.append(DateTimeMarshaller.serializeDateToUTC(doc.getCreateDate()));
1081
		sb.append("</date_created>");
1082
		sb.append("<date_updated>");
1083
		sb.append(DateTimeMarshaller.serializeDateToUTC(doc.getUpdateDate()));
1084
		sb.append("</date_updated>");
1085
		sb.append("<home_server>");
1086
		sb.append(doc.getDocHomeServer());
1087
		sb.append("</home_server>");
1088
		sb.append("<public_access>").append(doc.getPublicaccess());
1089
		sb.append("</public_access><rev>").append(doc.getRev());
1090
		sb.append("</rev>");
1091
1092
		sb.append("<accessControl>");
1093
1094
		AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
1095
		sb.append(acfsf.getAccessString());
1096
1097
		sb.append("</accessControl>");
1098
1099
		sb.append("</documentinfo>");
1100
1101
		return sb.toString();
1102
	}
1103
1104
	/**
1105 6118 leinfelder
	 * Sends System Metadata as XML
1106
	 */
1107
	protected static void handleGetSystemMetadataRequest(
1108
			Hashtable<String, String[]> params, HttpServletResponse response) {
1109
		String guid = ((String[]) (params.get("guid")))[0];
1110
		String systemMetadataXML = null;
1111
		try {
1112
1113
			// serialize the System Metadata as XML
1114
			SystemMetadata systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
1115
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
1116 6367 leinfelder
			TypeMarshaller.marshalTypeToOutputStream(systemMetadata, baos);
1117 6118 leinfelder
			systemMetadataXML = baos.toString("UTF-8");
1118
1119
			// get a writer for sending back to response
1120
			response.setContentType("text/xml");
1121
			Writer out = response.getWriter();
1122
			out.write(systemMetadataXML);
1123
			out.close();
1124 2286 tao
1125 6118 leinfelder
		} catch (Exception e) {
1126
			String msg = "ReplicationService.handleGetSystemMetadataRequest for guid: " + guid + " : " + e.getMessage();
1127
			logMetacat.error(msg);
1128
			logReplication.error(msg);
1129
		}
1130
1131
	}
1132 6119 leinfelder
1133
	/**
1134
	 * when a forcereplication request comes in, local host sends a read request
1135
	 * to the requesting server (remote server) for the specified docid. Then
1136
	 * store it in local database.
1137
	 */
1138
	protected static void handleForceReplicateSystemMetadataRequest(
1139
			Hashtable<String, String[]> params, HttpServletResponse response,
1140
			HttpServletRequest request) {
1141
		String server = ((String[]) params.get("server"))[0]; // the server that
1142
		String guid = ((String[]) params.get("guid"))[0]; // sent the document
1143
1144
		try {
1145
			logReplication.info("ReplicationService.handleForceReplicateSystemMetadataRequest - Force replication system metadata request from: " + server);
1146
			// get the system metadata from server
1147
			URL docinfourl = new URL("https://" + server + "?server="
1148
					+ MetacatUtil.getLocalReplicationServerName()
1149
					+ "&action=getsystemmetadata&guid=" + guid);
1150
1151
			String systemMetadataXML = ReplicationService.getURLContent(docinfourl);
1152
1153
			// process system metadata
1154
			if (systemMetadataXML != null) {
1155
				SystemMetadata sysMeta =
1156 6367 leinfelder
					TypeMarshaller.unmarshalTypeFromStream(
1157 6119 leinfelder
							SystemMetadata.class,
1158
							new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
1159 6447 leinfelder
				HazelcastService.getInstance().getSystemMetadataMap().put(sysMeta.getIdentifier(), sysMeta);
1160 7812 leinfelder
				// submit for indexing
1161
                HazelcastService.getInstance().getIndexQueue().add(sysMeta);
1162 6119 leinfelder
			}
1163
1164
			logReplication.info("ReplicationService.handleForceReplicateSystemMetadataRequest - processed guid: " + guid);
1165 6542 leinfelder
			EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER, guid, "systemMetadata");
1166 6118 leinfelder
1167 6119 leinfelder
		} catch (Exception e) {
1168
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG, e);
1169
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when processing guid: " + guid, e);
1170
		}
1171
	}
1172
1173 5014 daigle
	/**
1174
	 * Sends a datafile to a remote host
1175
	 */
1176
	protected static void handleGetDataFileRequest(OutputStream outPut,
1177
			Hashtable<String, String[]> params, HttpServletResponse response)
1178 2286 tao
1179 5014 daigle
	{
1180
		// File path for data file
1181
		String filepath;
1182
		// Request docid
1183
		String docId = ((String[]) (params.get("docid")))[0];
1184
		//check if the doicd is null
1185
		if (docId == null) {
1186
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1187
			logReplication.error("ReplicationService.handleGetDataFileRequest - Didn't specify docid for replication");
1188
			return;
1189
		}
1190 2286 tao
1191 5014 daigle
		//try to open a https stream to test if the request server's public key
1192
		//in the key store, this is security issue
1193
		try {
1194
			filepath = PropertyService.getProperty("application.datafilepath");
1195
			String server = params.get("server")[0];
1196
			URL u = new URL("https://" + server + "?server="
1197
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test");
1198
			String test = ReplicationService.getURLContent(u);
1199
			//couldn't pass the test
1200
			if (test.indexOf("successfully") == -1) {
1201
				//response.setContentType("text/xml");
1202
				//outPut.println("<error>Couldn't pass the trust test</error>");
1203
				logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1204
				logReplication.error("ReplicationService.handleGetDataFileRequest - Couldn't pass the trust test");
1205
				return;
1206
			}
1207
		}//try
1208
		catch (Exception ee) {
1209
			return;
1210
		}//catch
1211 2286 tao
1212 5014 daigle
		if (!filepath.endsWith("/")) {
1213
			filepath += "/";
1214
		}
1215
		// Get file aboslute file name
1216
		String filename = filepath + docId;
1217 2286 tao
1218 5014 daigle
		//MIME type
1219
		String contentType = null;
1220
		if (filename.endsWith(".xml")) {
1221
			contentType = "text/xml";
1222
		} else if (filename.endsWith(".css")) {
1223
			contentType = "text/css";
1224
		} else if (filename.endsWith(".dtd")) {
1225
			contentType = "text/plain";
1226
		} else if (filename.endsWith(".xsd")) {
1227
			contentType = "text/xml";
1228
		} else if (filename.endsWith("/")) {
1229
			contentType = "text/html";
1230
		} else {
1231
			File f = new File(filename);
1232
			if (f.isDirectory()) {
1233
				contentType = "text/html";
1234
			} else {
1235
				contentType = "application/octet-stream";
1236
			}
1237
		}
1238 2286 tao
1239 5014 daigle
		// Set the mime type
1240
		response.setContentType(contentType);
1241 2286 tao
1242 5014 daigle
		// Get the content of the file
1243
		FileInputStream fin = null;
1244
		try {
1245
			// FileInputStream to metacat
1246
			fin = new FileInputStream(filename);
1247
			// 4K buffer
1248
			byte[] buf = new byte[4 * 1024];
1249
			// Read data from file input stream to byte array
1250
			int b = fin.read(buf);
1251
			// Write to outStream from byte array
1252
			while (b != -1) {
1253
				outPut.write(buf, 0, b);
1254
				b = fin.read(buf);
1255
			}
1256
			// close file input stream
1257
			fin.close();
1258 2286 tao
1259 5014 daigle
		}//try
1260
		catch (Exception e) {
1261
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1262
			logReplication.error("ReplicationService.handleGetDataFileRequest - error getting data file from MetacatReplication."
1263
					+ "handlGetDataFileRequest " + e.getMessage());
1264
			e.printStackTrace(System.out);
1265
		}//catch
1266 2286 tao
1267 5014 daigle
	}
1268
1269
	/**
1270 4854 daigle
	 * Sends a document to a remote host
1271
	 */
1272 5755 leinfelder
	protected static void handleGetDocumentRequest(
1273 4854 daigle
			Hashtable<String, String[]> params, HttpServletResponse response) {
1274 2286 tao
1275 4854 daigle
		String urlString = null;
1276
		String documentPath = null;
1277 5755 leinfelder
		String errorMsg = null;
1278 4854 daigle
		try {
1279
			// try to open a https stream to test if the request server's public
1280
			// key
1281
			// in the key store, this is security issue
1282
			String server = params.get("server")[0];
1283
			urlString = "https://" + server + "?server="
1284
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test";
1285
			URL u = new URL(urlString);
1286 5014 daigle
			String test = ReplicationService.getURLContent(u);
1287 4854 daigle
			// couldn't pass the test
1288
			if (test.indexOf("successfully") == -1) {
1289
				response.setContentType("text/xml");
1290 5755 leinfelder
				Writer out = response.getWriter();
1291
				out.write("<error>Couldn't pass the trust test " + test + " </error>");
1292 4854 daigle
				out.close();
1293
				return;
1294
			}
1295 2286 tao
1296 4854 daigle
			String docid = params.get("docid")[0];
1297 5014 daigle
			logReplication.debug("ReplicationService.handleGetDocumentRequest - MetacatReplication.handleGetDocumentRequest for docid: "
1298
					+ docid);
1299 4854 daigle
			DocumentImpl di = new DocumentImpl(docid);
1300 2286 tao
1301 5014 daigle
			String documentDir = PropertyService
1302
					.getProperty("application.documentfilepath");
1303 4854 daigle
			documentPath = documentDir + FileUtil.getFS() + docid;
1304 4488 daigle
1305 4854 daigle
			// if the document does not exist on disk, read it from db and write
1306
			// it to disk.
1307
			if (FileUtil.getFileStatus(documentPath) == FileUtil.DOES_NOT_EXIST
1308
					|| FileUtil.getFileSize(documentPath) == 0) {
1309 5752 leinfelder
				FileOutputStream fos = new FileOutputStream(documentPath);
1310
				di.toXml(fos, null, null, true);
1311 4854 daigle
			}
1312 2286 tao
1313 5752 leinfelder
			// read the file from disk and send it to outputstream
1314
			OutputStream outputStream = response.getOutputStream();
1315
			di.readFromFileSystem(outputStream, null, null, documentPath);
1316 2286 tao
1317 5014 daigle
			logReplication.info("ReplicationService.handleGetDocumentRequest - document " + docid + " sent");
1318 4854 daigle
1319 5755 leinfelder
			// return to avoid continuing to the error reporting section at the end
1320
			return;
1321
1322 4854 daigle
		} catch (MalformedURLException mue) {
1323 5014 daigle
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1324
			logReplication.error("ReplicationService.handleGetDocumentRequest - Url error when getting document from MetacatReplication."
1325 4854 daigle
					+ "handlGetDocumentRequest for url: " + urlString + " : "
1326
					+ mue.getMessage());
1327
			// e.printStackTrace(System.out);
1328 5755 leinfelder
1329 4854 daigle
		} catch (IOException ioe) {
1330 5014 daigle
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1331
			logReplication.error("ReplicationService.handleGetDocumentRequest - I/O error when getting document from MetacatReplication."
1332
					+ "handlGetDocumentRequest for file: " + documentPath + " : "
1333
					+ ioe.getMessage());
1334 5755 leinfelder
			errorMsg = ioe.getMessage();
1335 4854 daigle
		} catch (PropertyNotFoundException pnfe) {
1336 5014 daigle
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1337
			logReplication
1338
					.error("ReplicationService.handleGetDocumentRequest - Error getting property when getting document from MetacatReplication."
1339
							+ "handlGetDocumentRequest for file: "
1340
							+ documentPath
1341
							+ " : "
1342
							+ pnfe.getMessage());
1343 4854 daigle
			// e.printStackTrace(System.out);
1344 5755 leinfelder
			errorMsg = pnfe.getMessage();
1345 4854 daigle
		} catch (McdbException me) {
1346 5014 daigle
			logReplication
1347
					.error("ReplicationService.handleGetDocumentRequest - Document implementation error  getting property when getting document from MetacatReplication."
1348
							+ "handlGetDocumentRequest for file: "
1349
							+ documentPath
1350
							+ " : "
1351
							+ me.getMessage());
1352 4854 daigle
			// e.printStackTrace(System.out);
1353 5755 leinfelder
			errorMsg = me.getMessage();
1354 4854 daigle
		}
1355 5755 leinfelder
1356
		// report any errors if we got here
1357
		response.setContentType("text/xml");
1358
		Writer out = null;
1359
		try {
1360
			response.getWriter();
1361
			out = response.getWriter();
1362
			out.write("<error>" + errorMsg + "</error>");
1363
		} catch (Exception e) {
1364
			logMetacat.error(e.getMessage(), e);
1365
		} finally {
1366
			try {
1367
				out.close();
1368
			} catch (IOException e) {
1369
				logMetacat.error(e.getMessage(), e);
1370
			}
1371
		}
1372
1373 4854 daigle
1374
	}
1375
1376 5014 daigle
	/**
1377 4854 daigle
	 * Sends a list of all of the documents on this sever along with their
1378
	 * revision numbers. The format is: <!ELEMENT replication (server, updates)>
1379
	 * <!ELEMENT server (#PCDATA)> <!ELEMENT updates ((updatedDocument |
1380
	 * deleteDocument | revisionDocument)*)> <!ELEMENT updatedDocument (docid,
1381
	 * rev, datafile*)> <!ELEMENT deletedDocument (docid, rev)> <!ELEMENT
1382
	 * revisionDocument (docid, rev, datafile*)> <!ELEMENT docid (#PCDATA)>
1383
	 * <!ELEMENT rev (#PCDATA)> <!ELEMENT datafile (#PCDATA)> note that the rev
1384
	 * in deletedDocument is always empty. I just left it in there to make the
1385
	 * parser implementation easier.
1386
	 */
1387 5755 leinfelder
	protected static void handleUpdateRequest(Hashtable<String, String[]> params,
1388 5014 daigle
			HttpServletResponse response) {
1389
		// Checked out DBConnection
1390
		DBConnection dbConn = null;
1391
		// DBConenction serial number when checked it out
1392
		int serialNumber = -1;
1393
		PreparedStatement pstmt = null;
1394
		// Server list to store server info of xml_replication table
1395
		ReplicationServerList serverList = null;
1396 5755 leinfelder
1397
		// a writer for response
1398
		Writer out = null;
1399 2286 tao
1400 5014 daigle
		try {
1401 5755 leinfelder
			// get writer, TODO: encoding?
1402
			response.setContentType("text/xml");
1403
			out = response.getWriter();
1404
1405 5014 daigle
			// Check out a DBConnection from pool
1406
			dbConn = DBConnectionPool
1407
					.getDBConnection("MetacatReplication.handleUpdateRequest");
1408
			serialNumber = dbConn.getCheckOutSerialNumber();
1409
			// Create a server list from xml_replication table
1410
			serverList = new ReplicationServerList();
1411 2286 tao
1412 5014 daigle
			// Get remote server name from param
1413
			String server = ((String[]) params.get("server"))[0];
1414
			// If no servr name in param, return a error
1415
			if (server == null || server.equals("")) {
1416 5755 leinfelder
				out.write("<error>Request didn't specify server name</error>");
1417 5014 daigle
				out.close();
1418
				return;
1419
			}//if
1420 2286 tao
1421 5014 daigle
			//try to open a https stream to test if the request server's public key
1422
			//in the key store, this is security issue
1423 5440 berkley
			String testUrl = "https://" + server + "?server="
1424 5441 berkley
            + MetacatUtil.getLocalReplicationServerName() + "&action=test";
1425 5440 berkley
			logReplication.info("Running trust test: " + testUrl);
1426
			URL u = new URL(testUrl);
1427 5014 daigle
			String test = ReplicationService.getURLContent(u);
1428 5441 berkley
			logReplication.info("Ouput from test is '" + test + "'");
1429 5014 daigle
			//couldn't pass the test
1430
			if (test.indexOf("successfully") == -1) {
1431 5441 berkley
			    logReplication.error("Trust test failed.");
1432 5755 leinfelder
				out.write("<error>Couldn't pass the trust test</error>");
1433 5014 daigle
				out.close();
1434
				return;
1435
			}
1436 5441 berkley
			logReplication.info("Trust test succeeded.");
1437 2286 tao
1438 5014 daigle
			// Check if local host configure to replicate xml documents to remote
1439
			// server. If not send back a error message
1440
			if (!serverList.getReplicationValue(server)) {
1441 5755 leinfelder
				out.write("<error>Configuration not allow to replicate document to you</error>");
1442 5014 daigle
				out.close();
1443
				return;
1444
			}//if
1445 2286 tao
1446 5014 daigle
			// Store the sql command
1447
			StringBuffer docsql = new StringBuffer();
1448
			StringBuffer revisionSql = new StringBuffer();
1449 7356 leinfelder
1450 5014 daigle
			// Store the data set file
1451
			Vector<Vector<String>> packageFiles = new Vector<Vector<String>>();
1452 2286 tao
1453 5014 daigle
			// Append local server's name and replication servlet to doclist
1454 7356 leinfelder
			out.append("<?xml version=\"1.0\"?><replication>");
1455
			out.append("<server>")
1456 5014 daigle
					.append(MetacatUtil.getLocalReplicationServerName());
1457
			//doclist.append(util.getProperty("replicationpath"));
1458 7356 leinfelder
			out.append("</server><updates>");
1459 2286 tao
1460 5014 daigle
			// Get correct docid that reside on this server according the requesting
1461
			// server's replicate and data replicate value in xml_replication table
1462 5319 jones
			docsql.append(DatabaseService.getInstance().getDBAdapter().getReplicationDocumentListSQL());
1463 5014 daigle
			//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)) ");
1464
			revisionSql.append("select docid, rev, doctype from xml_revisions ");
1465
			// If the localhost is not a hub to the remote server, only replicate
1466
			// the docid' which home server is local host (server_location =1)
1467
			if (!serverList.getHubValue(server)) {
1468
				String serverLocationDoc = " and a.server_location = 1";
1469
				String serverLocationRev = "where server_location = 1";
1470
				docsql.append(serverLocationDoc);
1471
				revisionSql.append(serverLocationRev);
1472
			}
1473
			logReplication.info("ReplicationService.handleUpdateRequest - Doc sql: " + docsql.toString());
1474 2286 tao
1475 5014 daigle
			// Get any deleted documents
1476 7636 jones
			StringBuffer delsql = new StringBuffer();
1477 7638 leinfelder
			delsql.append("SELECT t1.docid FROM xml_revisions t1 LEFT JOIN xml_documents t2 on t1.docid = t2.docid WHERE t2.docid IS NULL ");
1478 7636 jones
1479 5014 daigle
			// If the localhost is not a hub to the remote server, only replicate
1480
			// the docid' which home server is local host (server_location =1)
1481
			if (!serverList.getHubValue(server)) {
1482 7636 jones
				delsql.append("and t1.server_location = 1");
1483 5014 daigle
			}
1484
			logReplication.info("ReplicationService.handleUpdateRequest - Deleted sql: " + delsql.toString());
1485 2286 tao
1486 5014 daigle
			// Get docid list of local host
1487
			pstmt = dbConn.prepareStatement(docsql.toString());
1488
			pstmt.execute();
1489
			ResultSet rs = pstmt.getResultSet();
1490
			boolean tablehasrows = rs.next();
1491
			//If metacat configed to replicate data file
1492
			//if ((util.getProperty("replicationsenddata")).equals("on"))
1493
			boolean replicateData = serverList.getDataReplicationValue(server);
1494
			if (replicateData) {
1495
				while (tablehasrows) {
1496
					String recordDoctype = rs.getString(3);
1497
					Vector<String> packagedoctypes = MetacatUtil
1498
							.getOptionList(PropertyService
1499
									.getProperty("xml.packagedoctype"));
1500
					//if this is a package file, put it at the end
1501
					//because if a package file is read before all of the files it
1502
					//refers to are loaded then there is an error
1503
					if (recordDoctype != null && !packagedoctypes.contains(recordDoctype)) {
1504
						//If this is not data file
1505
						if (!recordDoctype.equals("BIN")) {
1506
							//for non-data file document
1507 7356 leinfelder
							out.append("<updatedDocument>");
1508
							out.append("<docid>").append(rs.getString(1));
1509
							out.append("</docid><rev>" + rs.getInt(2));
1510
							out.append("</rev>");
1511
							out.append("</updatedDocument>");
1512 5014 daigle
						}//if
1513
						else {
1514
							//for data file document, in datafile attributes
1515
							//we put "datafile" value there
1516 7356 leinfelder
							out.append("<updatedDocument>");
1517
							out.append("<docid>").append(rs.getString(1));
1518
							out.append("</docid><rev>" + rs.getInt(2));
1519
							out.append("</rev>");
1520
							out.append("<datafile>");
1521
							out.append(DATA_FILE_FLAG);
1522
							out.append("</datafile>");
1523
							out.append("</updatedDocument>");
1524 5014 daigle
						}//else
1525
					}//if packagedoctpes
1526
					else { //the package files are saved to be put into the xml later.
1527
						Vector<String> v = new Vector<String>();
1528
						v.add(rs.getString(1));
1529
						v.add(String.valueOf(rs.getInt(2)));
1530
						packageFiles.add(v);
1531
					}//esle
1532
					tablehasrows = rs.next();
1533
				}//while
1534
			}//if
1535
			else //metacat was configured not to send data file
1536
			{
1537
				while (tablehasrows) {
1538
					String recordDoctype = rs.getString(3);
1539
					if (!recordDoctype.equals("BIN")) { //don't replicate data files
1540
						Vector<String> packagedoctypes = MetacatUtil
1541
								.getOptionList(PropertyService
1542
										.getProperty("xml.packagedoctype"));
1543
						if (recordDoctype != null
1544
								&& !packagedoctypes.contains(recordDoctype)) { //if this is a package file, put it at the end
1545
							//because if a package file is read before all of the files it
1546
							//refers to are loaded then there is an error
1547 7356 leinfelder
							out.append("<updatedDocument>");
1548
							out.append("<docid>" + rs.getString(1));
1549
							out.append("</docid><rev>" + rs.getInt(2));
1550
							out.append("</rev>");
1551
							out.append("</updatedDocument>");
1552 5014 daigle
						} else { //the package files are saved to be put into the xml later.
1553
							Vector<String> v = new Vector<String>();
1554
							v.add(rs.getString(1));
1555
							v.add(String.valueOf(rs.getInt(2)));
1556
							packageFiles.add(v);
1557
						}
1558
					}//if
1559
					tablehasrows = rs.next();
1560
				}//while
1561
			}//else
1562 2286 tao
1563 5014 daigle
			pstmt = dbConn.prepareStatement(delsql.toString());
1564
			//usage count should increas 1
1565
			dbConn.increaseUsageCount(1);
1566 2286 tao
1567 5014 daigle
			pstmt.execute();
1568
			rs = pstmt.getResultSet();
1569
			tablehasrows = rs.next();
1570
			while (tablehasrows) { //handle the deleted documents
1571 7356 leinfelder
				out.append("<deletedDocument><docid>").append(rs.getString(1));
1572
				out.append("</docid><rev></rev></deletedDocument>");
1573 5014 daigle
				//note that rev is always empty for deleted docs
1574
				tablehasrows = rs.next();
1575
			}
1576 2286 tao
1577 5014 daigle
			//now we can put the package files into the xml results
1578
			for (int i = 0; i < packageFiles.size(); i++) {
1579
				Vector<String> v = packageFiles.elementAt(i);
1580 7356 leinfelder
				out.append("<updatedDocument>");
1581
				out.append("<docid>").append(v.elementAt(0));
1582
				out.append("</docid><rev>");
1583
				out.append(v.elementAt(1));
1584
				out.append("</rev>");
1585
				out.append("</updatedDocument>");
1586 5014 daigle
			}
1587
			// add revision doc list
1588 7356 leinfelder
			out.append(prepareRevisionDoc(dbConn, revisionSql.toString(),
1589 5014 daigle
					replicateData));
1590 2286 tao
1591 7356 leinfelder
			out.append("</updates></replication>");
1592
			logReplication.info("ReplicationService.handleUpdateRequest - done writing to output stream.");
1593 5014 daigle
			pstmt.close();
1594
			//conn.close();
1595 2286 tao
1596 5014 daigle
		} catch (Exception e) {
1597
			logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1598
			logReplication.error("ReplicationService.handleUpdateRequest - error in MetacatReplication." + "handleupdaterequest: "
1599
					+ e.getMessage());
1600
			//e.printStackTrace(System.out);
1601 5755 leinfelder
			try {
1602
				out.write("<error>" + e.getMessage() + "</error>");
1603
			} catch (IOException e1) {
1604
				logMetacat.error(e1.getMessage(), e1);
1605
			}
1606 5014 daigle
		} finally {
1607
			try {
1608
				pstmt.close();
1609
			}//try
1610
			catch (SQLException ee) {
1611
				logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1612
				logReplication.error("ReplicationService.handleUpdateRequest - Error in MetacatReplication."
1613
						+ "handleUpdaterequest to close pstmt: " + ee.getMessage());
1614
			}//catch
1615
			finally {
1616
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1617
			}//finally
1618 5755 leinfelder
			try {
1619
				out.close();
1620
			} catch (IOException e) {
1621
				logMetacat.error(e.getMessage(), e);
1622
			}
1623 5014 daigle
		}//finally
1624 2286 tao
1625 5014 daigle
	}//handlUpdateRequest
1626 2286 tao
1627 6015 leinfelder
	/**
1628
	 *
1629
	 * @param dbConn connection for doing the update
1630
	 * @param docid the document id to update
1631
	 * @param owner the user_owner
1632
	 * @param updater the user_updated
1633
	 * @throws SQLException
1634
	 */
1635
	public static void updateUserOwner(DBConnection dbConn, String docid, String owner, String updater) throws SQLException {
1636
1637
		String sql =
1638
			"UPDATE xml_documents " +
1639
			"SET user_owner = ?, " +
1640
			"user_updated = ? " +
1641
			"WHERE docid = ?;";
1642
		PreparedStatement pstmt = dbConn.prepareStatement(sql);
1643
		//usage count should increas 1
1644
		dbConn.increaseUsageCount(1);
1645
1646
		docid = DocumentUtil.getSmartDocId(docid);
1647
		pstmt.setString(1, owner);
1648
		pstmt.setString(2, updater);
1649
		pstmt.setString(3, docid);
1650
		pstmt.execute();
1651
		pstmt.close();
1652
1653
		dbConn.commit();
1654
	}
1655
1656 5014 daigle
	/*
1657
	 * This method will get the xml string for document in xml_revision
1658
	 * The schema look like <!ELEMENT revisionDocument (docid, rev, datafile*)>
1659
	 */
1660
	private static String prepareRevisionDoc(DBConnection dbConn, String revSql,
1661
			boolean replicateData) throws Exception {
1662
		logReplication.warn("ReplicationService.prepareRevisionDoc - The revision document sql is " + revSql);
1663
		StringBuffer revDocList = new StringBuffer();
1664
		PreparedStatement pstmt = dbConn.prepareStatement(revSql);
1665
		//usage count should increas 1
1666
		dbConn.increaseUsageCount(1);
1667 2286 tao
1668 5014 daigle
		pstmt.execute();
1669
		ResultSet rs = pstmt.getResultSet();
1670 7337 leinfelder
		logReplication.warn("Processing replication revision for documents");
1671 7338 leinfelder
		while (rs.next()) {
1672 5014 daigle
			String recordDoctype = rs.getString(3);
1673 2286 tao
1674 5014 daigle
			//If this is data file and it isn't configured to replicate data
1675
			if (recordDoctype.equals("BIN") && !replicateData) {
1676 7338 leinfelder
				logMetacat.debug("SKipping data file because data replication is not configured");
1677
1678 5014 daigle
				// do nothing
1679
			} else {
1680 7337 leinfelder
				String docid = rs.getString(1);
1681
				int rev = rs.getInt(2);
1682
				logMetacat.debug("Processing replication revision for docid: " + docid + "." + rev);
1683 2597 tao
1684 5014 daigle
				revDocList.append("<revisionDocument>");
1685 7337 leinfelder
				revDocList.append("<docid>").append(docid);
1686
				revDocList.append("</docid><rev>").append(rev);
1687 5014 daigle
				revDocList.append("</rev>");
1688
				// data file
1689
				if (recordDoctype.equals("BIN")) {
1690
					revDocList.append("<datafile>");
1691 7337 leinfelder
					revDocList.append(DATA_FILE_FLAG);
1692 5014 daigle
					revDocList.append("</datafile>");
1693
				}
1694
				revDocList.append("</revisionDocument>");
1695 2286 tao
1696 5014 daigle
			}//else
1697
		}
1698
		//System.out.println("The revision list is"+ revDocList.toString());
1699
		return revDocList.toString();
1700
	}
1701 2286 tao
1702 5014 daigle
	/**
1703
	 * Returns the xml_catalog table encoded in xml
1704
	 */
1705
	public static String getCatalogXML() {
1706 5755 leinfelder
		return handleGetCatalogRequest(null, null, false);
1707 5014 daigle
	}
1708 2286 tao
1709 5014 daigle
	/**
1710
	 * Sends the contents of the xml_catalog table encoded in xml
1711
	 * The xml format is:
1712
	 * <!ELEMENT xml_catalog (row*)>
1713
	 * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
1714
	 *                system_id)>
1715
	 * All of the sub elements of row are #PCDATA
1716 2286 tao
1717 5014 daigle
	 * If printFlag == false then do not print to out.
1718
	 */
1719 5755 leinfelder
	protected static String handleGetCatalogRequest(
1720 5014 daigle
			Hashtable<String, String[]> params, HttpServletResponse response,
1721
			boolean printFlag) {
1722
		DBConnection dbConn = null;
1723
		int serialNumber = -1;
1724
		PreparedStatement pstmt = null;
1725 5755 leinfelder
		Writer out = null;
1726 5014 daigle
		try {
1727 5755 leinfelder
			// get writer, TODO: encoding?
1728 5944 berkley
		    if(printFlag)
1729
		    {
1730
		        response.setContentType("text/xml");
1731
		        out = response.getWriter();
1732
		    }
1733 5014 daigle
			/*conn = MetacatReplication.getDBConnection("MetacatReplication." +
1734
			                                          "handleGetCatalogRequest");*/
1735
			dbConn = DBConnectionPool
1736
					.getDBConnection("MetacatReplication.handleGetCatalogRequest");
1737
			serialNumber = dbConn.getCheckOutSerialNumber();
1738
			pstmt = dbConn.prepareStatement("select entry_type, "
1739
					+ "source_doctype, target_doctype, public_id, "
1740
					+ "system_id from xml_catalog");
1741
			pstmt.execute();
1742
			ResultSet rs = pstmt.getResultSet();
1743
			boolean tablehasrows = rs.next();
1744
			StringBuffer sb = new StringBuffer();
1745
			sb.append("<?xml version=\"1.0\"?><xml_catalog>");
1746
			while (tablehasrows) {
1747
				sb.append("<row><entry_type>").append(rs.getString(1));
1748
				sb.append("</entry_type><source_doctype>").append(rs.getString(2));
1749
				sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
1750
				sb.append("</target_doctype><public_id>").append(rs.getString(4));
1751
				// system id may not have server url on front.  Add it if not.
1752
				String systemID = rs.getString(5);
1753
				if (!systemID.startsWith("http://")) {
1754
					systemID = SystemUtil.getContextURL() + systemID;
1755
				}
1756
				sb.append("</public_id><system_id>").append(systemID);
1757
				sb.append("</system_id></row>");
1758 2286 tao
1759 5014 daigle
				tablehasrows = rs.next();
1760
			}
1761
			sb.append("</xml_catalog>");
1762
			//conn.close();
1763
			if (printFlag) {
1764
				response.setContentType("text/xml");
1765 5755 leinfelder
				out.write(sb.toString());
1766 5014 daigle
			}
1767
			pstmt.close();
1768
			return sb.toString();
1769
		} catch (Exception e) {
1770
			logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1771
			logReplication.error("ReplicationService.handleGetCatalogRequest - error in MetacatReplication.handleGetCatalogRequest:"
1772
					+ e.getMessage());
1773
			e.printStackTrace(System.out);
1774
			if (printFlag) {
1775 5755 leinfelder
				try {
1776
					out.write("<error>" + e.getMessage() + "</error>");
1777
				} catch (IOException e1) {
1778
					logMetacat.error(e1.getMessage(), e1);
1779
				}
1780 5014 daigle
			}
1781
		} finally {
1782
			try {
1783
				pstmt.close();
1784
			}//try
1785
			catch (SQLException ee) {
1786
				logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1787
				logReplication.error("ReplicationService.handleGetCatalogRequest - Error in MetacatReplication.handleGetCatalogRequest: "
1788
						+ ee.getMessage());
1789
			}//catch
1790
			finally {
1791
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1792
			}//finally
1793 5755 leinfelder
			if (out != null) {
1794
				try {
1795
					out.close();
1796
				} catch (IOException e1) {
1797
					logMetacat.error(e1.getMessage(), e1);
1798
				}
1799
			}
1800 5014 daigle
		}//finally
1801 2286 tao
1802 5014 daigle
		return null;
1803
	}
1804 2286 tao
1805 5014 daigle
	/**
1806
	 * Sends the current system date to the remote server.  Using this action
1807
	 * for replication gets rid of any problems with syncronizing clocks
1808
	 * because a time specific to a document is always kept on its home server.
1809
	 */
1810 5755 leinfelder
	protected static void handleGetTimeRequest(
1811 5014 daigle
			Hashtable<String, String[]> params, HttpServletResponse response) {
1812 5755 leinfelder
1813 6614 leinfelder
		// use standard format -- the receiving end wants this too
1814
		String dateString = DateTimeMarshaller.serializeDateToUTC(Calendar.getInstance().getTime());
1815 6595 leinfelder
1816 5755 leinfelder
		// get a writer for sending back to response
1817 5014 daigle
		response.setContentType("text/xml");
1818 5755 leinfelder
		Writer out = null;
1819
		try {
1820
			out = response.getWriter();
1821
			out.write("<timestamp>" + dateString + "</timestamp>");
1822
			out.close();
1823
		} catch (IOException e) {
1824
			logMetacat.error(e.getMessage(), e);
1825
		}
1826
1827 5014 daigle
	}
1828 2286 tao
1829 5014 daigle
	/**
1830
	 * this method handles the timeout for a file lock.  when a lock is
1831
	 * granted it is granted for 30 seconds.  When this thread runs out
1832
	 * it deletes the docid from the queue, thus eliminating the lock.
1833
	 */
1834
	public void run() {
1835
		try {
1836
			logReplication.info("ReplicationService.run - thread started for docid: "
1837
					+ (String) fileLocks.elementAt(0));
1838 2286 tao
1839 5014 daigle
			Thread.sleep(30000); //the lock will expire in 30 seconds
1840
			logReplication.info("thread for docid: "
1841
					+ (String) fileLocks.elementAt(fileLocks.size() - 1) + " exiting.");
1842 2286 tao
1843 5014 daigle
			fileLocks.remove(fileLocks.size() - 1);
1844
			//fileLocks is treated as a FIFO queue.  If there are more than one lock
1845
			//in the vector, the first one inserted will be removed.
1846
		} catch (Exception e) {
1847
			logMetacat.error("ReplicationService.run - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1848
			logReplication.error("ReplicationService.run - error in file lock thread from "
1849
					+ "MetacatReplication.run: " + e.getMessage());
1850
		}
1851
	}
1852 2286 tao
1853 5014 daigle
	/**
1854
	 * Returns the name of a server given a serverCode
1855
	 * @param serverCode the serverid of the server
1856
	 * @return the servername or null if the specified serverCode does not
1857
	 *         exist.
1858
	 */
1859
	public static String getServerNameForServerCode(int serverCode) {
1860
		//System.out.println("serverid: " + serverCode);
1861
		DBConnection dbConn = null;
1862
		int serialNumber = -1;
1863
		PreparedStatement pstmt = null;
1864
		try {
1865
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServer");
1866
			serialNumber = dbConn.getCheckOutSerialNumber();
1867
			String sql = new String("select server from "
1868 6595 leinfelder
					+ "xml_replication where serverid = ?");
1869 5014 daigle
			pstmt = dbConn.prepareStatement(sql);
1870 6595 leinfelder
			pstmt.setInt(1, serverCode);
1871 5014 daigle
			//System.out.println("getserver sql: " + sql);
1872
			pstmt.execute();
1873
			ResultSet rs = pstmt.getResultSet();
1874
			boolean tablehasrows = rs.next();
1875
			if (tablehasrows) {
1876
				//System.out.println("server: " + rs.getString(1));
1877
				return rs.getString(1);
1878
			}
1879 2286 tao
1880 5014 daigle
			//conn.close();
1881
		} catch (Exception e) {
1882
			logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1883
			logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplication.getServer: " + e.getMessage());
1884
		} finally {
1885
			try {
1886
				pstmt.close();
1887
			}//try
1888
			catch (SQLException ee) {
1889
				logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1890
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacactReplication.getserver: "
1891
						+ ee.getMessage());
1892
			}//catch
1893
			finally {
1894
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1895
			}//fianlly
1896
		}//finally
1897 2286 tao
1898 5014 daigle
		return null;
1899
		//return null if the server does not exist
1900
	}
1901 2286 tao
1902 5014 daigle
	/**
1903
	 * Returns a server code given a server name
1904
	 * @param server the name of the server
1905
	 * @return integer > 0 representing the code of the server, 0 if the server
1906
	 *  does not exist.
1907
	 */
1908
	public static int getServerCodeForServerName(String server) throws ServiceException {
1909
		DBConnection dbConn = null;
1910
		int serialNumber = -1;
1911
		PreparedStatement pstmt = null;
1912
		int serverCode = 0;
1913 2286 tao
1914 5014 daigle
		try {
1915 837 bojilova
1916 5014 daigle
			//conn = util.openDBConnection();
1917
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServerCode");
1918
			serialNumber = dbConn.getCheckOutSerialNumber();
1919
			pstmt = dbConn.prepareStatement("SELECT serverid FROM xml_replication "
1920 6595 leinfelder
					+ "WHERE server LIKE ?");
1921
			pstmt.setString(1, server);
1922 5014 daigle
			pstmt.execute();
1923
			ResultSet rs = pstmt.getResultSet();
1924
			boolean tablehasrows = rs.next();
1925
			if (tablehasrows) {
1926
				serverCode = rs.getInt(1);
1927
				pstmt.close();
1928
				//conn.close();
1929
				return serverCode;
1930
			}
1931 837 bojilova
1932 5014 daigle
		} catch (SQLException sqle) {
1933
			throw new ServiceException("ReplicationService.getServerCodeForServerName - "
1934
					+ "SQL error when getting server code: " + sqle.getMessage());
1935 2286 tao
1936 5014 daigle
		} finally {
1937
			try {
1938
				pstmt.close();
1939
				//conn.close();
1940
			}//try
1941
			catch (Exception ee) {
1942
				logMetacat.error("ReplicationService.getServerCodeForServerName - " + ReplicationService.METACAT_REPL_ERROR_MSG);
1943
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplicatio.getServerCode: "
1944
						+ ee.getMessage());
1945 837 bojilova
1946 5014 daigle
			}//catch
1947
			finally {
1948
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1949
			}//finally
1950
		}//finally
1951 2286 tao
1952 5014 daigle
		return serverCode;
1953
	}
1954 2286 tao
1955 5014 daigle
	/**
1956
	 * Method to get a host server information for given docid
1957
	 * @param conn a connection to the database
1958
	 */
1959
	public static Hashtable<String, String> getHomeServerInfoForDocId(String docId) {
1960
		Hashtable<String, String> sl = new Hashtable<String, String>();
1961
		DBConnection dbConn = null;
1962
		int serialNumber = -1;
1963 5027 daigle
		docId = DocumentUtil.getDocIdFromString(docId);
1964 5014 daigle
		PreparedStatement pstmt = null;
1965
		int serverLocation;
1966
		try {
1967
			//get conection
1968
			dbConn = DBConnectionPool.getDBConnection("ReplicationHandler.getHomeServer");
1969
			serialNumber = dbConn.getCheckOutSerialNumber();
1970
			//get a server location from xml_document table
1971
			pstmt = dbConn.prepareStatement("select server_location from xml_documents "
1972
					+ "where docid = ?");
1973
			pstmt.setString(1, docId);
1974
			pstmt.execute();
1975
			ResultSet serverName = pstmt.getResultSet();
1976
			//get a server location
1977
			if (serverName.next()) {
1978
				serverLocation = serverName.getInt(1);
1979
				pstmt.close();
1980
			} else {
1981
				pstmt.close();
1982
				//ut.returnConnection(conn);
1983
				return null;
1984
			}
1985
			pstmt = dbConn.prepareStatement("select server, last_checked, replicate "
1986
					+ "from xml_replication where serverid = ?");
1987
			//increase usage count
1988
			dbConn.increaseUsageCount(1);
1989
			pstmt.setInt(1, serverLocation);
1990
			pstmt.execute();
1991
			ResultSet rs = pstmt.getResultSet();
1992
			boolean tableHasRows = rs.next();
1993
			if (tableHasRows) {
1994 2286 tao
1995 5014 daigle
				String server = rs.getString(1);
1996
				String last_checked = rs.getString(2);
1997
				if (!server.equals("localhost")) {
1998
					sl.put(server, last_checked);
1999
				}
2000 2286 tao
2001 5014 daigle
			} else {
2002
				pstmt.close();
2003
				//ut.returnConnection(conn);
2004
				return null;
2005
			}
2006
			pstmt.close();
2007
		} catch (Exception e) {
2008
			logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);
2009
			logReplication.error("ReplicationService.getHomeServerInfoForDocId - error in replicationHandler.getHomeServer(): "
2010
					+ e.getMessage());
2011
		} finally {
2012
			try {
2013
				pstmt.close();
2014
				//ut.returnConnection(conn);
2015
			} catch (Exception ee) {
2016
				logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);
2017
				logReplication.error("ReplicationService.getHomeServerInfoForDocId - Eror irn rplicationHandler.getHomeServer() "
2018
						+ "to close pstmt: " + ee.getMessage());
2019
			} finally {
2020
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2021
			}
2022 2286 tao
2023 5014 daigle
		}//finally
2024
		return sl;
2025
	}
2026 2286 tao
2027 5014 daigle
	/**
2028
	 * Returns a home server location  given a accnum
2029
	 * @param accNum , given accNum for a document
2030
	 *
2031
	 */
2032
	public static int getHomeServerCodeForDocId(String accNum) throws ServiceException {
2033
		DBConnection dbConn = null;
2034
		int serialNumber = -1;
2035
		PreparedStatement pstmt = null;
2036
		int serverCode = 1;
2037 5027 daigle
		String docId = DocumentUtil.getDocIdFromString(accNum);
2038 2286 tao
2039 5014 daigle
		try {
2040 1292 tao
2041 5014 daigle
			// Get DBConnection
2042
			dbConn = DBConnectionPool
2043
					.getDBConnection("ReplicationHandler.getServerLocation");
2044
			serialNumber = dbConn.getCheckOutSerialNumber();
2045
			pstmt = dbConn.prepareStatement("SELECT server_location FROM xml_documents "
2046 6595 leinfelder
					+ "WHERE docid LIKE ? ");
2047
			pstmt.setString(1, docId);
2048 5014 daigle
			pstmt.execute();
2049
			ResultSet rs = pstmt.getResultSet();
2050
			boolean tablehasrows = rs.next();
2051
			//If a document is find, return the server location for it
2052
			if (tablehasrows) {
2053
				serverCode = rs.getInt(1);
2054
				pstmt.close();
2055
				//conn.close();
2056
				return serverCode;
2057
			}
2058
			//if couldn't find in xml_documents table, we think server code is 1
2059
			//(this is new document)
2060
			else {
2061
				pstmt.close();
2062
				//conn.close();
2063
				return serverCode;
2064
			}
2065 1292 tao
2066 5014 daigle
		} catch (SQLException sqle) {
2067
			throw new ServiceException("ReplicationService.getHomeServerCodeForDocId - "
2068
					+ "SQL error when getting home server code for docid: " + docId + " : "
2069
					+ sqle.getMessage());
2070 2286 tao
2071 5014 daigle
		} finally {
2072
			try {
2073
				pstmt.close();
2074
				//conn.close();
2075 2286 tao
2076 5014 daigle
			} catch (SQLException sqle) {
2077
				logMetacat.error("ReplicationService.getHomeServerCodeForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);
2078
				logReplication.error("ReplicationService.getHomeServerCodeForDocId - ReplicationService.getHomeServerCodeForDocId - "
2079
						+ "SQL error when getting home server code for docid: " + docId + " : "
2080
						+ sqle.getMessage());
2081
			} finally {
2082
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2083
			}//finally
2084
		}//finally
2085
		//return serverCode;
2086
	}
2087 1292 tao
2088 5014 daigle
	/**
2089
	 * This method returns the content of a url
2090
	 * @param u the url to return the content from
2091
	 * @return a string representing the content of the url
2092
	 * @throws java.io.IOException
2093
	 */
2094
	public static String getURLContent(URL u) throws java.io.IOException {
2095
		char istreamChar;
2096
		int istreamInt;
2097 6582 leinfelder
		// get the response content
2098 6611 leinfelder
		InputStream input = getURLStream(u);
2099 6582 leinfelder
		logReplication.info("ReplicationService.getURLContent - After getting response from: " + u.toString());
2100 5014 daigle
		InputStreamReader istream = new InputStreamReader(input);
2101
		StringBuffer serverResponse = new StringBuffer();
2102
		while ((istreamInt = istream.read()) != -1) {
2103
			istreamChar = (char) istreamInt;
2104
			serverResponse.append(istreamChar);
2105
		}
2106
		istream.close();
2107
		input.close();
2108 2286 tao
2109 5014 daigle
		return serverResponse.toString();
2110
	}
2111 6582 leinfelder
2112
	/**
2113 6611 leinfelder
	 * This method returns the InputStream after opening a url
2114
	 * @param u the url to return the content from
2115
	 * @return a InputStream representing the content of the url
2116
	 * @throws java.io.IOException
2117
	 */
2118
	public static InputStream getURLStream(URL u) throws java.io.IOException {
2119
	    logReplication.info("Getting url stream from " + u.toString());
2120
		logReplication.info("ReplicationService.getURLStream - Before sending request to: " + u.toString());
2121
		// use httpclient to set up SSL
2122
		RestClient client = getSSLClient();
2123
		HttpResponse response = client.doGetRequest(u.toString());
2124
		// get the response content
2125
		InputStream input = response.getEntity().getContent();
2126
		logReplication.info("ReplicationService.getURLStream - After getting response from: " + u.toString());
2127
2128
		return input;
2129
	}
2130
2131
	/**
2132 6582 leinfelder
	 * Sets up an HttpClient with SSL connection.
2133
	 * Sends client certificate to the server when doing the request.
2134
	 * @return
2135
	 */
2136
	private static RestClient getSSLClient() {
2137
		RestClient client = new RestClient();
2138
2139
		// set up this server's client identity
2140
		String subject = null;
2141
		try {
2142 6616 leinfelder
			// TODO: should there be alternative ways to get the key and certificate?
2143 6620 leinfelder
			String certificateFile = PropertyService.getProperty("replication.certificate.file");
2144
	    	String keyFile = PropertyService.getProperty("replication.privatekey.file");
2145
			String keyPassword = PropertyService.getProperty("replication.privatekey.password");
2146
			X509Certificate certificate = CertificateManager.getInstance().loadCertificateFromFile(certificateFile);
2147
			PrivateKey privateKey = CertificateManager.getInstance().loadPrivateKeyFromFile(keyFile, keyPassword);
2148 6582 leinfelder
			subject = CertificateManager.getInstance().getSubjectDN(certificate);
2149 6620 leinfelder
			CertificateManager.getInstance().registerCertificate(subject, certificate, privateKey);
2150 6582 leinfelder
		} catch (Exception e) {
2151
			// this is pretty much required for replication communication
2152 6616 leinfelder
			logReplication.warn("Could not find server's client certificate/private key: " + e.getMessage());
2153 6582 leinfelder
		}
2154 7317 leinfelder
2155
		// set the configured timeout
2156
		client.setTimeouts(CLIENTTIMEOUT);
2157 7313 leinfelder
2158 6582 leinfelder
		SSLSocketFactory socketFactory = null;
2159
		try {
2160
			socketFactory = CertificateManager.getInstance().getSSLSocketFactory(subject);
2161
		} catch (FileNotFoundException e) {
2162
			// these are somewhat expected for anonymous client use
2163
			logReplication.warn("Could not set up SSL connection for client - likely because the certificate could not be located: " + e.getMessage());
2164
		} catch (Exception e) {
2165
			// this is likely more severe
2166
			logReplication.warn("Funky SSL going on: " + e.getClass() + ":: " + e.getMessage());
2167
		}
2168
		try {
2169
			//443 is the default port, this value is overridden if explicitly set in the URL
2170
			Scheme sch = new Scheme("https", 443, socketFactory);
2171
			client.getHttpClient().getConnectionManager().getSchemeRegistry().register(sch);
2172
		} catch (Exception e) {
2173
			// this is likely more severe
2174
			logReplication.error("Failed to set up SSL connection for client. Continuing. " + e.getClass() + ":: " + e.getMessage(), e);
2175
		}
2176
		return client;
2177
	}
2178
2179 2286 tao
2180 5014 daigle
//	/**
2181
//	 * Method for writing replication messages to a log file specified in
2182
//	 * metacat.properties
2183
//	 */
2184
//	public static void replLog(String message) {
2185
//		try {
2186
//			FileOutputStream fos = new FileOutputStream(PropertyService
2187
//					.getProperty("replication.logdir")
2188
//					+ "/metacatreplication.log", true);
2189
//			PrintWriter pw = new PrintWriter(fos);
2190
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
2191
//			java.util.Date localtime = new java.util.Date();
2192
//			String dateString = formatter.format(localtime);
2193
//			dateString += " :: " + message;
2194
//			// time stamp each entry
2195
//			pw.println(dateString);
2196
//			pw.flush();
2197
//		} catch (Exception e) {
2198
//			logReplication.error("error writing to replication log from "
2199
//					+ "MetacatReplication.replLog: " + e.getMessage());
2200
//			// e.printStackTrace(System.out);
2201
//		}
2202
//	}
2203 2286 tao
2204 5014 daigle
//	/**
2205
//	 * Method for writing replication messages to a log file specified in
2206
//	 * metacat.properties
2207
//	 */
2208
//	public static void replErrorLog(String message) {
2209
//		try {
2210
//			FileOutputStream fos = new FileOutputStream(PropertyService
2211
//					.getProperty("replication.logdir")
2212
//					+ "/metacatreplicationerror.log", true);
2213
//			PrintWriter pw = new PrintWriter(fos);
2214
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
2215
//			java.util.Date localtime = new java.util.Date();
2216
//			String dateString = formatter.format(localtime);
2217
//			dateString += " :: " + message;
2218
//			//time stamp each entry
2219
//			pw.println(dateString);
2220
//			pw.flush();
2221
//		} catch (Exception e) {
2222
//			logReplication.error("error writing to replication error log from "
2223
//					+ "MetacatReplication.replErrorLog: " + e.getMessage());
2224
//			//e.printStackTrace(System.out);
2225
//		}
2226
//	}
2227 2286 tao
2228 5014 daigle
	/**
2229
	 * Returns true if the replicate field for server in xml_replication is 1.
2230
	 * Returns false otherwise
2231 4080 daigle
	 */
2232 5014 daigle
	public static boolean replToServer(String server) {
2233
		DBConnection dbConn = null;
2234
		int serialNumber = -1;
2235
		PreparedStatement pstmt = null;
2236 4080 daigle
		try {
2237 5014 daigle
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.repltoServer");
2238
			serialNumber = dbConn.getCheckOutSerialNumber();
2239
			pstmt = dbConn.prepareStatement("select replicate from "
2240 6595 leinfelder
					+ "xml_replication where server like ? ");
2241
			pstmt.setString(1, server);
2242 5014 daigle
			pstmt.execute();
2243
			ResultSet rs = pstmt.getResultSet();
2244
			boolean tablehasrows = rs.next();
2245
			if (tablehasrows) {
2246
				int i = rs.getInt(1);
2247
				if (i == 1) {
2248
					pstmt.close();
2249
					//conn.close();
2250
					return true;
2251
				} else {
2252
					pstmt.close();
2253
					//conn.close();
2254
					return false;
2255
				}
2256
			}
2257
		} catch (SQLException sqle) {
2258
			logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);
2259
			logReplication.error("ReplicationService.replToServer - SQL error in MetacatReplication.replToServer: "
2260
					+ sqle.getMessage());
2261
		} finally {
2262
			try {
2263
				pstmt.close();
2264
				//conn.close();
2265
			}//try
2266
			catch (Exception ee) {
2267
				logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);
2268
				logReplication.error("ReplicationService.replToServer - Error in MetacatReplication.replToServer: "
2269
						+ ee.getMessage());
2270
			}//catch
2271
			finally {
2272
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2273
			}//finally
2274
		}//finally
2275
		return false;
2276
		//the default if this server does not exist is to not replicate to it.
2277 4080 daigle
	}
2278 2286 tao
2279 522 berkley
}