Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A class to asyncronously do delta-T replication checking
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: cjones $'
9
 *     '$Date: 2011-06-07 09:53:46 -0700 (Tue, 07 Jun 2011) $'
10
 * '$Revision: 6124 $'
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 edu.ucsb.nceas.metacat.CatalogMessageHandler;
30
import edu.ucsb.nceas.metacat.DBUtil;
31
import edu.ucsb.nceas.metacat.DocInfoHandler;
32
import edu.ucsb.nceas.metacat.DocumentImpl;
33
import edu.ucsb.nceas.metacat.DocumentImplWrapper;
34
import edu.ucsb.nceas.metacat.EventLog;
35
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
36
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlForSingleFile;
37
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessDAO;
38
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
39
import edu.ucsb.nceas.metacat.database.DBConnection;
40
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
41
import edu.ucsb.nceas.metacat.database.DatabaseService;
42
import edu.ucsb.nceas.metacat.properties.PropertyService;
43
import edu.ucsb.nceas.metacat.shared.HandlerException;
44
import edu.ucsb.nceas.metacat.util.MetacatUtil;
45
import edu.ucsb.nceas.metacat.util.ReplicationUtil;
46
import edu.ucsb.nceas.metacat.IdentifierManager;
47
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
48

    
49
import java.sql.*;
50
import java.util.*;
51
import java.util.Date;
52
import java.io.*;
53
import java.net.*;
54
import java.text.*;
55

    
56
import org.apache.log4j.Logger;
57
import org.dataone.service.types.SystemMetadata;
58
import org.dataone.service.types.util.ServiceTypeUtil;
59
import org.xml.sax.ContentHandler;
60
import org.xml.sax.ErrorHandler;
61
import org.xml.sax.InputSource;
62
import org.xml.sax.SAXException;
63
import org.xml.sax.XMLReader;
64
import org.xml.sax.helpers.XMLReaderFactory;
65
import org.xml.sax.helpers.DefaultHandler;
66

    
67

    
68

    
69
/**
70
 * This class handles deltaT replication checking.  Whenever this TimerTask
71
 * is fired it checks each server in xml_replication for updates and updates
72
 * the local db as needed.
73
 */
