Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements replication for metacat
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Chad Berkley
7
 *
8
 *   '$Author: leinfelder $'
9
 *     '$Date: 2011-10-20 14:03:19 -0700 (Thu, 20 Oct 2011) $'
10
 * '$Revision: 6542 $'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26

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

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

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

    
58
import org.apache.log4j.Logger;
59
import org.dataone.service.types.v1.SystemMetadata;
60
import org.dataone.service.util.TypeMarshaller;
61
import org.xml.sax.InputSource;
62
import org.xml.sax.SAXException;
63
import org.xml.sax.XMLReader;
64

    
65
import edu.ucsb.nceas.metacat.DocInfoHandler;
66
import edu.ucsb.nceas.metacat.DocumentImpl;
67
import edu.ucsb.nceas.metacat.DocumentImplWrapper;
68
import edu.ucsb.nceas.metacat.EventLog;
69
import edu.ucsb.nceas.metacat.IdentifierManager;
70
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
71
import edu.ucsb.nceas.metacat.McdbException;
72
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlException;
73
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlForSingleFile;
74
import edu.ucsb.nceas.metacat.accesscontrol.PermOrderException;
75
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessDAO;
76
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
77
import edu.ucsb.nceas.metacat.database.DBConnection;
78
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
79
import edu.ucsb.nceas.metacat.database.DatabaseService;
80
import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService;
81
import edu.ucsb.nceas.metacat.properties.PropertyService;
82
import edu.ucsb.nceas.metacat.shared.BaseService;
83
import edu.ucsb.nceas.metacat.shared.HandlerException;
84
import edu.ucsb.nceas.metacat.shared.ServiceException;
85
import edu.ucsb.nceas.metacat.util.DocumentUtil;
86
import edu.ucsb.nceas.metacat.util.MetacatUtil;
87
import edu.ucsb.nceas.metacat.util.ReplicationUtil;
88
import edu.ucsb.nceas.metacat.util.SystemUtil;
89
import edu.ucsb.nceas.utilities.FileUtil;
90
import edu.ucsb.nceas.utilities.GeneralPropertyException;
91
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
92

    
93
public class ReplicationService extends BaseService {
94

    
95
	private static ReplicationService replicationService = null;
96

    
97
	private long timeInterval;
98
	private Date firstTime;
99
	private boolean timedReplicationIsOn = false;
100
	Timer replicationDaemon;
101
	private static Vector<String> fileLocks = new Vector<String>();
102
//	private Thread lockThread = null;
103
	public static final String FORCEREPLICATEDELETE = "forcereplicatedelete";
104
	private static String TIMEREPLICATION = "replication.timedreplication";
105
	private static String TIMEREPLICATIONINTERVAl ="replication.timedreplicationinterval";
106
	private static String FIRSTTIME = "replication.firsttimedreplication";
107
	private static final int TIMEINTERVALLIMIT = 7200000;
108
	public static final String REPLICATIONUSER = "replication";
109

    
110
	public static final String REPLICATION_LOG_FILE_NAME = "metacatreplication.log";
111
	public static String METACAT_REPL_ERROR_MSG = null;
112
	private static Logger logReplication = Logger.getLogger("ReplicationLogging");
113
	private static Logger logMetacat = Logger.getLogger(ReplicationService.class);
114

    
115
	private ReplicationService() throws ServiceException {
116
		_serviceName = "ReplicationService";
117
		
118
		initialize();
119
	}
120
	
121
	private void initialize() throws ServiceException {
122
				
123
		// initialize db connections to handle any update requests
124
		// deltaT = util.getProperty("replication.deltaT");
125
		// the default deltaT can be set from metacat.properties
126
		// create a thread to do the delta-T check but don't execute it yet
127
		replicationDaemon = new Timer(true);
128
		try {
129
			String replLogFile = PropertyService.getProperty("replication.logdir")
130
				+ FileUtil.getFS() + REPLICATION_LOG_FILE_NAME;
131
			METACAT_REPL_ERROR_MSG = "An error occurred in replication.  Please see the " +
132
				"replication log at: " + replLogFile;
133
			
134
			String timedRepIsOnStr = 
135
				PropertyService.getProperty("replication.timedreplication");
136
			timedReplicationIsOn = (new Boolean(timedRepIsOnStr)).booleanValue();
137
			logReplication.info("ReplicationService.initialize - The timed replication on is" + timedReplicationIsOn);
138

    
139
			String timeIntervalStr = 
140
				PropertyService.getProperty("replication.timedreplicationinterval");
141
			timeInterval = (new Long(timeIntervalStr)).longValue();
142
			logReplication.info("ReplicationService.initialize - The timed replication time Interval is " + timeInterval);
143

    
144
			String firstTimeStr = 
145
				PropertyService.getProperty("replication.firsttimedreplication");
146
			logReplication.info("ReplicationService.initialize - first replication time form property is " + firstTimeStr);
147
			firstTime = ReplicationHandler.combinateCurrentDateAndGivenTime(firstTimeStr);
148

    
149
			logReplication.info("ReplicationService.initialize - After combine current time, the real first time is "
150
					+ firstTime.toString() + " minisec");
151

    
152
			// set up time replication if it is on
153
			if (timedReplicationIsOn) {
154
				replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(),
155
						firstTime, timeInterval);
156
				logReplication.info("ReplicationService.initialize - deltaT handler started with rate="
157
						+ timeInterval + " mini seconds at " + firstTime.toString());
158
			}
159

    
160
		} catch (PropertyNotFoundException pnfe) {
161
			throw new ServiceException(
162
					"ReplicationService.initialize - Property error while instantiating "
163
							+ "replication service: " + pnfe.getMessage());
164
		} catch (HandlerException he) {
165
			throw new ServiceException(
166
					"ReplicationService.initialize - Handler error while instantiating "
167
							+ "replication service" + he.getMessage());
168
		} 
169
	}
170

    
171
	/**
172
	 * Get the single instance of SessionService.
173
	 * 
174
	 * @return the single instance of SessionService
175
	 */
176
	public static ReplicationService getInstance() throws ServiceException {
177
		if (replicationService == null) {
178
			replicationService = new ReplicationService();
179
		}
180
		return replicationService;
181
	}
182

    
183
	public boolean refreshable() {
184
		return true;
185
	}
186

    
187
	protected void doRefresh() throws ServiceException {
188
		return;
189
	}
190
	
191
	public void stop() throws ServiceException{
192
		
193
	}
194

    
195
	public void stopReplication() throws ServiceException {
196
	      //stop the replication server
197
	      replicationDaemon.cancel();
198
	      replicationDaemon = new Timer(true);
199
	      timedReplicationIsOn = false;
200
	      try {
201
	    	  PropertyService.setProperty("replication.timedreplication", (new Boolean(timedReplicationIsOn)).toString());
202
	      } catch (GeneralPropertyException gpe) {
203
	    	  logReplication.warn("ReplicationService.stopReplication - Could not set replication.timedreplication property: " + gpe.getMessage());
204
	      }
205

    
206
	      logReplication.info("ReplicationService.stopReplication - deltaT handler stopped");
207
		return;
208
	}
209
	
210
	protected void startReplication(Hashtable<String, String[]> params) throws ServiceException {
211

    
212
	       String firstTimeStr = "";
213
	      //start the replication server
214
	       if ( params.containsKey("rate") ) {
215
	        timeInterval = new Long(
216
	               new String(((String[])params.get("rate"))[0])).longValue();
217
	        if(timeInterval < TIMEINTERVALLIMIT) {
218
	            //deltaT<30 is a timing mess!
219
	            timeInterval = TIMEINTERVALLIMIT;
220
	            throw new ServiceException("Replication deltaT rate cannot be less than "+
221
	                    TIMEINTERVALLIMIT + " millisecs and system automatically setup the rate to "+TIMEINTERVALLIMIT);
222
	        }
223
	      } else {
224
	        timeInterval = TIMEINTERVALLIMIT ;
225
	      }
226
	      logReplication.info("ReplicationService.startReplication - New rate is: " + timeInterval + " mini seconds.");
227
	      if ( params.containsKey("firsttime"))
228
	      {
229
	         firstTimeStr = ((String[])params.get("firsttime"))[0];
230
	         try
231
	         {
232
	           firstTime = ReplicationHandler.combinateCurrentDateAndGivenTime(firstTimeStr);
233
	           logReplication.info("ReplicationService.startReplication - The first time setting is "+firstTime.toString());
234
	         }
235
	         catch (HandlerException e)
236
	         {
237
	            throw new ServiceException(e.getMessage());
238
	         }
239
	         logReplication.warn("After combine current time, the real first time is "
240
	                                  +firstTime.toString()+" minisec");
241
	      }
242
	      else
243
	      {
244
	    	  logMetacat.error("ReplicationService.startReplication - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
245
	          logReplication.error("ReplicationService.startReplication - You should specify the first time " +
246
	                                  "to start a time replication");
247
	          return;
248
	      }
249
	      
250
	      timedReplicationIsOn = true;
251
	      try {
252
	      // save settings to property file
253
	      PropertyService.setProperty(TIMEREPLICATION, (new Boolean(timedReplicationIsOn)).toString());
254
	      // note we couldn't use firstTime object because it has date info
255
	      // we only need time info such as 10:00 PM
256
	      PropertyService.setProperty(FIRSTTIME, firstTimeStr);
257
	      PropertyService.setProperty(TIMEREPLICATIONINTERVAl, (new Long(timeInterval)).toString());
258
	      } catch (GeneralPropertyException gpe) {
259
	    	  logReplication.warn("ReplicationService.startReplication - Could not set property: " + gpe.getMessage());
260
	      }
261
	      replicationDaemon.cancel();
262
	      replicationDaemon = new Timer(true);
263
	      replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(), firstTime,
264
	                                            timeInterval);
265
	      
266
	      logReplication.info("ReplicationService.startReplication - deltaT handler started with rate=" +
267
	                                    timeInterval + " milliseconds at " +firstTime.toString());
268

    
269
	}
270
	
271
	public void runOnce() throws ServiceException {
272
	      //updates this server exactly once
273
	      replicationDaemon.schedule(new ReplicationHandler(), 0);
274
	}
