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: 2010-12-23 09:10:39 -0800 (Thu, 23 Dec 2010) $'
10
 * '$Revision: 5755 $'
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.File;
32
import java.io.FileInputStream;
33
import java.io.FileNotFoundException;
34
import java.io.FileOutputStream;
35
import java.io.IOException;
36
import java.io.InputStream;
37
import java.io.InputStreamReader;
38
import java.io.OutputStream;
39
import java.io.StringReader;
40
import java.io.Writer;
41
import java.net.MalformedURLException;
42
import java.net.URL;
43
import java.sql.PreparedStatement;
44
import java.sql.ResultSet;
45
import java.sql.SQLException;
46
import java.text.SimpleDateFormat;
47
import java.util.Date;
48
import java.util.Hashtable;
49
import java.util.Timer;
50
import java.util.Vector;
51

    
52
import javax.servlet.http.HttpServletRequest;
53
import javax.servlet.http.HttpServletResponse;
54

    
55
import org.apache.log4j.Logger;
56
import org.xml.sax.InputSource;
57
import org.xml.sax.SAXException;
58
import org.xml.sax.XMLReader;
59

    
60
import edu.ucsb.nceas.metacat.DocInfoHandler;
61
import edu.ucsb.nceas.metacat.DocumentImpl;
62
import edu.ucsb.nceas.metacat.DocumentImplWrapper;
63
import edu.ucsb.nceas.metacat.EventLog;
64
import edu.ucsb.nceas.metacat.IdentifierManager;
65
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
66
import edu.ucsb.nceas.metacat.McdbException;
67
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlException;
68
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlForSingleFile;
69
import edu.ucsb.nceas.metacat.accesscontrol.PermOrderException;
70
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessDAO;
71
import edu.ucsb.nceas.metacat.database.DBConnection;
72
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
73
import edu.ucsb.nceas.metacat.database.DatabaseService;
74
import edu.ucsb.nceas.metacat.properties.PropertyService;
75
import edu.ucsb.nceas.metacat.shared.BaseService;
76
import edu.ucsb.nceas.metacat.shared.HandlerException;
77
import edu.ucsb.nceas.metacat.shared.ServiceException;
78
import edu.ucsb.nceas.metacat.util.DocumentUtil;
79
import edu.ucsb.nceas.metacat.util.MetacatUtil;
80
import edu.ucsb.nceas.metacat.util.SystemUtil;
81
import edu.ucsb.nceas.utilities.FileUtil;
82
import edu.ucsb.nceas.utilities.GeneralPropertyException;
83
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
84

    
85
public class ReplicationService extends BaseService {
86

    
87
	private static ReplicationService replicationService = null;
88

    
89
	private long timeInterval;
90
	private Date firstTime;
91
	private boolean timedReplicationIsOn = false;
92
	Timer replicationDaemon;
93
	private static Vector<String> fileLocks = new Vector<String>();
94
//	private Thread lockThread = null;
95
	public static final String FORCEREPLICATEDELETE = "forcereplicatedelete";
96
	private static String TIMEREPLICATION = "replication.timedreplication";
97
	private static String TIMEREPLICATIONINTERVAl ="replication.timedreplicationinterval";
98
	private static String FIRSTTIME = "replication.firsttimedreplication";
99
	private static final int TIMEINTERVALLIMIT = 7200000;
100
	public static final String REPLICATIONUSER = "replication";
101

    
102
	public static final String REPLICATION_LOG_FILE_NAME = "metacatreplication.log";
103
	public static String METACAT_REPL_ERROR_MSG = null;
104
	private static Logger logReplication = Logger.getLogger("ReplicationLogging");
105
	private static Logger logMetacat = Logger.getLogger(ReplicationService.class);
106

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

    
131
			String timeIntervalStr = 
132
				PropertyService.getProperty("replication.timedreplicationinterval");
133
			timeInterval = (new Long(timeIntervalStr)).longValue();
134
			logReplication.info("ReplicationService.initialize - The timed replication time Interval is " + timeInterval);
135

    
136
			String firstTimeStr = 
137
				PropertyService.getProperty("replication.firsttimedreplication");
138
			logReplication.info("ReplicationService.initialize - first replication time form property is " + firstTimeStr);
139
			firstTime = ReplicationHandler.combinateCurrentDateAndGivenTime(firstTimeStr);
140

    
141
			logReplication.info("ReplicationService.initialize - After combine current time, the real first time is "
142
					+ firstTime.toString() + " minisec");
143

    
144
			// set up time replication if it is on
145
			if (timedReplicationIsOn) {
146
				replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(),
147
						firstTime, timeInterval);
148
				logReplication.info("ReplicationService.initialize - deltaT handler started with rate="
149
						+ timeInterval + " mini seconds at " + firstTime.toString());
150
			}
151

    
152
		} catch (PropertyNotFoundException pnfe) {
153
			throw new ServiceException(
154
					"ReplicationService.initialize - Property error while instantiating "
155
							+ "replication service: " + pnfe.getMessage());
156
		} catch (HandlerException he) {
157
			throw new ServiceException(
158
					"ReplicationService.initialize - Handler error while instantiating "
159
							+ "replication service" + he.getMessage());
160
		} 
161
	}
162

    
163
	/**
164
	 * Get the single instance of SessionService.
165
	 * 
166
	 * @return the single instance of SessionService
167
	 */
168
	public static ReplicationService getInstance() throws ServiceException {
169
		if (replicationService == null) {
170
			replicationService = new ReplicationService();
171
		}
172
		return replicationService;
173
	}
174

    
175
	public boolean refreshable() {
176
		return true;
177
	}
178

    
179
	protected void doRefresh() throws ServiceException {
180
		return;
181
	}
182
	
183
	public void stop() throws ServiceException{
184
		
185
	}