74
public class ReplicationHandler extends TimerTask
75
{
76
  int serverCheckCode = 1;
77
  ReplicationServerList serverList = null;
78
  //PrintWriter out;
79
//  private static final AbstractDatabase dbAdapter = MetacatUtil.dbAdapter;
80
  private static Logger logReplication = Logger.getLogger("ReplicationLogging");
81
  private static Logger logMetacat = Logger.getLogger(ReplicationHandler.class);
82
  private static Logger logD1 = Logger.getLogger("DataOneLogger");
83
  
84
  private static int DOCINSERTNUMBER = 1;
85
  private static int DOCERRORNUMBER  = 1;
86
  private static int REVINSERTNUMBER = 1;
87
  private static int REVERRORNUMBER  = 1;
88
  
89
  private static int _xmlDocQueryCount = 0;
90
  private static int _xmlRevQueryCount = 0;
91
  private static long _xmlDocQueryTime = 0;
92
  private static long _xmlRevQueryTime = 0;
93
  
94
  
95
  public ReplicationHandler()
96
  {
97
    //this.out = o;
98
    serverList = new ReplicationServerList();
99
  }
100

    
101
  public ReplicationHandler(int serverCheckCode)
102
  {
103
    //this.out = o;
104
    this.serverCheckCode = serverCheckCode;
105
    serverList = new ReplicationServerList();
106
  }
107

    
108
  /**
109
   * Method that implements TimerTask.run().  It runs whenever the timer is
110
   * fired.
111
   */
112
  public void run()
113
  {
114
    //find out the last_checked time of each server in the server list and
115
    //send a query to each server to see if there are any documents in
116
    //xml_documents with an update_date > last_checked
117
	  
118
      //if serverList is null, metacat don't need to replication
119
      if (serverList==null||serverList.isEmpty())
120
      {
121
        return;
122
      }
123
      updateCatalog();
124
      update();
125
      //conn.close();
126
  }
127

    
128
  /**
129
   * Method that uses revision tagging for replication instead of update_date.
130
   */
131
  private void update()
132
  {
133
	  
134
	  _xmlDocQueryCount = 0;
135
	  _xmlRevQueryCount = 0;
136
	  _xmlDocQueryTime = 0;
137
	  _xmlRevQueryTime = 0;
138
    /*
139
     Pseudo-algorithm
140
     - request a doc list from each server in xml_replication
141
     - check the rev number of each of those documents agains the
142
       documents in the local database
143
     - pull any documents that have a lesser rev number on the local server
144
       from the remote server
145
     - delete any documents that still exist in the local xml_documents but
146
       are in the deletedDocuments tag of the remote host response.
147
     - update last_checked to keep track of the last time it was checked.
148
       (this info is theoretically not needed using this system but probably
149
       should be kept anyway)
150
    */
151

    
152
    ReplicationServer replServer = null; // Variable to store the
153
                                        // ReplicationServer got from
154
                                        // Server list
155
    String server = null; // Variable to store server name
156
//    String update;
157
    Vector<String> responses = new Vector<String>();
158
    URL u;
159
    long replicationStartTime = System.currentTimeMillis();
160
    long timeToGetServerList = 0;
161
    
162
    //Check for every server in server list to get updated list and put
163
    // them in to response
164
    long startTimeToGetServers = System.currentTimeMillis();
165
    for (int i=0; i<serverList.size(); i++)
166
    {
167
        // Get ReplicationServer object from server list
168
        replServer = serverList.serverAt(i);
169
        // Get server name from ReplicationServer object
170
        server = replServer.getServerName().trim();
171
        String result = null;
172
        logReplication.info("ReplicationHandler.update - full update started to: " + server);
173
        // Send command to that server to get updated docid information
174
        try
175
        {
176
          u = new URL("https://" + server + "?server="
177
          +MetacatUtil.getLocalReplicationServerName()+"&action=update");
178
          logReplication.info("ReplicationHandler.update - Sending infomation " +u.toString());
179
          result = ReplicationService.getURLContent(u);
180
        }
181
        catch (Exception e)
182
        {
183
          logMetacat.error("ReplicationHandler.update - " + ReplicationService.METACAT_REPL_ERROR_MSG);
184
          logReplication.error( "ReplicationHandler.update - Failed to get updated doc list "+
185
                       "for server " + server + " because "+e.getMessage());
186
          continue;
187
        }
188

    
189
        //logReplication.info("ReplicationHandler.update - docid: "+server+" "+result);
190
        //check if result have error or not, if has skip it.
191
        if (result.indexOf("<error>")!=-1 && result.indexOf("</error>")!=-1)
192
        {
193
          logMetacat.error("ReplicationHandler.update - " + ReplicationService.METACAT_REPL_ERROR_MSG);
194
          logReplication.error( "ReplicationHandler.update - Failed to get updated doc list "+
195
                       "for server " + server + " because "+result);
196
          continue;
197
        }
198
        //Add result to vector
199
        responses.add(result);
200
    }
201
    timeToGetServerList = System.currentTimeMillis() - startTimeToGetServers;
202

    
203
    //make sure that there is updated file list
204
    //If response is null, metacat don't need do anything
205
    if (responses==null || responses.isEmpty())
206
    {
207
    	logMetacat.error("ReplicationHandler.update - " + ReplicationService.METACAT_REPL_ERROR_MSG);
208
        logReplication.info( "ReplicationHandler.update - No updated doc list for "+
209
                           "every server and failed to replicate");
210
        return;
211
    }
212

    
213

    
214
    //logReplication.info("ReplicationHandler.update - Responses from remote metacat about updated "+
215
    //               "document information: "+ responses.toString());
216
    
217
    long totalServerListParseTime = 0;
218
    // go through response vector(it contains updated vector and delete vector
219
    for(int i=0; i<responses.size(); i++)
220
    {
221
    	long startServerListParseTime = System.currentTimeMillis();
222
    	XMLReader parser;
223
    	ReplMessageHandler message = new ReplMessageHandler();
224
    	try
225
        {
226
          parser = initParser(message);
227
        }
228
        catch (Exception e)
229
        {
230
          logMetacat.error("ReplicationHandler.update - " + ReplicationService.METACAT_REPL_ERROR_MSG);
231
          logReplication.error("ReplicationHandler.update - Failed to replicate becaue couldn't " +
232
                                " initParser for message and " +e.getMessage());
233
           // stop replication
234
           return;
235
        }
236
    	
237
        try
238
        {
239
          parser.parse(new InputSource(
240
                     new StringReader(
241
                     (String)(responses.elementAt(i)))));
242
        }
243
        catch(Exception e)
244
        {
245
          logMetacat.error("ReplicationHandler.update - " + ReplicationService.METACAT_REPL_ERROR_MSG);
246
          logReplication.error("ReplicationHandler.update - Couldn't parse one responses "+
247
                                   "because "+ e.getMessage());
248
          continue;
249
        }
250
        //v is the list of updated documents
251
        Vector<Vector<String>> updateList = new Vector<Vector<String>>(message.getUpdatesVect());
252
        logReplication.info("ReplicationHandler.update - The document list size is "+updateList.size()+ " from "+message.getServerName());
253
        //d is the list of deleted documents
254
        Vector<Vector<String>> deleteList = new Vector<Vector<String>>(message.getDeletesVect());
255
        logReplication.info("ReplicationHandler.update - Update vector size: "+ updateList.size()+" from "+message.getServerName());
256
        logReplication.info("ReplicationHandler.update - Delete vector size: "+ deleteList.size()+" from "+message.getServerName());
257
        logReplication.info("ReplicationHandler.update - The delete document list size is "+deleteList.size()+" from "+message.getServerName());
258
        // go though every element in updated document vector
259
        handleDocList(updateList, DocumentImpl.DOCUMENTTABLE);
260
        //handle deleted docs
261
        for(int k=0; k<deleteList.size(); k++)
262
        { //delete the deleted documents;
263
          Vector<String> w = new Vector<String>(deleteList.elementAt(k));
264
          String docId = (String)w.elementAt(0);
265
          try
266
          {
267
            handleDeleteSingleDocument(docId, server);
268
          }
269
          catch (Exception ee)
270
          {
271
            continue;
272
          }
273
        }//for delete docs
274
        
275
        // handle replicate doc in xml_revision
276
        Vector<Vector<String>> revisionList = new Vector<Vector<String>>(message.getRevisionsVect());
277
        logReplication.info("ReplicationHandler.update - The revision document list size is "+revisionList.size()+ " from "+message.getServerName());
278
        handleDocList(revisionList, DocumentImpl.REVISIONTABLE);
279
        DOCINSERTNUMBER = 1;
280
        DOCERRORNUMBER  = 1;
281
        REVINSERTNUMBER = 1;
282
        REVERRORNUMBER  = 1;
283
        
284
        // handle system metadata
285
        Vector<Vector<String>> systemMetadataList = message.getSystemMetadataVect();
286
        for(int k = 0; k < systemMetadataList.size(); k++) { 
287
        	Vector<String> w = systemMetadataList.elementAt(k);
288
        	String guid = (String) w.elementAt(0);
289
        	String remoteserver = (String) w.elementAt(1);
290
        	try {
291
        		handleSystemMetadata(remoteserver, guid);
292
        	}
293
        	catch (Exception ee) {
294
        		logMetacat.error("Error replicating system metedata for guid: " + guid, ee);
295
        		continue;
296
        	}
297
        }
298
        
299
        totalServerListParseTime += (System.currentTimeMillis() - startServerListParseTime);
300
    }//for response
301

    
302
    //updated last_checked
303
    for (int i=0;i<serverList.size(); i++)
304
    {
305
       // Get ReplicationServer object from server list
306
       replServer = serverList.serverAt(i);
307
       try
308
       {
309
         updateLastCheckTimeForSingleServer(replServer);
310
       }
311
       catch(Exception e)
312
       {
313
         continue;
314
       }
315
    }//for
316
    
317
    long replicationEndTime = System.currentTimeMillis();
318
    logMetacat.debug("ReplicationHandler.update - Total replication time: " + 
319
    		(replicationEndTime - replicationStartTime));
320
    logMetacat.debug("ReplicationHandler.update - time to get server list: " + 
321
    		timeToGetServerList);
322
    logMetacat.debug("ReplicationHandler.update - server list parse time: " + 
323
    		totalServerListParseTime);
324
    logMetacat.debug("ReplicationHandler.update - 'in xml_documents' total query count: " + 
325
    		_xmlDocQueryCount);
326
    logMetacat.debug("ReplicationHandler.update - 'in xml_documents' total query time: " + 
327
    		_xmlDocQueryTime + " ms");
328
    logMetacat.debug("ReplicationHandler.update - 'in xml_revisions' total query count: " + 
329
    		_xmlRevQueryCount);
330
    logMetacat.debug("ReplicationHandler.update - 'in xml_revisions' total query time: " + 
331
    		_xmlRevQueryTime + " ms");;
332

    
333
  }//update
334

    
335
  /* Handle replicate single xml document*/
336
  private void handleSingleXMLDocument(String remoteserver, String actions,
337
                                       String accNumber, String tableName)
338
               throws HandlerException
339
  {
340
    DBConnection dbConn = null;
341
    int serialNumber = -1;
342
    try
343
    {
344
      // Get DBConnection from pool
345
      dbConn=DBConnectionPool.
346
                  getDBConnection("ReplicationHandler.handleSingleXMLDocument");
347
      serialNumber=dbConn.getCheckOutSerialNumber();
348
      //if the document needs to be updated or inserted, this is executed
349
      String readDocURLString = "https://" + remoteserver + "?server="+
350
              MetacatUtil.getLocalReplicationServerName()+"&action=read&docid="+accNumber;
351
      readDocURLString = MetacatUtil.replaceWhiteSpaceForURL(readDocURLString);
352
      URL u = new URL(readDocURLString);
353

    
354
      // Get docid content
355
      String newxmldoc = ReplicationService.getURLContent(u);
356
      // If couldn't get skip it
357
      if ( newxmldoc.indexOf("<error>")!= -1 && newxmldoc.indexOf("</error>")!=-1)
358
      {
359
         throw new HandlerException("ReplicationHandler.handleSingleXMLDocument - " + newxmldoc);
360
      }
361
      //logReplication.info("xml documnet:");
362
      //logReplication.info(newxmldoc);
363

    
364
      // Try get the docid info from remote server
365
      DocInfoHandler dih = new DocInfoHandler();
366
      XMLReader docinfoParser = initParser(dih);
367
      String docInfoURLStr = "https://" + remoteserver +
368
                       "?server="+MetacatUtil.getLocalReplicationServerName()+
369
                       "&action=getdocumentinfo&docid="+accNumber;
370
      docInfoURLStr = MetacatUtil.replaceWhiteSpaceForURL(docInfoURLStr);
371
      URL docinfoUrl = new URL(docInfoURLStr);
372
      logReplication.info("ReplicationHandler.handleSingleXMLDocument - Sending message: " + docinfoUrl.toString());
373
      String docInfoStr = ReplicationService.getURLContent(docinfoUrl);
374
      
375
      // strip out the system metadata portion
376
      String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
377
   	  docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);
378
      
379
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
380
      Hashtable<String, String> docinfoHash = dih.getDocInfo();
381
      // Get home server of the docid
382
      String docHomeServer = docinfoHash.get("home_server");
383
      logReplication.info("ReplicationHandler.handleSingleXMLDocument - doc home server in repl: "+docHomeServer);
384
      String createdDate = docinfoHash.get("date_created");
385
      String updatedDate = docinfoHash.get("date_updated");
386
      //docid should include rev number too
387
      /*String accnum=docId+util.getProperty("document.accNumSeparator")+
388
                                              (String)docinfoHash.get("rev");*/
389
      logReplication.info("ReplicationHandler.handleSingleXMLDocument - docid in repl: "+accNumber);
390
      String docType = docinfoHash.get("doctype");
391
      logReplication.info("ReplicationHandler.handleSingleXMLDocument - doctype in repl: "+docType);
392

    
393
      String parserBase = null;
394
      // this for eml2 and we need user eml2 parser
395
      if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE))