275

    
276
	/**
277
	 * This method can add, delete and list the servers currently included in
278
	 * xml_replication.
279
	 * action           subaction            other needed params
280
	 * ---------------------------------------------------------
281
	 * servercontrol    add                  server
282
	 * servercontrol    delete               server
283
	 * servercontrol    list
284
	 */
285
	protected static void handleServerControlRequest(
286
			Hashtable<String, String[]> params, HttpServletResponse response) {
287
		String subaction = ((String[]) params.get("subaction"))[0];
288
		DBConnection dbConn = null;
289
		int serialNumber = -1;
290
		PreparedStatement pstmt = null;
291
		String replicate = null;
292
		String server = null;
293
		String dataReplicate = null;
294
		String systemMetadataReplicate = null;
295
		String hub = null;
296
		Writer out = null;
297
		try {
298
			response.setContentType("text/xml");
299
			out = response.getWriter();
300
			
301
			//conn = util.openDBConnection();
302
			dbConn = DBConnectionPool
303
					.getDBConnection("MetacatReplication.handleServerControlRequest");
304
			serialNumber = dbConn.getCheckOutSerialNumber();
305

    
306
			// add server to server list
307
			if (subaction.equals("add")) {
308
				replicate = ((String[]) params.get("replicate"))[0];
309
				server = ((String[]) params.get("server"))[0];
310

    
311
				//Get data replication value
312
				dataReplicate = ((String[]) params.get("datareplicate"))[0];
313
				//Get system metadata replication value
314
				systemMetadataReplicate = ((String[]) params.get("systemmetadatareplicate"))[0];
315
				//Get hub value
316
				hub = ((String[]) params.get("hub"))[0];
317

    
318
				String toDateSql = DatabaseService.getInstance().getDBAdapter().toDate("01/01/1980","MM/DD/YYYY");
319
				String sql = "INSERT INTO xml_replication "
320
						+ "(server, last_checked, replicate, datareplicate, systemmetadatareplicate, hub) "
321
						+ "VALUES (?," + toDateSql + ",?,?,?,?)";
322
				
323
				pstmt = dbConn.prepareStatement(sql);
324
						
325
				pstmt.setString(1, server);
326
				pstmt.setInt(2, Integer.parseInt(replicate));
327
				pstmt.setInt(3, Integer.parseInt(dataReplicate));
328
				pstmt.setInt(4, Integer.parseInt(systemMetadataReplicate));
329
				pstmt.setInt(5, Integer.parseInt(hub));
330
				
331
				String sqlReport = "XMLAccessAccess.getXMLAccessForDoc - SQL: " + sql;
332
				sqlReport += " [" + server + "," + replicate + 
333
					"," + dataReplicate + "," + hub + "]";
334
				
335
				logMetacat.info(sqlReport);
336
				
337
				pstmt.execute();
338
				pstmt.close();
339
				dbConn.commit();
340
				out.write("Server " + server + " added");
341
				response.setContentType("text/html");
342
				out.write("<html><body><table border=\"1\">");
343
				out.write("<tr><td><b>server</b></td>");
344
				out.write("<td><b>last_checked</b></td>");
345
				out.write("<td><b>replicate</b></td>");
346
				out.write("<td><b>datareplicate</b></td>");
347
				out.write("<td><b>systemmetadatareplicate</b></td>");
348
				out.write("<td><b>hub</b></td></tr>");
349
				pstmt = dbConn.prepareStatement("SELECT serverid, server, last_checked, replicate, datareplicate, systemmetadatareplicate, hub FROM xml_replication");
350
				//increase dbconnection usage
351
				dbConn.increaseUsageCount(1);
352

    
353
				pstmt.execute();
354
				ResultSet rs = pstmt.getResultSet();
355
				boolean tablehasrows = rs.next();
356
				while (tablehasrows) {
357
					out.write("<tr><td>" + rs.getString(2) + "</td><td>");
358
					out.write(rs.getString(3) + "</td><td>");
359
					out.write(rs.getString(4) + "</td><td>");
360
					out.write(rs.getString(5) + "</td><td>");
361
					out.write(rs.getString(6) + "</td><td>");
362
					out.write(rs.getString(7) + "</td></tr>");
363

    
364
					tablehasrows = rs.next();
365
				}
366
				out.write("</table></body></html>");
367

    
368
				// download certificate with the public key on this server
369
				// and import it as a trusted certificate
370
				String certURL = ((String[]) params.get("certificate"))[0];
371
				if (certURL != null && !certURL.equals("")) {
372
					downloadCertificate(certURL);
373
				}
374

    
375
				// delete server from server list
376
			} else if (subaction.equals("delete")) {
377
				server = ((String[]) params.get("server"))[0];
378
				pstmt = dbConn.prepareStatement("DELETE FROM xml_replication "
379
						+ "WHERE server LIKE '" + server + "'");
380
				pstmt.execute();
381
				pstmt.close();
382
				dbConn.commit();
383
				out.write("Server " + server + " deleted");
384
				response.setContentType("text/html");
385
				out.write("<html><body><table border=\"1\">");
386
				out.write("<tr><td><b>server</b></td>");
387
				out.write("<td><b>last_checked</b></td>");
388
				out.write("<td><b>replicate</b></td>");
389
				out.write("<td><b>datareplicate</b></td>");
390
				out.write("<td><b>systemmetadatareplicate</b></td>");
391
				out.write("<td><b>hub</b></td></tr>");
392

    
393
				pstmt = dbConn.prepareStatement("SELECT serverid, server, last_checked, replicate, datareplicate, systemmetadatareplicate, hub FROM xml_replication");
394
				//increase dbconnection usage
395
				dbConn.increaseUsageCount(1);
396
				pstmt.execute();
397
				ResultSet rs = pstmt.getResultSet();
398
				boolean tablehasrows = rs.next();
399
				while (tablehasrows) {
400
					out.write("<tr><td>" + rs.getString(2) + "</td><td>");
401
					out.write(rs.getString(3) + "</td><td>");
402
					out.write(rs.getString(4) + "</td><td>");
403
					out.write(rs.getString(5) + "</td><td>");
404
					out.write(rs.getString(6) + "</td><td>");
405
					out.write(rs.getString(7) + "</td></tr>");
406
					tablehasrows = rs.next();
407
				}
408
				out.write("</table></body></html>");
409

    
410
				// list servers in server list
411
			} else if (subaction.equals("list")) {
412
				response.setContentType("text/html");
413
				out.write("<html><body><table border=\"1\">");
414
				out.write("<tr><td><b>server</b></td>");
415
				out.write("<td><b>last_checked</b></td>");
416
				out.write("<td><b>replicate</b></td>");
417
				out.write("<td><b>datareplicate</b></td>");
418
				out.write("<td><b>systemmetadatareplicate</b></td>");
419
				out.write("<td><b>hub</b></td></tr>");
420
				pstmt = dbConn.prepareStatement("SELECT serverid, server, last_checked, replicate, datareplicate, systemmetadatareplicate, hub FROM xml_replication");
421
				pstmt.execute();
422
				ResultSet rs = pstmt.getResultSet();
423
				boolean tablehasrows = rs.next();
424
				while (tablehasrows) {
425
					out.write("<tr><td>" + rs.getString(2) + "</td><td>");
426
					out.write(rs.getString(3) + "</td><td>");
427
					out.write(rs.getString(4) + "</td><td>");
428
					out.write(rs.getString(5) + "</td><td>");
429
					out.write(rs.getString(6) + "</td><td>");
430
					out.write(rs.getString(7) + "</td></tr>");
431

    
432
					tablehasrows = rs.next();
433
				}
434
				out.write("</table></body></html>");
435
			} else {
436

    
437
				out.write("<error>Unkonwn subaction</error>");
438

    
439
			}
440
			pstmt.close();
441
			//conn.close();
442

    
443
		} catch (Exception e) {
444
			logMetacat.error("ReplicationService.handleServerControlRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
445
			logReplication.error("ReplicationService.handleServerControlRequest - Error in "
446
					+ "MetacatReplication.handleServerControlRequest " + e.getMessage());
447
			e.printStackTrace(System.out);
448
		} finally {
449
			try {
450
				pstmt.close();
451
			}//try
452
			catch (SQLException ee) {
453
				logMetacat.error("ReplicationService.handleServerControlRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
454
				logReplication.error("ReplicationService.handleServerControlRequest - Error in MetacatReplication.handleServerControlRequest to close pstmt "
455
						+ ee.getMessage());
456
			}//catch
457
			finally {
458
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
459
			}//finally
460
			if (out != null) {
461
				try {
462
					out.close();
463
				} catch (IOException e) {
464
					logMetacat.error(e.getMessage(), e);
465
				}
466
			}
467
		}//finally
468

    
469
	}
470

    
471
	// download certificate with the public key from certURL and
472
	// upload it onto this server; it then must be imported as a
473
	// trusted certificate
474
	private static void downloadCertificate(String certURL) throws FileNotFoundException,
475
			IOException, MalformedURLException, PropertyNotFoundException {
476

    
477
		// the path to be uploaded to
478
		String certPath = SystemUtil.getContextDir();
479

    
480
		// get filename from the URL of the certificate
481
		String filename = certURL;
482
		int slash = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
483
		if (slash > -1) {
484
			filename = filename.substring(slash + 1);
485
		}
486

    
487
		// open file output strem to write the input into it
488
		File f = new File(certPath, filename);
489
		synchronized (f) {
490
			try {
491
				if (f.exists()) {
492
					throw new IOException("File already exist: " + f.getCanonicalFile());
493
					// if ( f.exists() && !f.canWrite() ) {
494
					// throw new IOException("Not writable: " +
495
					// f.getCanonicalFile());
496
				}
497
			} catch (SecurityException se) {
498
				// if a security manager exists,
499
				// its checkRead method is called for f.exist()
500
				// or checkWrite method is called for f.canWrite()
501
				throw se;
502
			}
503

    
504
			// create a buffered byte output stream
505
			// that uses a default-sized output buffer
506
			FileOutputStream fos = new FileOutputStream(f);
507
			BufferedOutputStream out = new BufferedOutputStream(fos);
508

    
509
			// this should be http url
510
			URL url = new URL(certURL);
511
			BufferedInputStream bis = null;
512
			try {
513
				bis = new BufferedInputStream(url.openStream());
514
				byte[] buf = new byte[4 * 1024]; // 4K buffer
515
				int b = bis.read(buf);
516
				while (b != -1) {
517
					out.write(buf, 0, b);
518
					b = bis.read(buf);
519
				}
520
			} finally {
521
				if (bis != null)
522
					bis.close();
523
			}
524
			// the input and the output streams must be closed
525
			bis.close();
526
			out.flush();
527
			out.close();
528
			fos.close();
529
		} // end of synchronized(f)
530
	}
531

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

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

    
565
			// get the document info from server
566
			URL docinfourl = new URL("https://" + server + "?server="
567
					+ MetacatUtil.getLocalReplicationServerName()
568
					+ "&action=getdocumentinfo&docid=" + docid);
569
			
570

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

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

    
637
				//process extra access rules before dealing with the write exception (doc exist already)			
638
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
639
		        if (accessControlList != null) {
640
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
641
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
642
		        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
643
		        			acfsf.insertPermissions(xmlAccessDAO);
644
							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
645
									+ " permissions added to DB");
646
		        		}
647
		            }