186

    
187
	public void stopReplication() throws ServiceException {
188
	      //stop the replication server
189
	      replicationDaemon.cancel();
190
	      replicationDaemon = new Timer(true);
191
	      timedReplicationIsOn = false;
192
	      try {
193
	    	  PropertyService.setProperty("replication.timedreplication", (new Boolean(timedReplicationIsOn)).toString());
194
	      } catch (GeneralPropertyException gpe) {
195
	    	  logReplication.warn("ReplicationService.stopReplication - Could not set replication.timedreplication property: " + gpe.getMessage());
196
	      }
197

    
198
	      logReplication.info("ReplicationService.stopReplication - deltaT handler stopped");
199
		return;
200
	}
201
	
202
	protected void startReplication(Hashtable<String, String[]> params) throws ServiceException {
203

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

    
261
	}
262
	
263
	public void runOnce() throws ServiceException {
264
	      //updates this server exactly once
265
	      replicationDaemon.schedule(new ReplicationHandler(), 0);
266
	}
267

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

    
297
			// add server to server list
298
			if (subaction.equals("add")) {
299
				replicate = ((String[]) params.get("replicate"))[0];
300
				server = ((String[]) params.get("server"))[0];
301

    
302
				//Get data replication value
303
				dataReplicate = ((String[]) params.get("datareplicate"))[0];
304
				//Get hub value
305
				hub = ((String[]) params.get("hub"))[0];
306

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

    
339
				pstmt.execute();
340
				ResultSet rs = pstmt.getResultSet();
341
				boolean tablehasrows = rs.next();
342
				while (tablehasrows) {
343
					out.write("<tr><td>" + rs.getString(2) + "</td><td>");
344
					out.write(rs.getString(3) + "</td><td>");
345
					out.write(rs.getString(4) + "</td><td>");
346
					out.write(rs.getString(5) + "</td><td>");
347
					out.write(rs.getString(6) + "</td></tr>");
348

    
349
					tablehasrows = rs.next();
350
				}
351
				out.write("</table></body></html>");
352

    
353
				// download certificate with the public key on this server
354
				// and import it as a trusted certificate
355
				String certURL = ((String[]) params.get("certificate"))[0];
356
				if (certURL != null && !certURL.equals("")) {
357
					downloadCertificate(certURL);
358
				}
359

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

    
376
				pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
377
				//increase dbconnection usage
378
				dbConn.increaseUsageCount(1);
379
				pstmt.execute();
380
				ResultSet rs = pstmt.getResultSet();
381
				boolean tablehasrows = rs.next();
382
				while (tablehasrows) {
383
					out.write("<tr><td>" + rs.getString(2) + "</td><td>");
384
					out.write(rs.getString(3) + "</td><td>");
385
					out.write(rs.getString(4) + "</td><td>");
386
					out.write(rs.getString(5) + "</td><td>");
387
					out.write(rs.getString(6) + "</td></tr>");
388
					tablehasrows = rs.next();
389
				}
390
				out.write("</table></body></html>");
391

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

    
415
				out.write("<error>Unkonwn subaction</error>");
416

    
417
			}
418
			pstmt.close();
419
			//conn.close();
420

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

    
447
	}
448

    
449
	// download certificate with the public key from certURL and
450
	// upload it onto this server; it then must be imported as a
451
	// trusted certificate
452
	private static void downloadCertificate(String certURL) throws FileNotFoundException,
453
			IOException, MalformedURLException, PropertyNotFoundException {
454

    
455
		// the path to be uploaded to
456
		String certPath = SystemUtil.getContextDir();
457

    
458
		// get filename from the URL of the certificate
459
		String filename = certURL;
460
		int slash = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
461
		if (slash > -1) {
462
			filename = filename.substring(slash + 1);
463
		}
464

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

    
482
			// create a buffered byte output stream
483
			// that uses a default-sized output buffer
484
			FileOutputStream fos = new FileOutputStream(f);
485
			BufferedOutputStream out = new BufferedOutputStream(fos);
486

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

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

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

    
543
			// get the document info from server
544
			URL docinfourl = new URL("https://" + server + "?server="
545
					+ MetacatUtil.getLocalReplicationServerName()
546
					+ "&action=getdocumentinfo&docid=" + docid);
547
			
548

    
549
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
550

    
551
			//dih is the parser for the docinfo xml format
552
			DocInfoHandler dih = new DocInfoHandler();
553
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
554
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
555
			//      Hashtable<String,Vector<AccessControlForSingleFile>> docinfoHash = dih.getDocInfo();
556
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
557

    
558
			// Get user owner of this docid
559
			String user = (String) docinfoHash.get("user_owner");
560
			// Get home server of this docid
561
			String homeServer = (String) docinfoHash.get("home_server");
562
			String guid = (String) docinfoHash.get("guid");
563
			logReplication.info("XXXXXXXXXXXXXXXX GUID found in dociinfoHash: " + guid);
564
			
565
			logReplication.info("Processing guid " + guid + 
566
			  " information from handleForceReplicationRequest: " + 
567
			  docinfoHash.toString());
568
      IdentifierManager idman = IdentifierManager.getInstance();
569
      if(guid != null)
570
      { //if the guid was passed in, put it in the identifiers table
571
        logReplication.info("YYYYYYYYYYYYYY Creating guid/docid mapping for docid " + 
572
          docinfoHash.get("docid") + " and guid: " + guid);
573
        
574
        docName = (String) docinfoHash.get("docname");
575
        logReplication.info("ZZZZZZZZZZZZ docName: " + docName);
576
        if(docName.trim().equals("systemMetadata"))
577
        {
578
            logReplication.info("creating mapping for systemMetadata: guid: " + guid + " localId: " + docinfoHash.get("docid"));
579
            idman.createSystemMetadataMapping(guid, docinfoHash.get("docid"));
580
        }
581
        else
582
        {
583
            logReplication.info("creating mapping: guid: " + guid + " localId: " + docinfoHash.get("docid"));
584
            idman.createMapping(guid, docinfoHash.get("docid"));
585
        }
586
      }
587
      else
588
      {
589
        logReplication.debug("No guid information was included with the replicated document");
590
      }
591
      
592
			String createdDate = (String) docinfoHash.get("date_created");
593
			String updatedDate = (String) docinfoHash.get("date_updated");
594
			logReplication.info("ReplicationService.handleForceReplicateRequest - homeServer: " + homeServer);
595
			// Get Document type
596
			String docType = (String) docinfoHash.get("doctype");
597
			logReplication.info("ReplicationService.handleForceReplicateRequest - docType: " + docType);
598
			String parserBase = null;
599
			// this for eml2 and we need user eml2 parser
600
			if (docType != null
601
					&& (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE)) {
602
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml200 document!");
603
				parserBase = DocumentImpl.EML200;
604
			} else if (docType != null
605
					&& (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE)) {
606
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.0.1 document!");
607
				parserBase = DocumentImpl.EML200;
608
			} else if (docType != null
609
					&& (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE)) {
610
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.0 document!");
611
				parserBase = DocumentImpl.EML210;
612
			} else if (docType != null
613
					&& (docType.trim()).equals(DocumentImpl.EML2_1_1NAMESPACE)) {
614
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.1 document!");
615
				parserBase = DocumentImpl.EML210;
616
			}
617
			logReplication.warn("ReplicationService.handleForceReplicateRequest - The parserBase is: " + parserBase);
618

    
619
			// Get DBConnection from pool
620
			dbConn = DBConnectionPool
621
					.getDBConnection("MetacatReplication.handleForceReplicateRequest");
622
			serialNumber = dbConn.getCheckOutSerialNumber();
623
			// write the document to local database
624
			DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false);
