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-05-25 15:53:55 -0700 (Wed, 25 May 2011) $'
10
 * '$Revision: 6102 $'
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.Enumeration;
51
import java.util.Hashtable;
52
import java.util.Timer;
53
import java.util.Vector;
54

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

    
58
import org.apache.log4j.Logger;
59
import org.dataone.service.types.SystemMetadata;
60
import org.dataone.service.types.util.ServiceTypeUtil;
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.properties.PropertyService;
81
import edu.ucsb.nceas.metacat.shared.BaseService;
82
import edu.ucsb.nceas.metacat.shared.HandlerException;
83
import edu.ucsb.nceas.metacat.shared.ServiceException;
84
import edu.ucsb.nceas.metacat.util.DocumentUtil;
85
import edu.ucsb.nceas.metacat.util.MetacatUtil;
86
import edu.ucsb.nceas.metacat.util.ReplicationUtil;
87
import edu.ucsb.nceas.metacat.util.SystemUtil;
88
import edu.ucsb.nceas.utilities.FileUtil;
89
import edu.ucsb.nceas.utilities.GeneralPropertyException;
90
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
91

    
92
public class ReplicationService extends BaseService {
93

    
94
	private static ReplicationService replicationService = null;
95

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
309
				//Get data replication value
310
				dataReplicate = ((String[]) params.get("datareplicate"))[0];
311
				//Get hub value
312
				hub = ((String[]) params.get("hub"))[0];
313

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

    
346
				pstmt.execute();
347
				ResultSet rs = pstmt.getResultSet();
348
				boolean tablehasrows = rs.next();
349
				while (tablehasrows) {
350
					out.write("<tr><td>" + rs.getString(2) + "</td><td>");
351
					out.write(rs.getString(3) + "</td><td>");
352
					out.write(rs.getString(4) + "</td><td>");
353
					out.write(rs.getString(5) + "</td><td>");
354
					out.write(rs.getString(6) + "</td></tr>");
355

    
356
					tablehasrows = rs.next();
357
				}
358
				out.write("</table></body></html>");
359

    
360
				// download certificate with the public key on this server
361
				// and import it as a trusted certificate
362
				String certURL = ((String[]) params.get("certificate"))[0];
363
				if (certURL != null && !certURL.equals("")) {
364
					downloadCertificate(certURL);
365
				}
366

    
367
				// delete server from server list
368
			} else if (subaction.equals("delete")) {
369
				server = ((String[]) params.get("server"))[0];
370
				pstmt = dbConn.prepareStatement("DELETE FROM xml_replication "
371
						+ "WHERE server LIKE '" + server + "'");
372
				pstmt.execute();
373
				pstmt.close();
374
				dbConn.commit();
375
				out.write("Server " + server + " deleted");
376
				response.setContentType("text/html");
377
				out.write("<html><body><table border=\"1\">");
378
				out.write("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
379
				out.write("<b>replicate</b></td>");
380
				out.write("<td><b>datareplicate</b></td>");
381
				out.write("<td><b>hub</b></td></tr>");
382

    
383
				pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
384
				//increase dbconnection usage
385
				dbConn.increaseUsageCount(1);
386
				pstmt.execute();
387
				ResultSet rs = pstmt.getResultSet();
388
				boolean tablehasrows = rs.next();
389
				while (tablehasrows) {
390
					out.write("<tr><td>" + rs.getString(2) + "</td><td>");
391
					out.write(rs.getString(3) + "</td><td>");
392
					out.write(rs.getString(4) + "</td><td>");
393
					out.write(rs.getString(5) + "</td><td>");
394
					out.write(rs.getString(6) + "</td></tr>");
395
					tablehasrows = rs.next();
396
				}
397
				out.write("</table></body></html>");
398

    
399
				// list servers in server list
400
			} else if (subaction.equals("list")) {
401
				response.setContentType("text/html");
402
				out.write("<html><body><table border=\"1\">");
403
				out.write("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
404
				out.write("<b>replicate</b></td>");
405
				out.write("<td><b>datareplicate</b></td>");
406
				out.write("<td><b>hub</b></td></tr>");
407
				pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
408
				pstmt.execute();
409
				ResultSet rs = pstmt.getResultSet();
410
				boolean tablehasrows = rs.next();
411
				while (tablehasrows) {
412
					out.write("<tr><td>" + rs.getString(2) + "</td><td>");
413
					out.write(rs.getString(3) + "</td><td>");
414
					out.write(rs.getString(4) + "</td><td>");
415
					out.write(rs.getString(5) + "</td><td>");
416
					out.write(rs.getString(6) + "</td></tr>");
417
					tablehasrows = rs.next();
418
				}
419
				out.write("</table></body></html>");
420
			} else {
421

    
422
				out.write("<error>Unkonwn subaction</error>");
423

    
424
			}
425
			pstmt.close();
426
			//conn.close();
427

    
428
		} catch (Exception e) {
429
			logMetacat.error("ReplicationService.handleServerControlRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
430
			logReplication.error("ReplicationService.handleServerControlRequest - Error in "
431
					+ "MetacatReplication.handleServerControlRequest " + e.getMessage());
432
			e.printStackTrace(System.out);
433
		} finally {
434
			try {
435
				pstmt.close();
436
			}//try
437
			catch (SQLException ee) {
438
				logMetacat.error("ReplicationService.handleServerControlRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
439
				logReplication.error("ReplicationService.handleServerControlRequest - Error in MetacatReplication.handleServerControlRequest to close pstmt "
440
						+ ee.getMessage());
441
			}//catch
442
			finally {
443
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
444
			}//finally
445
			if (out != null) {
446
				try {
447
					out.close();
448
				} catch (IOException e) {
449
					logMetacat.error(e.getMessage(), e);
450
				}
451
			}
452
		}//finally
453

    
454
	}
455

    
456
	// download certificate with the public key from certURL and
457
	// upload it onto this server; it then must be imported as a
458
	// trusted certificate
459
	private static void downloadCertificate(String certURL) throws FileNotFoundException,
460
			IOException, MalformedURLException, PropertyNotFoundException {
461

    
462
		// the path to be uploaded to
463
		String certPath = SystemUtil.getContextDir();
464

    
465
		// get filename from the URL of the certificate
466
		String filename = certURL;
467
		int slash = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
468
		if (slash > -1) {
469
			filename = filename.substring(slash + 1);
470
		}
471

    
472
		// open file output strem to write the input into it
473
		File f = new File(certPath, filename);
474
		synchronized (f) {
475
			try {
476
				if (f.exists()) {
477
					throw new IOException("File already exist: " + f.getCanonicalFile());
478
					// if ( f.exists() && !f.canWrite() ) {
479
					// throw new IOException("Not writable: " +
480
					// f.getCanonicalFile());
481
				}
482
			} catch (SecurityException se) {
483
				// if a security manager exists,
484
				// its checkRead method is called for f.exist()
485
				// or checkWrite method is called for f.canWrite()
486
				throw se;
487
			}
488

    
489
			// create a buffered byte output stream
490
			// that uses a default-sized output buffer
491
			FileOutputStream fos = new FileOutputStream(f);
492
			BufferedOutputStream out = new BufferedOutputStream(fos);
493

    
494
			// this should be http url
495
			URL url = new URL(certURL);
496
			BufferedInputStream bis = null;
497
			try {
498
				bis = new BufferedInputStream(url.openStream());
499
				byte[] buf = new byte[4 * 1024]; // 4K buffer
500
				int b = bis.read(buf);
501
				while (b != -1) {
502
					out.write(buf, 0, b);
503
					b = bis.read(buf);
504
				}
505
			} finally {
506
				if (bis != null)
507
					bis.close();
508
			}
509
			// the input and the output streams must be closed
510
			bis.close();
511
			out.flush();
512
			out.close();
513
			fos.close();
514
		} // end of synchronized(f)
515
	}
516

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

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

    
550
			// get the document info from server
551
			URL docinfourl = new URL("https://" + server + "?server="
552
					+ MetacatUtil.getLocalReplicationServerName()
553
					+ "&action=getdocumentinfo&docid=" + docid);
554
			
555

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

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

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

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

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

    
736
		}//catch
737

    
738
	}