648
		        }
649
		        
650
		        // process the real owner and updater
651
				String user = (String) docinfoHash.get("user_owner");
652
				String updated = (String) docinfoHash.get("user_updated");
653
		        updateUserOwner(dbConn, docid, user, updated);
654

    
655
				logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid + " added to DB with "
656
						+ "action " + dbaction);
657
				
658
				EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER, docid, dbaction);
659
			}
660
		} catch (SQLException sqle) {
661
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
662
			logReplication.error("ReplicationService.handleForceReplicateRequest - SQL error when adding doc " + docid + 
663
					" to DB with action " + dbaction + ": " + sqle.getMessage());
664
		} catch (MalformedURLException mue) {
665
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
666
			logReplication.error("ReplicationService.handleForceReplicateRequest - URL error when adding doc " + docid + 
667
					" to DB with action " + dbaction + ": " + mue.getMessage());
668
		} catch (SAXException se) {
669
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
670
			logReplication.error("ReplicationService.handleForceReplicateRequest - SAX parsing error when adding doc " + docid + 
671
					" to DB with action " + dbaction + ": " + se.getMessage());
672
		} catch (HandlerException he) {
673
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
674
			logReplication.error("ReplicationService.handleForceReplicateRequest - Handler error when adding doc " + docid + 
675
					" to DB with action " + dbaction + ": " + he.getMessage());
676
		} catch (IOException ioe) {
677
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
678
			logReplication.error("ReplicationService.handleForceReplicateRequest - I/O error when adding doc " + docid + 
679
					" to DB with action " + dbaction + ": " + ioe.getMessage());
680
		} catch (PermOrderException poe) {
681
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
682
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
683
					" to DB with action " + dbaction + ": " + poe.getMessage());
684
		} catch (AccessControlException ace) {
685
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
686
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
687
					" to DB with action " + dbaction + ": " + ace.getMessage());
688
		} catch (Exception e) {
689
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
690
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when adding doc " + docid + 
691
					" to DB with action " + dbaction + ": " + e.getMessage());
692
		} finally {
693
			// Return the checked out DBConnection
694
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
695
		}//finally
696
	}
697

    
698
	/*
699
	 * when a forcereplication delete request comes in, local host will delete this
700
	 * document
701
	 */
702
	protected static void handleForceReplicateDeleteRequest(
703
			Hashtable<String, String[]> params, HttpServletResponse response,
704
			HttpServletRequest request) {
705
		String server = ((String[]) params.get("server"))[0]; // the server that
706
		String docid = ((String[]) params.get("docid"))[0]; // sent the document
707
		try {
708
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - force replication delete request from " + server);
709
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - force replication delete docid " + docid);
710
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - Force replication delete request from: " + server);
711
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - Force replication delete docid: " + docid);
712
			DocumentImpl.delete(docid, null, null, server);
713
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - document " + docid + " was successfully deleted ");
714
			EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER, docid,
715
					"delete");
716
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - document " + docid + " was successfully deleted ");
717
		} catch (McdbDocNotFoundException e) {
718
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
719
			logReplication.error("document " + docid
720
					+ " failed to delete because " + e.getMessage());
721
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
722
		} catch (InsufficientKarmaException e) {
723
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
724
			logReplication.error("document " + docid
725
					+ " failed to delete because " + e.getMessage());
726
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
727
		} catch (SQLException e) {
728
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
729
			logReplication.error("document " + docid
730
					+ " failed to delete because " + e.getMessage());
731
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
732
		} catch (Exception e) {
733
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
734
			logReplication.error("document " + docid
735
					+ " failed to delete because " + e.getMessage());
736
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
737

    
738
		}//catch
739

    
740
	}
741

    
742
	/**
743
	 * when a forcereplication data file request comes in, local host sends a
744
	 * readdata request to the requesting server (remote server) for the specified
745
	 * docid. Then store it in local database and file system
746
	 */
747
	protected static void handleForceReplicateDataFileRequest(Hashtable<String, String[]> params,
748
			HttpServletRequest request) {
749

    
750
		//make sure there is some parameters
751
		if (params.isEmpty()) {
752
			return;
753
		}
754
		// Get remote server
755
		String server = ((String[]) params.get("server"))[0];
756
		// the docid should include rev number
757
		String docid = ((String[]) params.get("docid"))[0];
758
		// Make sure there is a docid and server
759
		if (docid == null || server == null || server.equals("")) {
760
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
761
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Didn't specify docid or server for replication");
762
			return;
763
		}
764

    
765
		// Overide or not
766
		//    boolean override = false;
767
		// dbaction - update or insert
768
		String dbaction = null;
769

    
770
		try {
771
			//docid was switch to two parts uinque code and rev
772
			//String uniqueCode=MetacatUtil.getDocIdFromString(docid);
773
			//int rev=MetacatUtil.getVersionFromString(docid);
774
			if (params.containsKey("dbaction")) {
775
				dbaction = ((String[]) params.get("dbaction"))[0];
776
			} else//default value is update
777
			{
778
				dbaction = "update";
779
			}
780

    
781
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication request from: " + server);
782
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication docid: " + docid);
783
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication action: " + dbaction);
784
			// get the document info from server
785
			URL docinfourl = new URL("https://" + server + "?server="
786
					+ MetacatUtil.getLocalReplicationServerName()
787
					+ "&action=getdocumentinfo&docid=" + docid);
788

    
789
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
790
			
791
			// strip out the system metadata portion
792
		    String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
793
		   	docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);
794

    
795
			//dih is the parser for the docinfo xml format
796
			DocInfoHandler dih = new DocInfoHandler();
797
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
798
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
799
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
800
			
801
			String docName = (String) docinfoHash.get("docname");
802

    
803
			String docType = (String) docinfoHash.get("doctype");
804

    
805
			String docHomeServer = (String) docinfoHash.get("home_server");
806

    
807
			String createdDate = (String) docinfoHash.get("date_created");
808

    
809
			String updatedDate = (String) docinfoHash.get("date_updated");
810
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - docHomeServer of datafile: " + docHomeServer);
811

    
812
			if (dbaction.equals("insert") || dbaction.equals("update")) {
813
				//Get data file and store it into local file system.
814
				// sending back readdata request to server
815
				URL url = new URL("https://" + server + "?server="
816
						+ MetacatUtil.getLocalReplicationServerName()
817
						+ "&action=readdata&docid=" + docid);
818
				String datafilePath = PropertyService
819
						.getProperty("application.datafilepath");
820

    
821
				Exception writeException = null;
822
				//register data file into xml_documents table and wite data file
823
				//into file system
824
				try {
825
					DocumentImpl.writeDataFileInReplication(url.openStream(),
826
							datafilePath, docName, docType, docid, null, docHomeServer,
827
							server, DocumentImpl.DOCUMENTTABLE, false, createdDate,
828
							updatedDate);
829
				} catch (Exception e) {
830
					writeException = e;
831
				}
832
				
833
				// process the real owner and updater
834
				DBConnection dbConn = DBConnectionPool.getDBConnection("ReplicationService.handleForceDataFileRequest");
835
		        int serialNumber = dbConn.getCheckOutSerialNumber();
836
		        dbConn.setAutoCommit(false);
837
				String user = (String) docinfoHash.get("user_owner");
838
				String updated = (String) docinfoHash.get("user_updated");
839
		        updateUserOwner(dbConn, docid, user, updated);
840
		        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
841
		        
842
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
843
		        if (accessControlList != null) {
844
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
845
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
846
		        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
847
		        			acfsf.insertPermissions(xmlAccessDAO);
848
							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
849
									+ " permissions added to DB");
850
		        		}
851
		            }
852
		        }
853
		        
854
		        // process system metadata
855
		        if (systemMetadataXML != null) {
856
		      	  SystemMetadata sysMeta = 
857
		      		TypeMarshaller.unmarshalTypeFromStream(
858
		      				  SystemMetadata.class, 
859
		      				  new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
860
		      	  // need the guid-to-docid mapping
861
		      	  IdentifierManager.getInstance().createMapping(sysMeta.getIdentifier().getValue(), docid);
862
		        }
863

    
864
				if (writeException != null) {
865
					throw writeException;
866
				}
867

    
868
				logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - datafile " + docid + " added to DB with "
869
						+ "action " + dbaction);
870
				EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER,
871
						docid, dbaction);
872
			}
873

    
874
		} catch (Exception e) {
875
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
876
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Datafile " + docid
877
					+ " failed to added to DB with " + "action " + dbaction + " because "
878
					+ e.getMessage());
879
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - ERROR in MetacatReplication.handleForceDataFileReplicate"
880
					+ "Request(): " + e.getMessage());
881
		}
882
	}
883

    
884
	/**
885
	 * Grants or denies a lock to a requesting host.
886
	 * The servlet parameters of interrest are:
887
	 * docid: the docid of the file the lock is being requested for
888
	 * currentdate: the timestamp of the document on the remote server
889
	 *
890
	 */