625
			//try this independently so we can set
626
//			Exception writeException = null;
627
			try {
628
				wrapper.writeReplication(dbConn, xmldoc, null, null,
629
						dbaction, docid, user, null, homeServer, server, createdDate,
630
						updatedDate);
631
			} finally {
632
//				writeException = e;
633

    
634
				//process extra access rules before dealing with the write exception (doc exist already)			
635
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
636
		        if (accessControlList != null) {
637
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
638
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
639
		        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
640
		        			acfsf.insertPermissions(xmlAccessDAO);
641
							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
642
									+ " permissions added to DB");
643
		        		}
644
		            }
645
		        }
646
//				if (accessControlList != null) {
647
//					for (int i = 0; i < accessControlList.size(); i++) {
648
//						AccessControlForSingleFile acfsf = (AccessControlForSingleFile) accessControlList
649
//								.get(i);
650
//						if (!acfsf.accessControlExists()) {
651
//							acfsf.insertPermissions();
652
//							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
653
//									+ " permissions added to DB");
654
//						}
655
//					}
656
//				}
657

    
658
//				if (writeException != null) {
659
//					throw writeException;
660
//				}
661

    
662
				logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid + " added to DB with "
663
						+ "action " + dbaction);
664
				
665
				if(guid != null)
666
                {
667
                    if(!docName.trim().equals("systemMetadata"))
668
                    {
669
                        logReplication.info("replicate D1GUID:" + guid + ":D1SCIMETADATA:" + 
670
                                docid + ":");
671
                    }
672
                    else
673
                    {
674
                        logReplication.info("replicate D1GUID:" + guid + ":D1SYSMETADATA:" + 
675
                                docid + ":");
676
                    }
677
                }
678
				EventLog.getInstance().log(request.getRemoteAddr(), REPLICATIONUSER, docid,
679
						dbaction);
680
			}
681
		} catch (SQLException sqle) {
682
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
683
			logReplication.error("ReplicationService.handleForceReplicateRequest - SQL error when adding doc " + docid + 
684
					" to DB with action " + dbaction + ": " + sqle.getMessage());
685
		} catch (MalformedURLException mue) {
686
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
687
			logReplication.error("ReplicationService.handleForceReplicateRequest - URL error when adding doc " + docid + 
688
					" to DB with action " + dbaction + ": " + mue.getMessage());
689
		} catch (SAXException se) {
690
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
691
			logReplication.error("ReplicationService.handleForceReplicateRequest - SAX parsing error when adding doc " + docid + 
692
					" to DB with action " + dbaction + ": " + se.getMessage());
693
		} catch (HandlerException he) {
694
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
695
			logReplication.error("ReplicationService.handleForceReplicateRequest - Handler error when adding doc " + docid + 
696
					" to DB with action " + dbaction + ": " + he.getMessage());
697
		} catch (IOException ioe) {
698
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
699
			logReplication.error("ReplicationService.handleForceReplicateRequest - I/O error when adding doc " + docid + 
700
					" to DB with action " + dbaction + ": " + ioe.getMessage());
701
		} catch (PermOrderException poe) {
702
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
703
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
704
					" to DB with action " + dbaction + ": " + poe.getMessage());
705
		} catch (AccessControlException ace) {
706
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
707
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
708
					" to DB with action " + dbaction + ": " + ace.getMessage());
709
		} catch (Exception e) {
710
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
711
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when adding doc " + docid + 
712
					" to DB with action " + dbaction + ": " + e.getMessage());
713
		} finally {
714
			// Return the checked out DBConnection
715
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
716
		}//finally
717
	}
718

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

    
744
		}//catch
745

    
746
	}
747

    
748
	/**
749
	 * when a forcereplication data file request comes in, local host sends a
750
	 * readdata request to the requesting server (remote server) for the specified
751
	 * docid. Then store it in local database and file system
752
	 */
