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-09-16 15:17:00 -0700 (Fri, 16 Sep 2011) $'
10
 * '$Revision: 6448 $'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26

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

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

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

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

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

    
92
public class ReplicationService extends BaseService {
93

    
94
	private static ReplicationService replicationService = null;
95

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
468
	}
469

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

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

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

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

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

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

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

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

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

    
570
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
571

    
572
			//dih is the parser for the docinfo xml format
573
			DocInfoHandler dih = new DocInfoHandler();
574
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
575
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
576
			//      Hashtable<String,Vector<AccessControlForSingleFile>> docinfoHash = dih.getDocInfo();
577
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
578
			
579
			// Get home server of this docid
580
			String homeServer = (String) docinfoHash.get("home_server");
581
      
582
        	// replicate doc contents
583
			String createdDate = (String) docinfoHash.get("date_created");
584
			String updatedDate = (String) docinfoHash.get("date_updated");
585
			logReplication.info("ReplicationService.handleForceReplicateRequest - homeServer: " + homeServer);
586
			// Get Document type
587
			String docType = (String) docinfoHash.get("doctype");
588
			logReplication.info("ReplicationService.handleForceReplicateRequest - docType: " + docType);
589
			String parserBase = null;
590
			// this for eml2 and we need user eml2 parser
591
			if (docType != null
592
					&& (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE)) {
593
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml200 document!");
594
				parserBase = DocumentImpl.EML200;
595
			} else if (docType != null
596
					&& (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE)) {
597
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.0.1 document!");
598
				parserBase = DocumentImpl.EML200;
599
			} else if (docType != null
600
					&& (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE)) {
601
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.0 document!");
602
				parserBase = DocumentImpl.EML210;
603
			} else if (docType != null
604
					&& (docType.trim()).equals(DocumentImpl.EML2_1_1NAMESPACE)) {
605
				logReplication.warn("ReplicationService.handleForceReplicateRequest - This is an eml2.1.1 document!");
606
				parserBase = DocumentImpl.EML210;
607
			}
608
			logReplication.warn("ReplicationService.handleForceReplicateRequest - The parserBase is: " + parserBase);
609

    
610
			// Get DBConnection from pool
611
			dbConn = DBConnectionPool
612
					.getDBConnection("MetacatReplication.handleForceReplicateRequest");
613
			serialNumber = dbConn.getCheckOutSerialNumber();
614
			// write the document to local database
615
			DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false);
616
			//try this independently so we can set access even if the update action is invalid (i.e docid has not changed)
617
			try {
618
				wrapper.writeReplication(dbConn, xmldoc, null, null,
619
						dbaction, docid, null, null, homeServer, server, createdDate,
620
						updatedDate);
621
			} finally {
622

    
623
				//process extra access rules before dealing with the write exception (doc exist already)			
624
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
625
		        if (accessControlList != null) {
626
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
627
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
628
		        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
629
		        			acfsf.insertPermissions(xmlAccessDAO);
630
							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
631
									+ " permissions added to DB");
632
		        		}
633
		            }
634
		        }
635
		        
636
		        // process the real owner and updater
637
				String user = (String) docinfoHash.get("user_owner");
638
				String updated = (String) docinfoHash.get("user_updated");
639
		        updateUserOwner(dbConn, docid, user, updated);
640

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

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

    
724
		}//catch
725

    
726
	}
727

    
728
	/**
729
	 * when a forcereplication data file request comes in, local host sends a
730
	 * readdata request to the requesting server (remote server) for the specified
731
	 * docid. Then store it in local database and file system
732
	 */
