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-24 16:18:55 -0700 (Tue, 24 May 2011) $'
10
 * '$Revision: 6097 $'
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.Enumeration;
49
import java.util.Hashtable;
50
import java.util.Timer;
51
import java.util.Vector;
52

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

    
56
import org.apache.log4j.Logger;
57
import org.dataone.service.types.SystemMetadata;
58
import org.xml.sax.InputSource;
59
import org.xml.sax.SAXException;
60
import org.xml.sax.XMLReader;
61

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

    
88
public class ReplicationService extends BaseService {
89

    
90
	private static ReplicationService replicationService = null;
91

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

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

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

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

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

    
144
			logReplication.info("ReplicationService.initialize - After combine current time, the real first time is "
145
					+ firstTime.toString() + " minisec");
146

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

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

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

    
178
	public boolean refreshable() {
179
		return true;
180
	}
181

    
182
	protected void doRefresh() throws ServiceException {
183
		return;
184
	}
185
	
186
	public void stop() throws ServiceException{
187
		
188
	}
189

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

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

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

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

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

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

    
305
				//Get data replication value
306
				dataReplicate = ((String[]) params.get("datareplicate"))[0];
307
				//Get hub value
308
				hub = ((String[]) params.get("hub"))[0];
309

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

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

    
352
					tablehasrows = rs.next();
353
				}
354
				out.write("</table></body></html>");
355

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

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

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

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

    
418
				out.write("<error>Unkonwn subaction</error>");
419

    
420
			}
421
			pstmt.close();
422
			//conn.close();
423

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

    
450
	}
451

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

    
458
		// the path to be uploaded to
459
		String certPath = SystemUtil.getContextDir();
460

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

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

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

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

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

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

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

    
552
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
553

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

    
561
			
562
			// Get home server of this docid
563
			String homeServer = (String) docinfoHash.get("home_server");
564
			String guid = (String) docinfoHash.get("guid");
565
			logReplication.info("XXXXXXXXXXXXXXXX GUID found in dociinfoHash: " + guid);
566
			
567
			logReplication.info("Processing guid " + guid + 
568
			  " information from handleForceReplicationRequest: " + 
569
			  docinfoHash.toString());
570
      IdentifierManager idman = IdentifierManager.getInstance();
571
      if(guid != null)
572
      { //if the guid was passed in, put it in the identifiers table
573
        logReplication.info("YYYYYYYYYYYYYY Creating guid/docid mapping for docid " + 
574
          docinfoHash.get("docid") + " and guid: " + guid);
575
        
576
        docName = (String) docinfoHash.get("docname");
577
        logReplication.info("ZZZZZZZZZZZZ docName: " + docName);
578
        if(docName.trim().equals("systemMetadata"))
579
        {
580
        	if (dbaction.equalsIgnoreCase("UPDATE")) {
581
        		logReplication.info("update mapping for systemMetadata: guid: " + guid + " localId: " + docinfoHash.get("docid"));
582
	            idman.updateSystemMetadataMapping(guid, docinfoHash.get("docid"));
583
	            logReplication.info("handleForceReplicateRequest: updating SM with additional info");
584
        	} else { // insert
585
	            logReplication.info("creating mapping for systemMetadata: guid: " + guid + " localId: " + docinfoHash.get("docid"));
586
	            idman.createSystemMetadataMapping(guid, docinfoHash.get("docid"));
587
        	}
588
        	logReplication.info("handleForceReplicateRequest: updating SM with additional info");
589
        	Date dateUploaded = new Date(new Long(docinfoHash.get("date_uploaded")));
590
	        Date dateModified = new Date(new Long(docinfoHash.get("date_modified")));
591
            SystemMetadata sysMeta = IdentifierManager.getInstance().asSystemMetadata(
592
                    dateUploaded, 
593
                    docinfoHash.get("rights_holder"),
594
                    docinfoHash.get("checksum"), 
595
                    docinfoHash.get("checksum_algorithm"), 
596
                    docinfoHash.get("origin_member_node"),
597
                    docinfoHash.get("authoritive_member_node"), 
598
                    dateModified,
599
                    docinfoHash.get("submitter"),
600
                    docinfoHash.get("guid"),
601
                    docinfoHash.get("object_format"),
602
                    new Long(docinfoHash.get("size")).longValue());
603
            IdentifierManager.getInstance().insertAdditionalSystemMetadataFields(sysMeta);
604
        }
605
        else
606
        {
607
        	if (dbaction.equalsIgnoreCase("UPDATE")) {
608
        		logReplication.info("updating mapping: guid: " + guid + " localId: " + docinfoHash.get("docid"));
609
	            idman.updateMapping(guid, docinfoHash.get("docid"));
610
        	} else { // insert
611
	            logReplication.info("creating mapping: guid: " + guid + " localId: " + docinfoHash.get("docid"));
612
	            idman.createMapping(guid, docinfoHash.get("docid"));
613
        	}
614
        }
615
      }
616
      else
617
      {
618
        logReplication.debug("No guid information was included with the replicated document");
619
      }
620
      
621
			String createdDate = (String) docinfoHash.get("date_created");
622
			String updatedDate = (String) docinfoHash.get("date_updated");
623
			logReplication.info("ReplicationService.handleForceReplicateRequest - homeServer: " + homeServer);
624
			// Get Document type
625
			String docType = (String) docinfoHash.get("doctype");
626
			logReplication.info("ReplicationService.handleForceReplicateRequest - docType: " + docType);
627
			String parserBase = null;
628
			// this for eml2 and we need user eml2 parser
629
			if (docType != null
630
					&& (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE)) {
631
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml200 document!");
632
				parserBase = DocumentImpl.EML200;
633
			} else if (docType != null
634
					&& (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE)) {
635
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.0.1 document!");
636
				parserBase = DocumentImpl.EML200;
637
			} else if (docType != null
638
					&& (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE)) {
639
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.0 document!");
640
				parserBase = DocumentImpl.EML210;
641
			} else if (docType != null
642
					&& (docType.trim()).equals(DocumentImpl.EML2_1_1NAMESPACE)) {
643
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.1 document!");
644
				parserBase = DocumentImpl.EML210;
645
			}
646
			logReplication.warn("ReplicationService.handleForceReplicateRequest - The parserBase is: " + parserBase);
647

    
648
			// Get DBConnection from pool
649
			dbConn = DBConnectionPool
650
					.getDBConnection("MetacatReplication.handleForceReplicateRequest");
651
			serialNumber = dbConn.getCheckOutSerialNumber();
652
			// write the document to local database
653
			DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false);
654
			//try this independently so we can set access even if the update action is invalid (i.e docid has not changed)
655
			try {
656
				wrapper.writeReplication(dbConn, xmldoc, null, null,
657
						dbaction, docid, null, null, homeServer, server, createdDate,
658
						updatedDate);
659
			} finally {
660

    
661
				//process extra access rules before dealing with the write exception (doc exist already)			
662
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
663
		        if (accessControlList != null) {
664
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
665
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
666
		        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
667
		        			acfsf.insertPermissions(xmlAccessDAO);
668
							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
669
									+ " permissions added to DB");
670
		        		}
671
		            }
672
		        }
673
		        
674
		        // process the real owner and updater
675
				String user = (String) docinfoHash.get("user_owner");
676
				String updated = (String) docinfoHash.get("user_updated");
677
		        updateUserOwner(dbConn, docid, user, updated);
678

    
679
				logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid + " added to DB with "
680
						+ "action " + dbaction);
681
				
682
				if(guid != null)
683
                {
684
                    if(!docName.trim().equals("systemMetadata"))
685
                    {
686
                        logReplication.info("replicate D1GUID:" + guid + ":D1SCIMETADATA:" + 
687
                                docid + ":");
688
                    }
689
                    else
690
                    {
691
                        logReplication.info("replicate D1GUID:" + guid + ":D1SYSMETADATA:" + 
692
                                docid + ":");
693
                    }
694
                }