753
	protected static void handleForceReplicateDataFileRequest(Hashtable<String, String[]> params,
754
			HttpServletRequest request) {
755

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

    
771
		// Overide or not
772
		//    boolean override = false;
773
		// dbaction - update or insert
774
		String dbaction = null;
775

    
776
		try {
777
			//docid was switch to two parts uinque code and rev
778
			//String uniqueCode=MetacatUtil.getDocIdFromString(docid);
779
			//int rev=MetacatUtil.getVersionFromString(docid);
780
			if (params.containsKey("dbaction")) {
781
				dbaction = ((String[]) params.get("dbaction"))[0];
782
			} else//default value is update
783
			{
784
				dbaction = "update";
785
			}
786

    
787
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - force replication request from " + server);
788
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication request from: " + server);
789
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication docid: " + docid);
790
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication action: " + dbaction);
791
			// get the document info from server
792
			URL docinfourl = new URL("https://" + server + "?server="
793
					+ MetacatUtil.getLocalReplicationServerName()
794
					+ "&action=getdocumentinfo&docid=" + docid);
795

    
796
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
797

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

    
805
			String docName = (String) docinfoHash.get("docname");
806

    
807
			String docType = (String) docinfoHash.get("doctype");
808

    
809
			String docHomeServer = (String) docinfoHash.get("home_server");
810

    
811
			String createdDate = (String) docinfoHash.get("date_created");
812

    
813
			String updatedDate = (String) docinfoHash.get("date_updated");
814
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - docHomeServer of datafile: " + docHomeServer);
815

    
816
			//if action is delete, we don't delete the data file. Just archieve
817
			//the xml_documents
818
			/*if (dbaction.equals("delete"))
819
			{
820
			  //conn = util.getConnection();
821
			  DocumentImpl.delete(docid,user,null);
822
			  //util.returnConnection(conn);
823
			}*/
824
			//To data file insert or update is same
825
			if (dbaction.equals("insert") || dbaction.equals("update")) {
826
				//Get data file and store it into local file system.
827
				// sending back readdata request to server
828
				URL url = new URL("https://" + server + "?server="
829
						+ MetacatUtil.getLocalReplicationServerName()
830
						+ "&action=readdata&docid=" + docid);
831
				String datafilePath = PropertyService
832
						.getProperty("application.datafilepath");
833

    
834
				Exception writeException = null;
835
				//register data file into xml_documents table and wite data file
836
				//into file system
837
				try {
838
					DocumentImpl.writeDataFileInReplication(url.openStream(),
839
							datafilePath, docName, docType, docid, user, docHomeServer,
840
							server, DocumentImpl.DOCUMENTTABLE, false, createdDate,
841
							updatedDate);
842
				} catch (Exception e) {
843
					writeException = e;
844
				}
845
				//process extra access rules
846
//				Vector<AccessControlForSingleFile> accessControlList = dih
847
//						.getAccessControlList();
848
//				if (accessControlList != null) {
849
//					for (int i = 0; i < accessControlList.size(); i++) {
850
//						AccessControlForSingleFile acfsf = (AccessControlForSingleFile) accessControlList
851
//								.get(i);
852
//						if (!acfsf.accessControlExists()) {
853
//							acfsf.insertPermissions();
854
//							logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - datafile " + docid
855
//									+ " permissions added to DB");
856
//						}
857
//					}
858
//				}
859
				
860
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
861
		        if (accessControlList != null) {
862
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
863
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
864
		        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
865
		        			acfsf.insertPermissions(xmlAccessDAO);
866
							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
867
									+ " permissions added to DB");
868
		        		}
869
		            }
870
		        }
871

    
872
				if (writeException != null) {
873
					throw writeException;
874
				}
875

    
876
				//false means non-timed replication
877
				logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - datafile " + docid + " added to DB with "
878
						+ "action " + dbaction);
879
				EventLog.getInstance().log(request.getRemoteAddr(), REPLICATIONUSER,
880
						docid, dbaction);
881
			}
882

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

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

    
903
		try {
904

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

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

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

    
958
		try {
959
		  IdentifierManager idman = IdentifierManager.getInstance();
960

    
961
			DocumentImpl doc = new DocumentImpl(docid);
962
			sb.append("<documentinfo><docid>").append(docid);
963
			sb.append("</docid>");
964
			try
965
			{
966
			  String guid = idman.getGUID(doc.getDocID(), doc.getRev());
967
			  sb.append("<guid>").append(guid).append("</guid>");
968
			  String smLocalId = idman.getSystemMetadataLocalId(guid);
969
			  if(smLocalId != null && !smLocalId.trim().equals(""))
970
			  {
971
			      sb.append("<systemmetadatalocalid>").append(smLocalId).append("</systemmetadatalocalid>");
972
			  }
973
			}
974
			catch(McdbDocNotFoundException e)
975
			{
976
			  //do nothing, there was no guid for this document
977
			}
978
			sb.append("<docname>").append(doc.getDocname());
979
			sb.append("</docname><doctype>").append(doc.getDoctype());
980
			sb.append("</doctype>");
981
			sb.append("<user_owner>").append(doc.getUserowner());
982
			sb.append("</user_owner><user_updated>").append(doc.getUserupdated());
983
			sb.append("</user_updated>");
984
			sb.append("<date_created>");
985
			sb.append(doc.getCreateDate());
986
			sb.append("</date_created>");
987
			sb.append("<date_updated>");
988
			sb.append(doc.getUpdateDate());
989
			sb.append("</date_updated>");
990
			sb.append("<home_server>");
991
			sb.append(doc.getDocHomeServer());
992
			sb.append("</home_server>");
993
			sb.append("<public_access>").append(doc.getPublicaccess());
994
			sb.append("</public_access><rev>").append(doc.getRev());
995
			sb.append("</rev>");
996

    
997
			sb.append("<accessControl>");
998

    
999
			AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid); 
1000
			sb.append(acfsf.getAccessString());
1001
			
1002
			sb.append("</accessControl>");
1003

    
1004
			sb.append("</documentinfo>");
1005
			// get a writer for sending back to response
1006
			response.setContentType("text/xml");
1007
			Writer out = response.getWriter();
1008
			out.write(sb.toString());
1009
			out.close();
1010

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

    
1017
	}
1018

    
1019
	/**
1020
	 * Sends a datafile to a remote host
1021
	 */
1022
	protected static void handleGetDataFileRequest(OutputStream outPut,
1023
			Hashtable<String, String[]> params, HttpServletResponse response)