396
      {
397
         parserBase = DocumentImpl.EML200;
398
      }
399
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE))
400
      {
401
        parserBase = DocumentImpl.EML200;
402
      }
403
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE))
404
      {
405
        parserBase = DocumentImpl.EML210;
406
      }
407
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_1_1NAMESPACE))
408
      {
409
        parserBase = DocumentImpl.EML210;
410
      }
411
      // Write the document into local host
412
      DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false);
413
      String newDocid = wrapper.writeReplication(dbConn,
414
                              newxmldoc,
415
                              docinfoHash.get("public_access"),
416
                              null,  /* the dtd text */
417
                              actions,
418
                              accNumber,
419
                              null, //docinfoHash.get("user_owner"),                              
420
                              null, /* null for groups[] */
421
                              docHomeServer,
422
                              remoteserver, tableName, true,// true is for time replication 
423
                              createdDate,
424
                              updatedDate);
425
      
426
      //set the user information
427
      String user = (String) docinfoHash.get("user_owner");
428
      String updated = (String) docinfoHash.get("user_updated");
429
      ReplicationService.updateUserOwner(dbConn, accNumber, user, updated);
430
      
431
      //process extra access rules 
432
      Vector<XMLAccessDAO> xmlAccessDAOList = dih.getAccessControlList();
433
      if (xmlAccessDAOList != null) {
434
      	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(accNumber);
435
      	for (XMLAccessDAO xmlAccessDAO : xmlAccessDAOList) {
436
      		if (!acfsf.accessControlExists(xmlAccessDAO)) {
437
      			acfsf.insertPermissions(xmlAccessDAO);
438
      		}
439
          }
440
      }
441
      
442
      // process system metadata
443
      if (systemMetadataXML != null) {
444
    	  SystemMetadata sysMeta = 
445
    		  (SystemMetadata) ServiceTypeUtil.deserializeServiceType(
446
    				  SystemMetadata.class, 
447
    				  new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
448
    	  String guid = sysMeta.getIdentifier().getValue();
449
    	  if (!IdentifierManager.getInstance().identifierExists(guid)) {
450
    		  logReplication.debug("Creating system metadata and guid/docid mapping for docid " + docinfoHash.get("docid") + " and guid: " + guid);
451
    		  IdentifierManager.getInstance().createMapping(guid, docinfoHash.get("docid"));
452
    		  IdentifierManager.getInstance().createSystemMetadata(sysMeta);
453
    	  } else {
454
    		  logReplication.debug("Updating guid/docid mapping for docid " + docinfoHash.get("docid") + " and guid: " + guid);
455
    		  IdentifierManager.getInstance().updateMapping(guid, docinfoHash.get("docid"));
456
    	  }
457
          IdentifierManager.getInstance().updateSystemMetadata(sysMeta);
458
      }
459
      
460
      logReplication.info("ReplicationHandler.handleSingleXMLDocument - Successfully replicated doc " + accNumber);
461
      if (tableName.equals(DocumentImpl.DOCUMENTTABLE))
462
      {
463
        logReplication.info("ReplicationHandler.handleSingleXMLDocument - " + DOCINSERTNUMBER + " Wrote xml doc " + accNumber +
464
                                     " into "+tableName + " from " +
465
                                         remoteserver);
466
        DOCINSERTNUMBER++;
467
      }
468
      else
469
      {
470
          logReplication.info("ReplicationHandler.handleSingleXMLDocument - " +REVINSERTNUMBER + " Wrote xml doc " + accNumber +
471
                  " into "+tableName + " from " +
472
                      remoteserver);
473
          REVINSERTNUMBER++;
474
      }
475
      String ip = getIpFromURL(u);
476
      EventLog.getInstance().log(ip, ReplicationService.REPLICATIONUSER, accNumber, actions);
477
      
478

    
479
    }//try
480
    catch(Exception e)