695
				EventLog.getInstance().log(request.getRemoteAddr(), REPLICATIONUSER, docid, dbaction);
696
			}
697
		} catch (SQLException sqle) {
698
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
699
			logReplication.error("ReplicationService.handleForceReplicateRequest - SQL error when adding doc " + docid + 
700
					" to DB with action " + dbaction + ": " + sqle.getMessage());
701
		} catch (MalformedURLException mue) {
702
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
703
			logReplication.error("ReplicationService.handleForceReplicateRequest - URL error when adding doc " + docid + 
704
					" to DB with action " + dbaction + ": " + mue.getMessage());
705
		} catch (SAXException se) {
706
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
707
			logReplication.error("ReplicationService.handleForceReplicateRequest - SAX parsing error when adding doc " + docid + 
708
					" to DB with action " + dbaction + ": " + se.getMessage());
709
		} catch (HandlerException he) {
710
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
711
			logReplication.error("ReplicationService.handleForceReplicateRequest - Handler error when adding doc " + docid + 
712
					" to DB with action " + dbaction + ": " + he.getMessage());
713
		} catch (IOException ioe) {
714
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
715
			logReplication.error("ReplicationService.handleForceReplicateRequest - I/O error when adding doc " + docid + 
716
					" to DB with action " + dbaction + ": " + ioe.getMessage());
717
		} catch (PermOrderException poe) {
718
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
719
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
720
					" to DB with action " + dbaction + ": " + poe.getMessage());
721
		} catch (AccessControlException ace) {
722
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
723
			logReplication.error("ReplicationService.handleForceReplicateRequest - Permissions order error when adding doc " + docid + 
724
					" to DB with action " + dbaction + ": " + ace.getMessage());
725
		} catch (Exception e) {
726
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
727
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when adding doc " + docid + 
728
					" to DB with action " + dbaction + ": " + e.getMessage());
729
		} finally {
730
			// Return the checked out DBConnection
731
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
732
		}//finally
733
	}
734

    
735
	/*
736
	 * when a forcereplication delete request comes in, local host will delete this
737
	 * document
738
	 */
739
	protected static void handleForceReplicateDeleteRequest(
740
			Hashtable<String, String[]> params, HttpServletResponse response,
741
			HttpServletRequest request) {
742
		String server = ((String[]) params.get("server"))[0]; // the server that
743
		String docid = ((String[]) params.get("docid"))[0]; // sent the document
744
		try {
745
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - force replication delete request from " + server);
746
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - force replication delete docid " + docid);
747
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - Force replication delete request from: " + server);
748
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - Force replication delete docid: " + docid);
749
			DocumentImpl.delete(docid, null, null, server);
750
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - document " + docid + " was successfully deleted ");
751
			EventLog.getInstance().log(request.getRemoteAddr(), REPLICATIONUSER, docid,
752
					"delete");
753
			logReplication.info("ReplicationService.handleForceReplicateDeleteRequest - document " + docid + " was successfully deleted ");
754
		} catch (McdbDocNotFoundException e) {
755
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
756
			logReplication.error("document " + docid
757
					+ " failed to delete because " + e.getMessage());
758
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
759
		} catch (InsufficientKarmaException e) {
760
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
761
			logReplication.error("document " + docid
762
					+ " failed to delete because " + e.getMessage());
763
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
764
		} catch (SQLException e) {
765
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
766
			logReplication.error("document " + docid
767
					+ " failed to delete because " + e.getMessage());
768
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
769
		} catch (Exception e) {
770
			logMetacat.error("ReplicationService.handleForceReplicateDeleteRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
771
			logReplication.error("document " + docid
772
					+ " failed to delete because " + e.getMessage());
773
			logReplication.error("ReplicationService.handleForceReplicateDeleteRequest - error: " + e.getMessage());
774

    
775
		}//catch
776

    
777
	}
778

    
779
	/**
780
	 * when a forcereplication data file request comes in, local host sends a
781
	 * readdata request to the requesting server (remote server) for the specified
782
	 * docid. Then store it in local database and file system
783
	 */
784
	protected static void handleForceReplicateDataFileRequest(Hashtable<String, String[]> params,
785
			HttpServletRequest request) {
786

    
787
		//make sure there is some parameters
788
		if (params.isEmpty()) {
789
			return;
790
		}
791
		// Get remote server
792
		String server = ((String[]) params.get("server"))[0];
793
		// the docid should include rev number
794
		String docid = ((String[]) params.get("docid"))[0];
795
		// Make sure there is a docid and server
796
		if (docid == null || server == null || server.equals("")) {
797
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
798
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Didn't specify docid or server for replication");
799
			return;
800
		}
801

    
802
		// Overide or not
803
		//    boolean override = false;
804
		// dbaction - update or insert
805
		String dbaction = null;
806

    
807
		try {
808
			//docid was switch to two parts uinque code and rev
809
			//String uniqueCode=MetacatUtil.getDocIdFromString(docid);
810
			//int rev=MetacatUtil.getVersionFromString(docid);
811
			if (params.containsKey("dbaction")) {
812
				dbaction = ((String[]) params.get("dbaction"))[0];
813
			} else//default value is update
814
			{
815
				dbaction = "update";
816
			}
817

    
818
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - force replication request from " + server);
819
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication request from: " + server);
820
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication docid: " + docid);
821
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication action: " + dbaction);
822
			// get the document info from server
823
			URL docinfourl = new URL("https://" + server + "?server="
824
					+ MetacatUtil.getLocalReplicationServerName()
825
					+ "&action=getdocumentinfo&docid=" + docid);
826

    
827
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
828

    
829
			//dih is the parser for the docinfo xml format
830
			DocInfoHandler dih = new DocInfoHandler();
831
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
832
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
833
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
834
			
835
			String docName = (String) docinfoHash.get("docname");
836

    
837
			String docType = (String) docinfoHash.get("doctype");
838

    
839
			String docHomeServer = (String) docinfoHash.get("home_server");
840

    
841
			String createdDate = (String) docinfoHash.get("date_created");
842

    
843
			String updatedDate = (String) docinfoHash.get("date_updated");
844
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - docHomeServer of datafile: " + docHomeServer);
845

    
846
			//if action is delete, we don't delete the data file. Just archieve
847
			//the xml_documents
848
			/*if (dbaction.equals("delete"))
849
			{
850
			  //conn = util.getConnection();
851
			  DocumentImpl.delete(docid,user,null);
852
			  //util.returnConnection(conn);
853
			}*/
854
			//To data file insert or update is same
855
			if (dbaction.equals("insert") || dbaction.equals("update")) {
856
				//Get data file and store it into local file system.
857
				// sending back readdata request to server
858
				URL url = new URL("https://" + server + "?server="
859
						+ MetacatUtil.getLocalReplicationServerName()
860
						+ "&action=readdata&docid=" + docid);
861
				String datafilePath = PropertyService
862
						.getProperty("application.datafilepath");
863

    
864
				Exception writeException = null;
865
				//register data file into xml_documents table and wite data file
866
				//into file system
867
				try {
868
					DocumentImpl.writeDataFileInReplication(url.openStream(),
869
							datafilePath, docName, docType, docid, null, docHomeServer,
870
							server, DocumentImpl.DOCUMENTTABLE, false, createdDate,
871
							updatedDate);
872
				} catch (Exception e) {
873
					writeException = e;
874
				}
875
				
876
				// process the real owner and updater
877
				DBConnection dbConn = DBConnectionPool.getDBConnection("ReplicationService.handleForceDataFileRequest");
878
		        int serialNumber = dbConn.getCheckOutSerialNumber();
879
		        dbConn.setAutoCommit(false);
880
				String user = (String) docinfoHash.get("user_owner");
881
				String updated = (String) docinfoHash.get("user_updated");
882
		        updateUserOwner(dbConn, docid, user, updated);
883
		        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
884
		        
885
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
886
		        if (accessControlList != null) {
887
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
888
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
889
		        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
890
		        			acfsf.insertPermissions(xmlAccessDAO);
891
							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
892
									+ " permissions added to DB");
893
		        		}
894
		            }
895
		        }
896

    
897
				if (writeException != null) {
898
					throw writeException;
899
				}
900

    
901
				//false means non-timed replication
902
				logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - datafile " + docid + " added to DB with "
903
						+ "action " + dbaction);