1024

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

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

    
1058
		if (!filepath.endsWith("/")) {
1059
			filepath += "/";
1060
		}
1061
		// Get file aboslute file name
1062
		String filename = filepath + docId;
1063

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

    
1085
		// Set the mime type
1086
		response.setContentType(contentType);
1087

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

    
1105
		}//try
1106
		catch (Exception e) {
1107
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1108
			logReplication.error("ReplicationService.handleGetDataFileRequest - error getting data file from MetacatReplication."
1109
					+ "handlGetDataFileRequest " + e.getMessage());
1110
			e.printStackTrace(System.out);
1111
		}//catch
1112

    
1113
	}
1114

    
1115
	/**
1116
	 * Sends a document to a remote host
1117
	 */
1118
	protected static void handleGetDocumentRequest(
1119
			Hashtable<String, String[]> params, HttpServletResponse response) {
1120

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

    
1142
			String docid = params.get("docid")[0];
1143
			logReplication.debug("ReplicationService.handleGetDocumentRequest - MetacatReplication.handleGetDocumentRequest for docid: "
1144
					+ docid);
1145
			DocumentImpl di = new DocumentImpl(docid);
1146

    
1147
			String documentDir = PropertyService
1148
					.getProperty("application.documentfilepath");
1149
			documentPath = documentDir + FileUtil.getFS() + docid;
1150

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

    
1159
			// read the file from disk and send it to outputstream
1160
			OutputStream outputStream = response.getOutputStream();
1161
			di.readFromFileSystem(outputStream, null, null, documentPath);
1162

    
1163
			logReplication.info("ReplicationService.handleGetDocumentRequest - document " + docid + " sent");
1164

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

    
1220
	}
1221

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

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

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

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

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

    
1292
			// Store the sql command
1293
			StringBuffer docsql = new StringBuffer();
1294
			StringBuffer revisionSql = new StringBuffer();
1295
			// Stroe the docid list
1296
			StringBuffer doclist = new StringBuffer();
1297
			// Store the deleted docid list
1298
			StringBuffer delsql = new StringBuffer();
1299
			// Store the data set file
1300
			Vector<Vector<String>> packageFiles = new Vector<Vector<String>>();
1301

    
1302
			// Append local server's name and replication servlet to doclist
1303
			doclist.append("<?xml version=\"1.0\"?><replication>");
1304
			doclist.append("<server>")
1305
					.append(MetacatUtil.getLocalReplicationServerName());
1306
			//doclist.append(util.getProperty("replicationpath"));
1307
			doclist.append("</server><updates>");
1308

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

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

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

    
1413
			pstmt = dbConn.prepareStatement(delsql.toString());
1414
			//usage count should increas 1
1415
			dbConn.increaseUsageCount(1);
1416

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

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

    
1441
			doclist.append("</updates></replication>");
1442
			logReplication.info("ReplicationService.handleUpdateRequest - doclist: " + doclist.toString());
1443
			pstmt.close();
1444
			//conn.close();
1445
			out.write(doclist.toString());
1446

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

    
1476
	}//handlUpdateRequest
1477

    
1478
	/*
1479
	 * This method will get the xml string for document in xml_revision
1480
	 * The schema look like <!ELEMENT revisionDocument (docid, rev, datafile*)>
1481
	 */
1482
	private static String prepareRevisionDoc(DBConnection dbConn, String revSql,
1483
			boolean replicateData) throws Exception {
1484
		logReplication.warn("ReplicationService.prepareRevisionDoc - The revision document sql is " + revSql);
1485
		StringBuffer revDocList = new StringBuffer();
1486
		PreparedStatement pstmt = dbConn.prepareStatement(revSql);
1487
		//usage count should increas 1
1488
		dbConn.increaseUsageCount(1);
1489

    
1490
		pstmt.execute();
1491
		ResultSet rs = pstmt.getResultSet();
1492
		boolean tablehasrows = rs.next();
1493
		while (tablehasrows) {
1494
			String recordDoctype = rs.getString(3);
1495

    
1496
			//If this is data file and it isn't configured to replicate data
1497
			if (recordDoctype.equals("BIN") && !replicateData) {
1498
				// do nothing
1499
				continue;
1500
			} else {
1501

    
1502
				revDocList.append("<revisionDocument>");
1503
				revDocList.append("<docid>").append(rs.getString(1));
1504
				revDocList.append("</docid><rev>").append(rs.getInt(2));
1505
				revDocList.append("</rev>");
1506
				// data file
1507
				if (recordDoctype.equals("BIN")) {
1508
					revDocList.append("<datafile>");
1509
					revDocList.append(PropertyService
1510
							.getProperty("replication.datafileflag"));
1511
					revDocList.append("</datafile>");
1512
				}
1513
				revDocList.append("</revisionDocument>");
1514

    
1515
			}//else
1516
			tablehasrows = rs.next();
1517
		}
1518
		//System.out.println("The revision list is"+ revDocList.toString());
1519
		return revDocList.toString();
1520
	}
1521

    
1522
	/**
1523
	 * Returns the xml_catalog table encoded in xml
1524
	 */
1525
	public static String getCatalogXML() {
1526
		return handleGetCatalogRequest(null, null, false);
1527
	}
1528

    
1529
	/**
1530
	 * Sends the contents of the xml_catalog table encoded in xml
1531
	 * The xml format is:
1532
	 * <!ELEMENT xml_catalog (row*)>
1533
	 * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
1534
	 *                system_id)>
1535
	 * All of the sub elements of row are #PCDATA
1536

    
1537
	 * If printFlag == false then do not print to out.
1538
	 */