733
	protected static void handleForceReplicateDataFileRequest(Hashtable<String, String[]> params,
734
			HttpServletRequest request) {
735

    
736
		//make sure there is some parameters
737
		if (params.isEmpty()) {
738
			return;
739
		}
740
		// Get remote server
741
		String server = ((String[]) params.get("server"))[0];
742
		// the docid should include rev number
743
		String docid = ((String[]) params.get("docid"))[0];
744
		// Make sure there is a docid and server
745
		if (docid == null || server == null || server.equals("")) {
746
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
747
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Didn't specify docid or server for replication");
748
			return;
749
		}
750

    
751
		// Overide or not
752
		//    boolean override = false;
753
		// dbaction - update or insert
754
		String dbaction = null;
755

    
756
		try {
757
			//docid was switch to two parts uinque code and rev
758
			//String uniqueCode=MetacatUtil.getDocIdFromString(docid);
759
			//int rev=MetacatUtil.getVersionFromString(docid);
760
			if (params.containsKey("dbaction")) {
761
				dbaction = ((String[]) params.get("dbaction"))[0];
762
			} else//default value is update
763
			{
764
				dbaction = "update";
765
			}
766

    
767
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication request from: " + server);
768
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication docid: " + docid);
769
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - Force replication action: " + dbaction);
770
			// get the document info from server
771
			URL docinfourl = new URL("https://" + server + "?server="
772
					+ MetacatUtil.getLocalReplicationServerName()
773
					+ "&action=getdocumentinfo&docid=" + docid);
774

    
775
			String docInfoStr = ReplicationService.getURLContent(docinfourl);
776
			
777
			//dih is the parser for the docinfo xml format
778
			DocInfoHandler dih = new DocInfoHandler();
779
			XMLReader docinfoParser = ReplicationHandler.initParser(dih);
780
			docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
781
			Hashtable<String, String> docinfoHash = dih.getDocInfo();
782
			
783
			String docName = (String) docinfoHash.get("docname");
784

    
785
			String docType = (String) docinfoHash.get("doctype");
786

    
787
			String docHomeServer = (String) docinfoHash.get("home_server");
788

    
789
			String createdDate = (String) docinfoHash.get("date_created");
790

    
791
			String updatedDate = (String) docinfoHash.get("date_updated");
792
			logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - docHomeServer of datafile: " + docHomeServer);
793

    
794
			if (dbaction.equals("insert") || dbaction.equals("update")) {
795
				//Get data file and store it into local file system.
796
				// sending back readdata request to server
797
				URL url = new URL("https://" + server + "?server="
798
						+ MetacatUtil.getLocalReplicationServerName()
799
						+ "&action=readdata&docid=" + docid);
800
				String datafilePath = PropertyService
801
						.getProperty("application.datafilepath");
802

    
803
				Exception writeException = null;
804
				//register data file into xml_documents table and wite data file
805
				//into file system
806
				try {
807
					DocumentImpl.writeDataFileInReplication(url.openStream(),
808
							datafilePath, docName, docType, docid, null, docHomeServer,
809
							server, DocumentImpl.DOCUMENTTABLE, false, createdDate,
810
							updatedDate);
811
				} catch (Exception e) {
812
					writeException = e;
813
				}
814
				
815
				// process the real owner and updater
816
				DBConnection dbConn = DBConnectionPool.getDBConnection("ReplicationService.handleForceDataFileRequest");
817
		        int serialNumber = dbConn.getCheckOutSerialNumber();
818
		        dbConn.setAutoCommit(false);
819
				String user = (String) docinfoHash.get("user_owner");
820
				String updated = (String) docinfoHash.get("user_updated");
821
		        updateUserOwner(dbConn, docid, user, updated);
822
		        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
823
		        
824
		        Vector<XMLAccessDAO> accessControlList = dih.getAccessControlList();
825
		        if (accessControlList != null) {
826
		        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid);
827
		        	for (XMLAccessDAO xmlAccessDAO : accessControlList) {
828
		        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
829
		        			acfsf.insertPermissions(xmlAccessDAO);
830
							logReplication.info("ReplicationService.handleForceReplicateRequest - document " + docid
831
									+ " permissions added to DB");
832
		        		}
833
		            }
834
		        }
835

    
836
				if (writeException != null) {
837
					throw writeException;
838
				}
839

    
840
				logReplication.info("ReplicationService.handleForceReplicateDataFileRequest - datafile " + docid + " added to DB with "
841
						+ "action " + dbaction);
842
				EventLog.getInstance().log(request.getRemoteAddr(), REPLICATIONUSER,
843
						docid, dbaction);
844
			}