481
    {
482
        
483
        if (tableName.equals(DocumentImpl.DOCUMENTTABLE))
484
        {
485
        	logMetacat.error("ReplicationHandler.handleSingleXMLDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
486
        	logReplication.error("ReplicationHandler.handleSingleXMLDocument - " +DOCERRORNUMBER + " Failed to write xml doc " + accNumber +
487
                                       " into "+tableName + " from " +
488
                                           remoteserver + " because "+e.getMessage());
489
          DOCERRORNUMBER++;
490
        }
491
        else
492
        {
493
        	logMetacat.error("ReplicationHandler.handleSingleXMLDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
494
        	logReplication.error("ReplicationHandler.handleSingleXMLDocument - " +REVERRORNUMBER + " Failed to write xml doc " + accNumber +
495
                    " into "+tableName + " from " +
496
                        remoteserver +" because "+e.getMessage());
497
            REVERRORNUMBER++;
498
        }
499
        logMetacat.error("ReplicationHandler.handleSingleXMLDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
500
        logReplication.error("ReplicationHandler.handleSingleXMLDocument - Failed to write doc " + accNumber +
501
                                      " into db because " +e.getMessage());
502
      throw new HandlerException("ReplicationHandler.handleSingleXMLDocument - generic exception " 
503
    		  + "writing Replication: " +e.getMessage());
504
    }
505
    finally
506
    {
507
       //return DBConnection
508
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
509
    }//finally
510
    logD1.info("replication.create localId:" + accNumber);
511
  }
512

    
513

    
514

    
515
  /* Handle replicate single xml document*/
516
  private void handleSingleDataFile(String remoteserver, String actions,
517
                                    String accNumber, String tableName)
518
               throws HandlerException
519
  {
520
    logReplication.info("ReplicationHandler.handleSingleDataFile - Try to replicate data file: " + accNumber);
521
    DBConnection dbConn = null;
522
    int serialNumber = -1;
523
    try
524
    {
525
      // Get DBConnection from pool
526
      dbConn=DBConnectionPool.
527
                  getDBConnection("ReplicationHandler.handleSinlgeDataFile");
528
      serialNumber=dbConn.getCheckOutSerialNumber();
529
      // Try get docid info from remote server
530
      DocInfoHandler dih = new DocInfoHandler();
531
      XMLReader docinfoParser = initParser(dih);
532
      String docInfoURLString = "https://" + remoteserver +
533
                  "?server="+MetacatUtil.getLocalReplicationServerName()+
534
                  "&action=getdocumentinfo&docid="+accNumber;
535
      docInfoURLString = MetacatUtil.replaceWhiteSpaceForURL(docInfoURLString);
536
      URL docinfoUrl = new URL(docInfoURLString);
537

    
538
      String docInfoStr = ReplicationService.getURLContent(docinfoUrl);
539
      
540
      // strip out the system metadata portion
541
      String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
542
   	  docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);  
543
   	  
544
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
545
      Hashtable<String, String> docinfoHash = dih.getDocInfo();
546
      
547
      // Get docid name (such as acl or dataset)
548
      String docName = docinfoHash.get("docname");
549
      // Get doc type (eml public id)
550
      String docType = docinfoHash.get("doctype");
551
      // Get docid home sever. it might be different to remoteserver
552
      // because of hub feature
553
      String docHomeServer = docinfoHash.get("home_server");
554
      String createdDate = docinfoHash.get("date_created");
555
      String updatedDate = docinfoHash.get("date_updated");
556
      //docid should include rev number too
557
      /*String accnum=docId+util.getProperty("document.accNumSeparator")+
558
                                              (String)docinfoHash.get("rev");*/
559

    
560
      String datafilePath = PropertyService.getProperty("application.datafilepath");
561
      // Get data file content
562
      String readDataURLString = "https://" + remoteserver + "?server="+
563
                                        MetacatUtil.getLocalReplicationServerName()+
564
                                            "&action=readdata&docid="+accNumber;
565
      readDataURLString = MetacatUtil.replaceWhiteSpaceForURL(readDataURLString);
566
      URL u = new URL(readDataURLString);
567
      InputStream input = u.openStream();
568
      //register data file into xml_documents table and wite data file
569
      //into file system
570
      if ( input != null)
571
      {
572
        DocumentImpl.writeDataFileInReplication(input,
573
                                                datafilePath,
574
                                                docName,docType,
575
                                                accNumber,
576
                                                null,
577
                                                docHomeServer,
578
                                                remoteserver,
579
                                                tableName,
580
                                                true, //true means timed replication
581
                                                createdDate,
582
                                                updatedDate);
583
                                         
584
        //set the user information
585
        String user = (String) docinfoHash.get("user_owner");
586
		String updated = (String) docinfoHash.get("user_updated");
587
        ReplicationService.updateUserOwner(dbConn, accNumber, user, updated);
588
        
589
        //process extra access rules
590
        Vector<XMLAccessDAO> xmlAccessDAOList = dih.getAccessControlList();
591
        if (xmlAccessDAOList != null) {
592
        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(accNumber);
593
        	for (XMLAccessDAO xmlAccessDAO : xmlAccessDAOList) {
594
        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
595
        			acfsf.insertPermissions(xmlAccessDAO);
596
        		}
597
            }
598
        }
599
        
600
        //process guid
601
     // process system metadata
602
        if (systemMetadataXML != null) {
603
      	  SystemMetadata sysMeta = 
604
      		  (SystemMetadata) ServiceTypeUtil.deserializeServiceType(
605
      				  SystemMetadata.class, 
606
      				  new ByteArrayInputStream(systemMetadataXML.getBytes("UTF-8")));
607
      	  String guid = sysMeta.getIdentifier().getValue();
608
      	  if (!IdentifierManager.getInstance().identifierExists(guid)) {
609
      		  logReplication.debug("Creating system metadata and guid/docid mapping for docid " + docinfoHash.get("docid") + " and guid: " + guid);
610
      		  IdentifierManager.getInstance().createMapping(guid, docinfoHash.get("docid"));
611
      		  IdentifierManager.getInstance().createSystemMetadata(sysMeta);
612
      	  } else {
613
      		  logReplication.debug("Updating guid/docid mapping for docid " + docinfoHash.get("docid") + " and guid: " + guid);
614
      		  IdentifierManager.getInstance().updateMapping(guid, docinfoHash.get("docid"));
615
      	  }
616
            IdentifierManager.getInstance().updateSystemMetadata(sysMeta);
617
        }
618
        
619
        logReplication.info("ReplicationHandler.handleSingleDataFile - Successfully to write datafile " + accNumber);
620
        /*MetacatReplication.replLog("wrote datafile " + accNumber + " from " +
621
                                    remote server);*/
622
        if (tableName.equals(DocumentImpl.DOCUMENTTABLE))
623
        {
624
          logReplication.info("ReplicationHandler.handleSingleDataFile - " + DOCINSERTNUMBER + " Wrote data file" + accNumber +
625
                                       " into "+tableName + " from " +
626
                                           remoteserver);
627
          DOCINSERTNUMBER++;
628
        }
629
        else
630
        {
631
            logReplication.info("ReplicationHandler.handleSingleDataFile - " + REVINSERTNUMBER + " Wrote data file" + accNumber +
632
                    " into "+tableName + " from " +
633
                        remoteserver);
634
            REVINSERTNUMBER++;
635
        }
636
        String ip = getIpFromURL(u);
637
        EventLog.getInstance().log(ip, ReplicationService.REPLICATIONUSER, accNumber, actions);
638
        
639
      }//if
640
      else
641
      {
642
         logReplication.info("ReplicationHandler.handleSingleDataFile - Couldn't open the data file: " + accNumber);
643
         throw new HandlerException("ReplicationHandler.handleSingleDataFile - Couldn't open the data file: " + accNumber);
644
      }//else
645

    
646
    }//try
647
    catch(Exception e)
648
    {
649
      /*MetacatReplication.replErrorLog("Failed to try wrote data file " + accNumber +
650
                                      " because " +e.getMessage());*/
651
      if (tableName.equals(DocumentImpl.DOCUMENTTABLE))
652
      {
653
    	logMetacat.error("ReplicationHandler.handleSingleDataFile - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
654
    	logReplication.error("ReplicationHandler.handleSingleDataFile - " + DOCERRORNUMBER + " Failed to write data file " + accNumber +
655
                                     " into " + tableName + " from " +
656
                                         remoteserver + " because " + e.getMessage());
657
        DOCERRORNUMBER++;
658
      }
659
      else
660
      {
661
    	  logMetacat.error("ReplicationHandler.handleSingleDataFile - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
662
    	  logReplication.error("ReplicationHandler.handleSingleDataFile - " + REVERRORNUMBER + " Failed to write data file" + accNumber +
663
                  " into " + tableName + " from " +
664
                      remoteserver +" because "+ e.getMessage());
665
          REVERRORNUMBER++;
666
      }
667
      logMetacat.error("ReplicationHandler.handleSingleDataFile - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
668
      logReplication.error("ReplicationHandler.handleSingleDataFile - Failed to try wrote datafile " + accNumber +
669
                                      " because " + e.getMessage());
670
      throw new HandlerException("ReplicationHandler.handleSingleDataFile - generic exception " 
671
    		  + "writing Replication: " + e.getMessage());
672
    }
673
    finally
674
    {
675
       //return DBConnection
676
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
677
    }//finally
678
    logD1.info("replication.create localId:" + accNumber);
679
  }
680

    
681

    
682

    
683
  /* Handle delete single document*/
684
  private void handleDeleteSingleDocument(String docId, String notifyServer)
685
               throws HandlerException
686
  {
687
    logReplication.info("ReplicationHandler.handleDeleteSingleDocument - Try delete doc: "+docId);
688
    DBConnection dbConn = null;
689
    int serialNumber = -1;
690
    try
691
    {
692
      // Get DBConnection from pool
693
      dbConn=DBConnectionPool.
694
                  getDBConnection("ReplicationHandler.handleDeleteSingleDoc");
695
      serialNumber=dbConn.getCheckOutSerialNumber();
696
      if(!alreadyDeleted(docId))
697
      {
698

    
699
         //because delete method docid should have rev number
700
         //so we just add one for it. This rev number is no sence.
701
         String accnum=docId+PropertyService.getProperty("document.accNumSeparator")+"1";
702
         DocumentImpl.delete(accnum, null, null, notifyServer);
703
         logReplication.info("ReplicationHandler.handleDeleteSingleDocument - Successfully deleted doc " + docId);
704
         logReplication.info("ReplicationHandler.handleDeleteSingleDocument - Doc " + docId + " deleted");
705
         URL u = new URL("https://"+notifyServer);
706
         String ip = getIpFromURL(u);
707
         EventLog.getInstance().log(ip, ReplicationService.REPLICATIONUSER, docId, "delete");
708
      }
709

    
710
    }//try
711
    catch(McdbDocNotFoundException e)
712
    {
713
      logMetacat.error("ReplicationHandler.handleDeleteSingleDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
714
      logReplication.error("ReplicationHandler.handleDeleteSingleDocument - Failed to delete doc " + docId +
715
                                 " in db because because " + e.getMessage());
716
      throw new HandlerException("ReplicationHandler.handleDeleteSingleDocument - generic exception " 
717
    		  + "when handling document: " + e.getMessage());
718
    }
719
    catch(InsufficientKarmaException e)
720
    {
721
      logMetacat.error("ReplicationHandler.handleDeleteSingleDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
722
      logReplication.error("ReplicationHandler.handleDeleteSingleDocument - Failed to delete doc " + docId +
723
                                 " in db because because " + e.getMessage());
724
      throw new HandlerException("ReplicationHandler.handleDeleteSingleDocument - generic exception " 
725
    		  + "when handling document: " + e.getMessage());
726
    }
727
    catch(SQLException e)
728
    {
729
      logMetacat.error("ReplicationHandler.handleDeleteSingleDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
730
      logReplication.error("ReplicationHandler.handleDeleteSingleDocument - Failed to delete doc " + docId +
731
                                 " in db because because " + e.getMessage());
732
      throw new HandlerException("ReplicationHandler.handleDeleteSingleDocument - generic exception " 
733
    		  + "when handling document: " + e.getMessage());
734
    }
735
    catch(Exception e)
736
    {
737
      logMetacat.error("ReplicationHandler.handleDeleteSingleDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
738
      logReplication.error("ReplicationHandler.handleDeleteSingleDocument - Failed to delete doc " + docId +
739
                                 " in db because because " + e.getMessage());
740
      throw new HandlerException("ReplicationHandler.handleDeleteSingleDocument - generic exception " 
741
    		  + "when handling document: " + e.getMessage());
742
    }
743
    finally
744
    {
745
       //return DBConnection
746
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
747
    }//finally
748
    logD1.info("replication.handleDeleteSingleDocument localId:" + docId);
749
  }
750

    
751
  /* Handle updateLastCheckTimForSingleServer*/
752
  private void updateLastCheckTimeForSingleServer(ReplicationServer repServer)
753
                                                  throws HandlerException
754
  {
755
    String server = repServer.getServerName();
756
    DBConnection dbConn = null;
757
    int serialNumber = -1;
758
    PreparedStatement pstmt = null;
759
    try
760
    {
761
      // Get DBConnection from pool
762
      dbConn=DBConnectionPool.
763
             getDBConnection("ReplicationHandler.updateLastCheckTimeForServer");
764
      serialNumber=dbConn.getCheckOutSerialNumber();
765

    
766
      logReplication.info("ReplicationHandler.updateLastCheckTimeForSingleServer - Try to update last_check for server: "+server);
767
      // Get time from remote server
768
      URL dateurl = new URL("https://" + server + "?server="+
769
      MetacatUtil.getLocalReplicationServerName()+"&action=gettime");
770
      String datexml = ReplicationService.getURLContent(dateurl);
771
      logReplication.info("ReplicationHandler.updateLastCheckTimeForSingleServer - datexml: "+datexml);
772
      if (datexml!=null && !datexml.equals(""))
773
      {
774
         String datestr = datexml.substring(11, datexml.indexOf('<', 11));
775
         StringBuffer sql = new StringBuffer();
776
         /*sql.append("update xml_replication set last_checked = to_date('");
777
         sql.append(datestr).append("', 'YY-MM-DD HH24:MI:SS') where ");
778
         sql.append("server like '").append(server).append("'");*/
779
         sql.append("update xml_replication set last_checked = ");
780
         sql.append(DatabaseService.getInstance().getDBAdapter().toDate(datestr, "MM/DD/YY HH24:MI:SS"));
781
         sql.append(" where server like '").append(server).append("'");
782
         pstmt = dbConn.prepareStatement(sql.toString());
783

    
784
         pstmt.executeUpdate();
785
         dbConn.commit();
786
         pstmt.close();
787
         logReplication.info("ReplicationHandler.updateLastCheckTimeForSingleServer - last_checked updated to "+datestr+" on "
788
                                      + server);
789
      }//if
790
      else
791
      {
792

    
793
         logReplication.info("ReplicationHandler.updateLastCheckTimeForSingleServer - Failed to update last_checked for server "  +
794
                                  server + " in db because couldn't get time "
795
                                  );
796
         throw new Exception("Couldn't get time for server "+ server);
797
      }
798

    
799
    }//try
800
    catch(Exception e)
801
    {
802
      logMetacat.error("ReplicationHandler.updateLastCheckTimeForSingleServer - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
803
      logReplication.error("ReplicationHandler.updateLastCheckTimeForSingleServer - Failed to update last_checked for server " +
804
                                server + " in db because because " + e.getMessage());
805
      throw new HandlerException("ReplicationHandler.updateLastCheckTimeForSingleServer - " 
806
    		  + "Error updating last checked time: " + e.getMessage());
807
    }
808
    finally
809
    {
810
       //return DBConnection
811
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
812
    }//finally
813
  }
814
  
815
  	/**
816
	 * Handle replicate system metadata
817
	 * 
818
	 * @param remoteserver
819
	 * @param guid
820
	 * @throws HandlerException
821
	 */
822
	private void handleSystemMetadata(String remoteserver, String guid) 
823
		throws HandlerException {
824
		try {
825

    
826
			// Try get the system metadata from remote server
827
			String sysMetaURLStr = "https://" + remoteserver + "?server="
828
					+ MetacatUtil.getLocalReplicationServerName()
829
					+ "&action=getsystemmetadata&guid=" + guid;
830
			sysMetaURLStr = MetacatUtil.replaceWhiteSpaceForURL(sysMetaURLStr);
831
			URL sysMetaUrl = new URL(sysMetaURLStr);
832
			logReplication.info("ReplicationHandler.handleSystemMetadata - Sending message: "
833
							+ sysMetaUrl.toString());
834
			String systemMetadataXML = ReplicationService.getURLContent(sysMetaUrl);
835

    
836
			logReplication.info("ReplicationHandler.handleSystemMetadata - guid in repl: " + guid);
837

    
838
			// process system metadata
839
			if (systemMetadataXML != null) {
840
				SystemMetadata sysMeta = (SystemMetadata) ServiceTypeUtil
841
						.deserializeServiceType(SystemMetadata.class,
842
								new ByteArrayInputStream(systemMetadataXML
843
										.getBytes("UTF-8")));
844
				// String guid = sysMeta.getIdentifier().getValue();
845
				if (!IdentifierManager.getInstance().identifierExists(guid)) {
846
					logReplication.debug("Creating system metadata for guid: " + guid);
847
					IdentifierManager.getInstance().createSystemMetadata(sysMeta);
848
				}
849
				IdentifierManager.getInstance().updateSystemMetadata(sysMeta);
850
			}
851

    
852
			logReplication.info("ReplicationHandler.handleSystemMetadata - Successfully replicated system metadata for guid: "
853
							+ guid);
854

    
855
			String ip = getIpFromURL(sysMetaUrl);
856
			EventLog.getInstance().log(ip, ReplicationService.REPLICATIONUSER, guid, "systemMetadata");
857

    
858
		} catch (Exception e) {
859
			logMetacat.error("ReplicationHandler.handleSystemMetadata - "
860
					+ ReplicationService.METACAT_REPL_ERROR_MSG);
861
			logReplication
862
					.error("ReplicationHandler.handleSystemMetadata - Failed to write system metadata "
863
							+ guid + " into db because " + e.getMessage());
864
			throw new HandlerException(
865
					"ReplicationHandler.handleSystemMetadata - generic exception "
866
							+ "writing Replication: " + e.getMessage());
867
		}
868

    
869
	}
870

    
871
  /**
872
   * updates xml_catalog with entries from other servers.
873
   */
874
  private void updateCatalog()
875
  {
876
    logReplication.info("ReplicationHandler.updateCatalog - Start of updateCatalog");
877
    // ReplicationServer object in server list
878
    ReplicationServer replServer = null;
879
    PreparedStatement pstmt = null;
880
    String server = null;
881

    
882

    
883
    // Go through each ReplicationServer object in sererlist
884
    for (int j=0; j<serverList.size(); j++)
885
    {
886
      Vector<Vector<String>> remoteCatalog = new Vector<Vector<String>>();
887
      Vector<String> publicId = new Vector<String>();
888
      try
889
      {
890
        // Get ReplicationServer object from server list
891
        replServer = serverList.serverAt(j);
892
        // Get server name from the ReplicationServer object
893
        server = replServer.getServerName();
894
        // Try to get catalog
895
        URL u = new URL("https://" + server + "?server="+
896
        MetacatUtil.getLocalReplicationServerName()+"&action=getcatalog");
897
        logReplication.info("ReplicationHandler.updateCatalog - sending message " + u.toString());
898
        String catxml = ReplicationService.getURLContent(u);
899

    
900
        // Make sure there are not error, no empty string
901
        if (catxml.indexOf("error")!=-1 || catxml==null||catxml.equals(""))
902
        {
903
          throw new Exception("Couldn't get catalog list form server " +server);
904
        }
905
        logReplication.debug("ReplicationHandler.updateCatalog - catxml: " + catxml);
906
        CatalogMessageHandler cmh = new CatalogMessageHandler();
907
        XMLReader catparser = initParser(cmh);
908
        catparser.parse(new InputSource(new StringReader(catxml)));
909
        //parse the returned catalog xml and put it into a vector
910
        remoteCatalog = cmh.getCatalogVect();
911

    
912
        // Make sure remoteCatalog is not empty
913
        if (remoteCatalog.isEmpty())
914
        {
915
          throw new Exception("Couldn't get catalog list form server " +server);
916
        }
917

    
918
        String localcatxml = ReplicationService.getCatalogXML();
919

    
920
        // Make sure local catalog is no empty
921
        if (localcatxml==null||localcatxml.equals(""))
922
        {
923
          throw new Exception("Couldn't get catalog list form server " +server);
924
        }
925

    
926
        cmh = new CatalogMessageHandler();
927
        catparser = initParser(cmh);
928
        catparser.parse(new InputSource(new StringReader(localcatxml)));
929
        Vector<Vector<String>> localCatalog = cmh.getCatalogVect();
930

    
931
        //now we have the catalog from the remote server and this local server
932
        //we now need to compare the two and merge the differences.
933
        //the comparison is base on the public_id fields which is the 4th
934
        //entry in each row vector.
935
        publicId = new Vector<String>();
936
        for(int i=0; i<localCatalog.size(); i++)
937
        {
938
          Vector<String> v = new Vector<String>(localCatalog.elementAt(i));
939
          logReplication.info("ReplicationHandler.updateCatalog - v1: " + v.toString());
940
          publicId.add(new String((String)v.elementAt(3)));
941
        }
942
      }//try
943
      catch (Exception e)
944
      {
945
        logMetacat.error("ReplicationHandler.updateCatalog - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
946
        logReplication.error("ReplicationHandler.updateCatalog - Failed to update catalog for server "+
947
                                    server + " because " +e.getMessage());
948
      }//catch
949

    
950
      for(int i=0; i<remoteCatalog.size(); i++)
951
      {
952
         // DConnection
953
        DBConnection dbConn = null;
954
        // DBConnection checkout serial number
955
        int serialNumber = -1;
956
        try
957
        {
958
            dbConn=DBConnectionPool.
959
                  getDBConnection("ReplicationHandler.updateCatalog");
960
            serialNumber=dbConn.getCheckOutSerialNumber();
961
            Vector<String> v = remoteCatalog.elementAt(i);
962
            //logMetacat.debug("v2: " + v.toString());
963
            //logMetacat.debug("i: " + i);
964
            //logMetacat.debug("remoteCatalog.size(): " + remoteCatalog.size());
965
            //logMetacat.debug("publicID: " + publicId.toString());
966
            logReplication.info
967
                              ("ReplicationHandler.updateCatalog - v.elementAt(3): " + (String)v.elementAt(3));
968
           if(!publicId.contains(v.elementAt(3)))
969
           { //so we don't have this public id in our local table so we need to
970
             //add it.
971
             //logMetacat.debug("in if");
972
             StringBuffer sql = new StringBuffer();
973
             sql.append("insert into xml_catalog (entry_type, source_doctype, ");
974
             sql.append("target_doctype, public_id, system_id) values (?,?,?,");
975
             sql.append("?,?)");
976
             //logMetacat.debug("sql: " + sql.toString());
977
             pstmt = dbConn.prepareStatement(sql.toString());
978
             pstmt.setString(1, (String)v.elementAt(0));
979
             pstmt.setString(2, (String)v.elementAt(1));
980
             pstmt.setString(3, (String)v.elementAt(2));
981
             pstmt.setString(4, (String)v.elementAt(3));
982
             pstmt.setString(5, (String)v.elementAt(4));
983
             pstmt.execute();
984
             pstmt.close();
985
             logReplication.info("ReplicationHandler.updateCatalog - Success fully to insert new publicid "+
986
                               (String)v.elementAt(3) + " from server"+server);
987
           }
988
        }
989
        catch(Exception e)
990
        {
991
           logMetacat.error("ReplicationHandler.updateCatalog - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
992
           logReplication.error("ReplicationHandler.updateCatalog - Failed to update catalog for server "+
993
                                    server + " because " +e.getMessage());
994
        }//catch
995
        finally
996
        {
997
           DBConnectionPool.returnDBConnection(dbConn, serialNumber);
998
        }//finally
999
      }//for remote catalog
1000
    }//for server list
1001
    logReplication.info("End of updateCatalog");
1002
  }
1003

    
1004
  /**
1005
   * Method that returns true if docid has already been "deleted" from metacat.
1006
   * This method really implements a truth table for deleted documents
1007
   * The table is (a docid in one of the tables is represented by the X):
1008
   * xml_docs      xml_revs      deleted?
1009
   * ------------------------------------
1010
   *   X             X             FALSE
1011
   *   X             _             FALSE
1012
   *   _             X             TRUE
1013
   *   _             _             TRUE
1014
   */
1015
  private static boolean alreadyDeleted(String docid) throws HandlerException
1016
  {
1017
    DBConnection dbConn = null;
1018
    int serialNumber = -1;
1019
    PreparedStatement pstmt = null;
1020
    try
1021
    {
1022
      dbConn=DBConnectionPool.
1023
                  getDBConnection("ReplicationHandler.alreadyDeleted");
1024
      serialNumber=dbConn.getCheckOutSerialNumber();
1025
      boolean xml_docs = false;
1026
      boolean xml_revs = false;
1027

    
1028
      StringBuffer sb = new StringBuffer();
1029
      sb.append("select docid from xml_revisions where docid like '");
1030
      sb.append(docid).append("'");
1031
      pstmt = dbConn.prepareStatement(sb.toString());
1032
      pstmt.execute();
1033
      ResultSet rs = pstmt.getResultSet();
1034
      boolean tablehasrows = rs.next();
1035
      if(tablehasrows)
1036
      {
1037
        xml_revs = true;
1038
      }
1039

    
1040
      sb = new StringBuffer();
1041
      sb.append("select docid from xml_documents where docid like '");
1042
      sb.append(docid).append("'");
1043
      pstmt.close();
1044
      pstmt = dbConn.prepareStatement(sb.toString());
1045
      //increase usage count
1046
      dbConn.increaseUsageCount(1);
1047
      pstmt.execute();
1048
      rs = pstmt.getResultSet();
1049
      tablehasrows = rs.next();
1050
      pstmt.close();
1051
      if(tablehasrows)
1052
      {
1053
        xml_docs = true;
1054
      }
1055

    
1056
      if(xml_docs && xml_revs)
1057
      {
1058
        return false;
1059
      }
1060
      else if(xml_docs && !xml_revs)
1061
      {
1062
        return false;
1063
      }
1064
      else if(!xml_docs && xml_revs)
1065
      {
1066
        return true;
1067
      }
1068
      else if(!xml_docs && !xml_revs)
1069
      {
1070
        return true;
1071
      }
1072
    }
1073
    catch(Exception e)
1074
    {
1075
      logMetacat.error("ReplicationHandler.alreadyDeleted - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1076
      logReplication.error("ReplicationHandler.alreadyDeleted - general error in alreadyDeleted: " +
1077
                          e.getMessage());
1078
      throw new HandlerException("ReplicationHandler.alreadyDeleted - general error: " 
1079
    		  + e.getMessage());
1080
    }
1081
    finally
1082
    {
1083
      try
1084
      {
1085
        pstmt.close();
1086
      }//try
1087
      catch (SQLException ee)
1088
      {
1089
    	logMetacat.error("ReplicationHandler.alreadyDeleted - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1090
        logReplication.error("ReplicationHandler.alreadyDeleted - Error in replicationHandler.alreadyDeleted "+
1091
                          "to close pstmt: "+ee.getMessage());
1092
        throw new HandlerException("ReplicationHandler.alreadyDeleted - SQL error when closing prepared statement: " 
1093
      		  + ee.getMessage());
1094
      }//catch
1095
      finally
1096
      {
1097
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1098
      }//finally
1099
    }//finally
1100
    return false;
1101
  }
1102

    
1103

    
1104
  /**
1105
   * Method to initialize the message parser
1106
   */
1107
  public static XMLReader initParser(DefaultHandler dh)
1108
          throws HandlerException
1109
  {
1110
    XMLReader parser = null;
1111

    
1112
    try {
1113
      ContentHandler chandler = dh;
1114

    
1115
      // Get an instance of the parser
1116
      String parserName = PropertyService.getProperty("xml.saxparser");
1117
      parser = XMLReaderFactory.createXMLReader(parserName);
1118

    
1119
      // Turn off validation
1120
      parser.setFeature("http://xml.org/sax/features/validation", false);
1121

    
1122
      parser.setContentHandler((ContentHandler)chandler);
1123
      parser.setErrorHandler((ErrorHandler)chandler);
1124

    
1125
    } catch (SAXException se) {
1126
      throw new HandlerException("ReplicationHandler.initParser - Sax error when " 
1127
    		  + " initializing parser: " + se.getMessage());
1128
    } catch (PropertyNotFoundException pnfe) {
1129
        throw new HandlerException("ReplicationHandler.initParser - Property error when " 
1130
      		  + " getting parser name: " + pnfe.getMessage());
1131
    } 
1132

    
1133
    return parser;
1134
  }
1135

    
1136
  /**
1137
	 * This method will combine given time string(in short format) to current
1138
	 * date. If the given time (e.g 10:00 AM) passed the current time (e.g 2:00
1139
	 * PM Aug 21, 2005), then the time will set to second day, 10:00 AM Aug 22,
1140
	 * 2005. If the given time (e.g 10:00 AM) haven't passed the current time
1141
	 * (e.g 8:00 AM Aug 21, 2005) The time will set to be 10:00 AM Aug 21, 2005.
1142
	 * 
1143
	 * @param givenTime
1144
	 *            the format should be "10:00 AM " or "2:00 PM"
1145
	 * @return
1146
	 * @throws Exception
1147
	 */
1148
	public static Date combinateCurrentDateAndGivenTime(String givenTime) throws HandlerException
1149
  {
1150
	  try {
1151
     Date givenDate = parseTime(givenTime);
1152
     Date newDate = null;
1153
     Date now = new Date();
1154
     String currentTimeString = getTimeString(now);
1155
     Date currentTime = parseTime(currentTimeString); 
1156
     if ( currentTime.getTime() >= givenDate.getTime())
1157
     {
1158
        logReplication.info("ReplicationHandler.combinateCurrentDateAndGivenTime - Today already pass the given time, we should set it as tomorrow");
1159
        String dateAndTime = getDateString(now) + " " + givenTime;
1160
        Date combinationDate = parseDateTime(dateAndTime);
1161
        // new date should plus 24 hours to make is the second day
1162
        newDate = new Date(combinationDate.getTime()+24*3600*1000);
1163
     }
1164
     else
1165
     {
1166
         logReplication.info("ReplicationHandler.combinateCurrentDateAndGivenTime - Today haven't pass the given time, we should it as today");
1167
         String dateAndTime = getDateString(now) + " " + givenTime;
1168
         newDate = parseDateTime(dateAndTime);
1169
     }
1170
     logReplication.warn("ReplicationHandler.combinateCurrentDateAndGivenTime - final setting time is "+ newDate.toString());
1171
     return newDate;
1172
	  } catch (ParseException pe) {
1173
		  throw new HandlerException("ReplicationHandler.combinateCurrentDateAndGivenTime - "
1174
				  + "parsing error: "  + pe.getMessage());
1175
	  }
1176
  }
1177

    
1178
  /*
1179
	 * parse a given string to Time in short format. For example, given time is
1180
	 * 10:00 AM, the date will be return as Jan 1 1970, 10:00 AM
1181
	 */
1182
  private static Date parseTime(String timeString) throws ParseException
1183
  {
1184
    DateFormat format = DateFormat.getTimeInstance(DateFormat.SHORT);
1185
    Date time = format.parse(timeString); 
1186
    logReplication.info("ReplicationHandler.parseTime - Date string is after parse a time string "
1187
                              +time.toString());
1188
    return time;
1189

    
1190
  }
1191
  
1192
  /*
1193
   * Parse a given string to date and time. Date format is long and time
1194
   * format is short.
1195
   */
1196
  private static Date parseDateTime(String timeString) throws ParseException
1197
  {
1198
    DateFormat format = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT);
1199
    Date time = format.parse(timeString);
1200
    logReplication.info("ReplicationHandler.parseDateTime - Date string is after parse a time string "+
1201
                             time.toString());
1202
    return time;
1203
  }
1204
  
1205
  /*
1206
   * Get a date string from a Date object. The date format will be long
1207
   */
1208
  private static String getDateString(Date now)
1209
  {
1210
     DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
1211
     String s = df.format(now);
1212
     logReplication.info("ReplicationHandler.getDateString - Today is " + s);
1213
     return s;
1214
  }
1215
  
1216
  /*
1217
   * Get a time string from a Date object, the time format will be short
1218
   */
1219
  private static String getTimeString(Date now)
1220
  {
1221
     DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
1222
     String s = df.format(now);
1223
     logReplication.info("ReplicationHandler.getTimeString - Time is " + s);
1224
     return s;
1225
  }
1226
  
1227
  
1228
  /*
1229
	 * This method will go through the docid list both in xml_Documents table
1230
	 * and in xml_revisions table @author tao
1231
	 */
1232
	private void handleDocList(Vector<Vector<String>> docList, String tableName) {
1233
		boolean dataFile = false;
1234
		for (int j = 0; j < docList.size(); j++) {
1235
			// initial dataFile is false
1236
			dataFile = false;
1237
			// w is information for one document, information contain
1238
			// docid, rev, server or datafile.
1239
			Vector<String> w = new Vector<String>(docList.elementAt(j));
1240
			// Check if the vector w contain "datafile"
1241
			// If it has, this document is data file
1242
			try {
1243
				if (w.contains((String) PropertyService.getProperty("replication.datafileflag"))) {
1244
					dataFile = true;
1245
				}
1246
			} catch (PropertyNotFoundException pnfe) {
1247
				logMetacat.error("ReplicationHandler.handleDocList - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1248
				logReplication.error("ReplicationHandler.handleDocList - Could not retrieve data file flag property.  "
1249
						+ "Leaving as false: " + pnfe.getMessage());
1250
			}
1251
			// logMetacat.debug("w: " + w.toString());
1252
			// Get docid
1253
			String docid = (String) w.elementAt(0);
1254
			logReplication.info("docid: " + docid);
1255
			// Get revision number
1256
			int rev = Integer.parseInt((String) w.elementAt(1));
1257
			logReplication.info("rev: " + rev);
1258
			// Get remote server name (it is may not be doc home server because
1259
			// the new hub feature
1260
			String remoteServer = (String) w.elementAt(2);
1261
			remoteServer = remoteServer.trim();
1262

    
1263
			try {
1264
				if (tableName.equals(DocumentImpl.DOCUMENTTABLE)) {
1265
					handleDocInXMLDocuments(docid, rev, remoteServer, dataFile);
1266
				} else if (tableName.equals(DocumentImpl.REVISIONTABLE)) {
1267
					handleDocInXMLRevisions(docid, rev, remoteServer, dataFile);
1268
				} else {
1269
					continue;
1270
				}
1271

    
1272
			} catch (Exception e) {
1273
				logMetacat.error("ReplicationHandler.handleDocList - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1274
				logReplication.error("ReplicationHandler.handleDocList - error to handle update doc in " + tableName
1275
						+ " in time replication" + e.getMessage());
1276
				continue;
1277
			}
1278
			
1279
	        if (_xmlDocQueryCount > 0 && (_xmlDocQueryCount % 100) == 0) {
1280
	        	logMetacat.debug("ReplicationHandler.update - xml_doc query count: " + _xmlDocQueryCount + 
1281
	        			", xml_doc avg query time: " + (_xmlDocQueryTime / _xmlDocQueryCount));
1282
	        }
1283
	        
1284
	        if (_xmlRevQueryCount > 0 && (_xmlRevQueryCount % 100) == 0) {
1285
	        	logMetacat.debug("ReplicationHandler.update - xml_rev query count: " + _xmlRevQueryCount + 
1286
	        			", xml_rev avg query time: " + (_xmlRevQueryTime / _xmlRevQueryCount));
1287
	        }
1288

    
1289
		}// for update docs
1290

    
1291
	}
1292
   
1293
   /*
1294
	 * This method will handle doc in xml_documents table.
1295
	 */
1296
   private void handleDocInXMLDocuments(String docid, int rev, String remoteServer, boolean dataFile) 
1297
                                        throws HandlerException
1298
   {
1299
       // compare the update rev and local rev to see what need happen
1300
       int localrev = -1;
1301
       String action = null;
1302
       boolean flag = false;
1303
       try
1304
       {
1305
    	 long docQueryStartTime = System.currentTimeMillis();
1306
         localrev = DBUtil.getLatestRevisionInDocumentTable(docid);
1307
         long docQueryEndTime = System.currentTimeMillis();
1308
         _xmlDocQueryTime += (docQueryEndTime - docQueryStartTime);
1309
         _xmlDocQueryCount++;
1310
       }
1311
       catch (SQLException e)
1312
       {
1313
    	 logMetacat.error("ReplicationHandler.handleDocInXMLDocuments - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1314
         logReplication.error("ReplicationHandler.handleDocInXMLDocuments - Local rev for docid "+ docid + " could not "+
1315
                                " be found because " + e.getMessage());
1316
         logReplication.error("ReplicationHandler.handleDocInXMLDocuments - " + DOCERRORNUMBER+"Docid "+ docid + " could not be "+
1317
                 "written because error happend to find it's local revision");
1318
         DOCERRORNUMBER++;
1319
         throw new HandlerException ("ReplicationHandler.handleDocInXMLDocuments - Local rev for docid "+ docid + " could not "+
1320
                 " be found: " + e.getMessage());
1321
       }
1322
       logReplication.info("ReplicationHandler.handleDocInXMLDocuments - Local rev for docid "+ docid + " is "+
1323
                               localrev);
1324

    
1325
       //check the revs for an update because this document is in the
1326
       //local DB, it might be out of date.
1327
       if (localrev == -1)
1328
       {
1329
          // check if the revision is in the revision table
1330
    	   Vector<Integer> localRevVector = null;
1331
    	 try {
1332
        	 long revQueryStartTime = System.currentTimeMillis();
1333
    		 localRevVector = DBUtil.getRevListFromRevisionTable(docid);
1334
             long revQueryEndTime = System.currentTimeMillis();
1335
             _xmlRevQueryTime += (revQueryEndTime - revQueryStartTime);
1336
             _xmlRevQueryCount++;
1337
    	 } catch (SQLException sqle) {
1338
    		 throw new HandlerException("ReplicationHandler.handleDocInXMLDocuments - SQL error " 
1339
    				 + " when getting rev list for docid: " + docid + " : " + sqle.getMessage());
1340
    	 }
1341
         if (localRevVector != null && localRevVector.contains(new Integer(rev)))
1342
         {
1343
             // this version was deleted, so don't need replicate
1344
             flag = false;
1345
         }
1346
         else
1347
         {
1348
           //insert this document as new because it is not in the local DB
1349
           action = "INSERT";
1350
           flag = true;
1351
         }
1352
       }
1353
       else
1354
       {
1355
         if(localrev == rev)
1356
         {
1357
           // Local meatacat has the same rev to remote host, don't need
1358
           // update and flag set false
1359
           flag = false;
1360
         }
1361
         else if(localrev < rev)
1362
         {
1363
           //this document needs to be updated so send an read request
1364
           action = "UPDATE";
1365
           flag = true;
1366
         }
1367
       }
1368
       
1369
       String accNumber = null;
1370
       try {
1371
    	   accNumber = docid + PropertyService.getProperty("document.accNumSeparator") + rev;
1372
       } catch (PropertyNotFoundException pnfe) {
1373
    	   throw new HandlerException("ReplicationHandler.handleDocInXMLDocuments - error getting " 
1374
    			   + "account number separator : " + pnfe.getMessage());
1375
       }
1376
       // this is non-data file
1377
       if(flag && !dataFile)
1378
       {
1379
         try
1380
         {
1381
           handleSingleXMLDocument(remoteServer, action, accNumber, DocumentImpl.DOCUMENTTABLE);
1382
         }
1383
         catch(HandlerException he)
1384
         {
1385
           // skip this document
1386
           throw he;
1387
         }
1388
       }//if for non-data file
1389

    
1390
        // this is for data file
1391
       if(flag && dataFile)
1392
       {
1393
         try
1394
         {
1395
           handleSingleDataFile(remoteServer, action, accNumber, DocumentImpl.DOCUMENTTABLE);
1396
         }
1397
         catch(HandlerException he)
1398
         {
1399
           // skip this data file
1400
           throw he;
1401
         }
1402

    
1403
       }//for data file
1404
   }
1405
   
1406
   /*
1407
    * This method will handle doc in xml_documents table.
1408
    */
1409
   private void handleDocInXMLRevisions(String docid, int rev, String remoteServer, boolean dataFile) 
1410
                                        throws HandlerException
1411
   {
1412
       // compare the update rev and local rev to see what need happen
1413
       logReplication.info("ReplicationHandler.handleDocInXMLRevisions - In handle repliation revsion table");
1414
       logReplication.info("ReplicationHandler.handleDocInXMLRevisions - the docid is "+ docid);
1415
       logReplication.info("ReplicationHandler.handleDocInXMLRevisions - The rev is "+rev);
1416
       Vector<Integer> localrev = null;
1417
       String action = "INSERT";
1418
       boolean flag = false;
1419
       try
1420
       {
1421
      	 long revQueryStartTime = System.currentTimeMillis();
1422
         localrev = DBUtil.getRevListFromRevisionTable(docid);
1423
         long revQueryEndTime = System.currentTimeMillis();
1424
         _xmlRevQueryTime += (revQueryEndTime - revQueryStartTime);
1425
         _xmlRevQueryCount++;
1426
       }
1427
       catch (SQLException sqle)
1428
       {
1429
    	 logMetacat.error("ReplicationHandler.handleDocInXMLDocuments - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1430
         logReplication.error("ReplicationHandler.handleDocInXMLRevisions - Local rev for docid "+ docid + " could not "+
1431
                                " be found because " + sqle.getMessage());
1432
         REVERRORNUMBER++;
1433
         throw new HandlerException ("ReplicationHandler.handleDocInXMLRevisions - SQL exception getting rev list: " 
1434
        		 + sqle.getMessage());
1435
       }
1436
       logReplication.info("ReplicationHandler.handleDocInXMLRevisions - rev list in xml_revision table for docid "+ docid + " is "+
1437
                               localrev.toString());
1438
       
1439
       // if the rev is not in the xml_revision, we need insert it
1440
       if (!localrev.contains(new Integer(rev)))
1441
       {
1442
           flag = true;    
1443
       }
1444
     
1445
       String accNumber = null;
1446
       try {
1447
    	   accNumber = docid + PropertyService.getProperty("document.accNumSeparator") + rev;
1448
       } catch (PropertyNotFoundException pnfe) {
1449
    	   throw new HandlerException("ReplicationHandler.handleDocInXMLRevisions - error getting " 
1450
    			   + "account number separator : " + pnfe.getMessage());
1451
       }
1452
       // this is non-data file
1453
       if(flag && !dataFile)
1454
       {
1455
         try
1456
         {
1457
           
1458
           handleSingleXMLDocument(remoteServer, action, accNumber, DocumentImpl.REVISIONTABLE);
1459
         }
1460
         catch(HandlerException he)
1461
         {
1462
           // skip this document
1463
           throw he;
1464
         }
1465
       }//if for non-data file
1466

    
1467
        // this is for data file
1468
       if(flag && dataFile)
1469
       {
1470
         try
1471
         {
1472
           handleSingleDataFile(remoteServer, action, accNumber, DocumentImpl.REVISIONTABLE);
1473
         }
1474
         catch(HandlerException he)
1475
         {
1476
           // skip this data file
1477
           throw he;
1478
         }
1479

    
1480
       }//for data file
1481
   }
1482
   
1483
   /*
1484
    * Return a ip address for given url
1485
    */
1486
   private String getIpFromURL(URL url)
1487
   {
1488
	   String ip = null;
1489
	   try
1490
	   {
1491
	      InetAddress address = InetAddress.getByName(url.getHost());
1492
	      ip = address.getHostAddress();
1493
	   }
1494
	   catch(UnknownHostException e)
1495
	   {
1496
		   logMetacat.error("ReplicationHandler.getIpFromURL - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1497
		   logReplication.error("ReplicationHandler.getIpFromURL - Error in get ip address for host: "
1498
                   +e.getMessage());
1499
	   }
1500

    
1501
	   return ip;
1502
   }
1503
  
1504
}
1505

    
(4-4/8)