1539
	protected static String handleGetCatalogRequest(
1540
			Hashtable<String, String[]> params, HttpServletResponse response,
1541
			boolean printFlag) {
1542
		DBConnection dbConn = null;
1543
		int serialNumber = -1;
1544
		PreparedStatement pstmt = null;
1545
		Writer out = null;
1546
		try {
1547
			// get writer, TODO: encoding?
1548
			response.setContentType("text/xml");
1549
			out = response.getWriter();
1550
			
1551
			/*conn = MetacatReplication.getDBConnection("MetacatReplication." +
1552
			                                          "handleGetCatalogRequest");*/
1553
			dbConn = DBConnectionPool
1554
					.getDBConnection("MetacatReplication.handleGetCatalogRequest");
1555
			serialNumber = dbConn.getCheckOutSerialNumber();
1556
			pstmt = dbConn.prepareStatement("select entry_type, "
1557
					+ "source_doctype, target_doctype, public_id, "
1558
					+ "system_id from xml_catalog");
1559
			pstmt.execute();
1560
			ResultSet rs = pstmt.getResultSet();
1561
			boolean tablehasrows = rs.next();
1562
			StringBuffer sb = new StringBuffer();
1563
			sb.append("<?xml version=\"1.0\"?><xml_catalog>");
1564
			while (tablehasrows) {
1565
				sb.append("<row><entry_type>").append(rs.getString(1));
1566
				sb.append("</entry_type><source_doctype>").append(rs.getString(2));
1567
				sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
1568
				sb.append("</target_doctype><public_id>").append(rs.getString(4));
1569
				// system id may not have server url on front.  Add it if not.
1570
				String systemID = rs.getString(5);
1571
				if (!systemID.startsWith("http://")) {
1572
					systemID = SystemUtil.getContextURL() + systemID;
1573
				}
1574
				sb.append("</public_id><system_id>").append(systemID);
1575
				sb.append("</system_id></row>");
1576

    
1577
				tablehasrows = rs.next();
1578
			}
1579
			sb.append("</xml_catalog>");
1580
			//conn.close();
1581
			if (printFlag) {
1582
				response.setContentType("text/xml");
1583
				out.write(sb.toString());
1584
			}
1585
			pstmt.close();
1586
			return sb.toString();
1587
		} catch (Exception e) {
1588
			logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1589
			logReplication.error("ReplicationService.handleGetCatalogRequest - error in MetacatReplication.handleGetCatalogRequest:"
1590
					+ e.getMessage());
1591
			e.printStackTrace(System.out);
1592
			if (printFlag) {
1593
				try {
1594
					out.write("<error>" + e.getMessage() + "</error>");
1595
				} catch (IOException e1) {
1596
					logMetacat.error(e1.getMessage(), e1);
1597
				}
1598
			}
1599
		} finally {
1600
			try {
1601
				pstmt.close();
1602
			}//try
1603
			catch (SQLException ee) {
1604
				logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1605
				logReplication.error("ReplicationService.handleGetCatalogRequest - Error in MetacatReplication.handleGetCatalogRequest: "
1606
						+ ee.getMessage());
1607
			}//catch
1608
			finally {
1609
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1610
			}//finally
1611
			if (out != null) {
1612
				try {
1613
					out.close();
1614
				} catch (IOException e1) {
1615
					logMetacat.error(e1.getMessage(), e1);
1616
				}
1617
			}
1618
		}//finally
1619

    
1620
		return null;
1621
	}
1622

    
1623
	/**
1624
	 * Sends the current system date to the remote server.  Using this action
1625
	 * for replication gets rid of any problems with syncronizing clocks
1626
	 * because a time specific to a document is always kept on its home server.
1627
	 */
1628
	protected static void handleGetTimeRequest(
1629
			Hashtable<String, String[]> params, HttpServletResponse response) {
1630
		SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yy HH:mm:ss");
1631
		java.util.Date localtime = new java.util.Date();
1632
		String dateString = formatter.format(localtime);
1633
		
1634
		// get a writer for sending back to response
1635
		response.setContentType("text/xml");
1636
		Writer out = null;
1637
		try {
1638
			out = response.getWriter();
1639
			out.write("<timestamp>" + dateString + "</timestamp>");
1640
			out.close();
1641
		} catch (IOException e) {
1642
			logMetacat.error(e.getMessage(), e);
1643
		}
1644
		
1645
	}
1646

    
1647
	/**
1648
	 * this method handles the timeout for a file lock.  when a lock is
1649
	 * granted it is granted for 30 seconds.  When this thread runs out
1650
	 * it deletes the docid from the queue, thus eliminating the lock.
1651
	 */
1652
	public void run() {
1653
		try {
1654
			logReplication.info("ReplicationService.run - thread started for docid: "
1655
					+ (String) fileLocks.elementAt(0));
1656

    
1657
			Thread.sleep(30000); //the lock will expire in 30 seconds
1658
			logReplication.info("thread for docid: "
1659
					+ (String) fileLocks.elementAt(fileLocks.size() - 1) + " exiting.");
1660

    
1661
			fileLocks.remove(fileLocks.size() - 1);
1662
			//fileLocks is treated as a FIFO queue.  If there are more than one lock
1663
			//in the vector, the first one inserted will be removed.
1664
		} catch (Exception e) {
1665
			logMetacat.error("ReplicationService.run - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1666
			logReplication.error("ReplicationService.run - error in file lock thread from "
1667
					+ "MetacatReplication.run: " + e.getMessage());
1668
		}
1669
	}
1670

    
1671
	/**
1672
	 * Returns the name of a server given a serverCode
1673
	 * @param serverCode the serverid of the server
1674
	 * @return the servername or null if the specified serverCode does not
1675
	 *         exist.
1676
	 */
1677
	public static String getServerNameForServerCode(int serverCode) {
1678
		//System.out.println("serverid: " + serverCode);
1679
		DBConnection dbConn = null;
1680
		int serialNumber = -1;
1681
		PreparedStatement pstmt = null;
1682
		try {
1683
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServer");
1684
			serialNumber = dbConn.getCheckOutSerialNumber();
1685
			String sql = new String("select server from "
1686
					+ "xml_replication where serverid = " + serverCode);
1687
			pstmt = dbConn.prepareStatement(sql);
1688
			//System.out.println("getserver sql: " + sql);
1689
			pstmt.execute();
1690
			ResultSet rs = pstmt.getResultSet();
1691
			boolean tablehasrows = rs.next();
1692
			if (tablehasrows) {
1693
				//System.out.println("server: " + rs.getString(1));
1694
				return rs.getString(1);
1695
			}
1696

    
1697
			//conn.close();
1698
		} catch (Exception e) {
1699
			logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1700
			logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplication.getServer: " + e.getMessage());
1701
		} finally {
1702
			try {
1703
				pstmt.close();
1704
			}//try
1705
			catch (SQLException ee) {
1706
				logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1707
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacactReplication.getserver: "
1708
						+ ee.getMessage());
1709
			}//catch
1710
			finally {
1711
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1712
			}//fianlly
1713
		}//finally
1714

    
1715
		return null;
1716
		//return null if the server does not exist
1717
	}