845

    
846
		} catch (Exception e) {
847
			logMetacat.error("ReplicationService.handleForceReplicateDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
848
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - Datafile " + docid
849
					+ " failed to added to DB with " + "action " + dbaction + " because "
850
					+ e.getMessage());
851
			logReplication.error("ReplicationService.handleForceReplicateDataFileRequest - ERROR in MetacatReplication.handleForceDataFileReplicate"
852
					+ "Request(): " + e.getMessage());
853
		}
854
	}
855

    
856
	/**
857
	 * Grants or denies a lock to a requesting host.
858
	 * The servlet parameters of interrest are:
859
	 * docid: the docid of the file the lock is being requested for
860
	 * currentdate: the timestamp of the document on the remote server
861
	 *
862
	 */
863
	protected static void handleGetLockRequest(
864
			Hashtable<String, String[]> params, HttpServletResponse response) {
865

    
866
		try {
867

    
868
			String docid = ((String[]) params.get("docid"))[0];
869
			String remoteRev = ((String[]) params.get("updaterev"))[0];
870
			DocumentImpl requestDoc = new DocumentImpl(docid);
871
			logReplication.info("ReplicationService.handleGetLockRequest - lock request for " + docid);
872
			int localRevInt = requestDoc.getRev();
873
			int remoteRevInt = Integer.parseInt(remoteRev);
874

    
875
			// get a writer for sending back to response
876
			response.setContentType("text/xml");
877
			Writer out = response.getWriter();
878
			
879
			if (remoteRevInt >= localRevInt) {
880
				if (!fileLocks.contains(docid)) { //grant the lock if it is not already locked
881
					fileLocks.add(0, docid); //insert at the beginning of the queue Vector
882
					//send a message back to the the remote host authorizing the insert
883
					out.write("<lockgranted><docid>" + docid
884
									+ "</docid></lockgranted>");
885
					//          lockThread = new Thread(this);
886
					//          lockThread.setPriority(Thread.MIN_PRIORITY);
887
					//          lockThread.start();
888
					logReplication.info("ReplicationService.handleGetLockRequest - lock granted for " + docid);
889
				} else { //deny the lock
890
					out.write("<filelocked><docid>" + docid + "</docid></filelocked>");
891
					logReplication.info("ReplicationService.handleGetLockRequest - lock denied for " + docid
892
							+ "reason: file already locked");
893
				}
894
			} else {//deny the lock.
895
				out.write("<outdatedfile><docid>" + docid + "</docid></filelocked>");
896
				logReplication.info("ReplicationService.handleGetLockRequest - lock denied for " + docid
897
						+ "reason: client has outdated file");
898
			}
899
			out.close();
900
			//conn.close();
901
		} catch (Exception e) {
902
			logMetacat.error("ReplicationService.handleGetLockRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
903
			logReplication.error("ReplicationService.handleGetLockRequest - error requesting file lock from MetacatReplication."
904
					+ "handleGetLockRequest: " + e.getMessage());
905
			e.printStackTrace(System.out);
906
		}
907
	}
908

    
909
	/**
910
	 * Sends all of the xml_documents information encoded in xml to a requestor
911
	 * the format is:
912
	 * <!ELEMENT documentinfo (docid, docname, doctype, doctitle, user_owner,
913
	 *                  user_updated, home_server, public_access, rev)/>
914
	 * all of the subelements of document info are #PCDATA
915
	 */
916
	protected static void handleGetDocumentInfoRequest(
917
			Hashtable<String, String[]> params, HttpServletResponse response) {
918
		String docid = ((String[]) (params.get("docid")))[0];
919
		StringBuffer sb = new StringBuffer();
920

    
921
		try {
922
			DocumentImpl doc = new DocumentImpl(docid);
923
			sb.append("<documentinfo><docid>").append(docid);
924
			sb.append("</docid>");
925
			sb.append("<docname>").append(doc.getDocname());
926
			sb.append("</docname><doctype>").append(doc.getDoctype());
927
			sb.append("</doctype>");
928
			sb.append("<user_owner>").append(doc.getUserowner());
929
			sb.append("</user_owner><user_updated>").append(doc.getUserupdated());
930
			sb.append("</user_updated>");
931
			sb.append("<date_created>");
932
			sb.append(doc.getCreateDate());
933
			sb.append("</date_created>");
934
			sb.append("<date_updated>");
935
			sb.append(doc.getUpdateDate());
936
			sb.append("</date_updated>");
937
			sb.append("<home_server>");
938
			sb.append(doc.getDocHomeServer());
939
			sb.append("</home_server>");
940
			sb.append("<public_access>").append(doc.getPublicaccess());
941
			sb.append("</public_access><rev>").append(doc.getRev());
942
			sb.append("</rev>");
943

    
944
			sb.append("<accessControl>");
945

    
946
			AccessControlForSingleFile acfsf = new AccessControlForSingleFile(docid); 
947
			sb.append(acfsf.getAccessString());
948
			
949
			sb.append("</accessControl>");
950

    
951
			sb.append("</documentinfo>");
952
			// get a writer for sending back to response
953
			response.setContentType("text/xml");
954
			Writer out = response.getWriter();
955
			out.write(sb.toString());
956
			out.close();
957

    
958
		} catch (Exception e) {
959
			logMetacat.error("ReplicationService.handleGetDocumentInfoRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
960
			logReplication.error("ReplicationService.handleGetDocumentInfoRequest - error in metacatReplication.handlegetdocumentinforequest "
961
					+ "for doc: " + docid + " : " + e.getMessage());
962
		}
963

    
964
	}
965
	
966
	/**
967
	 * Sends System Metadata as XML
968
	 */
969
	protected static void handleGetSystemMetadataRequest(
970
			Hashtable<String, String[]> params, HttpServletResponse response) {
971
		String guid = ((String[]) (params.get("guid")))[0];
972
		String systemMetadataXML = null;
973
		try {
974
			
975
			// serialize the System Metadata as XML 
976
			SystemMetadata systemMetadata = IdentifierManager.getInstance().getSystemMetadata(guid);
977
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
978
			TypeMarshaller.marshalTypeToOutputStream(systemMetadata, baos);
979
			systemMetadataXML = baos.toString("UTF-8");
980
				
981
			// get a writer for sending back to response
982
			response.setContentType("text/xml");
983
			Writer out = response.getWriter();
984
			out.write(systemMetadataXML);
985
			out.close();
986

    
987
		} catch (Exception e) {
988
			String msg = "ReplicationService.handleGetSystemMetadataRequest for guid: " + guid + " : " + e.getMessage();
989
			logMetacat.error(msg);                         
990
			logReplication.error(msg);
991
		}
992

    
993
	}
994
	
995
	/**
996
	 * when a forcereplication request comes in, local host sends a read request
997
	 * to the requesting server (remote server) for the specified docid. Then
998
	 * store it in local database.
999
	 */
1000
	protected static void handleForceReplicateSystemMetadataRequest(
1001
			Hashtable<String, String[]> params, HttpServletResponse response,
1002
			HttpServletRequest request) {
1003
		String server = ((String[]) params.get("server"))[0]; // the server that
1004
		String guid = ((String[]) params.get("guid"))[0]; // sent the document
1005
		
1006
		try {
1007
			logReplication.info("ReplicationService.handleForceReplicateSystemMetadataRequest - Force replication system metadata request from: " + server);
1008
			// get the system metadata from server
1009
			URL docinfourl = new URL("https://" + server + "?server="
1010
					+ MetacatUtil.getLocalReplicationServerName()
1011
					+ "&action=getsystemmetadata&guid=" + guid);
1012
			
1013
			String systemMetadataXML = ReplicationService.getURLContent(docinfourl);
1014
						
1015
			// process system metadata
1016
			if (systemMetadataXML != null) {
1017
				SystemMetadata sysMeta = 
1018
					TypeMarshaller.unmarshalTypeFromStream(
1019
							SystemMetadata.class,
1020
							new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
1021
				HazelcastService.getInstance().getSystemMetadataMap().put(sysMeta.getIdentifier(), sysMeta);
1022
			}
1023
      
1024
			logReplication.info("ReplicationService.handleForceReplicateSystemMetadataRequest - processed guid: " + guid);
1025
			EventLog.getInstance().log(request.getRemoteAddr(), REPLICATIONUSER, guid, "systemMetadata");
1026

    
1027
		} catch (Exception e) {
1028
			logMetacat.error("ReplicationService.handleForceReplicateRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG, e);                         
1029
			logReplication.error("ReplicationService.handleForceReplicateRequest - General error when processing guid: " + guid, e);
1030
		}
1031
	}
1032

    
1033
	/**
1034
	 * Sends a datafile to a remote host
1035
	 */
1036
	protected static void handleGetDataFileRequest(OutputStream outPut,
1037
			Hashtable<String, String[]> params, HttpServletResponse response)
1038

    
1039
	{
1040
		// File path for data file
1041
		String filepath;
1042
		// Request docid
1043
		String docId = ((String[]) (params.get("docid")))[0];
1044
		//check if the doicd is null
1045
		if (docId == null) {
1046
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1047
			logReplication.error("ReplicationService.handleGetDataFileRequest - Didn't specify docid for replication");
1048
			return;
1049
		}
1050

    
1051
		//try to open a https stream to test if the request server's public key
1052
		//in the key store, this is security issue
1053
		try {
1054
			filepath = PropertyService.getProperty("application.datafilepath");
1055
			String server = params.get("server")[0];
1056
			URL u = new URL("https://" + server + "?server="
1057
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test");
1058
			String test = ReplicationService.getURLContent(u);
1059
			//couldn't pass the test
1060
			if (test.indexOf("successfully") == -1) {
1061
				//response.setContentType("text/xml");
1062
				//outPut.println("<error>Couldn't pass the trust test</error>");
1063
				logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1064
				logReplication.error("ReplicationService.handleGetDataFileRequest - Couldn't pass the trust test");
1065
				return;
1066
			}
1067
		}//try
1068
		catch (Exception ee) {
1069
			return;
1070
		}//catch
1071

    
1072
		if (!filepath.endsWith("/")) {
1073
			filepath += "/";
1074
		}
1075
		// Get file aboslute file name
1076
		String filename = filepath + docId;
1077

    
1078
		//MIME type
1079
		String contentType = null;
1080
		if (filename.endsWith(".xml")) {
1081
			contentType = "text/xml";
1082
		} else if (filename.endsWith(".css")) {
1083
			contentType = "text/css";
1084
		} else if (filename.endsWith(".dtd")) {
1085
			contentType = "text/plain";
1086
		} else if (filename.endsWith(".xsd")) {
1087
			contentType = "text/xml";
1088
		} else if (filename.endsWith("/")) {
1089
			contentType = "text/html";
1090
		} else {
1091
			File f = new File(filename);
1092
			if (f.isDirectory()) {
1093
				contentType = "text/html";
1094
			} else {
1095
				contentType = "application/octet-stream";
1096
			}
1097
		}
1098

    
1099
		// Set the mime type
1100
		response.setContentType(contentType);
1101

    
1102
		// Get the content of the file
1103
		FileInputStream fin = null;
1104
		try {
1105
			// FileInputStream to metacat
1106
			fin = new FileInputStream(filename);
1107
			// 4K buffer
1108
			byte[] buf = new byte[4 * 1024];
1109
			// Read data from file input stream to byte array
1110
			int b = fin.read(buf);
1111
			// Write to outStream from byte array
1112
			while (b != -1) {
1113
				outPut.write(buf, 0, b);
1114
				b = fin.read(buf);
1115
			}
1116
			// close file input stream
1117
			fin.close();
1118

    
1119
		}//try
1120
		catch (Exception e) {
1121
			logMetacat.error("ReplicationService.handleGetDataFileRequest - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1122
			logReplication.error("ReplicationService.handleGetDataFileRequest - error getting data file from MetacatReplication."
1123
					+ "handlGetDataFileRequest " + e.getMessage());
1124
			e.printStackTrace(System.out);
1125
		}//catch
1126

    
1127
	}
1128

    
1129
	/**
1130
	 * Sends a document to a remote host
1131
	 */
1132
	protected static void handleGetDocumentRequest(
1133
			Hashtable<String, String[]> params, HttpServletResponse response) {
1134

    
1135
		String urlString = null;
1136
		String documentPath = null;
1137
		String errorMsg = null;
1138
		try {
1139
			// try to open a https stream to test if the request server's public
1140
			// key
1141
			// in the key store, this is security issue
1142
			String server = params.get("server")[0];
1143
			urlString = "https://" + server + "?server="
1144
					+ MetacatUtil.getLocalReplicationServerName() + "&action=test";
1145
			URL u = new URL(urlString);
1146
			String test = ReplicationService.getURLContent(u);
1147
			// couldn't pass the test
1148
			if (test.indexOf("successfully") == -1) {
1149
				response.setContentType("text/xml");
1150
				Writer out = response.getWriter();
1151
				out.write("<error>Couldn't pass the trust test " + test + " </error>");
1152
				out.close();
1153
				return;
1154
			}
1155

    
1156
			String docid = params.get("docid")[0];
1157
			logReplication.debug("ReplicationService.handleGetDocumentRequest - MetacatReplication.handleGetDocumentRequest for docid: "
1158
					+ docid);
1159
			DocumentImpl di = new DocumentImpl(docid);
1160

    
1161
			String documentDir = PropertyService
1162
					.getProperty("application.documentfilepath");
1163
			documentPath = documentDir + FileUtil.getFS() + docid;
1164

    
1165
			// if the document does not exist on disk, read it from db and write
1166
			// it to disk.
1167
			if (FileUtil.getFileStatus(documentPath) == FileUtil.DOES_NOT_EXIST
1168
					|| FileUtil.getFileSize(documentPath) == 0) {
1169
				FileOutputStream fos = new FileOutputStream(documentPath);
1170
				di.toXml(fos, null, null, true);
1171
			}
1172

    
1173
			// read the file from disk and send it to outputstream
1174
			OutputStream outputStream = response.getOutputStream();
1175
			di.readFromFileSystem(outputStream, null, null, documentPath);
1176

    
1177
			logReplication.info("ReplicationService.handleGetDocumentRequest - document " + docid + " sent");
1178

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

    
1234
	}
1235

    
1236
	/**
1237
	 * Sends a list of all of the documents on this sever along with their
1238
	 * revision numbers. The format is: <!ELEMENT replication (server, updates)>
1239
	 * <!ELEMENT server (#PCDATA)> <!ELEMENT updates ((updatedDocument |
1240
	 * deleteDocument | revisionDocument)*)> <!ELEMENT updatedDocument (docid,
1241
	 * rev, datafile*)> <!ELEMENT deletedDocument (docid, rev)> <!ELEMENT
1242
	 * revisionDocument (docid, rev, datafile*)> <!ELEMENT docid (#PCDATA)>
1243
	 * <!ELEMENT rev (#PCDATA)> <!ELEMENT datafile (#PCDATA)> note that the rev
1244
	 * in deletedDocument is always empty. I just left it in there to make the
1245
	 * parser implementation easier.
1246
	 */
1247
	protected static void handleUpdateRequest(Hashtable<String, String[]> params,
1248
			HttpServletResponse response) {
1249
		// Checked out DBConnection
1250
		DBConnection dbConn = null;
1251
		// DBConenction serial number when checked it out
1252
		int serialNumber = -1;
1253
		PreparedStatement pstmt = null;
1254
		// Server list to store server info of xml_replication table
1255
		ReplicationServerList serverList = null;
1256
		
1257
		// a writer for response
1258
		Writer out = null;
1259

    
1260
		try {
1261
			// get writer, TODO: encoding?
1262
			response.setContentType("text/xml");
1263
			out = response.getWriter();
1264
			
1265
			// Check out a DBConnection from pool
1266
			dbConn = DBConnectionPool
1267
					.getDBConnection("MetacatReplication.handleUpdateRequest");
1268
			serialNumber = dbConn.getCheckOutSerialNumber();
1269
			// Create a server list from xml_replication table
1270
			serverList = new ReplicationServerList();
1271

    
1272
			// Get remote server name from param
1273
			String server = ((String[]) params.get("server"))[0];
1274
			// If no servr name in param, return a error
1275
			if (server == null || server.equals("")) {
1276
				out.write("<error>Request didn't specify server name</error>");
1277
				out.close();
1278
				return;
1279
			}//if
1280

    
1281
			//try to open a https stream to test if the request server's public key
1282
			//in the key store, this is security issue
1283
			String testUrl = "https://" + server + "?server="
1284
            + MetacatUtil.getLocalReplicationServerName() + "&action=test";
1285
			logReplication.info("Running trust test: " + testUrl);
1286
			URL u = new URL(testUrl);
1287
			String test = ReplicationService.getURLContent(u);
1288
			logReplication.info("Ouput from test is '" + test + "'");
1289
			//couldn't pass the test
1290
			if (test.indexOf("successfully") == -1) {
1291
			    logReplication.error("Trust test failed.");
1292
				out.write("<error>Couldn't pass the trust test</error>");
1293
				out.close();
1294
				return;
1295
			}
1296
			logReplication.info("Trust test succeeded.");
1297

    
1298
			// Check if local host configure to replicate xml documents to remote
1299
			// server. If not send back a error message
1300
			if (!serverList.getReplicationValue(server)) {
1301
				out.write("<error>Configuration not allow to replicate document to you</error>");
1302
				out.close();
1303
				return;
1304
			}//if
1305

    
1306
			// Store the sql command
1307
			StringBuffer docsql = new StringBuffer();
1308
			StringBuffer revisionSql = new StringBuffer();
1309
			// Stroe the docid list
1310
			StringBuffer doclist = new StringBuffer();
1311
			// Store the deleted docid list
1312
			StringBuffer delsql = new StringBuffer();
1313
			// Store the data set file
1314
			Vector<Vector<String>> packageFiles = new Vector<Vector<String>>();
1315

    
1316
			// Append local server's name and replication servlet to doclist
1317
			doclist.append("<?xml version=\"1.0\"?><replication>");
1318
			doclist.append("<server>")
1319
					.append(MetacatUtil.getLocalReplicationServerName());
1320
			//doclist.append(util.getProperty("replicationpath"));
1321
			doclist.append("</server><updates>");
1322

    
1323
			// Get correct docid that reside on this server according the requesting
1324
			// server's replicate and data replicate value in xml_replication table
1325
			docsql.append(DatabaseService.getInstance().getDBAdapter().getReplicationDocumentListSQL());
1326
			//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)) ");
1327
			revisionSql.append("select docid, rev, doctype from xml_revisions ");
1328
			// If the localhost is not a hub to the remote server, only replicate
1329
			// the docid' which home server is local host (server_location =1)
1330
			if (!serverList.getHubValue(server)) {
1331
				String serverLocationDoc = " and a.server_location = 1";
1332
				String serverLocationRev = "where server_location = 1";
1333
				docsql.append(serverLocationDoc);
1334
				revisionSql.append(serverLocationRev);
1335
			}
1336
			logReplication.info("ReplicationService.handleUpdateRequest - Doc sql: " + docsql.toString());
1337

    
1338
			// Get any deleted documents
1339
			delsql.append("select distinct docid from ");
1340
			delsql.append("xml_revisions where docid not in (select docid from ");
1341
			delsql.append("xml_documents) ");
1342
			// If the localhost is not a hub to the remote server, only replicate
1343
			// the docid' which home server is local host (server_location =1)
1344
			if (!serverList.getHubValue(server)) {
1345
				delsql.append("and server_location = 1");
1346
			}
1347
			logReplication.info("ReplicationService.handleUpdateRequest - Deleted sql: " + delsql.toString());
1348

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

    
1427
			pstmt = dbConn.prepareStatement(delsql.toString());
1428
			//usage count should increas 1
1429
			dbConn.increaseUsageCount(1);
1430

    
1431
			pstmt.execute();
1432
			rs = pstmt.getResultSet();
1433
			tablehasrows = rs.next();
1434
			while (tablehasrows) { //handle the deleted documents
1435
				doclist.append("<deletedDocument><docid>").append(rs.getString(1));
1436
				doclist.append("</docid><rev></rev></deletedDocument>");
1437
				//note that rev is always empty for deleted docs
1438
				tablehasrows = rs.next();
1439
			}
1440

    
1441
			//now we can put the package files into the xml results
1442
			for (int i = 0; i < packageFiles.size(); i++) {
1443
				Vector<String> v = packageFiles.elementAt(i);
1444
				doclist.append("<updatedDocument>");
1445
				doclist.append("<docid>").append(v.elementAt(0));
1446
				doclist.append("</docid><rev>");
1447
				doclist.append(v.elementAt(1));
1448
				doclist.append("</rev>");
1449
				doclist.append("</updatedDocument>");
1450
			}
1451
			// add revision doc list  
1452
			doclist.append(prepareRevisionDoc(dbConn, revisionSql.toString(),
1453
					replicateData));
1454
			
1455
			// add the system metadata entries if configured to replicate them
1456
			boolean replicateSystemMetadata = serverList.getSystemMetadataReplicationValue(server);
1457
			if (replicateSystemMetadata) {
1458
				Date since = new Date(System.currentTimeMillis());
1459
				since = serverList.getLastCheckedDate(server);
1460
				List<String> systemMetadataEntries = 
1461
					IdentifierManager.getInstance().getUpdatedSystemMetadataIds(since);
1462
				for (int i = 0; i < systemMetadataEntries.size(); i++) {
1463
					String guid = systemMetadataEntries.get(i);
1464
					doclist.append("<updatedSystemMetadata>");
1465
					doclist.append("<guid>");
1466
					doclist.append(guid);
1467
					doclist.append("</guid>");
1468
					doclist.append("</updatedSystemMetadata>");
1469
				}
1470
			}
1471

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

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

    
1507
	}//handlUpdateRequest
1508

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

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

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

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

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

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

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

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

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

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

    
1682
		return null;
1683
	}
1684

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

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

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

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

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

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

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

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

    
1793
		try {
1794

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

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

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

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

    
1830
		return serverCode;
1831
	}
1832

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

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

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

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

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

    
1917
		try {
1918

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

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

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

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

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

    
1987
		return serverResponse.toString();
1988
	}
1989

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

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

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

    
2088
}
(7-7/8)