739

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

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

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

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

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

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

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

    
801
			String docType = (String) docinfoHash.get("doctype");
802

    
803
			String docHomeServer = (String) docinfoHash.get("home_server");
804

    
805
			String createdDate = (String) docinfoHash.get("date_created");
806

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

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

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

    
870
				if (writeException != null) {
871
					throw writeException;
872
				}
873

    
874
				logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - datafile " + docid + " added to DB with "
875
						+ "action " + dbaction);
876
				EventLog.getInstance().log(request.getRemoteAddr(), REPLICATIONUSER,
877
						docid, dbaction);
878
			}
879

    
880
		} catch (Exception e) {
881
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
882
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Datafile " + docid
883
					+ " failed to added to DB with " + "action " + dbaction + " because "
884
					+ e.getMessage());
885
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - ERROR in MetacatReplication.handleForceDataFileReplicate"
886
					+ "Request(): " + e.getMessage());
887
		}
888
	}
889

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

    
900
		try {
901

    
902
			String docid = ((String[]) params.get("docid"))[0];
903
			String remoteRev = ((String[]) params.get("updaterev"))[0];
904
			DocumentImpl requestDoc = new DocumentImpl(docid);
905
			logReplication.info("ReplicationService.handleGetLockRequest - lock request for " + docid);
906
			int localRevInt = requestDoc.getRev();
907
			int remoteRevInt = Integer.parseInt(remoteRev);
908

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

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

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

    
992
			sb.append("<accessControl>");
993

    
994
			AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid); 
995
			sb.append(acfsf.getAccessString());
996
			
997
			sb.append("</accessControl>");
998

    
999
			sb.append("</documentinfo>");
1000
			// get a writer for sending back to response
1001
			response.setContentType("text/xml");
1002
			Writer out = response.getWriter();
1003
			out.write(sb.toString());
1004
			out.close();
1005

    
1006
		} catch (Exception e) {
1007
			logMetacat.error("ReplicationService.handleGetDocumentInfoRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1008
			logReplication.error("ReplicationService.handleGetDocumentInfoRequest - error in metacatReplication.handlegetdocumentinforequest "
1009
					+ "for doc: " + docid + " : " + e.getMessage());
1010
		}
1011

    
1012
	}
1013

    
1014
	/**
1015
	 * Sends a datafile to a remote host
1016
	 */
1017
	protected static void handleGetDataFileRequest(OutputStream outPut,
1018
			Hashtable<String, String[]> params, HttpServletResponse response)