1718

    
1719
	/**
1720
	 * Returns a server code given a server name
1721
	 * @param server the name of the server
1722
	 * @return integer > 0 representing the code of the server, 0 if the server
1723
	 *  does not exist.
1724
	 */
1725
	public static int getServerCodeForServerName(String server) throws ServiceException {
1726
		DBConnection dbConn = null;
1727
		int serialNumber = -1;
1728
		PreparedStatement pstmt = null;
1729
		int serverCode = 0;
1730

    
1731
		try {
1732

    
1733
			//conn = util.openDBConnection();
1734
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServerCode");
1735
			serialNumber = dbConn.getCheckOutSerialNumber();
1736
			pstmt = dbConn.prepareStatement("SELECT serverid FROM xml_replication "
1737
					+ "WHERE server LIKE '" + server + "'");
1738
			pstmt.execute();
1739
			ResultSet rs = pstmt.getResultSet();
1740
			boolean tablehasrows = rs.next();
1741
			if (tablehasrows) {
1742
				serverCode = rs.getInt(1);
1743
				pstmt.close();
1744
				//conn.close();
1745
				return serverCode;
1746
			}
1747

    
1748
		} catch (SQLException sqle) {
1749
			throw new ServiceException("ReplicationService.getServerCodeForServerName - " 
1750
					+ "SQL error when getting server code: " + sqle.getMessage());
1751

    
1752
		} finally {
1753
			try {
1754
				pstmt.close();
1755
				//conn.close();
1756
			}//try
1757
			catch (Exception ee) {
1758
				logMetacat.error("ReplicationService.getServerCodeForServerName - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1759
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplicatio.getServerCode: "
1760
						+ ee.getMessage());
1761

    
1762
			}//catch
1763
			finally {
1764
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1765
			}//finally
1766
		}//finally
1767

    
1768
		return serverCode;
1769
	}
1770

    
1771
	/**
1772
	 * Method to get a host server information for given docid
1773
	 * @param conn a connection to the database
1774
	 */
1775
	public static Hashtable<String, String> getHomeServerInfoForDocId(String docId) {
1776
		Hashtable<String, String> sl = new Hashtable<String, String>();
1777
		DBConnection dbConn = null;
1778
		int serialNumber = -1;
1779
		docId = DocumentUtil.getDocIdFromString(docId);
1780
		PreparedStatement pstmt = null;
1781
		int serverLocation;
1782
		try {
1783
			//get conection
1784
			dbConn = DBConnectionPool.getDBConnection("ReplicationHandler.getHomeServer");
1785
			serialNumber = dbConn.getCheckOutSerialNumber();
1786
			//get a server location from xml_document table
1787
			pstmt = dbConn.prepareStatement("select server_location from xml_documents "
1788
					+ "where docid = ?");
1789
			pstmt.setString(1, docId);
1790
			pstmt.execute();
1791
			ResultSet serverName = pstmt.getResultSet();
1792
			//get a server location
1793
			if (serverName.next()) {
1794
				serverLocation = serverName.getInt(1);
1795
				pstmt.close();
1796
			} else {
1797
				pstmt.close();
1798
				//ut.returnConnection(conn);
1799
				return null;
1800
			}
1801
			pstmt = dbConn.prepareStatement("select server, last_checked, replicate "
1802
					+ "from xml_replication where serverid = ?");
1803
			//increase usage count
1804
			dbConn.increaseUsageCount(1);
1805
			pstmt.setInt(1, serverLocation);
1806
			pstmt.execute();
1807
			ResultSet rs = pstmt.getResultSet();
1808
			boolean tableHasRows = rs.next();
1809
			if (tableHasRows) {
1810

    
1811
				String server = rs.getString(1);
1812
				String last_checked = rs.getString(2);
1813
				if (!server.equals("localhost")) {
1814
					sl.put(server, last_checked);
1815
				}
1816

    
1817
			} else {
1818
				pstmt.close();
1819
				//ut.returnConnection(conn);
1820
				return null;
1821
			}
1822
			pstmt.close();
1823
		} catch (Exception e) {
1824
			logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1825
			logReplication.error("ReplicationService.getHomeServerInfoForDocId - error in replicationHandler.getHomeServer(): "
1826
					+ e.getMessage());
1827
		} finally {
1828
			try {
1829
				pstmt.close();
1830
				//ut.returnConnection(conn);
1831
			} catch (Exception ee) {
1832
				logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1833
				logReplication.error("ReplicationService.getHomeServerInfoForDocId - Eror irn rplicationHandler.getHomeServer() "
1834
						+ "to close pstmt: " + ee.getMessage());
1835
			} finally {
1836
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1837
			}
1838

    
1839
		}//finally
1840
		return sl;
1841
	}
1842

    
1843
	/**
1844
	 * Returns a home server location  given a accnum
1845
	 * @param accNum , given accNum for a document
1846
	 *
1847
	 */
