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