904
				EventLog.getInstance().log(request.getRemoteAddr(), REPLICATIONUSER,
905
						docid, dbaction);
906
			}
907

    
908
		} catch (Exception e) {
909
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
910
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Datafile " + docid
911
					+ " failed to added to DB with " + "action " + dbaction + " because "
912
					+ e.getMessage());
913
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - ERROR in MetacatReplication.handleForceDataFileReplicate"
914
					+ "Request(): " + e.getMessage());
915
		}
916
	}
917

    
918
	/**
919
	 * Grants or denies a lock to a requesting host.
920
	 * The servlet parameters of interrest are:
921
	 * docid: the docid of the file the lock is being requested for
922
	 * currentdate: the timestamp of the document on the remote server
923
	 *
924
	 */
925
	protected static void handleGetLockRequest(
926
			Hashtable<String, String[]> params, HttpServletResponse response) {
927

    
928
		try {
929

    
930
			String docid = ((String[]) params.get("docid"))[0];
931
			String remoteRev = ((String[]) params.get("updaterev"))[0];
932
			DocumentImpl requestDoc = new DocumentImpl(docid);
933
			logReplication.info("ReplicationService.handleGetLockRequest - lock request for " + docid);
934
			int localRevInt = requestDoc.getRev();
935
			int remoteRevInt = Integer.parseInt(remoteRev);
936

    
937
			// get a writer for sending back to response
938
			response.setContentType("text/xml");
939
			Writer out = response.getWriter();
940
			
941
			if (remoteRevInt >= localRevInt) {
942
				if (!fileLocks.contains(docid)) { //grant the lock if it is not already locked
943
					fileLocks.add(0, docid); //insert at the beginning of the queue Vector
944
					//send a message back to the the remote host authorizing the insert
945
					out.write("<lockgranted><docid>" + docid
946
									+ "</docid></lockgranted>");
947
					//          lockThread = new Thread(this);
948
					//          lockThread.setPriority(Thread.MIN_PRIORITY);
949
					//          lockThread.start();
950
					logReplication.info("ReplicationService.handleGetLockRequest - lock granted for " + docid);
951
				} else { //deny the lock
952
					out.write("<filelocked><docid>" + docid + "</docid></filelocked>");
953
					logReplication.info("ReplicationService.handleGetLockRequest - lock denied for " + docid
954
							+ "reason: file already locked");
955
				}
956
			} else {//deny the lock.
957
				out.write("<outdatedfile><docid>" + docid + "</docid></filelocked>");
958
				logReplication.info("ReplicationService.handleGetLockRequest - lock denied for " + docid
959
						+ "reason: client has outdated file");
960
			}
961
			out.close();
962
			//conn.close();
963
		} catch (Exception e) {
964
			logMetacat.error("ReplicationService.handleGetLockRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
965
			logReplication.error("ReplicationService.handleGetLockRequest - error requesting file lock from MetacatReplication."
966
					+ "handleGetLockRequest: " + e.getMessage());
967
			e.printStackTrace(System.out);
968
		}
969
	}
970

    
971
	/**
972
	 * Sends all of the xml_documents information encoded in xml to a requestor
973
	 * the format is:
974
	 * <!ELEMENT documentinfo (docid, docname, doctype, doctitle, user_owner,
975
	 *                  user_updated, home_server, public_access, rev)/>
976
	 * all of the subelements of document info are #PCDATA
977
	 */
978
	protected static void handleGetDocumentInfoRequest(
979
			Hashtable<String, String[]> params, HttpServletResponse response) {
980
		String docid = ((String[]) (params.get("docid")))[0];
981
		StringBuffer sb = new StringBuffer();
982

    
983
		try {
984
		  IdentifierManager idman = IdentifierManager.getInstance();
985

    
986
			DocumentImpl doc = new DocumentImpl(docid);
987
			sb.append("<documentinfo><docid>").append(docid);
988
			sb.append("</docid>");
989
			try
990
			{
991
			  String guid = idman.getGUID(doc.getDocID(), doc.getRev());
992
			  sb.append("<guid>").append(guid).append("</guid>");
993
			  String smLocalId = idman.getSystemMetadataLocalId(guid);
994
			  Hashtable<String, String> sysmetaInfo = idman.getSystemMetadataInfo(smLocalId);
995
			  if(smLocalId != null && !smLocalId.trim().equals(""))
996
			  {
997
			      sb.append("<systemmetadatalocalid>").append(smLocalId).append("</systemmetadatalocalid>");
998
			  }
999
			  
1000
			  Enumeration<String> sysmetaKeys = sysmetaInfo.keys();
1001
			  while(sysmetaKeys.hasMoreElements())
1002
			  {
1003
			      String key = sysmetaKeys.nextElement();
1004
			      sb.append("<" + key + ">" + sysmetaInfo.get(key).toString() + "</" + key + ">");
1005
			  }
1006
			  
1007
			}
1008
			catch(McdbDocNotFoundException e)
1009
			{
1010
			  //do nothing, there was no guid for this document
1011
			}
1012
			sb.append("<docname>").append(doc.getDocname());
1013
			sb.append("</docname><doctype>").append(doc.getDoctype());
1014
			sb.append("</doctype>");
1015
			sb.append("<user_owner>").append(doc.getUserowner());
1016
			sb.append("</user_owner><user_updated>").append(doc.getUserupdated());
1017
			sb.append("</user_updated>");
1018
			sb.append("<date_created>");
1019
			sb.append(doc.getCreateDate());
1020
			sb.append("</date_created>");
1021
			sb.append("<date_updated>");
1022
			sb.append(doc.getUpdateDate());
1023
			sb.append("</date_updated>");
1024
			sb.append("<home_server>");
1025
			sb.append(doc.getDocHomeServer());
1026
			sb.append("</home_server>");
1027
			sb.append("<public_access>").append(doc.getPublicaccess());
1028
			sb.append("</public_access><rev>").append(doc.getRev());
1029
			sb.append("</rev>");
1030

    
1031
			sb.append("<accessControl>");
1032

    
1033
			AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid); 
1034
			sb.append(acfsf.getAccessString());
1035
			
1036
			sb.append("</accessControl>");
1037

    
1038
			sb.append("</documentinfo>");
1039
			// get a writer for sending back to response
1040
			response.setContentType("text/xml");
1041
			Writer out = response.getWriter();
1042
			out.write(sb.toString());
1043
			out.close();
1044

    
1045
		} catch (Exception e) {
1046
			logMetacat.error("ReplicationService.handleGetDocumentInfoRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1047
			logReplication.error("ReplicationService.handleGetDocumentInfoRequest - error in metacatReplication.handlegetdocumentinforequest "
1048
					+ "for doc: " + docid + " : " + e.getMessage());
1049
		}
1050

    
1051
	}
1052

    
1053
	/**
1054
	 * Sends a datafile to a remote host
1055
	 */
1056
	protected static void handleGetDataFileRequest(OutputStream outPut,
1057
			Hashtable<String, String[]> params, HttpServletResponse response)
1058

    
1059
	{
1060
		// File path for data file
1061
		String filepath;
1062
		// Request docid
1063
		String docId = ((String[]) (params.get("docid")))[0];
1064
		//check if the doicd is null
1065
		if (docId == null) {
1066
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1067
			logReplication.error("ReplicationService.handleGetDataFileRequest - Didn't specify docid for replication");
1068
			return;
1069
		}
1070

    
1071
		//try to open a https stream to test if the request server's public key
1072
		//in the key store, this is security issue
1073
		try {
1074
			filepath = PropertyService.getProperty("application.datafilepath");
1075
			String server = params.get("server")[0];
1076
			URL u = new URL("https://" + server + "?server="
1077
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test");
1078
			String test = ReplicationService.getURLContent(u);
1079
			//couldn't pass the test
1080
			if (test.indexOf("successfully") == -1) {
1081
				//response.setContentType("text/xml");
1082
				//outPut.println("<error>Couldn't pass the trust test</error>");
1083
				logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1084
				logReplication.error("ReplicationService.handleGetDataFileRequest - Couldn't pass the trust test");
1085
				return;
1086
			}
1087
		}//try
1088
		catch (Exception ee) {
1089
			return;
1090
		}//catch
1091

    
1092
		if (!filepath.endsWith("/")) {
1093
			filepath += "/";
1094
		}
1095
		// Get file aboslute file name
1096
		String filename = filepath + docId;
1097

    
1098
		//MIME type
1099
		String contentType = null;
1100
		if (filename.endsWith(".xml")) {
1101
			contentType = "text/xml";
1102
		} else if (filename.endsWith(".css")) {
1103
			contentType = "text/css";
1104
		} else if (filename.endsWith(".dtd")) {
1105
			contentType = "text/plain";
1106
		} else if (filename.endsWith(".xsd")) {
1107
			contentType = "text/xml";
1108
		} else if (filename.endsWith("/")) {
1109
			contentType = "text/html";
1110
		} else {
1111
			File f = new File(filename);
1112
			if (f.isDirectory()) {
1113
				contentType = "text/html";
1114
			} else {
1115
				contentType = "application/octet-stream";
1116
			}
1117
		}
1118

    
1119
		// Set the mime type
1120
		response.setContentType(contentType);
1121

    
1122
		// Get the content of the file
1123
		FileInputStream fin = null;
1124
		try {
1125
			// FileInputStream to metacat
1126
			fin = new FileInputStream(filename);
1127
			// 4K buffer
1128
			byte[] buf = new byte[4 * 1024];
1129
			// Read data from file input stream to byte array
1130
			int b = fin.read(buf);
1131
			// Write to outStream from byte array
1132
			while (b != -1) {
1133
				outPut.write(buf, 0, b);
1134
				b = fin.read(buf);
1135
			}
1136
			// close file input stream
1137
			fin.close();
1138

    
1139
		}//try
1140
		catch (Exception e) {
1141
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1142
			logReplication.error("ReplicationService.handleGetDataFileRequest - error getting data file from MetacatReplication."
1143
					+ "handlGetDataFileRequest " + e.getMessage());
1144
			e.printStackTrace(System.out);
1145
		}//catch
1146

    
1147
	}
1148

    
1149
	/**
1150
	 * Sends a document to a remote host
1151
	 */
1152
	protected static void handleGetDocumentRequest(
1153
			Hashtable<String, String[]> params, HttpServletResponse response) {
1154

    
1155
		String urlString = null;
1156
		String documentPath = null;
1157
		String errorMsg = null;
1158
		try {
1159
			// try to open a https stream to test if the request server's public
1160
			// key
1161
			// in the key store, this is security issue
1162
			String server = params.get("server")[0];
1163
			urlString = "https://" + server + "?server="
1164
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test";
1165
			URL u = new URL(urlString);
1166
			String test = ReplicationService.getURLContent(u);
1167
			// couldn't pass the test
1168
			if (test.indexOf("successfully") == -1) {
1169
				response.setContentType("text/xml");
1170
				Writer out = response.getWriter();
1171
				out.write("<error>Couldn't pass the trust test " + test + " </error>");
1172
				out.close();
1173
				return;
1174
			}
1175

    
1176
			String docid = params.get("docid")[0];
1177
			logReplication.debug("ReplicationService.handleGetDocumentRequest - MetacatReplication.handleGetDocumentRequest for docid: "
1178
					+ docid);
1179
			DocumentImpl di = new DocumentImpl(docid);
1180

    
1181
			String documentDir = PropertyService
1182
					.getProperty("application.documentfilepath");
1183
			documentPath = documentDir + FileUtil.getFS() + docid;
1184

    
1185
			// if the document does not exist on disk, read it from db and write
1186
			// it to disk.
1187
			if (FileUtil.getFileStatus(documentPath) == FileUtil.DOES_NOT_EXIST
1188
					|| FileUtil.getFileSize(documentPath) == 0) {
1189
				FileOutputStream fos = new FileOutputStream(documentPath);
1190
				di.toXml(fos, null, null, true);
1191
			}
1192

    
1193
			// read the file from disk and send it to outputstream
1194
			OutputStream outputStream = response.getOutputStream();
1195
			di.readFromFileSystem(outputStream, null, null, documentPath);
1196

    
1197
			logReplication.info("ReplicationService.handleGetDocumentRequest - document " + docid + " sent");
1198

    
1199
			// return to avoid continuing to the error reporting section at the end
1200
			return;
1201
			
1202
		} catch (MalformedURLException mue) {
1203
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1204
			logReplication.error("ReplicationService.handleGetDocumentRequest - Url error when getting document from MetacatReplication."
1205
					+ "handlGetDocumentRequest for url: " + urlString + " : "
1206
					+ mue.getMessage());
1207
			// e.printStackTrace(System.out);
1208
			
1209
		} catch (IOException ioe) {
1210
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1211
			logReplication.error("ReplicationService.handleGetDocumentRequest - I/O error when getting document from MetacatReplication."
1212
					+ "handlGetDocumentRequest for file: " + documentPath + " : "
1213
					+ ioe.getMessage());
1214
			errorMsg = ioe.getMessage();
1215
		} catch (PropertyNotFoundException pnfe) {
1216
			logMetacat.error("ReplicationService.handleGetDocumentRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1217
			logReplication
1218
					.error("ReplicationService.handleGetDocumentRequest - Error getting property when getting document from MetacatReplication."
1219
							+ "handlGetDocumentRequest for file: "
1220
							+ documentPath
1221
							+ " : "
1222
							+ pnfe.getMessage());
1223
			// e.printStackTrace(System.out);
1224
			errorMsg = pnfe.getMessage();
1225
		} catch (McdbException me) {
1226
			logReplication
1227
					.error("ReplicationService.handleGetDocumentRequest - Document implementation error  getting property when getting document from MetacatReplication."
1228
							+ "handlGetDocumentRequest for file: "
1229
							+ documentPath
1230
							+ " : "
1231
							+ me.getMessage());
1232
			// e.printStackTrace(System.out);
1233
			errorMsg = me.getMessage();
1234
		}
1235
		
1236
		// report any errors if we got here
1237
		response.setContentType("text/xml");
1238
		Writer out = null;
1239
		try {
1240
			response.getWriter();
1241
			out = response.getWriter();
1242
			out.write("<error>" + errorMsg + "</error>");
1243
		} catch (Exception e) {
1244
			logMetacat.error(e.getMessage(), e);
1245
		} finally {
1246
			try {
1247
				out.close();
1248
			} catch (IOException e) {
1249
				logMetacat.error(e.getMessage(), e);
1250
			}
1251
		}
1252
		
1253

    
1254
	}
1255

    
1256
	/**
1257
	 * Sends a list of all of the documents on this sever along with their
1258
	 * revision numbers. The format is: <!ELEMENT replication (server, updates)>
1259
	 * <!ELEMENT server (#PCDATA)> <!ELEMENT updates ((updatedDocument |
1260
	 * deleteDocument | revisionDocument)*)> <!ELEMENT updatedDocument (docid,
1261
	 * rev, datafile*)> <!ELEMENT deletedDocument (docid, rev)> <!ELEMENT
1262
	 * revisionDocument (docid, rev, datafile*)> <!ELEMENT docid (#PCDATA)>
1263
	 * <!ELEMENT rev (#PCDATA)> <!ELEMENT datafile (#PCDATA)> note that the rev
1264
	 * in deletedDocument is always empty. I just left it in there to make the
1265
	 * parser implementation easier.
1266
	 */
1267
	protected static void handleUpdateRequest(Hashtable<String, String[]> params,
1268
			HttpServletResponse response) {
1269
		// Checked out DBConnection
1270
		DBConnection dbConn = null;
1271
		// DBConenction serial number when checked it out
1272
		int serialNumber = -1;
1273
		PreparedStatement pstmt = null;
1274
		// Server list to store server info of xml_replication table
1275
		ReplicationServerList serverList = null;
1276
		
1277
		// a writer for response
1278
		Writer out = null;
1279

    
1280
		try {
1281
			// get writer, TODO: encoding?
1282
			response.setContentType("text/xml");
1283
			out = response.getWriter();
1284
			
1285
			// Check out a DBConnection from pool
1286
			dbConn = DBConnectionPool
1287
					.getDBConnection("MetacatReplication.handleUpdateRequest");
1288
			serialNumber = dbConn.getCheckOutSerialNumber();
1289
			// Create a server list from xml_replication table
1290
			serverList = new ReplicationServerList();
1291

    
1292
			// Get remote server name from param
1293
			String server = ((String[]) params.get("server"))[0];
1294
			// If no servr name in param, return a error
1295
			if (server == null || server.equals("")) {
1296
				out.write("<error>Request didn't specify server name</error>");
1297
				out.close();
1298
				return;
1299
			}//if
1300

    
1301
			//try to open a https stream to test if the request server's public key
1302
			//in the key store, this is security issue
1303
			String testUrl = "https://" + server + "?server="
1304
            + MetacatUtil.getLocalReplicationServerName() + "&action=test";
1305
			logReplication.info("Running trust test: " + testUrl);
1306
			URL u = new URL(testUrl);
1307
			String test = ReplicationService.getURLContent(u);
1308
			logReplication.info("Ouput from test is '" + test + "'");
1309
			//couldn't pass the test
1310
			if (test.indexOf("successfully") == -1) {
1311
			    logReplication.error("Trust test failed.");
1312
				out.write("<error>Couldn't pass the trust test</error>");
1313
				out.close();
1314
				return;
1315
			}
1316
			logReplication.info("Trust test succeeded.");
1317

    
1318
			// Check if local host configure to replicate xml documents to remote
1319
			// server. If not send back a error message
1320
			if (!serverList.getReplicationValue(server)) {
1321
				out.write("<error>Configuration not allow to replicate document to you</error>");
1322
				out.close();
1323
				return;
1324
			}//if
1325

    
1326
			// Store the sql command
1327
			StringBuffer docsql = new StringBuffer();
1328
			StringBuffer revisionSql = new StringBuffer();
1329
			// Stroe the docid list
1330
			StringBuffer doclist = new StringBuffer();
1331
			// Store the deleted docid list
1332
			StringBuffer delsql = new StringBuffer();
1333
			// Store the data set file
1334
			Vector<Vector<String>> packageFiles = new Vector<Vector<String>>();
1335

    
1336
			// Append local server's name and replication servlet to doclist
1337
			doclist.append("<?xml version=\"1.0\"?><replication>");
1338
			doclist.append("<server>")
1339
					.append(MetacatUtil.getLocalReplicationServerName());
1340
			//doclist.append(util.getProperty("replicationpath"));
1341
			doclist.append("</server><updates>");
1342

    
1343
			// Get correct docid that reside on this server according the requesting
1344
			// server's replicate and data replicate value in xml_replication table
1345
			docsql.append(DatabaseService.getInstance().getDBAdapter().getReplicationDocumentListSQL());
1346
			//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)) ");
1347
			revisionSql.append("select docid, rev, doctype from xml_revisions ");
1348
			// If the localhost is not a hub to the remote server, only replicate
1349
			// the docid' which home server is local host (server_location =1)
1350
			if (!serverList.getHubValue(server)) {
1351
				String serverLocationDoc = " and a.server_location = 1";
1352
				String serverLocationRev = "where server_location = 1";
1353
				docsql.append(serverLocationDoc);
1354
				revisionSql.append(serverLocationRev);
1355
			}
1356
			logReplication.info("ReplicationService.handleUpdateRequest - Doc sql: " + docsql.toString());
1357

    
1358
			// Get any deleted documents
1359
			delsql.append("select distinct docid from ");
1360
			delsql.append("xml_revisions where docid not in (select docid from ");
1361
			delsql.append("xml_documents) ");
1362
			// If the localhost is not a hub to the remote server, only replicate
1363
			// the docid' which home server is local host (server_location =1)
1364
			if (!serverList.getHubValue(server)) {
1365
				delsql.append("and server_location = 1");
1366
			}
1367
			logReplication.info("ReplicationService.handleUpdateRequest - Deleted sql: " + delsql.toString());
1368

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

    
1447
			pstmt = dbConn.prepareStatement(delsql.toString());
1448
			//usage count should increas 1
1449
			dbConn.increaseUsageCount(1);
1450

    
1451
			pstmt.execute();
1452
			rs = pstmt.getResultSet();
1453
			tablehasrows = rs.next();
1454
			while (tablehasrows) { //handle the deleted documents
1455
				doclist.append("<deletedDocument><docid>").append(rs.getString(1));
1456
				doclist.append("</docid><rev></rev></deletedDocument>");
1457
				//note that rev is always empty for deleted docs
1458
				tablehasrows = rs.next();
1459
			}
1460

    
1461
			//now we can put the package files into the xml results
1462
			for (int i = 0; i < packageFiles.size(); i++) {
1463
				Vector<String> v = packageFiles.elementAt(i);
1464
				doclist.append("<updatedDocument>");
1465
				doclist.append("<docid>").append(v.elementAt(0));
1466
				doclist.append("</docid><rev>");
1467
				doclist.append(v.elementAt(1));
1468
				doclist.append("</rev>");
1469
				doclist.append("</updatedDocument>");
1470
			}
1471
			// add revision doc list  
1472
			doclist.append(prepareRevisionDoc(dbConn, revisionSql.toString(),
1473
					replicateData));
1474

    
1475
			doclist.append("</updates></replication>");
1476
			logReplication.info("ReplicationService.handleUpdateRequest - doclist: " + doclist.toString());
1477
			pstmt.close();
1478
			//conn.close();
1479
			out.write(doclist.toString());
1480

    
1481
		} catch (Exception e) {
1482
			logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1483
			logReplication.error("ReplicationService.handleUpdateRequest - error in MetacatReplication." + "handleupdaterequest: "
1484
					+ e.getMessage());
1485
			//e.printStackTrace(System.out);
1486
			try {
1487
				out.write("<error>" + e.getMessage() + "</error>");
1488
			} catch (IOException e1) {
1489
				logMetacat.error(e1.getMessage(), e1);
1490
			}
1491
		} finally {
1492
			try {
1493
				pstmt.close();
1494
			}//try
1495
			catch (SQLException ee) {
1496
				logMetacat.error("ReplicationService.handleUpdateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1497
				logReplication.error("ReplicationService.handleUpdateRequest - Error in MetacatReplication."
1498
						+ "handleUpdaterequest to close pstmt: " + ee.getMessage());
1499
			}//catch
1500
			finally {
1501
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1502
			}//finally
1503
			try {
1504
				out.close();
1505
			} catch (IOException e) {
1506
				logMetacat.error(e.getMessage(), e);
1507
			}
1508
		}//finally
1509

    
1510
	}//handlUpdateRequest
1511

    
1512
	/**
1513
	 * 
1514
	 * @param dbConn connection for doing the update
1515
	 * @param docid the document id to update
1516
	 * @param owner the user_owner
1517
	 * @param updater the user_updated
1518
	 * @throws SQLException
1519
	 */
1520
	public static void updateUserOwner(DBConnection dbConn, String docid, String owner, String updater) throws SQLException {
1521
	
1522
		String sql = 
1523
			"UPDATE xml_documents " +
1524
			"SET user_owner = ?, " +
1525
			"user_updated = ? " +
1526
			"WHERE docid = ?;";
1527
		PreparedStatement pstmt = dbConn.prepareStatement(sql);
1528
		//usage count should increas 1
1529
		dbConn.increaseUsageCount(1);
1530

    
1531
		docid = DocumentUtil.getSmartDocId(docid);
1532
		pstmt.setString(1, owner);
1533
		pstmt.setString(2, updater);
1534
		pstmt.setString(3, docid);
1535
		pstmt.execute();
1536
		pstmt.close();
1537
		
1538
		dbConn.commit();
1539
	}
1540
	
1541
	/*
1542
	 * This method will get the xml string for document in xml_revision
1543
	 * The schema look like <!ELEMENT revisionDocument (docid, rev, datafile*)>
1544
	 */
1545
	private static String prepareRevisionDoc(DBConnection dbConn, String revSql,
1546
			boolean replicateData) throws Exception {
1547
		logReplication.warn("ReplicationService.prepareRevisionDoc - The revision document sql is " + revSql);
1548
		StringBuffer revDocList = new StringBuffer();
1549
		PreparedStatement pstmt = dbConn.prepareStatement(revSql);
1550
		//usage count should increas 1
1551
		dbConn.increaseUsageCount(1);
1552

    
1553
		pstmt.execute();
1554
		ResultSet rs = pstmt.getResultSet();
1555
		boolean tablehasrows = rs.next();
1556
		while (tablehasrows) {
1557
			String recordDoctype = rs.getString(3);
1558

    
1559
			//If this is data file and it isn't configured to replicate data
1560
			if (recordDoctype.equals("BIN") && !replicateData) {
1561
				// do nothing
1562
				continue;
1563
			} else {
1564

    
1565
				revDocList.append("<revisionDocument>");
1566
				revDocList.append("<docid>").append(rs.getString(1));
1567
				revDocList.append("</docid><rev>").append(rs.getInt(2));
1568
				revDocList.append("</rev>");
1569
				// data file
1570
				if (recordDoctype.equals("BIN")) {
1571
					revDocList.append("<datafile>");
1572
					revDocList.append(PropertyService
1573
							.getProperty("replication.datafileflag"));
1574
					revDocList.append("</datafile>");
1575
				}
1576
				revDocList.append("</revisionDocument>");
1577

    
1578
			}//else
1579
			tablehasrows = rs.next();
1580
		}
1581
		//System.out.println("The revision list is"+ revDocList.toString());
1582
		return revDocList.toString();
1583
	}
1584

    
1585
	/**
1586
	 * Returns the xml_catalog table encoded in xml
1587
	 */
1588
	public static String getCatalogXML() {
1589
		return handleGetCatalogRequest(null, null, false);
1590
	}
1591

    
1592
	/**
1593
	 * Sends the contents of the xml_catalog table encoded in xml
1594
	 * The xml format is:
1595
	 * <!ELEMENT xml_catalog (row*)>
1596
	 * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
1597
	 *                system_id)>
1598
	 * All of the sub elements of row are #PCDATA
1599

    
1600
	 * If printFlag == false then do not print to out.
1601
	 */
1602
	protected static String handleGetCatalogRequest(
1603
			Hashtable<String, String[]> params, HttpServletResponse response,
1604
			boolean printFlag) {
1605
		DBConnection dbConn = null;
1606
		int serialNumber = -1;
1607
		PreparedStatement pstmt = null;
1608
		Writer out = null;
1609
		try {
1610
			// get writer, TODO: encoding?
1611
		    if(printFlag)
1612
		    {
1613
		        response.setContentType("text/xml");
1614
		        out = response.getWriter();
1615
		    }
1616
			/*conn = MetacatReplication.getDBConnection("MetacatReplication." +
1617
			                                          "handleGetCatalogRequest");*/
1618
			dbConn = DBConnectionPool
1619
					.getDBConnection("MetacatReplication.handleGetCatalogRequest");
1620
			serialNumber = dbConn.getCheckOutSerialNumber();
1621
			pstmt = dbConn.prepareStatement("select entry_type, "
1622
					+ "source_doctype, target_doctype, public_id, "
1623
					+ "system_id from xml_catalog");
1624
			pstmt.execute();
1625
			ResultSet rs = pstmt.getResultSet();
1626
			boolean tablehasrows = rs.next();
1627
			StringBuffer sb = new StringBuffer();
1628
			sb.append("<?xml version=\"1.0\"?><xml_catalog>");
1629
			while (tablehasrows) {
1630
				sb.append("<row><entry_type>").append(rs.getString(1));
1631
				sb.append("</entry_type><source_doctype>").append(rs.getString(2));
1632
				sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
1633
				sb.append("</target_doctype><public_id>").append(rs.getString(4));
1634
				// system id may not have server url on front.  Add it if not.
1635
				String systemID = rs.getString(5);
1636
				if (!systemID.startsWith("http://")) {
1637
					systemID = SystemUtil.getContextURL() + systemID;
1638
				}
1639
				sb.append("</public_id><system_id>").append(systemID);
1640
				sb.append("</system_id></row>");
1641

    
1642
				tablehasrows = rs.next();
1643
			}
1644
			sb.append("</xml_catalog>");
1645
			//conn.close();
1646
			if (printFlag) {
1647
				response.setContentType("text/xml");
1648
				out.write(sb.toString());
1649
			}
1650
			pstmt.close();
1651
			return sb.toString();
1652
		} catch (Exception e) {
1653
			logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1654
			logReplication.error("ReplicationService.handleGetCatalogRequest - error in MetacatReplication.handleGetCatalogRequest:"
1655
					+ e.getMessage());
1656
			e.printStackTrace(System.out);
1657
			if (printFlag) {
1658
				try {
1659
					out.write("<error>" + e.getMessage() + "</error>");
1660
				} catch (IOException e1) {
1661
					logMetacat.error(e1.getMessage(), e1);
1662
				}
1663
			}
1664
		} finally {
1665
			try {
1666
				pstmt.close();
1667
			}//try
1668
			catch (SQLException ee) {
1669
				logMetacat.error("ReplicationService.handleGetCatalogRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1670
				logReplication.error("ReplicationService.handleGetCatalogRequest - Error in MetacatReplication.handleGetCatalogRequest: "
1671
						+ ee.getMessage());
1672
			}//catch
1673
			finally {
1674
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1675
			}//finally
1676
			if (out != null) {
1677
				try {
1678
					out.close();
1679
				} catch (IOException e1) {
1680
					logMetacat.error(e1.getMessage(), e1);
1681
				}
1682
			}
1683
		}//finally
1684

    
1685
		return null;
1686
	}
1687

    
1688
	/**
1689
	 * Sends the current system date to the remote server.  Using this action
1690
	 * for replication gets rid of any problems with syncronizing clocks
1691
	 * because a time specific to a document is always kept on its home server.
1692
	 */
1693
	protected static void handleGetTimeRequest(
1694
			Hashtable<String, String[]> params, HttpServletResponse response) {
1695
		SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yy HH:mm:ss");
1696
		java.util.Date localtime = new java.util.Date();
1697
		String dateString = formatter.format(localtime);
1698
		
1699
		// get a writer for sending back to response
1700
		response.setContentType("text/xml");
1701
		Writer out = null;
1702
		try {
1703
			out = response.getWriter();
1704
			out.write("<timestamp>" + dateString + "</timestamp>");
1705
			out.close();
1706
		} catch (IOException e) {
1707
			logMetacat.error(e.getMessage(), e);
1708
		}
1709
		
1710
	}
1711

    
1712
	/**
1713
	 * this method handles the timeout for a file lock.  when a lock is
1714
	 * granted it is granted for 30 seconds.  When this thread runs out
1715
	 * it deletes the docid from the queue, thus eliminating the lock.
1716
	 */
1717
	public void run() {
1718
		try {
1719
			logReplication.info("ReplicationService.run - thread started for docid: "
1720
					+ (String) fileLocks.elementAt(0));
1721

    
1722
			Thread.sleep(30000); //the lock will expire in 30 seconds
1723
			logReplication.info("thread for docid: "
1724
					+ (String) fileLocks.elementAt(fileLocks.size() - 1) + " exiting.");
1725

    
1726
			fileLocks.remove(fileLocks.size() - 1);
1727
			//fileLocks is treated as a FIFO queue.  If there are more than one lock
1728
			//in the vector, the first one inserted will be removed.
1729
		} catch (Exception e) {
1730
			logMetacat.error("ReplicationService.run - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1731
			logReplication.error("ReplicationService.run - error in file lock thread from "
1732
					+ "MetacatReplication.run: " + e.getMessage());
1733
		}
1734
	}
1735

    
1736
	/**
1737
	 * Returns the name of a server given a serverCode
1738
	 * @param serverCode the serverid of the server
1739
	 * @return the servername or null if the specified serverCode does not
1740
	 *         exist.
1741
	 */
1742
	public static String getServerNameForServerCode(int serverCode) {
1743
		//System.out.println("serverid: " + serverCode);
1744
		DBConnection dbConn = null;
1745
		int serialNumber = -1;
1746
		PreparedStatement pstmt = null;
1747
		try {
1748
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServer");
1749
			serialNumber = dbConn.getCheckOutSerialNumber();
1750
			String sql = new String("select server from "
1751
					+ "xml_replication where serverid = " + serverCode);
1752
			pstmt = dbConn.prepareStatement(sql);
1753
			//System.out.println("getserver sql: " + sql);
1754
			pstmt.execute();
1755
			ResultSet rs = pstmt.getResultSet();
1756
			boolean tablehasrows = rs.next();
1757
			if (tablehasrows) {
1758
				//System.out.println("server: " + rs.getString(1));
1759
				return rs.getString(1);
1760
			}
1761

    
1762
			//conn.close();
1763
		} catch (Exception e) {
1764
			logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1765
			logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplication.getServer: " + e.getMessage());
1766
		} finally {
1767
			try {
1768
				pstmt.close();
1769
			}//try
1770
			catch (SQLException ee) {
1771
				logMetacat.error("ReplicationService.getServerNameForServerCode - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1772
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacactReplication.getserver: "
1773
						+ ee.getMessage());
1774
			}//catch
1775
			finally {
1776
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1777
			}//fianlly
1778
		}//finally
1779

    
1780
		return null;
1781
		//return null if the server does not exist
1782
	}
1783

    
1784
	/**
1785
	 * Returns a server code given a server name
1786
	 * @param server the name of the server
1787
	 * @return integer > 0 representing the code of the server, 0 if the server
1788
	 *  does not exist.
1789
	 */
1790
	public static int getServerCodeForServerName(String server) throws ServiceException {
1791
		DBConnection dbConn = null;
1792
		int serialNumber = -1;
1793
		PreparedStatement pstmt = null;
1794
		int serverCode = 0;
1795

    
1796
		try {
1797

    
1798
			//conn = util.openDBConnection();
1799
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.getServerCode");
1800
			serialNumber = dbConn.getCheckOutSerialNumber();
1801
			pstmt = dbConn.prepareStatement("SELECT serverid FROM xml_replication "
1802
					+ "WHERE server LIKE '" + server + "'");
1803
			pstmt.execute();
1804
			ResultSet rs = pstmt.getResultSet();
1805
			boolean tablehasrows = rs.next();
1806
			if (tablehasrows) {
1807
				serverCode = rs.getInt(1);
1808
				pstmt.close();
1809
				//conn.close();
1810
				return serverCode;
1811
			}
1812

    
1813
		} catch (SQLException sqle) {
1814
			throw new ServiceException("ReplicationService.getServerCodeForServerName - " 
1815
					+ "SQL error when getting server code: " + sqle.getMessage());
1816

    
1817
		} finally {
1818
			try {
1819
				pstmt.close();
1820
				//conn.close();
1821
			}//try
1822
			catch (Exception ee) {
1823
				logMetacat.error("ReplicationService.getServerCodeForServerName - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1824
				logReplication.error("ReplicationService.getServerNameForServerCode - Error in MetacatReplicatio.getServerCode: "
1825
						+ ee.getMessage());
1826

    
1827
			}//catch
1828
			finally {
1829
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1830
			}//finally
1831
		}//finally
1832

    
1833
		return serverCode;
1834
	}
1835

    
1836
	/**
1837
	 * Method to get a host server information for given docid
1838
	 * @param conn a connection to the database
1839
	 */
1840
	public static Hashtable<String, String> getHomeServerInfoForDocId(String docId) {
1841
		Hashtable<String, String> sl = new Hashtable<String, String>();
1842
		DBConnection dbConn = null;
1843
		int serialNumber = -1;
1844
		docId = DocumentUtil.getDocIdFromString(docId);
1845
		PreparedStatement pstmt = null;
1846
		int serverLocation;
1847
		try {
1848
			//get conection
1849
			dbConn = DBConnectionPool.getDBConnection("ReplicationHandler.getHomeServer");
1850
			serialNumber = dbConn.getCheckOutSerialNumber();
1851
			//get a server location from xml_document table
1852
			pstmt = dbConn.prepareStatement("select server_location from xml_documents "
1853
					+ "where docid = ?");
1854
			pstmt.setString(1, docId);
1855
			pstmt.execute();
1856
			ResultSet serverName = pstmt.getResultSet();
1857
			//get a server location
1858
			if (serverName.next()) {
1859
				serverLocation = serverName.getInt(1);
1860
				pstmt.close();
1861
			} else {
1862
				pstmt.close();
1863
				//ut.returnConnection(conn);
1864
				return null;
1865
			}
1866
			pstmt = dbConn.prepareStatement("select server, last_checked, replicate "
1867
					+ "from xml_replication where serverid = ?");
1868
			//increase usage count
1869
			dbConn.increaseUsageCount(1);
1870
			pstmt.setInt(1, serverLocation);
1871
			pstmt.execute();
1872
			ResultSet rs = pstmt.getResultSet();
1873
			boolean tableHasRows = rs.next();
1874
			if (tableHasRows) {
1875

    
1876
				String server = rs.getString(1);
1877
				String last_checked = rs.getString(2);
1878
				if (!server.equals("localhost")) {
1879
					sl.put(server, last_checked);
1880
				}
1881

    
1882
			} else {
1883
				pstmt.close();
1884
				//ut.returnConnection(conn);
1885
				return null;
1886
			}
1887
			pstmt.close();
1888
		} catch (Exception e) {
1889
			logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1890
			logReplication.error("ReplicationService.getHomeServerInfoForDocId - error in replicationHandler.getHomeServer(): "
1891
					+ e.getMessage());
1892
		} finally {
1893
			try {
1894
				pstmt.close();
1895
				//ut.returnConnection(conn);
1896
			} catch (Exception ee) {
1897
				logMetacat.error("ReplicationService.getHomeServerInfoForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1898
				logReplication.error("ReplicationService.getHomeServerInfoForDocId - Eror irn rplicationHandler.getHomeServer() "
1899
						+ "to close pstmt: " + ee.getMessage());
1900
			} finally {
1901
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1902
			}
1903

    
1904
		}//finally
1905
		return sl;
1906
	}
1907

    
1908
	/**
1909
	 * Returns a home server location  given a accnum
1910
	 * @param accNum , given accNum for a document
1911
	 *
1912
	 */
1913
	public static int getHomeServerCodeForDocId(String accNum) throws ServiceException {
1914
		DBConnection dbConn = null;
1915
		int serialNumber = -1;
1916
		PreparedStatement pstmt = null;
1917
		int serverCode = 1;
1918
		String docId = DocumentUtil.getDocIdFromString(accNum);
1919

    
1920
		try {
1921

    
1922
			// Get DBConnection
1923
			dbConn = DBConnectionPool
1924
					.getDBConnection("ReplicationHandler.getServerLocation");
1925
			serialNumber = dbConn.getCheckOutSerialNumber();
1926
			pstmt = dbConn.prepareStatement("SELECT server_location FROM xml_documents "
1927
					+ "WHERE docid LIKE '" + docId + "'");
1928
			pstmt.execute();
1929
			ResultSet rs = pstmt.getResultSet();
1930
			boolean tablehasrows = rs.next();
1931
			//If a document is find, return the server location for it
1932
			if (tablehasrows) {
1933
				serverCode = rs.getInt(1);
1934
				pstmt.close();
1935
				//conn.close();
1936
				return serverCode;
1937
			}
1938
			//if couldn't find in xml_documents table, we think server code is 1
1939
			//(this is new document)
1940
			else {
1941
				pstmt.close();
1942
				//conn.close();
1943
				return serverCode;
1944
			}
1945

    
1946
		} catch (SQLException sqle) {
1947
			throw new ServiceException("ReplicationService.getHomeServerCodeForDocId - " 
1948
					+ "SQL error when getting home server code for docid: " + docId + " : " 
1949
					+ sqle.getMessage());
1950

    
1951
		} finally {
1952
			try {
1953
				pstmt.close();
1954
				//conn.close();
1955

    
1956
			} catch (SQLException sqle) {
1957
				logMetacat.error("ReplicationService.getHomeServerCodeForDocId - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1958
				logReplication.error("ReplicationService.getHomeServerCodeForDocId - ReplicationService.getHomeServerCodeForDocId - " 
1959
						+ "SQL error when getting home server code for docid: " + docId + " : " 
1960
						+ sqle.getMessage());
1961
			} finally {
1962
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1963
			}//finally
1964
		}//finally
1965
		//return serverCode;
1966
	}
1967

    
1968
	/**
1969
	 * This method returns the content of a url
1970
	 * @param u the url to return the content from
1971
	 * @return a string representing the content of the url
1972
	 * @throws java.io.IOException
1973
	 */
1974
	public static String getURLContent(URL u) throws java.io.IOException {
1975
	    logReplication.info("Getting url content from " + u.toString());
1976
		char istreamChar;
1977
		int istreamInt;
1978
		logReplication.info("ReplicationService.getURLContent - Before open the stream" + u.toString());
1979
		InputStream input = u.openStream();
1980
		logReplication.info("ReplicationService.getURLContent - After open the stream" + u.toString());
1981
		InputStreamReader istream = new InputStreamReader(input);
1982
		StringBuffer serverResponse = new StringBuffer();
1983
		while ((istreamInt = istream.read()) != -1) {
1984
			istreamChar = (char) istreamInt;
1985
			serverResponse.append(istreamChar);
1986
		}
1987
		istream.close();
1988
		input.close();
1989

    
1990
		return serverResponse.toString();
1991
	}
1992

    
1993
//	/**
1994
//	 * Method for writing replication messages to a log file specified in
1995
//	 * metacat.properties
1996
//	 */
1997
//	public static void replLog(String message) {
1998
//		try {
1999
//			FileOutputStream fos = new FileOutputStream(PropertyService
2000
//					.getProperty("replication.logdir")
2001
//					+ "/metacatreplication.log", true);
2002
//			PrintWriter pw = new PrintWriter(fos);
2003
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
2004
//			java.util.Date localtime = new java.util.Date();
2005
//			String dateString = formatter.format(localtime);
2006
//			dateString += " :: " + message;
2007
//			// time stamp each entry
2008
//			pw.println(dateString);
2009
//			pw.flush();
2010
//		} catch (Exception e) {
2011
//			logReplication.error("error writing to replication log from "
2012
//					+ "MetacatReplication.replLog: " + e.getMessage());
2013
//			// e.printStackTrace(System.out);
2014
//		}
2015
//	}
2016

    
2017
//	/**
2018
//	 * Method for writing replication messages to a log file specified in
2019
//	 * metacat.properties
2020
//	 */
2021
//	public static void replErrorLog(String message) {
2022
//		try {
2023
//			FileOutputStream fos = new FileOutputStream(PropertyService
2024
//					.getProperty("replication.logdir")
2025
//					+ "/metacatreplicationerror.log", true);
2026
//			PrintWriter pw = new PrintWriter(fos);
2027
//			SimpleDateFormat formatter = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
2028
//			java.util.Date localtime = new java.util.Date();
2029
//			String dateString = formatter.format(localtime);
2030
//			dateString += " :: " + message;
2031
//			//time stamp each entry
2032
//			pw.println(dateString);
2033
//			pw.flush();
2034
//		} catch (Exception e) {
2035
//			logReplication.error("error writing to replication error log from "
2036
//					+ "MetacatReplication.replErrorLog: " + e.getMessage());
2037
//			//e.printStackTrace(System.out);
2038
//		}
2039
//	}
2040

    
2041
	/**
2042
	 * Returns true if the replicate field for server in xml_replication is 1.
2043
	 * Returns false otherwise
2044
	 */
2045
	public static boolean replToServer(String server) {
2046
		DBConnection dbConn = null;
2047
		int serialNumber = -1;
2048
		PreparedStatement pstmt = null;
2049
		try {
2050
			dbConn = DBConnectionPool.getDBConnection("MetacatReplication.repltoServer");
2051
			serialNumber = dbConn.getCheckOutSerialNumber();
2052
			pstmt = dbConn.prepareStatement("select replicate from "
2053
					+ "xml_replication where server like '" + server + "'");
2054
			pstmt.execute();
2055
			ResultSet rs = pstmt.getResultSet();
2056
			boolean tablehasrows = rs.next();
2057
			if (tablehasrows) {
2058
				int i = rs.getInt(1);
2059
				if (i == 1) {
2060
					pstmt.close();
2061
					//conn.close();
2062
					return true;
2063
				} else {
2064
					pstmt.close();
2065
					//conn.close();
2066
					return false;
2067
				}
2068
			}
2069
		} catch (SQLException sqle) {
2070
			logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2071
			logReplication.error("ReplicationService.replToServer - SQL error in MetacatReplication.replToServer: "
2072
					+ sqle.getMessage());
2073
		} finally {
2074
			try {
2075
				pstmt.close();
2076
				//conn.close();
2077
			}//try
2078
			catch (Exception ee) {
2079
				logMetacat.error("ReplicationService.replToServer - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
2080
				logReplication.error("ReplicationService.replToServer - Error in MetacatReplication.replToServer: "
2081
						+ ee.getMessage());
2082
			}//catch
2083
			finally {
2084
				DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2085
			}//finally
2086
		}//finally
2087
		return false;
2088
		//the default if this server does not exist is to not replicate to it.
2089
	}
2090

    
2091
}
(6-6/7)