1848
	public static int getHomeServerCodeForDocId(String accNum) throws ServiceException {
1849
		DBConnection dbConn = null;
1850
		int serialNumber = -1;
1851
		PreparedStatement pstmt = null;
1852
		int serverCode = 1;
1853
		String docId = DocumentUtil.getDocIdFromString(accNum);
1854

    
1855
		try {
1856

    
1857
			// Get DBConnection
1858
			dbConn = DBConnectionPool
1859
					.getDBConnection("ReplicationHandler.getServerLocation");
1860
			serialNumber = dbConn.getCheckOutSerialNumber();
1861
			pstmt = dbConn.prepareStatement("SELECT server_location FROM xml_documents "
1862
					+ "WHERE docid LIKE '" + docId + "'");
1863
			pstmt.execute();
1864
			ResultSet rs = pstmt.getResultSet();
1865
			boolean tablehasrows = rs.next();
1866
			//If a document is find, return the server location for it
1867
			if (tablehasrows) {
1868
				serverCode = rs.getInt(1);
1869
				pstmt.close();
1870
				//conn.close();
1871
				return serverCode;
1872
			}
1873
			//if couldn't find in xml_documents table, we think server code is 1
1874
			//(this is new document)
1875
			else {
1876
				pstmt.close();
1877
				//conn.close();
1878
				return serverCode;
1879
			}
1880

    
1881
		} catch (SQLException sqle) {
1882
			throw new ServiceException("ReplicationService.getHomeServerCodeForDocId - " 
1883
					+ "SQL error when getting home server code for docid: " + docId + " : " 
1884
					+ sqle.getMessage());
1885

    
1886
		} finally {
1887
			try {
1888
				pstmt.close();
1889
				//conn.close();
1890

    
1891
			} catch (SQLException sqle) {
1892
				logMetacat.error("ReplicationService.getHomeServerCodeForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1893
				logReplication.error("ReplicationService.getHomeServerCodeForDocId - ReplicationService.getHomeServerCodeForDocId - " 
1894
						+ "SQL error when getting home server code for docid: " + docId + " : " 
1895
						+ sqle.getMessage());
1896
			} finally {
1897
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1898
			}//finally
1899
		}//finally
1900
		//return serverCode;
1901
	}
1902

    
1903
	/**
1904
	 * This method returns the content of a url
1905
	 * @param u the url to return the content from
1906
	 * @return a string representing the content of the url
1907
	 * @throws java.io.IOException
1908
	 */
1909
	public static String getURLContent(URL u) throws java.io.IOException {
1910
	    logReplication.info("Getting url content from " + u.toString());
1911
		char istreamChar;
1912
		int istreamInt;
1913
		logReplication.info("ReplicationService.getURLContent - Before open the stream" + u.toString());
1914
		InputStream input = u.openStream();
1915
		logReplication.info("ReplicationService.getURLContent - After open the stream" + u.toString());
1916
		InputStreamReader istream = new InputStreamReader(input);
1917
		StringBuffer serverResponse = new StringBuffer();
1918
		while ((istreamInt = istream.read()) != -1) {
1919
			istreamChar = (char) istreamInt;
1920
			serverResponse.append(istreamChar);
1921
		}
1922
		istream.close();
1923
		input.close();
1924

    
1925
		return serverResponse.toString();
1926
	}
1927

    
1928
//	/**
1929
//	 * Method for writing replication messages to a log file specified in
1930
//	 * metacat.properties
1931
//	 */
1932
//	public static void replLog(String message) {
1933
//		try {
1934
//			FileOutputStream fos = new FileOutputStream(PropertyService
1935
//					.getProperty("replication.logdir")
1936
//					+ "/metacatreplication.log", true);
1937
//			PrintWriter pw = new PrintWriter(fos);
1938
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
1939
//			java.util.Date localtime = new java.util.Date();
1940
//			String dateString = formatter.format(localtime);
1941
//			dateString += " :: " + message;
1942
//			// time stamp each entry
1943
//			pw.println(dateString);
1944
//			pw.flush();
1945
//		} catch (Exception e) {
1946
//			logReplication.error("error writing to replication log from "
1947
//					+ "MetacatReplication.replLog: " + e.getMessage());
1948
//			// e.printStackTrace(System.out);
1949
//		}
1950
//	}
1951

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

    
1976
	/**
1977
	 * Returns true if the replicate field for server in xml_replication is 1.
1978
	 * Returns false otherwise
1979
	 */
1980
	public static boolean replToServer(String server) {
1981
		DBConnection dbConn = null;
1982
		int serialNumber = -1;
1983
		PreparedStatement pstmt = null;
1984
		try {
1985
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.repltoServer");
1986
			serialNumber = dbConn.getCheckOutSerialNumber();
1987
			pstmt = dbConn.prepareStatement("select replicate from "
1988
					+ "xml_replication where server like '" + server + "'");
1989
			pstmt.execute();
1990
			ResultSet rs = pstmt.getResultSet();
1991
			boolean tablehasrows = rs.next();
1992
			if (tablehasrows) {
1993
				int i = rs.getInt(1);
1994
				if (i == 1) {
1995
					pstmt.close();
1996
					//conn.close();
1997
					return true;
1998
				} else {
1999
					pstmt.close();
2000
					//conn.close();
2001
					return false;
2002
				}
2003
			}
2004
		} catch (SQLException sqle) {
2005
			logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2006
			logReplication.error("ReplicationService.replToServer - SQL error in MetacatReplication.replToServer: "
2007
					+ sqle.getMessage());
2008
		} finally {
2009
			try {
2010
				pstmt.close();
2011
				//conn.close();
2012
			}//try
2013
			catch (Exception ee) {
2014
				logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2015
				logReplication.error("ReplicationService.replToServer - Error in MetacatReplication.replToServer: "
2016
						+ ee.getMessage());
2017
			}//catch
2018
			finally {
2019
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2020
			}//finally
2021
		}//finally
2022
		return false;
2023
		//the default if this server does not exist is to not replicate to it.
2024
	}
2025

    
2026
}
(6-6/7)