1019

    
1020
	{
1021
		// File path for data file
1022
		String filepath;
1023
		// Request docid
1024
		String docId = ((String[]) (params.get("docid")))[0];
1025
		//check if the doicd is null
1026
		if (docId == null) {
1027
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1028
			logReplication.error("ReplicationService.handleGetDataFileRequest - Didn't specify docid for replication");
1029
			return;
1030
		}
1031

    
1032
		//try to open a https stream to test if the request server's public key
1033
		//in the key store, this is security issue
1034
		try {
1035
			filepath = PropertyService.getProperty("application.datafilepath");
1036
			String server = params.get("server")[0];
1037
			URL u = new URL("https://" + server + "?server="
1038
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test");
1039
			String test = ReplicationService.getURLContent(u);
1040
			//couldn't pass the test
1041
			if (test.indexOf("successfully") == -1) {
1042
				//response.setContentType("text/xml");
1043
				//outPut.println("<error>Couldn't pass the trust test</error>");
1044
				logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1045
				logReplication.error("ReplicationService.handleGetDataFileRequest - Couldn't pass the trust test");
1046
				return;
1047
			}
1048
		}//try
1049
		catch (Exception ee) {
1050
			return;
1051
		}//catch
1052

    
1053
		if (!filepath.endsWith("/")) {
1054
			filepath += "/";
1055
		}
1056
		// Get file aboslute file name
1057
		String filename = filepath + docId;
1058

    
1059
		//MIME type
1060
		String contentType = null;
1061
		if (filename.endsWith(".xml")) {
1062
			contentType = "text/xml";
1063
		} else if (filename.endsWith(".css")) {
1064
			contentType = "text/css";
1065
		} else if (filename.endsWith(".dtd")) {
1066
			contentType = "text/plain";
1067
		} else if (filename.endsWith(".xsd")) {
1068
			contentType = "text/xml";
1069
		} else if (filename.endsWith("/")) {
1070
			contentType = "text/html";
1071
		} else {
1072
			File f = new File(filename);
1073
			if (f.isDirectory()) {
1074
				contentType = "text/html";
1075
			} else {
1076
				contentType = "application/octet-stream";
1077
			}
1078
		}
1079

    
1080
		// Set the mime type
1081
		response.setContentType(contentType);
1082

    
1083
		// Get the content of the file
1084
		FileInputStream fin = null;
1085
		try {
1086
			// FileInputStream to metacat
1087
			fin = new FileInputStream(filename);
1088
			// 4K buffer
1089
			byte[] buf = new byte[4 * 1024];
1090
			// Read data from file input stream to byte array
1091
			int b = fin.read(buf);
1092
			// Write to outStream from byte array
1093
			while (b != -1) {
1094
				outPut.write(buf, 0, b);
1095
				b = fin.read(buf);
1096
			}
1097
			// close file input stream
1098
			fin.close();
1099

    
1100
		}//try
1101
		catch (Exception e) {
1102
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1103
			logReplication.error("ReplicationService.handleGetDataFileRequest - error getting data file from MetacatReplication."
1104
					+ "handlGetDataFileRequest " + e.getMessage());
1105
			e.printStackTrace(System.out);
1106
		}//catch
1107

    
1108
	}
1109

    
1110
	/**
1111
	 * Sends a document to a remote host
1112
	 */
1113
	protected static void handleGetDocumentRequest(
1114
			Hashtable<String, String[]> params, HttpServletResponse response) {
1115

    
1116
		String urlString = null;
1117
		String documentPath = null;
1118
		String errorMsg = null;
1119
		try {
1120
			// try to open a https stream to test if the request server's public
1121
			// key
1122
			// in the key store, this is security issue
1123
			String server = params.get("server")[0];
1124
			urlString = "https://" + server + "?server="
1125
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test";
1126
			URL u = new URL(urlString);
1127
			String test = ReplicationService.getURLContent(u);
1128
			// couldn't pass the test
1129
			if (test.indexOf("successfully") == -1) {
1130
				response.setContentType("text/xml");
1131
				Writer out = response.getWriter();
1132
				out.write("<error>Couldn't pass the trust test " + test + " </error>");
1133
				out.close();
1134
				return;
1135
			}
1136

    
1137
			String docid = params.get("docid")[0];
1138
			logReplication.debug("ReplicationService.handleGetDocumentRequest - MetacatReplication.handleGetDocumentRequest for docid: "
1139
					+ docid);
1140
			DocumentImpl di = new DocumentImpl(docid);
1141

    
1142
			String documentDir = PropertyService
1143
					.getProperty("application.documentfilepath");
1144
			documentPath = documentDir + FileUtil.getFS() + docid;
1145

    
1146
			// if the document does not exist on disk, read it from db and write
1147
			// it to disk.
1148
			if (FileUtil.getFileStatus(documentPath) == FileUtil.DOES_NOT_EXIST
1149
					|| FileUtil.getFileSize(documentPath) == 0) {
1150
				FileOutputStream fos = new FileOutputStream(documentPath);
1151
				di.toXml(fos, null, null, true);
1152
			}
1153

    
1154
			// read the file from disk and send it to outputstream
1155
			OutputStream outputStream = response.getOutputStream();
1156
			di.readFromFileSystem(outputStream, null, null, documentPath);
1157

    
1158
			logReplication.info("ReplicationService.handleGetDocumentRequest - document " + docid + " sent");
1159

    
1160
			// return to avoid continuing to the error reporting section at the end
1161
			return;
1162
			
1163
		} catch (MalformedURLException mue) {
1164
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1165
			logReplication.error("ReplicationService.handleGetDocumentRequest - Url error when getting document from MetacatReplication."
1166
					+ "handlGetDocumentRequest for url: " + urlString + " : "
1167
					+ mue.getMessage());
1168
			// e.printStackTrace(System.out);
1169
			
1170
		} catch (IOException ioe) {
1171
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1172
			logReplication.error("ReplicationService.handleGetDocumentRequest - I/O error when getting document from MetacatReplication."
1173
					+ "handlGetDocumentRequest for file: " + documentPath + " : "
1174
					+ ioe.getMessage());
1175
			errorMsg = ioe.getMessage();
1176
		} catch (PropertyNotFoundException pnfe) {
1177
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1178
			logReplication
1179
					.error("ReplicationService.handleGetDocumentRequest - Error getting property when getting document from MetacatReplication."
1180
							+ "handlGetDocumentRequest for file: "
1181
							+ documentPath
1182
							+ " : "
1183
							+ pnfe.getMessage());
1184
			// e.printStackTrace(System.out);
1185
			errorMsg = pnfe.getMessage();
1186
		} catch (McdbException me) {
1187
			logReplication
1188
					.error("ReplicationService.handleGetDocumentRequest - Document implementation error  getting property when getting document from MetacatReplication."
1189
							+ "handlGetDocumentRequest for file: "
1190
							+ documentPath
1191
							+ " : "
1192
							+ me.getMessage());
1193
			// e.printStackTrace(System.out);
1194
			errorMsg = me.getMessage();
1195
		}
1196
		
1197
		// report any errors if we got here
1198
		response.setContentType("text/xml");
1199
		Writer out = null;
1200
		try {
1201
			response.getWriter();
1202
			out = response.getWriter();
1203
			out.write("<error>" + errorMsg + "</error>");
1204
		} catch (Exception e) {
1205
			logMetacat.error(e.getMessage(), e);
1206
		} finally {
1207
			try {
1208
				out.close();
1209
			} catch (IOException e) {
1210
				logMetacat.error(e.getMessage(), e);
1211
			}
1212
		}
1213
		
1214

    
1215
	}
1216

    
1217
	/**
1218
	 * Sends a list of all of the documents on this sever along with their
1219
	 * revision numbers. The format is: <!ELEMENT replication (server, updates)>
1220
	 * <!ELEMENT server (#PCDATA)> <!ELEMENT updates ((updatedDocument |
1221
	 * deleteDocument | revisionDocument)*)> <!ELEMENT updatedDocument (docid,
1222
	 * rev, datafile*)> <!ELEMENT deletedDocument (docid, rev)> <!ELEMENT
1223
	 * revisionDocument (docid, rev, datafile*)> <!ELEMENT docid (#PCDATA)>
1224
	 * <!ELEMENT rev (#PCDATA)> <!ELEMENT datafile (#PCDATA)> note that the rev
1225
	 * in deletedDocument is always empty. I just left it in there to make the
1226
	 * parser implementation easier.
1227
	 */
1228
	protected static void handleUpdateRequest(Hashtable<String, String[]> params,
1229
			HttpServletResponse response) {
1230
		// Checked out DBConnection
1231
		DBConnection dbConn = null;
1232
		// DBConenction serial number when checked it out
1233
		int serialNumber = -1;
1234
		PreparedStatement pstmt = null;
1235
		// Server list to store server info of xml_replication table
1236
		ReplicationServerList serverList = null;
1237
		
1238
		// a writer for response
1239
		Writer out = null;
1240

    
1241
		try {
1242
			// get writer, TODO: encoding?
1243
			response.setContentType("text/xml");
1244
			out = response.getWriter();
1245
			
1246
			// Check out a DBConnection from pool
1247
			dbConn = DBConnectionPool
1248
					.getDBConnection("MetacatReplication.handleUpdateRequest");
1249
			serialNumber = dbConn.getCheckOutSerialNumber();
1250
			// Create a server list from xml_replication table
1251
			serverList = new ReplicationServerList();
1252

    
1253
			// Get remote server name from param
1254
			String server = ((String[]) params.get("server"))[0];
1255
			// If no servr name in param, return a error
1256
			if (server == null || server.equals("")) {
1257
				out.write("<error>Request didn't specify server name</error>");
1258
				out.close();
1259
				return;
1260
			}//if
1261

    
1262
			//try to open a https stream to test if the request server's public key
1263
			//in the key store, this is security issue
1264
			String testUrl = "https://" + server + "?server="
1265
            + MetacatUtil.getLocalReplicationServerName() + "&action=test";
1266
			logReplication.info("Running trust test: " + testUrl);
1267
			URL u = new URL(testUrl);
1268
			String test = ReplicationService.getURLContent(u);
1269
			logReplication.info("Ouput from test is '" + test + "'");
1270
			//couldn't pass the test
1271
			if (test.indexOf("successfully") == -1) {
1272
			    logReplication.error("Trust test failed.");
1273
				out.write("<error>Couldn't pass the trust test</error>");
1274
				out.close();
1275
				return;
1276
			}
1277
			logReplication.info("Trust test succeeded.");
1278

    
1279
			// Check if local host configure to replicate xml documents to remote
1280
			// server. If not send back a error message
1281
			if (!serverList.getReplicationValue(server)) {
1282
				out.write("<error>Configuration not allow to replicate document to you</error>");
1283
				out.close();
1284
				return;
1285
			}//if
1286

    
1287
			// Store the sql command
1288
			StringBuffer docsql = new StringBuffer();
1289
			StringBuffer revisionSql = new StringBuffer();
1290
			// Stroe the docid list
1291
			StringBuffer doclist = new StringBuffer();
1292
			// Store the deleted docid list
1293
			StringBuffer delsql = new StringBuffer();
1294
			// Store the data set file
1295
			Vector<Vector<String>> packageFiles = new Vector<Vector<String>>();
1296

    
1297
			// Append local server's name and replication servlet to doclist
1298
			doclist.append("<?xml version=\"1.0\"?><replication>");
1299
			doclist.append("<server>")
1300
					.append(MetacatUtil.getLocalReplicationServerName());
1301
			//doclist.append(util.getProperty("replicationpath"));
1302
			doclist.append("</server><updates>");
1303

    
1304
			// Get correct docid that reside on this server according the requesting
1305
			// server's replicate and data replicate value in xml_replication table
1306
			docsql.append(DatabaseService.getInstance().getDBAdapter().getReplicationDocumentListSQL());
1307
			//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)) ");
1308
			revisionSql.append("select docid, rev, doctype from xml_revisions ");
1309
			// If the localhost is not a hub to the remote server, only replicate
1310
			// the docid' which home server is local host (server_location =1)
1311
			if (!serverList.getHubValue(server)) {
1312
				String serverLocationDoc = " and a.server_location = 1";
1313
				String serverLocationRev = "where server_location = 1";
1314
				docsql.append(serverLocationDoc);
1315
				revisionSql.append(serverLocationRev);
1316
			}
1317
			logReplication.info("ReplicationService.handleUpdateRequest - Doc sql: " + docsql.toString());
1318

    
1319
			// Get any deleted documents
1320
			delsql.append("select distinct docid from ");
1321
			delsql.append("xml_revisions where docid not in (select docid from ");
1322
			delsql.append("xml_documents) ");
1323
			// If the localhost is not a hub to the remote server, only replicate
1324
			// the docid' which home server is local host (server_location =1)
1325
			if (!serverList.getHubValue(server)) {
1326
				delsql.append("and server_location = 1");
1327
			}
1328
			logReplication.info("ReplicationService.handleUpdateRequest - Deleted sql: " + delsql.toString());
1329

    
1330
			// Get docid list of local host
1331
			pstmt = dbConn.prepareStatement(docsql.toString());
1332
			pstmt.execute();
1333
			ResultSet rs = pstmt.getResultSet();
1334
			boolean tablehasrows = rs.next();
1335
			//If metacat configed to replicate data file
1336
			//if ((util.getProperty("replicationsenddata")).equals("on"))
1337
			boolean replicateData = serverList.getDataReplicationValue(server);
1338
			if (replicateData) {
1339
				while (tablehasrows) {
1340
					String recordDoctype = rs.getString(3);
1341
					Vector<String> packagedoctypes = MetacatUtil
1342
							.getOptionList(PropertyService
1343
									.getProperty("xml.packagedoctype"));
1344
					//if this is a package file, put it at the end
1345
					//because if a package file is read before all of the files it
1346
					//refers to are loaded then there is an error
1347
					if (recordDoctype != null && !packagedoctypes.contains(recordDoctype)) {
1348
						//If this is not data file
1349
						if (!recordDoctype.equals("BIN")) {
1350
							//for non-data file document
1351
							doclist.append("<updatedDocument>");
1352
							doclist.append("<docid>").append(rs.getString(1));
1353
							doclist.append("</docid><rev>").append(rs.getInt(2));
1354
							doclist.append("</rev>");
1355
							doclist.append("</updatedDocument>");
1356
						}//if
1357
						else {
1358
							//for data file document, in datafile attributes
1359
							//we put "datafile" value there
1360
							doclist.append("<updatedDocument>");
1361
							doclist.append("<docid>").append(rs.getString(1));
1362
							doclist.append("</docid><rev>").append(rs.getInt(2));
1363
							doclist.append("</rev>");
1364
							doclist.append("<datafile>");
1365
							doclist.append(PropertyService
1366
									.getProperty("replication.datafileflag"));
1367
							doclist.append("</datafile>");
1368
							doclist.append("</updatedDocument>");
1369
						}//else
1370
					}//if packagedoctpes
1371
					else { //the package files are saved to be put into the xml later.
1372
						Vector<String> v = new Vector<String>();
1373
						v.add(rs.getString(1));
1374
						v.add(String.valueOf(rs.getInt(2)));
1375
						packageFiles.add(v);
1376
					}//esle
1377
					tablehasrows = rs.next();
1378
				}//while
1379
			}//if
1380
			else //metacat was configured not to send data file
1381
			{
1382
				while (tablehasrows) {
1383
					String recordDoctype = rs.getString(3);
1384
					if (!recordDoctype.equals("BIN")) { //don't replicate data files
1385
						Vector<String> packagedoctypes = MetacatUtil
1386
								.getOptionList(PropertyService
1387
										.getProperty("xml.packagedoctype"));
1388
						if (recordDoctype != null
1389
								&& !packagedoctypes.contains(recordDoctype)) { //if this is a package file, put it at the end
1390
							//because if a package file is read before all of the files it
1391
							//refers to are loaded then there is an error
1392
							doclist.append("<updatedDocument>");
1393
							doclist.append("<docid>").append(rs.getString(1));
1394
							doclist.append("</docid><rev>").append(rs.getInt(2));
1395
							doclist.append("</rev>");
1396
							doclist.append("</updatedDocument>");
1397
						} else { //the package files are saved to be put into the xml later.
1398
							Vector<String> v = new Vector<String>();
1399
							v.add(rs.getString(1));
1400
							v.add(String.valueOf(rs.getInt(2)));
1401
							packageFiles.add(v);
1402
						}
1403
					}//if
1404
					tablehasrows = rs.next();
1405
				}//while
1406
			}//else
1407

    
1408
			pstmt = dbConn.prepareStatement(delsql.toString());
1409
			//usage count should increas 1
1410
			dbConn.increaseUsageCount(1);
1411

    
1412
			pstmt.execute();
1413
			rs = pstmt.getResultSet();
1414
			tablehasrows = rs.next();
1415
			while (tablehasrows) { //handle the deleted documents
1416
				doclist.append("<deletedDocument><docid>").append(rs.getString(1));
1417
				doclist.append("</docid><rev></rev></deletedDocument>");
1418
				//note that rev is always empty for deleted docs
1419
				tablehasrows = rs.next();
1420
			}
1421

    
1422
			//now we can put the package files into the xml results
1423
			for (int i = 0; i < packageFiles.size(); i++) {
1424
				Vector<String> v = packageFiles.elementAt(i);
1425
				doclist.append("<updatedDocument>");
1426
				doclist.append("<docid>").append(v.elementAt(0));
1427
				doclist.append("</docid><rev>");
1428
				doclist.append(v.elementAt(1));
1429
				doclist.append("</rev>");
1430
				doclist.append("</updatedDocument>");
1431
			}
1432
			// add revision doc list  
1433
			doclist.append(prepareRevisionDoc(dbConn, revisionSql.toString(),
1434
					replicateData));
1435

    
1436
			doclist.append("</updates></replication>");
1437
			logReplication.info("ReplicationService.handleUpdateRequest - doclist: " + doclist.toString());
1438
			pstmt.close();
1439
			//conn.close();
1440
			out.write(doclist.toString());
1441

    
1442
		} catch (Exception e) {
1443
			logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1444
			logReplication.error("ReplicationService.handleUpdateRequest - error in MetacatReplication." + "handleupdaterequest: "
1445
					+ e.getMessage());
1446
			//e.printStackTrace(System.out);
1447
			try {
1448
				out.write("<error>" + e.getMessage() + "</error>");
1449
			} catch (IOException e1) {
1450
				logMetacat.error(e1.getMessage(), e1);
1451
			}
1452
		} finally {
1453
			try {
1454
				pstmt.close();
1455
			}//try
1456
			catch (SQLException ee) {
1457
				logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1458
				logReplication.error("ReplicationService.handleUpdateRequest - Error in MetacatReplication."
1459
						+ "handleUpdaterequest to close pstmt: " + ee.getMessage());
1460
			}//catch
1461
			finally {
1462
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1463
			}//finally
1464
			try {
1465
				out.close();
1466
			} catch (IOException e) {
1467
				logMetacat.error(e.getMessage(), e);
1468
			}
1469
		}//finally
1470

    
1471
	}//handlUpdateRequest
1472

    
1473
	/**
1474
	 * 
1475
	 * @param dbConn connection for doing the update
1476
	 * @param docid the document id to update
1477
	 * @param owner the user_owner
1478
	 * @param updater the user_updated
1479
	 * @throws SQLException
1480
	 */
1481
	public static void updateUserOwner(DBConnection dbConn, String docid, String owner, String updater) throws SQLException {
1482
	
1483
		String sql = 
1484
			"UPDATE xml_documents " +
1485
			"SET user_owner = ?, " +
1486
			"user_updated = ? " +
1487
			"WHERE docid = ?;";
1488
		PreparedStatement pstmt = dbConn.prepareStatement(sql);
1489
		//usage count should increas 1
1490
		dbConn.increaseUsageCount(1);
1491

    
1492
		docid = DocumentUtil.getSmartDocId(docid);
1493
		pstmt.setString(1, owner);
1494
		pstmt.setString(2, updater);
1495
		pstmt.setString(3, docid);
1496
		pstmt.execute();
1497
		pstmt.close();
1498
		
1499
		dbConn.commit();
1500
	}
1501
	
1502
	/*
1503
	 * This method will get the xml string for document in xml_revision
1504
	 * The schema look like <!ELEMENT revisionDocument (docid, rev, datafile*)>
1505
	 */
1506
	private static String prepareRevisionDoc(DBConnection dbConn, String revSql,
1507
			boolean replicateData) throws Exception {
1508
		logReplication.warn("ReplicationService.prepareRevisionDoc - The revision document sql is " + revSql);
1509
		StringBuffer revDocList = new StringBuffer();
1510
		PreparedStatement pstmt = dbConn.prepareStatement(revSql);
1511
		//usage count should increas 1
1512
		dbConn.increaseUsageCount(1);
1513

    
1514
		pstmt.execute();
1515
		ResultSet rs = pstmt.getResultSet();
1516
		boolean tablehasrows = rs.next();
1517
		while (tablehasrows) {
1518
			String recordDoctype = rs.getString(3);
1519

    
1520
			//If this is data file and it isn't configured to replicate data
1521
			if (recordDoctype.equals("BIN") && !replicateData) {
1522
				// do nothing
1523
				continue;
1524
			} else {
1525

    
1526
				revDocList.append("<revisionDocument>");
1527
				revDocList.append("<docid>").append(rs.getString(1));
1528
				revDocList.append("</docid><rev>").append(rs.getInt(2));
1529
				revDocList.append("</rev>");
1530
				// data file
1531
				if (recordDoctype.equals("BIN")) {
1532
					revDocList.append("<datafile>");
1533
					revDocList.append(PropertyService
1534
							.getProperty("replication.datafileflag"));
1535
					revDocList.append("</datafile>");
1536
				}
1537
				revDocList.append("</revisionDocument>");
1538

    
1539
			}//else
1540
			tablehasrows = rs.next();
1541
		}
1542
		//System.out.println("The revision list is"+ revDocList.toString());
1543
		return revDocList.toString();
1544
	}
1545

    
1546
	/**
1547
	 * Returns the xml_catalog table encoded in xml
1548
	 */
1549
	public static String getCatalogXML() {
1550
		return handleGetCatalogRequest(null, null, false);
1551
	}
1552

    
1553
	/**
1554
	 * Sends the contents of the xml_catalog table encoded in xml
1555
	 * The xml format is:
1556
	 * <!ELEMENT xml_catalog (row*)>
1557
	 * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
1558
	 *                system_id)>
1559
	 * All of the sub elements of row are #PCDATA
1560

    
1561
	 * If printFlag == false then do not print to out.
1562
	 */
1563
	protected static String handleGetCatalogRequest(
1564
			Hashtable<String, String[]> params, HttpServletResponse response,
1565
			boolean printFlag) {
1566
		DBConnection dbConn = null;
1567
		int serialNumber = -1;
1568
		PreparedStatement pstmt = null;
1569
		Writer out = null;
1570
		try {
1571
			// get writer, TODO: encoding?
1572
		    if(printFlag)
1573
		    {
1574
		        response.setContentType("text/xml");
1575
		        out = response.getWriter();
1576
		    }
1577
			/*conn = MetacatReplication.getDBConnection("MetacatReplication." +
1578
			                                          "handleGetCatalogRequest");*/
1579
			dbConn = DBConnectionPool
1580
					.getDBConnection("MetacatReplication.handleGetCatalogRequest");
1581
			serialNumber = dbConn.getCheckOutSerialNumber();
1582
			pstmt = dbConn.prepareStatement("select entry_type, "
1583
					+ "source_doctype, target_doctype, public_id, "
1584
					+ "system_id from xml_catalog");
1585
			pstmt.execute();
1586
			ResultSet rs = pstmt.getResultSet();
1587
			boolean tablehasrows = rs.next();
1588
			StringBuffer sb = new StringBuffer();
1589
			sb.append("<?xml version=\"1.0\"?><xml_catalog>");
1590
			while (tablehasrows) {
1591
				sb.append("<row><entry_type>").append(rs.getString(1));
1592
				sb.append("</entry_type><source_doctype>").append(rs.getString(2));
1593
				sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
1594
				sb.append("</target_doctype><public_id>").append(rs.getString(4));
1595
				// system id may not have server url on front.  Add it if not.
1596
				String systemID = rs.getString(5);
1597
				if (!systemID.startsWith("http://")) {
1598
					systemID = SystemUtil.getContextURL() + systemID;
1599
				}
1600
				sb.append("</public_id><system_id>").append(systemID);
1601
				sb.append("</system_id></row>");
1602

    
1603
				tablehasrows = rs.next();
1604
			}
1605
			sb.append("</xml_catalog>");
1606
			//conn.close();
1607
			if (printFlag) {
1608
				response.setContentType("text/xml");
1609
				out.write(sb.toString());
1610
			}
1611
			pstmt.close();
1612
			return sb.toString();
1613
		} catch (Exception e) {
1614
			logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1615
			logReplication.error("ReplicationService.handleGetCatalogRequest - error in MetacatReplication.handleGetCatalogRequest:"
1616
					+ e.getMessage());
1617
			e.printStackTrace(System.out);
1618
			if (printFlag) {
1619
				try {
1620
					out.write("<error>" + e.getMessage() + "</error>");
1621
				} catch (IOException e1) {
1622
					logMetacat.error(e1.getMessage(), e1);
1623
				}
1624
			}
1625
		} finally {
1626
			try {
1627
				pstmt.close();
1628
			}//try
1629
			catch (SQLException ee) {
1630
				logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1631
				logReplication.error("ReplicationService.handleGetCatalogRequest - Error in MetacatReplication.handleGetCatalogRequest: "
1632
						+ ee.getMessage());
1633
			}//catch
1634
			finally {
1635
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1636
			}//finally
1637
			if (out != null) {
1638
				try {
1639
					out.close();
1640
				} catch (IOException e1) {
1641
					logMetacat.error(e1.getMessage(), e1);
1642
				}
1643
			}
1644
		}//finally
1645

    
1646
		return null;
1647
	}
1648

    
1649
	/**
1650
	 * Sends the current system date to the remote server.  Using this action
1651
	 * for replication gets rid of any problems with syncronizing clocks
1652
	 * because a time specific to a document is always kept on its home server.
1653
	 */
1654
	protected static void handleGetTimeRequest(
1655
			Hashtable<String, String[]> params, HttpServletResponse response) {
1656
		SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yy HH:mm:ss");
1657
		java.util.Date localtime = new java.util.Date();
1658
		String dateString = formatter.format(localtime);
1659
		
1660
		// get a writer for sending back to response
1661
		response.setContentType("text/xml");
1662
		Writer out = null;
1663
		try {
1664
			out = response.getWriter();
1665
			out.write("<timestamp>" + dateString + "</timestamp>");
1666
			out.close();
1667
		} catch (IOException e) {
1668
			logMetacat.error(e.getMessage(), e);
1669
		}
1670
		
1671
	}
1672

    
1673
	/**
1674
	 * this method handles the timeout for a file lock.  when a lock is
1675
	 * granted it is granted for 30 seconds.  When this thread runs out
1676
	 * it deletes the docid from the queue, thus eliminating the lock.
1677
	 */
1678
	public void run() {
1679
		try {
1680
			logReplication.info("ReplicationService.run - thread started for docid: "
1681
					+ (String) fileLocks.elementAt(0));
1682

    
1683
			Thread.sleep(30000); //the lock will expire in 30 seconds
1684
			logReplication.info("thread for docid: "
1685
					+ (String) fileLocks.elementAt(fileLocks.size() - 1) + " exiting.");
1686

    
1687
			fileLocks.remove(fileLocks.size() - 1);
1688
			//fileLocks is treated as a FIFO queue.  If there are more than one lock
1689
			//in the vector, the first one inserted will be removed.
1690
		} catch (Exception e) {
1691
			logMetacat.error("ReplicationService.run - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1692
			logReplication.error("ReplicationService.run - error in file lock thread from "
1693
					+ "MetacatReplication.run: " + e.getMessage());
1694
		}
1695
	}
1696

    
1697
	/**
1698
	 * Returns the name of a server given a serverCode
1699
	 * @param serverCode the serverid of the server
1700
	 * @return the servername or null if the specified serverCode does not
1701
	 *         exist.
1702
	 */
1703
	public static String getServerNameForServerCode(int serverCode) {
1704
		//System.out.println("serverid: " + serverCode);
1705
		DBConnection dbConn = null;
1706
		int serialNumber = -1;
1707
		PreparedStatement pstmt = null;
1708
		try {
1709
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServer");
1710
			serialNumber = dbConn.getCheckOutSerialNumber();
1711
			String sql = new String("select server from "
1712
					+ "xml_replication where serverid = " + serverCode);
1713
			pstmt = dbConn.prepareStatement(sql);
1714
			//System.out.println("getserver sql: " + sql);
1715
			pstmt.execute();
1716
			ResultSet rs = pstmt.getResultSet();
1717
			boolean tablehasrows = rs.next();
1718
			if (tablehasrows) {
1719
				//System.out.println("server: " + rs.getString(1));
1720
				return rs.getString(1);
1721
			}
1722

    
1723
			//conn.close();
1724
		} catch (Exception e) {
1725
			logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1726
			logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplication.getServer: " + e.getMessage());
1727
		} finally {
1728
			try {
1729
				pstmt.close();
1730
			}//try
1731
			catch (SQLException ee) {
1732
				logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1733
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacactReplication.getserver: "
1734
						+ ee.getMessage());
1735
			}//catch
1736
			finally {
1737
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1738
			}//fianlly
1739
		}//finally
1740

    
1741
		return null;
1742
		//return null if the server does not exist
1743
	}
1744

    
1745
	/**
1746
	 * Returns a server code given a server name
1747
	 * @param server the name of the server
1748
	 * @return integer > 0 representing the code of the server, 0 if the server
1749
	 *  does not exist.
1750
	 */
1751
	public static int getServerCodeForServerName(String server) throws ServiceException {
1752
		DBConnection dbConn = null;
1753
		int serialNumber = -1;
1754
		PreparedStatement pstmt = null;
1755
		int serverCode = 0;
1756

    
1757
		try {
1758

    
1759
			//conn = util.openDBConnection();
1760
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServerCode");
1761
			serialNumber = dbConn.getCheckOutSerialNumber();
1762
			pstmt = dbConn.prepareStatement("SELECT serverid FROM xml_replication "
1763
					+ "WHERE server LIKE '" + server + "'");
1764
			pstmt.execute();
1765
			ResultSet rs = pstmt.getResultSet();
1766
			boolean tablehasrows = rs.next();
1767
			if (tablehasrows) {
1768
				serverCode = rs.getInt(1);
1769
				pstmt.close();
1770
				//conn.close();
1771
				return serverCode;
1772
			}
1773

    
1774
		} catch (SQLException sqle) {
1775
			throw new ServiceException("ReplicationService.getServerCodeForServerName - " 
1776
					+ "SQL error when getting server code: " + sqle.getMessage());
1777

    
1778
		} finally {
1779
			try {
1780
				pstmt.close();
1781
				//conn.close();
1782
			}//try
1783
			catch (Exception ee) {
1784
				logMetacat.error("ReplicationService.getServerCodeForServerName - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1785
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplicatio.getServerCode: "
1786
						+ ee.getMessage());
1787

    
1788
			}//catch
1789
			finally {
1790
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1791
			}//finally
1792
		}//finally
1793

    
1794
		return serverCode;
1795
	}
1796

    
1797
	/**
1798
	 * Method to get a host server information for given docid
1799
	 * @param conn a connection to the database
1800
	 */
1801
	public static Hashtable<String, String> getHomeServerInfoForDocId(String docId) {
1802
		Hashtable<String, String> sl = new Hashtable<String, String>();
1803
		DBConnection dbConn = null;
1804
		int serialNumber = -1;
1805
		docId = DocumentUtil.getDocIdFromString(docId);
1806
		PreparedStatement pstmt = null;
1807
		int serverLocation;
1808
		try {
1809
			//get conection
1810
			dbConn = DBConnectionPool.getDBConnection("ReplicationHandler.getHomeServer");
1811
			serialNumber = dbConn.getCheckOutSerialNumber();
1812
			//get a server location from xml_document table
1813
			pstmt = dbConn.prepareStatement("select server_location from xml_documents "
1814
					+ "where docid = ?");
1815
			pstmt.setString(1, docId);
1816
			pstmt.execute();
1817
			ResultSet serverName = pstmt.getResultSet();
1818
			//get a server location
1819
			if (serverName.next()) {
1820
				serverLocation = serverName.getInt(1);
1821
				pstmt.close();
1822
			} else {
1823
				pstmt.close();
1824
				//ut.returnConnection(conn);
1825
				return null;
1826
			}
1827
			pstmt = dbConn.prepareStatement("select server, last_checked, replicate "
1828
					+ "from xml_replication where serverid = ?");
1829
			//increase usage count
1830
			dbConn.increaseUsageCount(1);
1831
			pstmt.setInt(1, serverLocation);
1832
			pstmt.execute();
1833
			ResultSet rs = pstmt.getResultSet();
1834
			boolean tableHasRows = rs.next();
1835
			if (tableHasRows) {
1836

    
1837
				String server = rs.getString(1);
1838
				String last_checked = rs.getString(2);
1839
				if (!server.equals("localhost")) {
1840
					sl.put(server, last_checked);
1841
				}
1842

    
1843
			} else {
1844
				pstmt.close();
1845
				//ut.returnConnection(conn);
1846
				return null;
1847
			}
1848
			pstmt.close();
1849
		} catch (Exception e) {
1850
			logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1851
			logReplication.error("ReplicationService.getHomeServerInfoForDocId - error in replicationHandler.getHomeServer(): "
1852
					+ e.getMessage());
1853
		} finally {
1854
			try {
1855
				pstmt.close();
1856
				//ut.returnConnection(conn);
1857
			} catch (Exception ee) {
1858
				logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1859
				logReplication.error("ReplicationService.getHomeServerInfoForDocId - Eror irn rplicationHandler.getHomeServer() "
1860
						+ "to close pstmt: " + ee.getMessage());
1861
			} finally {
1862
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1863
			}
1864

    
1865
		}//finally
1866
		return sl;
1867
	}
1868

    
1869
	/**
1870
	 * Returns a home server location  given a accnum
1871
	 * @param accNum , given accNum for a document
1872
	 *
1873
	 */
1874
	public static int getHomeServerCodeForDocId(String accNum) throws ServiceException {
1875
		DBConnection dbConn = null;
1876
		int serialNumber = -1;
1877
		PreparedStatement pstmt = null;
1878
		int serverCode = 1;
1879
		String docId = DocumentUtil.getDocIdFromString(accNum);
1880

    
1881
		try {
1882

    
1883
			// Get DBConnection
1884
			dbConn = DBConnectionPool
1885
					.getDBConnection("ReplicationHandler.getServerLocation");
1886
			serialNumber = dbConn.getCheckOutSerialNumber();
1887
			pstmt = dbConn.prepareStatement("SELECT server_location FROM xml_documents "
1888
					+ "WHERE docid LIKE '" + docId + "'");
1889
			pstmt.execute();
1890
			ResultSet rs = pstmt.getResultSet();
1891
			boolean tablehasrows = rs.next();
1892
			//If a document is find, return the server location for it
1893
			if (tablehasrows) {
1894
				serverCode = rs.getInt(1);
1895
				pstmt.close();
1896
				//conn.close();
1897
				return serverCode;
1898
			}
1899
			//if couldn't find in xml_documents table, we think server code is 1
1900
			//(this is new document)
1901
			else {
1902
				pstmt.close();
1903
				//conn.close();
1904
				return serverCode;
1905
			}
1906

    
1907
		} catch (SQLException sqle) {
1908
			throw new ServiceException("ReplicationService.getHomeServerCodeForDocId - " 
1909
					+ "SQL error when getting home server code for docid: " + docId + " : " 
1910
					+ sqle.getMessage());
1911

    
1912
		} finally {
1913
			try {
1914
				pstmt.close();
1915
				//conn.close();
1916

    
1917
			} catch (SQLException sqle) {
1918
				logMetacat.error("ReplicationService.getHomeServerCodeForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1919
				logReplication.error("ReplicationService.getHomeServerCodeForDocId - ReplicationService.getHomeServerCodeForDocId - " 
1920
						+ "SQL error when getting home server code for docid: " + docId + " : " 
1921
						+ sqle.getMessage());
1922
			} finally {
1923
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1924
			}//finally
1925
		}//finally
1926
		//return serverCode;
1927
	}
1928

    
1929
	/**
1930
	 * This method returns the content of a url
1931
	 * @param u the url to return the content from
1932
	 * @return a string representing the content of the url
1933
	 * @throws java.io.IOException
1934
	 */
1935
	public static String getURLContent(URL u) throws java.io.IOException {
1936
	    logReplication.info("Getting url content from " + u.toString());
1937
		char istreamChar;
1938
		int istreamInt;
1939
		logReplication.info("ReplicationService.getURLContent - Before open the stream" + u.toString());
1940
		InputStream input = u.openStream();
1941
		logReplication.info("ReplicationService.getURLContent - After open the stream" + u.toString());
1942
		InputStreamReader istream = new InputStreamReader(input);
1943
		StringBuffer serverResponse = new StringBuffer();
1944
		while ((istreamInt = istream.read()) != -1) {
1945
			istreamChar = (char) istreamInt;
1946
			serverResponse.append(istreamChar);
1947
		}
1948
		istream.close();
1949
		input.close();
1950

    
1951
		return serverResponse.toString();
1952
	}
1953

    
1954
//	/**
1955
//	 * Method for writing replication messages to a log file specified in
1956
//	 * metacat.properties
1957
//	 */
1958
//	public static void replLog(String message) {
1959
//		try {
1960
//			FileOutputStream fos = new FileOutputStream(PropertyService
1961
//					.getProperty("replication.logdir")
1962
//					+ "/metacatreplication.log", true);
1963
//			PrintWriter pw = new PrintWriter(fos);
1964
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
1965
//			java.util.Date localtime = new java.util.Date();
1966
//			String dateString = formatter.format(localtime);
1967
//			dateString += " :: " + message;
1968
//			// time stamp each entry
1969
//			pw.println(dateString);
1970
//			pw.flush();
1971
//		} catch (Exception e) {
1972
//			logReplication.error("error writing to replication log from "
1973
//					+ "MetacatReplication.replLog: " + e.getMessage());
1974
//			// e.printStackTrace(System.out);
1975
//		}
1976
//	}
1977

    
1978
//	/**
1979
//	 * Method for writing replication messages to a log file specified in
1980
//	 * metacat.properties
1981
//	 */
1982
//	public static void replErrorLog(String message) {
1983
//		try {
1984
//			FileOutputStream fos = new FileOutputStream(PropertyService
1985
//					.getProperty("replication.logdir")
1986
//					+ "/metacatreplicationerror.log", true);
1987
//			PrintWriter pw = new PrintWriter(fos);
1988
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
1989
//			java.util.Date localtime = new java.util.Date();
1990
//			String dateString = formatter.format(localtime);
1991
//			dateString += " :: " + message;
1992
//			//time stamp each entry
1993
//			pw.println(dateString);
1994
//			pw.flush();
1995
//		} catch (Exception e) {
1996
//			logReplication.error("error writing to replication error log from "
1997
//					+ "MetacatReplication.replErrorLog: " + e.getMessage());
1998
//			//e.printStackTrace(System.out);
1999
//		}
2000
//	}
2001

    
2002
	/**
2003
	 * Returns true if the replicate field for server in xml_replication is 1.
2004
	 * Returns false otherwise
2005
	 */
2006
	public static boolean replToServer(String server) {
2007
		DBConnection dbConn = null;
2008
		int serialNumber = -1;
2009
		PreparedStatement pstmt = null;
2010
		try {
2011
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.repltoServer");
2012
			serialNumber = dbConn.getCheckOutSerialNumber();
2013
			pstmt = dbConn.prepareStatement("select replicate from "
2014
					+ "xml_replication where server like '" + server + "'");
2015
			pstmt.execute();
2016
			ResultSet rs = pstmt.getResultSet();
2017
			boolean tablehasrows = rs.next();
2018
			if (tablehasrows) {
2019
				int i = rs.getInt(1);
2020
				if (i == 1) {
2021
					pstmt.close();
2022
					//conn.close();
2023
					return true;
2024
				} else {
2025
					pstmt.close();
2026
					//conn.close();
2027
					return false;
2028
				}
2029
			}
2030
		} catch (SQLException sqle) {
2031
			logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2032
			logReplication.error("ReplicationService.replToServer - SQL error in MetacatReplication.replToServer: "
2033
					+ sqle.getMessage());
2034
		} finally {
2035
			try {
2036
				pstmt.close();
2037
				//conn.close();
2038
			}//try
2039
			catch (Exception ee) {
2040
				logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2041
				logReplication.error("ReplicationService.replToServer - Error in MetacatReplication.replToServer: "
2042
						+ ee.getMessage());
2043
			}//catch
2044
			finally {
2045
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2046
			}//finally
2047
		}//finally
2048
		return false;
2049
		//the default if this server does not exist is to not replicate to it.
2050
	}
2051

    
2052
}
(6-6/7)