891
	protected static void handleGetLockRequest(
892
			Hashtable<String, String[]> params, HttpServletResponse response) {
893

    
894
		try {
895

    
896
			String docid = ((String[]) params.get("docid"))[0];
897
			String remoteRev = ((String[]) params.get("updaterev"))[0];
898
			DocumentImpl requestDoc = new DocumentImpl(docid);
899
			logReplication.info("ReplicationService.handleGetLockRequest - lock request for " + docid);
900
			int localRevInt = requestDoc.getRev();
901
			int remoteRevInt = Integer.parseInt(remoteRev);
902

    
903
			// get a writer for sending back to response
904
			response.setContentType("text/xml");
905
			Writer out = response.getWriter();
906
			
907
			if (remoteRevInt >= localRevInt) {
908
				if (!fileLocks.contains(docid)) { //grant the lock if it is not already locked
909
					fileLocks.add(0, docid); //insert at the beginning of the queue Vector
910
					//send a message back to the the remote host authorizing the insert
911
					out.write("<lockgranted><docid>" + docid
912
									+ "</docid></lockgranted>");
913
					//          lockThread = new Thread(this);
914
					//          lockThread.setPriority(Thread.MIN_PRIORITY);
915
					//          lockThread.start();
916
					logReplication.info("ReplicationService.handleGetLockRequest - lock granted for " + docid);
917
				} else { //deny the lock
918
					out.write("<filelocked><docid>" + docid + "</docid></filelocked>");
919
					logReplication.info("ReplicationService.handleGetLockRequest - lock denied for " + docid
920
							+ "reason: file already locked");
921
				}
922
			} else {//deny the lock.
923
				out.write("<outdatedfile><docid>" + docid + "</docid></filelocked>");
924
				logReplication.info("ReplicationService.handleGetLockRequest - lock denied for " + docid
925
						+ "reason: client has outdated file");
926
			}
927
			out.close();
928
			//conn.close();
929
		} catch (Exception e) {
930
			logMetacat.error("ReplicationService.handleGetLockRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
931
			logReplication.error("ReplicationService.handleGetLockRequest - error requesting file lock from MetacatReplication."
932
					+ "handleGetLockRequest: " + e.getMessage());
933
			e.printStackTrace(System.out);
934
		}
935
	}
936

    
937
	/**
938
	 * Sends all of the xml_documents information encoded in xml to a requestor
939
	 * the format is:
940
	 * <!ELEMENT documentinfo (docid, docname, doctype, doctitle, user_owner,
941
	 *                  user_updated, home_server, public_access, rev)/>
942
	 * all of the subelements of document info are #PCDATA
943
	 */
944
	protected static void handleGetDocumentInfoRequest(
945
			Hashtable<String, String[]> params, HttpServletResponse response) {
946
		String docid = ((String[]) (params.get("docid")))[0];
947
		StringBuffer sb = new StringBuffer();
948

    
949
		try {
950
			DocumentImpl doc = new DocumentImpl(docid);
951
			sb.append("<documentinfo><docid>").append(docid);
952
			sb.append("</docid>");
953
			
954
			try {
955
				// serialize the System Metadata as XML for docinfo
956
				String guid = IdentifierManager.getInstance().getGUID(doc.getDocID(), doc.getRev());
957
				SystemMetadata systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
958
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
959
				TypeMarshaller.marshalTypeToOutputStream(systemMetadata, baos);
960
				String systemMetadataXML = baos.toString("UTF-8");
961
				sb.append("<systemMetadata>");
962
				sb.append(systemMetadataXML);
963
				sb.append("</systemMetadata>");
964
			} catch(McdbDocNotFoundException e) {
965
			  logMetacat.warn("No SystemMetadata found for: " + docid);
966
			}
967
			sb.append("<docname>").append(doc.getDocname());
968
			sb.append("</docname><doctype>").append(doc.getDoctype());
969
			sb.append("</doctype>");
970
			sb.append("<user_owner>").append(doc.getUserowner());
971
			sb.append("</user_owner><user_updated>").append(doc.getUserupdated());
972
			sb.append("</user_updated>");
973
			sb.append("<date_created>");
974
			sb.append(doc.getCreateDate());
975
			sb.append("</date_created>");
976
			sb.append("<date_updated>");
977
			sb.append(doc.getUpdateDate());
978
			sb.append("</date_updated>");
979
			sb.append("<home_server>");
980
			sb.append(doc.getDocHomeServer());
981
			sb.append("</home_server>");
982
			sb.append("<public_access>").append(doc.getPublicaccess());
983
			sb.append("</public_access><rev>").append(doc.getRev());
984
			sb.append("</rev>");
985

    
986
			sb.append("<accessControl>");
987

    
988
			AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid); 
989
			sb.append(acfsf.getAccessString());
990
			
991
			sb.append("</accessControl>");
992

    
993
			sb.append("</documentinfo>");
994
			// get a writer for sending back to response
995
			response.setContentType("text/xml");
996
			Writer out = response.getWriter();
997
			out.write(sb.toString());
998
			out.close();
999

    
1000
		} catch (Exception e) {
1001
			logMetacat.error("ReplicationService.handleGetDocumentInfoRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1002
			logReplication.error("ReplicationService.handleGetDocumentInfoRequest - error in metacatReplication.handlegetdocumentinforequest "
1003
					+ "for doc: " + docid + " : " + e.getMessage());
1004
		}
1005

    
1006
	}
1007
	
1008
	/**
1009
	 * Sends System Metadata as XML
1010
	 */
1011
	protected static void handleGetSystemMetadataRequest(
1012
			Hashtable<String, String[]> params, HttpServletResponse response) {
1013
		String guid = ((String[]) (params.get("guid")))[0];
1014
		String systemMetadataXML = null;
1015
		try {
1016
			
1017
			// serialize the System Metadata as XML 
1018
			SystemMetadata systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
1019
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
1020
			TypeMarshaller.marshalTypeToOutputStream(systemMetadata, baos);
1021
			systemMetadataXML = baos.toString("UTF-8");
1022
				
1023
			// get a writer for sending back to response
1024
			response.setContentType("text/xml");
1025
			Writer out = response.getWriter();
1026
			out.write(systemMetadataXML);
1027
			out.close();
1028

    
1029
		} catch (Exception e) {
1030
			String msg = "ReplicationService.handleGetSystemMetadataRequest for guid: " + guid + " : " + e.getMessage();
1031
			logMetacat.error(msg);                         
1032
			logReplication.error(msg);
1033
		}
1034

    
1035
	}
1036
	
1037
	/**
1038
	 * when a forcereplication request comes in, local host sends a read request
1039
	 * to the requesting server (remote server) for the specified docid. Then
1040
	 * store it in local database.
1041
	 */
1042
	protected static void handleForceReplicateSystemMetadataRequest(
1043
			Hashtable<String, String[]> params, HttpServletResponse response,
1044
			HttpServletRequest request) {
1045
		String server = ((String[]) params.get("server"))[0]; // the server that
1046
		String guid = ((String[]) params.get("guid"))[0]; // sent the document
1047
		
1048
		try {
1049
			logReplication.info("ReplicationService.handleForceReplicateSystemMetadataRequest - Force replication system metadata request from: " + server);
1050
			// get the system metadata from server
1051
			URL docinfourl = new URL("https://" + server + "?server="
1052
					+ MetacatUtil.getLocalReplicationServerName()
1053
					+ "&action=getsystemmetadata&guid=" + guid);
1054
			
1055
			String systemMetadataXML = ReplicationService.getURLContent(docinfourl);
1056
						
1057
			// process system metadata
1058
			if (systemMetadataXML != null) {
1059
				SystemMetadata sysMeta = 
1060
					TypeMarshaller.unmarshalTypeFromStream(
1061
							SystemMetadata.class,
1062
							new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
1063
				HazelcastService.getInstance().getSystemMetadataMap().put(sysMeta.getIdentifier(), sysMeta);
1064
			}
1065
      
1066
			logReplication.info("ReplicationService.handleForceReplicateSystemMetadataRequest - processed guid: " + guid);
1067
			EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), REPLICATIONUSER, guid, "systemMetadata");
1068

    
1069
		} catch (Exception e) {
1070
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG, e);                         
1071
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when processing guid: " + guid, e);
1072
		}
1073
	}
1074

    
1075
	/**
1076
	 * Sends a datafile to a remote host
1077
	 */
1078
	protected static void handleGetDataFileRequest(OutputStream outPut,
1079
			Hashtable<String, String[]> params, HttpServletResponse response)
