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-05 15:14:07 -0700 (Thu, 05 May 2011) $'
10
 * '$Revision: 6079 $'
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.xml.sax.InputSource;
58
import org.xml.sax.SAXException;
59
import org.xml.sax.XMLReader;
60

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

    
87
public class ReplicationService extends BaseService {
88

    
89
	private static ReplicationService replicationService = null;
90

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
449
	}
450

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
773
		}//catch
774

    
775
	}
776

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

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

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

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

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

    
825
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
826

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

    
835
			String docType = (String) docinfoHash.get("doctype");
836

    
837
			String docHomeServer = (String) docinfoHash.get("home_server");
838

    
839
			String createdDate = (String) docinfoHash.get("date_created");
840

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

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

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

    
895
				if (writeException != null) {
896
					throw writeException;
897
				}
898

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

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

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

    
926
		try {
927

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

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

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

    
981
		try {
982
		  IdentifierManager idman = IdentifierManager.getInstance();
983

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

    
1029
			sb.append("<accessControl>");
1030

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

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

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

    
1049
	}
1050

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

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

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

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

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

    
1117
		// Set the mime type
1118
		response.setContentType(contentType);
1119

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

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

    
1145
	}
1146

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

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

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

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

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

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

    
1195
			logReplication.info("ReplicationService.handleGetDocumentRequest - document " + docid + " sent");
1196

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

    
1252
	}
1253

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1508
	}//handlUpdateRequest
1509

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

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

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

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

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

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

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

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

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

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

    
1683
		return null;
1684
	}
1685

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

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

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

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

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

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

    
1778
		return null;
1779
		//return null if the server does not exist
1780
	}
1781

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

    
1794
		try {
1795

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

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

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

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

    
1831
		return serverCode;
1832
	}
1833

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

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

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

    
1902
		}//finally
1903
		return sl;
1904
	}
1905

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

    
1918
		try {
1919

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

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

    
1949
		} finally {
1950
			try {
1951
				pstmt.close();
1952
				//conn.close();
1953

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

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

    
1988
		return serverResponse.toString();
1989
	}
1990

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

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

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

    
2089
}
(6-6/7)