1080

    
1081
	{
1082
		// File path for data file
1083
		String filepath;
1084
		// Request docid
1085
		String docId = ((String[]) (params.get("docid")))[0];
1086
		//check if the doicd is null
1087
		if (docId == null) {
1088
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1089
			logReplication.error("ReplicationService.handleGetDataFileRequest - Didn't specify docid for replication");
1090
			return;
1091
		}
1092

    
1093
		//try to open a https stream to test if the request server's public key
1094
		//in the key store, this is security issue
1095
		try {
1096
			filepath = PropertyService.getProperty("application.datafilepath");
1097
			String server = params.get("server")[0];
1098
			URL u = new URL("https://" + server + "?server="
1099
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test");
1100
			String test = ReplicationService.getURLContent(u);
1101
			//couldn't pass the test
1102
			if (test.indexOf("successfully") == -1) {
1103
				//response.setContentType("text/xml");
1104
				//outPut.println("<error>Couldn't pass the trust test</error>");
1105
				logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1106
				logReplication.error("ReplicationService.handleGetDataFileRequest - Couldn't pass the trust test");
1107
				return;
1108
			}
1109
		}//try
1110
		catch (Exception ee) {
1111
			return;
1112
		}//catch
1113

    
1114
		if (!filepath.endsWith("/")) {
1115
			filepath += "/";
1116
		}
1117
		// Get file aboslute file name
1118
		String filename = filepath + docId;
1119

    
1120
		//MIME type
1121
		String contentType = null;
1122
		if (filename.endsWith(".xml")) {
1123
			contentType = "text/xml";
1124
		} else if (filename.endsWith(".css")) {
1125
			contentType = "text/css";
1126
		} else if (filename.endsWith(".dtd")) {
1127
			contentType = "text/plain";
1128
		} else if (filename.endsWith(".xsd")) {
1129
			contentType = "text/xml";
1130
		} else if (filename.endsWith("/")) {
1131
			contentType = "text/html";
1132
		} else {
1133
			File f = new File(filename);
1134
			if (f.isDirectory()) {
1135
				contentType = "text/html";
1136
			} else {
1137
				contentType = "application/octet-stream";
1138
			}
1139
		}
1140

    
1141
		// Set the mime type
1142
		response.setContentType(contentType);
1143

    
1144
		// Get the content of the file
1145
		FileInputStream fin = null;
1146
		try {
1147
			// FileInputStream to metacat
1148
			fin = new FileInputStream(filename);
1149
			// 4K buffer
1150
			byte[] buf = new byte[4 * 1024];
1151
			// Read data from file input stream to byte array
1152
			int b = fin.read(buf);
1153
			// Write to outStream from byte array
1154
			while (b != -1) {
1155
				outPut.write(buf, 0, b);
1156
				b = fin.read(buf);
1157
			}
1158
			// close file input stream
1159
			fin.close();
1160

    
1161
		}//try
1162
		catch (Exception e) {
1163
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1164
			logReplication.error("ReplicationService.handleGetDataFileRequest - error getting data file from MetacatReplication."
1165
					+ "handlGetDataFileRequest " + e.getMessage());
1166
			e.printStackTrace(System.out);
1167
		}//catch
1168

    
1169
	}
1170

    
1171
	/**
1172
	 * Sends a document to a remote host
1173
	 */
1174
	protected static void handleGetDocumentRequest(
1175
			Hashtable<String, String[]> params, HttpServletResponse response) {
1176

    
1177
		String urlString = null;
1178
		String documentPath = null;
1179
		String errorMsg = null;
1180
		try {
1181
			// try to open a https stream to test if the request server's public
1182
			// key
1183
			// in the key store, this is security issue
1184
			String server = params.get("server")[0];
1185
			urlString = "https://" + server + "?server="
1186
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test";
1187
			URL u = new URL(urlString);
1188
			String test = ReplicationService.getURLContent(u);
1189
			// couldn't pass the test
1190
			if (test.indexOf("successfully") == -1) {
1191
				response.setContentType("text/xml");
1192
				Writer out = response.getWriter();
1193
				out.write("<error>Couldn't pass the trust test " + test + " </error>");
1194
				out.close();
1195
				return;
1196
			}
1197

    
1198
			String docid = params.get("docid")[0];
1199
			logReplication.debug("ReplicationService.handleGetDocumentRequest - MetacatReplication.handleGetDocumentRequest for docid: "
1200
					+ docid);
1201
			DocumentImpl di = new DocumentImpl(docid);
1202

    
1203
			String documentDir = PropertyService
1204
					.getProperty("application.documentfilepath");
1205
			documentPath = documentDir + FileUtil.getFS() + docid;
1206

    
1207
			// if the document does not exist on disk, read it from db and write
1208
			// it to disk.
1209
			if (FileUtil.getFileStatus(documentPath) == FileUtil.DOES_NOT_EXIST
1210
					|| FileUtil.getFileSize(documentPath) == 0) {
1211
				FileOutputStream fos = new FileOutputStream(documentPath);
1212
				di.toXml(fos, null, null, true);
1213
			}
1214

    
1215
			// read the file from disk and send it to outputstream
1216
			OutputStream outputStream = response.getOutputStream();
1217
			di.readFromFileSystem(outputStream, null, null, documentPath);
1218

    
1219
			logReplication.info("ReplicationService.handleGetDocumentRequest - document " + docid + " sent");
1220

    
1221
			// return to avoid continuing to the error reporting section at the end
1222
			return;
1223
			
1224
		} catch (MalformedURLException mue) {
1225
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1226
			logReplication.error("ReplicationService.handleGetDocumentRequest - Url error when getting document from MetacatReplication."
1227
					+ "handlGetDocumentRequest for url: " + urlString + " : "
1228
					+ mue.getMessage());
1229
			// e.printStackTrace(System.out);
1230
			
1231
		} catch (IOException ioe) {
1232
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1233
			logReplication.error("ReplicationService.handleGetDocumentRequest - I/O error when getting document from MetacatReplication."
1234
					+ "handlGetDocumentRequest for file: " + documentPath + " : "
1235
					+ ioe.getMessage());
1236
			errorMsg = ioe.getMessage();
1237
		} catch (PropertyNotFoundException pnfe) {
1238
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1239
			logReplication
1240
					.error("ReplicationService.handleGetDocumentRequest - Error getting property when getting document from MetacatReplication."
1241
							+ "handlGetDocumentRequest for file: "
1242
							+ documentPath
1243
							+ " : "
1244
							+ pnfe.getMessage());
1245
			// e.printStackTrace(System.out);
1246
			errorMsg = pnfe.getMessage();
1247
		} catch (McdbException me) {
1248
			logReplication
1249
					.error("ReplicationService.handleGetDocumentRequest - Document implementation error  getting property when getting document from MetacatReplication."
1250
							+ "handlGetDocumentRequest for file: "
1251
							+ documentPath
1252
							+ " : "
1253
							+ me.getMessage());
1254
			// e.printStackTrace(System.out);
1255
			errorMsg = me.getMessage();
1256
		}
1257
		
1258
		// report any errors if we got here
1259
		response.setContentType("text/xml");
1260
		Writer out = null;
1261
		try {
1262
			response.getWriter();
1263
			out = response.getWriter();
1264
			out.write("<error>" + errorMsg + "</error>");
1265
		} catch (Exception e) {
1266
			logMetacat.error(e.getMessage(), e);
1267
		} finally {
1268
			try {
1269
				out.close();
1270
			} catch (IOException e) {
1271
				logMetacat.error(e.getMessage(), e);
1272
			}
1273
		}
1274
		
1275

    
1276
	}
1277

    
1278
	/**
1279
	 * Sends a list of all of the documents on this sever along with their
1280
	 * revision numbers. The format is: <!ELEMENT replication (server, updates)>
1281
	 * <!ELEMENT server (#PCDATA)> <!ELEMENT updates ((updatedDocument |
1282
	 * deleteDocument | revisionDocument)*)> <!ELEMENT updatedDocument (docid,
1283
	 * rev, datafile*)> <!ELEMENT deletedDocument (docid, rev)> <!ELEMENT
1284
	 * revisionDocument (docid, rev, datafile*)> <!ELEMENT docid (#PCDATA)>
1285
	 * <!ELEMENT rev (#PCDATA)> <!ELEMENT datafile (#PCDATA)> note that the rev
1286
	 * in deletedDocument is always empty. I just left it in there to make the
1287
	 * parser implementation easier.
1288
	 */
1289
	protected static void handleUpdateRequest(Hashtable<String, String[]> params,
1290
			HttpServletResponse response) {
1291
		// Checked out DBConnection
1292
		DBConnection dbConn = null;
1293
		// DBConenction serial number when checked it out
1294
		int serialNumber = -1;
1295
		PreparedStatement pstmt = null;
1296
		// Server list to store server info of xml_replication table
1297
		ReplicationServerList serverList = null;
1298
		
1299
		// a writer for response
1300
		Writer out = null;
1301

    
1302
		try {
1303
			// get writer, TODO: encoding?
1304
			response.setContentType("text/xml");
1305
			out = response.getWriter();
1306
			
1307
			// Check out a DBConnection from pool
1308
			dbConn = DBConnectionPool
1309
					.getDBConnection("MetacatReplication.handleUpdateRequest");
1310
			serialNumber = dbConn.getCheckOutSerialNumber();
1311
			// Create a server list from xml_replication table
1312
			serverList = new ReplicationServerList();
1313

    
1314
			// Get remote server name from param
1315
			String server = ((String[]) params.get("server"))[0];
1316
			// If no servr name in param, return a error
1317
			if (server == null || server.equals("")) {
1318
				out.write("<error>Request didn't specify server name</error>");
1319
				out.close();
1320
				return;
1321
			}//if
1322

    
1323
			//try to open a https stream to test if the request server's public key
1324
			//in the key store, this is security issue
1325
			String testUrl = "https://" + server + "?server="
1326
            + MetacatUtil.getLocalReplicationServerName() + "&action=test";
1327
			logReplication.info("Running trust test: " + testUrl);
1328
			URL u = new URL(testUrl);
1329
			String test = ReplicationService.getURLContent(u);
1330
			logReplication.info("Ouput from test is '" + test + "'");
1331
			//couldn't pass the test
1332
			if (test.indexOf("successfully") == -1) {
1333
			    logReplication.error("Trust test failed.");
1334
				out.write("<error>Couldn't pass the trust test</error>");
1335
				out.close();
1336
				return;
1337
			}
1338
			logReplication.info("Trust test succeeded.");
1339

    
1340
			// Check if local host configure to replicate xml documents to remote
1341
			// server. If not send back a error message
1342
			if (!serverList.getReplicationValue(server)) {
1343
				out.write("<error>Configuration not allow to replicate document to you</error>");
1344
				out.close();
1345
				return;
1346
			}//if
1347

    
1348
			// Store the sql command
1349
			StringBuffer docsql = new StringBuffer();
1350
			StringBuffer revisionSql = new StringBuffer();
1351
			// Stroe the docid list
1352
			StringBuffer doclist = new StringBuffer();
1353
			// Store the deleted docid list
1354
			StringBuffer delsql = new StringBuffer();
1355
			// Store the data set file
1356
			Vector<Vector<String>> packageFiles = new Vector<Vector<String>>();
1357

    
1358
			// Append local server's name and replication servlet to doclist
1359
			doclist.append("<?xml version=\"1.0\"?><replication>");
1360
			doclist.append("<server>")
1361
					.append(MetacatUtil.getLocalReplicationServerName());
1362
			//doclist.append(util.getProperty("replicationpath"));
1363
			doclist.append("</server><updates>");
1364

    
1365
			// Get correct docid that reside on this server according the requesting
1366
			// server's replicate and data replicate value in xml_replication table
1367
			docsql.append(DatabaseService.getInstance().getDBAdapter().getReplicationDocumentListSQL());
1368
			//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)) ");
1369
			revisionSql.append("select docid, rev, doctype from xml_revisions ");
1370
			// If the localhost is not a hub to the remote server, only replicate
1371
			// the docid' which home server is local host (server_location =1)
1372
			if (!serverList.getHubValue(server)) {
1373
				String serverLocationDoc = " and a.server_location = 1";
1374
				String serverLocationRev = "where server_location = 1";
1375
				docsql.append(serverLocationDoc);
1376
				revisionSql.append(serverLocationRev);
1377
			}
1378
			logReplication.info("ReplicationService.handleUpdateRequest - Doc sql: " + docsql.toString());
1379

    
1380
			// Get any deleted documents
1381
			delsql.append("select distinct docid from ");
1382
			delsql.append("xml_revisions where docid not in (select docid from ");
1383
			delsql.append("xml_documents) ");
1384
			// If the localhost is not a hub to the remote server, only replicate
1385
			// the docid' which home server is local host (server_location =1)
1386
			if (!serverList.getHubValue(server)) {
1387
				delsql.append("and server_location = 1");
1388
			}
1389
			logReplication.info("ReplicationService.handleUpdateRequest - Deleted sql: " + delsql.toString());
1390

    
1391
			// Get docid list of local host
1392
			pstmt = dbConn.prepareStatement(docsql.toString());
1393
			pstmt.execute();
1394
			ResultSet rs = pstmt.getResultSet();
1395
			boolean tablehasrows = rs.next();
1396
			//If metacat configed to replicate data file
1397
			//if ((util.getProperty("replicationsenddata")).equals("on"))
1398
			boolean replicateData = serverList.getDataReplicationValue(server);
1399
			if (replicateData) {
1400
				while (tablehasrows) {
1401
					String recordDoctype = rs.getString(3);
1402
					Vector<String> packagedoctypes = MetacatUtil
1403
							.getOptionList(PropertyService
1404
									.getProperty("xml.packagedoctype"));
1405
					//if this is a package file, put it at the end
1406
					//because if a package file is read before all of the files it
1407
					//refers to are loaded then there is an error
1408
					if (recordDoctype != null && !packagedoctypes.contains(recordDoctype)) {
1409
						//If this is not data file
1410
						if (!recordDoctype.equals("BIN")) {
1411
							//for non-data file document
1412
							doclist.append("<updatedDocument>");
1413
							doclist.append("<docid>").append(rs.getString(1));
1414
							doclist.append("</docid><rev>").append(rs.getInt(2));
1415
							doclist.append("</rev>");
1416
							doclist.append("</updatedDocument>");
1417
						}//if
1418
						else {
1419
							//for data file document, in datafile attributes
1420
							//we put "datafile" value there
1421
							doclist.append("<updatedDocument>");
1422
							doclist.append("<docid>").append(rs.getString(1));
1423
							doclist.append("</docid><rev>").append(rs.getInt(2));
1424
							doclist.append("</rev>");
1425
							doclist.append("<datafile>");
1426
							doclist.append(PropertyService
1427
									.getProperty("replication.datafileflag"));
1428
							doclist.append("</datafile>");
1429
							doclist.append("</updatedDocument>");
1430
						}//else
1431
					}//if packagedoctpes
1432
					else { //the package files are saved to be put into the xml later.
1433
						Vector<String> v = new Vector<String>();
1434
						v.add(rs.getString(1));
1435
						v.add(String.valueOf(rs.getInt(2)));
1436
						packageFiles.add(v);
1437
					}//esle
1438
					tablehasrows = rs.next();
1439
				}//while
1440
			}//if
1441
			else //metacat was configured not to send data file
1442
			{
1443
				while (tablehasrows) {
1444
					String recordDoctype = rs.getString(3);
1445
					if (!recordDoctype.equals("BIN")) { //don't replicate data files
1446
						Vector<String> packagedoctypes = MetacatUtil
1447
								.getOptionList(PropertyService
1448
										.getProperty("xml.packagedoctype"));
1449
						if (recordDoctype != null
1450
								&& !packagedoctypes.contains(recordDoctype)) { //if this is a package file, put it at the end
1451
							//because if a package file is read before all of the files it
1452
							//refers to are loaded then there is an error
1453
							doclist.append("<updatedDocument>");
1454
							doclist.append("<docid>").append(rs.getString(1));
1455
							doclist.append("</docid><rev>").append(rs.getInt(2));
1456
							doclist.append("</rev>");
1457
							doclist.append("</updatedDocument>");
1458
						} else { //the package files are saved to be put into the xml later.
1459
							Vector<String> v = new Vector<String>();
1460
							v.add(rs.getString(1));
1461
							v.add(String.valueOf(rs.getInt(2)));
1462
							packageFiles.add(v);
1463
						}
1464
					}//if
1465
					tablehasrows = rs.next();
1466
				}//while
1467
			}//else
1468

    
1469
			pstmt = dbConn.prepareStatement(delsql.toString());
1470
			//usage count should increas 1
1471
			dbConn.increaseUsageCount(1);
1472

    
1473
			pstmt.execute();
1474
			rs = pstmt.getResultSet();
1475
			tablehasrows = rs.next();
1476
			while (tablehasrows) { //handle the deleted documents
1477
				doclist.append("<deletedDocument><docid>").append(rs.getString(1));
1478
				doclist.append("</docid><rev></rev></deletedDocument>");
1479
				//note that rev is always empty for deleted docs
1480
				tablehasrows = rs.next();
1481
			}
1482

    
1483
			//now we can put the package files into the xml results
1484
			for (int i = 0; i < packageFiles.size(); i++) {
1485
				Vector<String> v = packageFiles.elementAt(i);
1486
				doclist.append("<updatedDocument>");
1487
				doclist.append("<docid>").append(v.elementAt(0));
1488
				doclist.append("</docid><rev>");
1489
				doclist.append(v.elementAt(1));
1490
				doclist.append("</rev>");
1491
				doclist.append("</updatedDocument>");
1492
			}
1493
			// add revision doc list  
1494
			doclist.append(prepareRevisionDoc(dbConn, revisionSql.toString(),
1495
					replicateData));
1496
			
1497
			// add the system metadata entries if configured to replicate them
1498
			boolean replicateSystemMetadata = serverList.getSystemMetadataReplicationValue(server);
1499
			if (replicateSystemMetadata) {
1500
				Date since = new Date(System.currentTimeMillis());
1501
				since = serverList.getLastCheckedDate(server);
1502
				List<String> systemMetadataEntries = 
1503
					IdentifierManager.getInstance().getUpdatedSystemMetadataIds(since);
1504
				for (int i = 0; i < systemMetadataEntries.size(); i++) {
1505
					String guid = systemMetadataEntries.get(i);
1506
					doclist.append("<updatedSystemMetadata>");
1507
					doclist.append("<guid>");
1508
					doclist.append(guid);
1509
					doclist.append("</guid>");
1510
					doclist.append("</updatedSystemMetadata>");
1511
				}
1512
			}
1513

    
1514
			doclist.append("</updates></replication>");
1515
			logReplication.info("ReplicationService.handleUpdateRequest - doclist: " + doclist.toString());
1516
			pstmt.close();
1517
			//conn.close();
1518
			out.write(doclist.toString());
1519

    
1520
		} catch (Exception e) {
1521
			logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1522
			logReplication.error("ReplicationService.handleUpdateRequest - error in MetacatReplication." + "handleupdaterequest: "
1523
					+ e.getMessage());
1524
			//e.printStackTrace(System.out);
1525
			try {
1526
				out.write("<error>" + e.getMessage() + "</error>");
1527
			} catch (IOException e1) {
1528
				logMetacat.error(e1.getMessage(), e1);
1529
			}
1530
		} finally {
1531
			try {
1532
				pstmt.close();
1533
			}//try
1534
			catch (SQLException ee) {
1535
				logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1536
				logReplication.error("ReplicationService.handleUpdateRequest - Error in MetacatReplication."
1537
						+ "handleUpdaterequest to close pstmt: " + ee.getMessage());
1538
			}//catch
1539
			finally {
1540
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1541
			}//finally
1542
			try {
1543
				out.close();
1544
			} catch (IOException e) {
1545
				logMetacat.error(e.getMessage(), e);
1546
			}
1547
		}//finally
1548

    
1549
	}//handlUpdateRequest
1550

    
1551
	/**
1552
	 * 
1553
	 * @param dbConn connection for doing the update
1554
	 * @param docid the document id to update
1555
	 * @param owner the user_owner
1556
	 * @param updater the user_updated
1557
	 * @throws SQLException
1558
	 */
1559
	public static void updateUserOwner(DBConnection dbConn, String docid, String owner, String updater) throws SQLException {
1560
	
1561
		String sql = 
1562
			"UPDATE xml_documents " +
1563
			"SET user_owner = ?, " +
1564
			"user_updated = ? " +
1565
			"WHERE docid = ?;";
1566
		PreparedStatement pstmt = dbConn.prepareStatement(sql);
1567
		//usage count should increas 1
1568
		dbConn.increaseUsageCount(1);
1569

    
1570
		docid = DocumentUtil.getSmartDocId(docid);
1571
		pstmt.setString(1, owner);
1572
		pstmt.setString(2, updater);
1573
		pstmt.setString(3, docid);
1574
		pstmt.execute();
1575
		pstmt.close();
1576
		
1577
		dbConn.commit();
1578
	}
1579
	
1580
	/*
1581
	 * This method will get the xml string for document in xml_revision
1582
	 * The schema look like <!ELEMENT revisionDocument (docid, rev, datafile*)>
1583
	 */
1584
	private static String prepareRevisionDoc(DBConnection dbConn, String revSql,
1585
			boolean replicateData) throws Exception {
1586
		logReplication.warn("ReplicationService.prepareRevisionDoc - The revision document sql is " + revSql);
1587
		StringBuffer revDocList = new StringBuffer();
1588
		PreparedStatement pstmt = dbConn.prepareStatement(revSql);
1589
		//usage count should increas 1
1590
		dbConn.increaseUsageCount(1);
1591

    
1592
		pstmt.execute();
1593
		ResultSet rs = pstmt.getResultSet();
1594
		boolean tablehasrows = rs.next();
1595
		while (tablehasrows) {
1596
			String recordDoctype = rs.getString(3);
1597

    
1598
			//If this is data file and it isn't configured to replicate data
1599
			if (recordDoctype.equals("BIN") && !replicateData) {
1600
				// do nothing
1601
				continue;
1602
			} else {
1603

    
1604
				revDocList.append("<revisionDocument>");
1605
				revDocList.append("<docid>").append(rs.getString(1));
1606
				revDocList.append("</docid><rev>").append(rs.getInt(2));
1607
				revDocList.append("</rev>");
1608
				// data file
1609
				if (recordDoctype.equals("BIN")) {
1610
					revDocList.append("<datafile>");
1611
					revDocList.append(PropertyService
1612
							.getProperty("replication.datafileflag"));
1613
					revDocList.append("</datafile>");
1614
				}
1615
				revDocList.append("</revisionDocument>");
1616

    
1617
			}//else
1618
			tablehasrows = rs.next();
1619
		}
1620
		//System.out.println("The revision list is"+ revDocList.toString());
1621
		return revDocList.toString();
1622
	}
1623

    
1624
	/**
1625
	 * Returns the xml_catalog table encoded in xml
1626
	 */
1627
	public static String getCatalogXML() {
1628
		return handleGetCatalogRequest(null, null, false);
1629
	}
1630

    
1631
	/**
1632
	 * Sends the contents of the xml_catalog table encoded in xml
1633
	 * The xml format is:
1634
	 * <!ELEMENT xml_catalog (row*)>
1635
	 * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
1636
	 *                system_id)>
1637
	 * All of the sub elements of row are #PCDATA
1638

    
1639
	 * If printFlag == false then do not print to out.
1640
	 */
1641
	protected static String handleGetCatalogRequest(
1642
			Hashtable<String, String[]> params, HttpServletResponse response,
1643
			boolean printFlag) {
1644
		DBConnection dbConn = null;
1645
		int serialNumber = -1;
1646
		PreparedStatement pstmt = null;
1647
		Writer out = null;
1648
		try {
1649
			// get writer, TODO: encoding?
1650
		    if(printFlag)
1651
		    {
1652
		        response.setContentType("text/xml");
1653
		        out = response.getWriter();
1654
		    }
1655
			/*conn = MetacatReplication.getDBConnection("MetacatReplication." +
1656
			                                          "handleGetCatalogRequest");*/
1657
			dbConn = DBConnectionPool
1658
					.getDBConnection("MetacatReplication.handleGetCatalogRequest");
1659
			serialNumber = dbConn.getCheckOutSerialNumber();
1660
			pstmt = dbConn.prepareStatement("select entry_type, "
1661
					+ "source_doctype, target_doctype, public_id, "
1662
					+ "system_id from xml_catalog");
1663
			pstmt.execute();
1664
			ResultSet rs = pstmt.getResultSet();
1665
			boolean tablehasrows = rs.next();
1666
			StringBuffer sb = new StringBuffer();
1667
			sb.append("<?xml version=\"1.0\"?><xml_catalog>");
1668
			while (tablehasrows) {
1669
				sb.append("<row><entry_type>").append(rs.getString(1));
1670
				sb.append("</entry_type><source_doctype>").append(rs.getString(2));
1671
				sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
1672
				sb.append("</target_doctype><public_id>").append(rs.getString(4));
1673
				// system id may not have server url on front.  Add it if not.
1674
				String systemID = rs.getString(5);
1675
				if (!systemID.startsWith("http://")) {
1676
					systemID = SystemUtil.getContextURL() + systemID;
1677
				}
1678
				sb.append("</public_id><system_id>").append(systemID);
1679
				sb.append("</system_id></row>");
1680

    
1681
				tablehasrows = rs.next();
1682
			}
1683
			sb.append("</xml_catalog>");
1684
			//conn.close();
1685
			if (printFlag) {
1686
				response.setContentType("text/xml");
1687
				out.write(sb.toString());
1688
			}
1689
			pstmt.close();
1690
			return sb.toString();
1691
		} catch (Exception e) {
1692
			logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1693
			logReplication.error("ReplicationService.handleGetCatalogRequest - error in MetacatReplication.handleGetCatalogRequest:"
1694
					+ e.getMessage());
1695
			e.printStackTrace(System.out);
1696
			if (printFlag) {
1697
				try {
1698
					out.write("<error>" + e.getMessage() + "</error>");
1699
				} catch (IOException e1) {
1700
					logMetacat.error(e1.getMessage(), e1);
1701
				}
1702
			}
1703
		} finally {
1704
			try {
1705
				pstmt.close();
1706
			}//try
1707
			catch (SQLException ee) {
1708
				logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1709
				logReplication.error("ReplicationService.handleGetCatalogRequest - Error in MetacatReplication.handleGetCatalogRequest: "
1710
						+ ee.getMessage());
1711
			}//catch
1712
			finally {
1713
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1714
			}//finally
1715
			if (out != null) {
1716
				try {
1717
					out.close();
1718
				} catch (IOException e1) {
1719
					logMetacat.error(e1.getMessage(), e1);
1720
				}
1721
			}
1722
		}//finally
1723

    
1724
		return null;
1725
	}
1726

    
1727
	/**
1728
	 * Sends the current system date to the remote server.  Using this action
1729
	 * for replication gets rid of any problems with syncronizing clocks
1730
	 * because a time specific to a document is always kept on its home server.
1731
	 */
1732
	protected static void handleGetTimeRequest(
1733
			Hashtable<String, String[]> params, HttpServletResponse response) {
1734
		SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yy HH:mm:ss");
1735
		java.util.Date localtime = new java.util.Date();
1736
		String dateString = formatter.format(localtime);
1737
		
1738
		// get a writer for sending back to response
1739
		response.setContentType("text/xml");
1740
		Writer out = null;
1741
		try {
1742
			out = response.getWriter();
1743
			out.write("<timestamp>" + dateString + "</timestamp>");
1744
			out.close();
1745
		} catch (IOException e) {
1746
			logMetacat.error(e.getMessage(), e);
1747
		}
1748
		
1749
	}
1750

    
1751
	/**
1752
	 * this method handles the timeout for a file lock.  when a lock is
1753
	 * granted it is granted for 30 seconds.  When this thread runs out
1754
	 * it deletes the docid from the queue, thus eliminating the lock.
1755
	 */
1756
	public void run() {
1757
		try {
1758
			logReplication.info("ReplicationService.run - thread started for docid: "
1759
					+ (String) fileLocks.elementAt(0));
1760

    
1761
			Thread.sleep(30000); //the lock will expire in 30 seconds
1762
			logReplication.info("thread for docid: "
1763
					+ (String) fileLocks.elementAt(fileLocks.size() - 1) + " exiting.");
1764

    
1765
			fileLocks.remove(fileLocks.size() - 1);
1766
			//fileLocks is treated as a FIFO queue.  If there are more than one lock
1767
			//in the vector, the first one inserted will be removed.
1768
		} catch (Exception e) {
1769
			logMetacat.error("ReplicationService.run - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1770
			logReplication.error("ReplicationService.run - error in file lock thread from "
1771
					+ "MetacatReplication.run: " + e.getMessage());
1772
		}
1773
	}
1774

    
1775
	/**
1776
	 * Returns the name of a server given a serverCode
1777
	 * @param serverCode the serverid of the server
1778
	 * @return the servername or null if the specified serverCode does not
1779
	 *         exist.
1780
	 */
1781
	public static String getServerNameForServerCode(int serverCode) {
1782
		//System.out.println("serverid: " + serverCode);
1783
		DBConnection dbConn = null;
1784
		int serialNumber = -1;
1785
		PreparedStatement pstmt = null;
1786
		try {
1787
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServer");
1788
			serialNumber = dbConn.getCheckOutSerialNumber();
1789
			String sql = new String("select server from "
1790
					+ "xml_replication where serverid = " + serverCode);
1791
			pstmt = dbConn.prepareStatement(sql);
1792
			//System.out.println("getserver sql: " + sql);
1793
			pstmt.execute();
1794
			ResultSet rs = pstmt.getResultSet();
1795
			boolean tablehasrows = rs.next();
1796
			if (tablehasrows) {
1797
				//System.out.println("server: " + rs.getString(1));
1798
				return rs.getString(1);
1799
			}
1800

    
1801
			//conn.close();
1802
		} catch (Exception e) {
1803
			logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1804
			logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplication.getServer: " + e.getMessage());
1805
		} finally {
1806
			try {
1807
				pstmt.close();
1808
			}//try
1809
			catch (SQLException ee) {
1810
				logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1811
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacactReplication.getserver: "
1812
						+ ee.getMessage());
1813
			}//catch
1814
			finally {
1815
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1816
			}//fianlly
1817
		}//finally
1818

    
1819
		return null;
1820
		//return null if the server does not exist
1821
	}
1822

    
1823
	/**
1824
	 * Returns a server code given a server name
1825
	 * @param server the name of the server
1826
	 * @return integer > 0 representing the code of the server, 0 if the server
1827
	 *  does not exist.
1828
	 */
1829
	public static int getServerCodeForServerName(String server) throws ServiceException {
1830
		DBConnection dbConn = null;
1831
		int serialNumber = -1;
1832
		PreparedStatement pstmt = null;
1833
		int serverCode = 0;
1834

    
1835
		try {
1836

    
1837
			//conn = util.openDBConnection();
1838
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServerCode");
1839
			serialNumber = dbConn.getCheckOutSerialNumber();
1840
			pstmt = dbConn.prepareStatement("SELECT serverid FROM xml_replication "
1841
					+ "WHERE server LIKE '" + server + "'");
1842
			pstmt.execute();
1843
			ResultSet rs = pstmt.getResultSet();
1844
			boolean tablehasrows = rs.next();
1845
			if (tablehasrows) {
1846
				serverCode = rs.getInt(1);
1847
				pstmt.close();
1848
				//conn.close();
1849
				return serverCode;
1850
			}
1851

    
1852
		} catch (SQLException sqle) {
1853
			throw new ServiceException("ReplicationService.getServerCodeForServerName - " 
1854
					+ "SQL error when getting server code: " + sqle.getMessage());
1855

    
1856
		} finally {
1857
			try {
1858
				pstmt.close();
1859
				//conn.close();
1860
			}//try
1861
			catch (Exception ee) {
1862
				logMetacat.error("ReplicationService.getServerCodeForServerName - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1863
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplicatio.getServerCode: "
1864
						+ ee.getMessage());
1865

    
1866
			}//catch
1867
			finally {
1868
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1869
			}//finally
1870
		}//finally
1871

    
1872
		return serverCode;
1873
	}
1874

    
1875
	/**
1876
	 * Method to get a host server information for given docid
1877
	 * @param conn a connection to the database
1878
	 */
1879
	public static Hashtable<String, String> getHomeServerInfoForDocId(String docId) {
1880
		Hashtable<String, String> sl = new Hashtable<String, String>();
1881
		DBConnection dbConn = null;
1882
		int serialNumber = -1;
1883
		docId = DocumentUtil.getDocIdFromString(docId);
1884
		PreparedStatement pstmt = null;
1885
		int serverLocation;
1886
		try {
1887
			//get conection
1888
			dbConn = DBConnectionPool.getDBConnection("ReplicationHandler.getHomeServer");
1889
			serialNumber = dbConn.getCheckOutSerialNumber();
1890
			//get a server location from xml_document table
1891
			pstmt = dbConn.prepareStatement("select server_location from xml_documents "
1892
					+ "where docid = ?");
1893
			pstmt.setString(1, docId);
1894
			pstmt.execute();
1895
			ResultSet serverName = pstmt.getResultSet();
1896
			//get a server location
1897
			if (serverName.next()) {
1898
				serverLocation = serverName.getInt(1);
1899
				pstmt.close();
1900
			} else {
1901
				pstmt.close();
1902
				//ut.returnConnection(conn);
1903
				return null;
1904
			}
1905
			pstmt = dbConn.prepareStatement("select server, last_checked, replicate "
1906
					+ "from xml_replication where serverid = ?");
1907
			//increase usage count
1908
			dbConn.increaseUsageCount(1);
1909
			pstmt.setInt(1, serverLocation);
1910
			pstmt.execute();
1911
			ResultSet rs = pstmt.getResultSet();
1912
			boolean tableHasRows = rs.next();
1913
			if (tableHasRows) {
1914

    
1915
				String server = rs.getString(1);
1916
				String last_checked = rs.getString(2);
1917
				if (!server.equals("localhost")) {
1918
					sl.put(server, last_checked);
1919
				}
1920

    
1921
			} else {
1922
				pstmt.close();
1923
				//ut.returnConnection(conn);
1924
				return null;
1925
			}
1926
			pstmt.close();
1927
		} catch (Exception e) {
1928
			logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1929
			logReplication.error("ReplicationService.getHomeServerInfoForDocId - error in replicationHandler.getHomeServer(): "
1930
					+ e.getMessage());
1931
		} finally {
1932
			try {
1933
				pstmt.close();
1934
				//ut.returnConnection(conn);
1935
			} catch (Exception ee) {
1936
				logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1937
				logReplication.error("ReplicationService.getHomeServerInfoForDocId - Eror irn rplicationHandler.getHomeServer() "
1938
						+ "to close pstmt: " + ee.getMessage());
1939
			} finally {
1940
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1941
			}
1942

    
1943
		}//finally
1944
		return sl;
1945
	}
1946

    
1947
	/**
1948
	 * Returns a home server location  given a accnum
1949
	 * @param accNum , given accNum for a document
1950
	 *
1951
	 */
1952
	public static int getHomeServerCodeForDocId(String accNum) throws ServiceException {
1953
		DBConnection dbConn = null;
1954
		int serialNumber = -1;
1955
		PreparedStatement pstmt = null;
1956
		int serverCode = 1;
1957
		String docId = DocumentUtil.getDocIdFromString(accNum);
1958

    
1959
		try {
1960

    
1961
			// Get DBConnection
1962
			dbConn = DBConnectionPool
1963
					.getDBConnection("ReplicationHandler.getServerLocation");
1964
			serialNumber = dbConn.getCheckOutSerialNumber();
1965
			pstmt = dbConn.prepareStatement("SELECT server_location FROM xml_documents "
1966
					+ "WHERE docid LIKE '" + docId + "'");
1967
			pstmt.execute();
1968
			ResultSet rs = pstmt.getResultSet();
1969
			boolean tablehasrows = rs.next();
1970
			//If a document is find, return the server location for it
1971
			if (tablehasrows) {
1972
				serverCode = rs.getInt(1);
1973
				pstmt.close();
1974
				//conn.close();
1975
				return serverCode;
1976
			}
1977
			//if couldn't find in xml_documents table, we think server code is 1
1978
			//(this is new document)
1979
			else {
1980
				pstmt.close();
1981
				//conn.close();
1982
				return serverCode;
1983
			}
1984

    
1985
		} catch (SQLException sqle) {
1986
			throw new ServiceException("ReplicationService.getHomeServerCodeForDocId - " 
1987
					+ "SQL error when getting home server code for docid: " + docId + " : " 
1988
					+ sqle.getMessage());
1989

    
1990
		} finally {
1991
			try {
1992
				pstmt.close();
1993
				//conn.close();
1994

    
1995
			} catch (SQLException sqle) {
1996
				logMetacat.error("ReplicationService.getHomeServerCodeForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1997
				logReplication.error("ReplicationService.getHomeServerCodeForDocId - ReplicationService.getHomeServerCodeForDocId - " 
1998
						+ "SQL error when getting home server code for docid: " + docId + " : " 
1999
						+ sqle.getMessage());
2000
			} finally {
2001
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2002
			}//finally
2003
		}//finally
2004
		//return serverCode;
2005
	}
2006

    
2007
	/**
2008
	 * This method returns the content of a url
2009
	 * @param u the url to return the content from
2010
	 * @return a string representing the content of the url
2011
	 * @throws java.io.IOException
2012
	 */
2013
	public static String getURLContent(URL u) throws java.io.IOException {
2014
	    logReplication.info("Getting url content from " + u.toString());
2015
		char istreamChar;
2016
		int istreamInt;
2017
		logReplication.info("ReplicationService.getURLContent - Before open the stream" + u.toString());
2018
		InputStream input = u.openStream();
2019
		logReplication.info("ReplicationService.getURLContent - After open the stream" + u.toString());
2020
		InputStreamReader istream = new InputStreamReader(input);
2021
		StringBuffer serverResponse = new StringBuffer();
2022
		while ((istreamInt = istream.read()) != -1) {
2023
			istreamChar = (char) istreamInt;
2024
			serverResponse.append(istreamChar);
2025
		}
2026
		istream.close();
2027
		input.close();
2028

    
2029
		return serverResponse.toString();
2030
	}
2031

    
2032
//	/**
2033
//	 * Method for writing replication messages to a log file specified in
2034
//	 * metacat.properties
2035
//	 */
2036
//	public static void replLog(String message) {
2037
//		try {
2038
//			FileOutputStream fos = new FileOutputStream(PropertyService
2039
//					.getProperty("replication.logdir")
2040
//					+ "/metacatreplication.log", true);
2041
//			PrintWriter pw = new PrintWriter(fos);
2042
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
2043
//			java.util.Date localtime = new java.util.Date();
2044
//			String dateString = formatter.format(localtime);
2045
//			dateString += " :: " + message;
2046
//			// time stamp each entry
2047
//			pw.println(dateString);
2048
//			pw.flush();
2049
//		} catch (Exception e) {
2050
//			logReplication.error("error writing to replication log from "
2051
//					+ "MetacatReplication.replLog: " + e.getMessage());
2052
//			// e.printStackTrace(System.out);
2053
//		}
2054
//	}
2055

    
2056
//	/**
2057
//	 * Method for writing replication messages to a log file specified in
2058
//	 * metacat.properties
2059
//	 */
2060
//	public static void replErrorLog(String message) {
2061
//		try {
2062
//			FileOutputStream fos = new FileOutputStream(PropertyService
2063
//					.getProperty("replication.logdir")
2064
//					+ "/metacatreplicationerror.log", true);
2065
//			PrintWriter pw = new PrintWriter(fos);
2066
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
2067
//			java.util.Date localtime = new java.util.Date();
2068
//			String dateString = formatter.format(localtime);
2069
//			dateString += " :: " + message;
2070
//			//time stamp each entry
2071
//			pw.println(dateString);
2072
//			pw.flush();
2073
//		} catch (Exception e) {
2074
//			logReplication.error("error writing to replication error log from "
2075
//					+ "MetacatReplication.replErrorLog: " + e.getMessage());
2076
//			//e.printStackTrace(System.out);
2077
//		}
2078
//	}
2079

    
2080
	/**
2081
	 * Returns true if the replicate field for server in xml_replication is 1.
2082
	 * Returns false otherwise
2083
	 */
2084
	public static boolean replToServer(String server) {
2085
		DBConnection dbConn = null;
2086
		int serialNumber = -1;
2087
		PreparedStatement pstmt = null;
2088
		try {
2089
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.repltoServer");
2090
			serialNumber = dbConn.getCheckOutSerialNumber();
2091
			pstmt = dbConn.prepareStatement("select replicate from "
2092
					+ "xml_replication where server like '" + server + "'");
2093
			pstmt.execute();
2094
			ResultSet rs = pstmt.getResultSet();
2095
			boolean tablehasrows = rs.next();
2096
			if (tablehasrows) {
2097
				int i = rs.getInt(1);
2098
				if (i == 1) {
2099
					pstmt.close();
2100
					//conn.close();
2101
					return true;
2102
				} else {
2103
					pstmt.close();
2104
					//conn.close();
2105
					return false;
2106
				}
2107
			}
2108
		} catch (SQLException sqle) {
2109
			logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2110
			logReplication.error("ReplicationService.replToServer - SQL error in MetacatReplication.replToServer: "
2111
					+ sqle.getMessage());
2112
		} finally {
2113
			try {
2114
				pstmt.close();
2115
				//conn.close();
2116
			}//try
2117
			catch (Exception ee) {
2118
				logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2119
				logReplication.error("ReplicationService.replToServer - Error in MetacatReplication.replToServer: "
2120
						+ ee.getMessage());
2121
			}//catch
2122
			finally {
2123
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2124
			}//finally
2125
		}//finally
2126
		return false;
2127
		//the default if this server does not exist is to not replicate to it.
2128
	}
2129

    
2130
}
(7-7/8)