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: berkley $'
9
 *     '$Date: 2011-02-10 16:17:05 -0800 (Thu, 10 Feb 2011) $'
10
 * '$Revision: 5944 $'
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.accesscontrol.AccessControlForSingleFile;
36
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessDAO;
37
import edu.ucsb.nceas.metacat.database.DBConnection;
38
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
39
import edu.ucsb.nceas.metacat.database.DatabaseService;
40
import edu.ucsb.nceas.metacat.properties.PropertyService;
41
import edu.ucsb.nceas.metacat.shared.HandlerException;
42
import edu.ucsb.nceas.metacat.util.MetacatUtil;
43
import edu.ucsb.nceas.metacat.IdentifierManager;
44
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
45

    
46
import java.sql.*;
47
import java.util.*;
48
import java.util.Date;
49
import java.io.*;
50
import java.net.*;
51
import java.text.*;
52

    
53
import org.apache.log4j.Logger;
54
import org.xml.sax.ContentHandler;
55
import org.xml.sax.ErrorHandler;
56
import org.xml.sax.InputSource;
57
import org.xml.sax.SAXException;
58
import org.xml.sax.XMLReader;
59
import org.xml.sax.helpers.XMLReaderFactory;
60
import org.xml.sax.helpers.DefaultHandler;
61

    
62

    
63

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

    
96
  public ReplicationHandler(int serverCheckCode)
97
  {
98
    //this.out = o;
99
    this.serverCheckCode = serverCheckCode;
100
    serverList = new ReplicationServerList();
101
  }
102

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

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

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

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

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

    
208

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

    
284
    //updated last_checked
285
    for (int i=0;i<serverList.size(); i++)
286
    {
287
       // Get ReplicationServer object from server list
288
       replServer = serverList.serverAt(i);
289
       try
290
       {
291
         updateLastCheckTimeForSingleServer(replServer);
292
       }
293
       catch(Exception e)
294
       {
295
         continue;
296
       }
297
    }//for
298
    
299
    long replicationEndTime = System.currentTimeMillis();
300
    logMetacat.debug("ReplicationHandler.update - Total replication time: " + 
301
    		(replicationEndTime - replicationStartTime));
302
    logMetacat.debug("ReplicationHandler.update - time to get server list: " + 
303
    		timeToGetServerList);
304
    logMetacat.debug("ReplicationHandler.update - server list parse time: " + 
305
    		totalServerListParseTime);
306
    logMetacat.debug("ReplicationHandler.update - 'in xml_documents' total query count: " + 
307
    		_xmlDocQueryCount);
308
    logMetacat.debug("ReplicationHandler.update - 'in xml_documents' total query time: " + 
309
    		_xmlDocQueryTime + " ms");
310
    logMetacat.debug("ReplicationHandler.update - 'in xml_revisions' total query count: " + 
311
    		_xmlRevQueryCount);
312
    logMetacat.debug("ReplicationHandler.update - 'in xml_revisions' total query time: " + 
313
    		_xmlRevQueryTime + " ms");;
314

    
315
  }//update
316

    
317
  /* Handle replicate single xml document*/
318
  private void handleSingleXMLDocument(String remoteserver, String actions,
319
                                       String accNumber, String tableName)
320
               throws HandlerException
321
  {
322
    DBConnection dbConn = null;
323
    int serialNumber = -1;
324
    try
325
    {
326
      // Get DBConnection from pool
327
      dbConn=DBConnectionPool.
328
                  getDBConnection("ReplicationHandler.handleSingleXMLDocument");
329
      serialNumber=dbConn.getCheckOutSerialNumber();
330
      //if the document needs to be updated or inserted, this is executed
331
      String readDocURLString = "https://" + remoteserver + "?server="+
332
              MetacatUtil.getLocalReplicationServerName()+"&action=read&docid="+accNumber;
333
      readDocURLString = MetacatUtil.replaceWhiteSpaceForURL(readDocURLString);
334
      URL u = new URL(readDocURLString);
335

    
336
      // Get docid content
337
      String newxmldoc = ReplicationService.getURLContent(u);
338
      // If couldn't get skip it
339
      if ( newxmldoc.indexOf("<error>")!= -1 && newxmldoc.indexOf("</error>")!=-1)
340
      {
341
         throw new HandlerException("ReplicationHandler.handleSingleXMLDocument - " + newxmldoc);
342
      }
343
      //logReplication.info("xml documnet:");
344
      //logReplication.info(newxmldoc);
345

    
346
      // Try get the docid info from remote server
347
      DocInfoHandler dih = new DocInfoHandler();
348
      XMLReader docinfoParser = initParser(dih);
349
      String docInfoURLStr = "https://" + remoteserver +
350
                       "?server="+MetacatUtil.getLocalReplicationServerName()+
351
                       "&action=getdocumentinfo&docid="+accNumber;
352
      docInfoURLStr = MetacatUtil.replaceWhiteSpaceForURL(docInfoURLStr);
353
      URL docinfoUrl = new URL(docInfoURLStr);
354
      logReplication.info("ReplicationHandler.handleSingleXMLDocument - Sending message: " +
355
                                                  docinfoUrl.toString());
356
      String docInfoStr = ReplicationService.getURLContent(docinfoUrl);
357
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
358
      Hashtable<String, String> docinfoHash = dih.getDocInfo();
359
      // Get home server of the docid
360
      String docHomeServer = docinfoHash.get("home_server");
361
      logReplication.info("ReplicationHandler.handleSingleXMLDocument - doc home server in repl: "+docHomeServer);
362
      String createdDate = docinfoHash.get("date_created");
363
      String updatedDate = docinfoHash.get("date_updated");
364
      //docid should include rev number too
365
      /*String accnum=docId+util.getProperty("document.accNumSeparator")+
366
                                              (String)docinfoHash.get("rev");*/
367
      logReplication.info("ReplicationHandler.handleSingleXMLDocument - docid in repl: "+accNumber);
368
      String docType = docinfoHash.get("doctype");
369
      logReplication.info("ReplicationHandler.handleSingleXMLDocument - doctype in repl: "+docType);
370

    
371
      String parserBase = null;
372
      // this for eml2 and we need user eml2 parser
373
      if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE))
374
      {
375
         parserBase = DocumentImpl.EML200;
376
      }
377
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE))
378
      {
379
        parserBase = DocumentImpl.EML200;
380
      }
381
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE))
382
      {
383
        parserBase = DocumentImpl.EML210;
384
      }
385
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_1_1NAMESPACE))
386
      {
387
        parserBase = DocumentImpl.EML210;
388
      }
389
      // Write the document into local host
390
      DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false);
391
      String newDocid = wrapper.writeReplication(dbConn,
392
                              newxmldoc,
393
                              docinfoHash.get("public_access"),
394
                              null,  /* the dtd text */
395
                              actions,
396
                              accNumber,
397
                              docinfoHash.get("user_owner"),
398
                              null, /* null for groups[] */
399
                              docHomeServer,
400
                              remoteserver, tableName, true,// true is for time replication 
401
                              createdDate,
402
                              updatedDate);
403
      
404
      //process extra access rules 
405
      Vector<XMLAccessDAO> xmlAccessDAOList = dih.getAccessControlList();
406
      if (xmlAccessDAOList != null) {
407
      	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(accNumber);
408
      	for (XMLAccessDAO xmlAccessDAO : xmlAccessDAOList) {
409
      		if (!acfsf.accessControlExists(xmlAccessDAO)) {
410
      			acfsf.insertPermissions(xmlAccessDAO);
411
      		}
412
          }
413
      }
414
      
415
      //process guid
416
      logReplication.debug("Processing guid information from docinfoHash: " + docinfoHash.toString());
417
      String guid = docinfoHash.get("guid");
418
      String docName = docinfoHash.get("docname");
419
      System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%%guid passed from docinfo hash: " + guid);
420
      IdentifierManager idman = IdentifierManager.getInstance();
421
      
422
      System.out.println("docname: " + docName);
423
      
424
      if(guid != null && !idman.identifierExists(guid))
425
      { //if the guid was passed in, put it in the identifiers table
426
        logReplication.debug("Creating guid/docid mapping for docid " + 
427
          docinfoHash.get("docid") + " and guid: " + guid);
428
        
429
        
430
        System.out.println("creating mapping: guid: " + guid + " localId: " + docinfoHash.get("docid"));
431
        idman.createMapping(guid, docinfoHash.get("docid"));
432
      }
433
      else
434
      {
435
        logReplication.debug("No guid information was included with the replicated document");
436
      }
437
      
438
      //handle systemMetadata
439
      if(docName.trim().equals("systemMetadata"))
440
      {
441
          System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!creating mapping for systemMetadata: guid: " + guid + " localId: " + docinfoHash.get("docid"));
442
          idman.createSystemMetadataMapping(guid, docinfoHash.get("docid"));
443
          System.out.println("1");
444
          Long dateUploadedLong = new Long(docinfoHash.get("date_uploaded"));
445
          System.out.println("2");
446
          Long dateModifiedLong = new Long(docinfoHash.get("date_modified"));
447
          System.out.println("3");
448
          idman.insertAdditionalSystemMetadataFields(
449
                  dateUploadedLong.longValue(), 
450
                  docinfoHash.get("rights_holder"),
451
                  docinfoHash.get("checksum"), 
452
                  docinfoHash.get("checksum_algorithm"), 
453
                  docinfoHash.get("origin_member_node"),
454
                  docinfoHash.get("authoritive_member_node"), 
455
                  dateModifiedLong.longValue(),
456
                  docinfoHash.get("submitter"),
457
                  docinfoHash.get("guid"),
458
                  docinfoHash.get("objectFormat"),
459
                  new Long(docinfoHash.get("size")).longValue());
460
          System.out.println("4");
461
      }
462
      
463
      if(guid != null)
464
      {
465
          if(!docName.trim().equals("systemMetadata"))
466
          {
467
              logReplication.info("replicate D1GUID:" + guid + ":D1SCIMETADATA:" + 
468
                      accNumber + ":");
469
          }
470
          else
471
          {
472
              logReplication.info("replicate D1GUID:" + guid + ":D1SYSMETADATA:" + 
473
                      accNumber + ":");
474
          }
475
      }
476
      
477
      logReplication.info("ReplicationHandler.handleSingleXMLDocument - Successfully replicated doc " + accNumber);
478
      if (tableName.equals(DocumentImpl.DOCUMENTTABLE))
479
      {
480
        logReplication.info("ReplicationHandler.handleSingleXMLDocument - " + DOCINSERTNUMBER + " Wrote xml doc " + accNumber +
481
                                     " into "+tableName + " from " +
482
                                         remoteserver);
483
        DOCINSERTNUMBER++;
484
      }
485
      else
486
      {
487
          logReplication.info("ReplicationHandler.handleSingleXMLDocument - " +REVINSERTNUMBER + " Wrote xml doc " + accNumber +
488
                  " into "+tableName + " from " +
489
                      remoteserver);
490
          REVINSERTNUMBER++;
491
      }
492
      String ip = getIpFromURL(u);
493
      EventLog.getInstance().log(ip, ReplicationService.REPLICATIONUSER, accNumber, actions);
494
      
495

    
496
    }//try
497
    catch(Exception e)
498
    {
499
        
500
        if (tableName.equals(DocumentImpl.DOCUMENTTABLE))
501
        {
502
        	logMetacat.error("ReplicationHandler.handleSingleXMLDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
503
        	logReplication.error("ReplicationHandler.handleSingleXMLDocument - " +DOCERRORNUMBER + " Failed to write xml doc " + accNumber +
504
                                       " into "+tableName + " from " +
505
                                           remoteserver + " because "+e.getMessage());
506
          DOCERRORNUMBER++;
507
        }
508
        else
509
        {
510
        	logMetacat.error("ReplicationHandler.handleSingleXMLDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
511
        	logReplication.error("ReplicationHandler.handleSingleXMLDocument - " +REVERRORNUMBER + " Failed to write xml doc " + accNumber +
512
                    " into "+tableName + " from " +
513
                        remoteserver +" because "+e.getMessage());
514
            REVERRORNUMBER++;
515
        }
516
        logMetacat.error("ReplicationHandler.handleSingleXMLDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
517
        logReplication.error("ReplicationHandler.handleSingleXMLDocument - Failed to write doc " + accNumber +
518
                                      " into db because " +e.getMessage());
519
      throw new HandlerException("ReplicationHandler.handleSingleXMLDocument - generic exception " 
520
    		  + "writing Replication: " +e.getMessage());
521
    }
522
    finally
523
    {
524
       //return DBConnection
525
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
526
    }//finally
527
    logD1.info("replication.create localId:" + accNumber);
528
  }
529

    
530

    
531

    
532
  /* Handle replicate single xml document*/
533
  private void handleSingleDataFile(String remoteserver, String actions,
534
                                    String accNumber, String tableName)
535
               throws HandlerException
536
  {
537
    logReplication.info("ReplicationHandler.handleSingleDataFile - Try to replicate data file: " + accNumber);
538
    DBConnection dbConn = null;
539
    int serialNumber = -1;
540
    try
541
    {
542
      // Get DBConnection from pool
543
      dbConn=DBConnectionPool.
544
                  getDBConnection("ReplicationHandler.handleSinlgeDataFile");
545
      serialNumber=dbConn.getCheckOutSerialNumber();
546
      // Try get docid info from remote server
547
      DocInfoHandler dih = new DocInfoHandler();
548
      XMLReader docinfoParser = initParser(dih);
549
      String docInfoURLString = "https://" + remoteserver +
550
                  "?server="+MetacatUtil.getLocalReplicationServerName()+
551
                  "&action=getdocumentinfo&docid="+accNumber;
552
      docInfoURLString = MetacatUtil.replaceWhiteSpaceForURL(docInfoURLString);
553
      URL docinfoUrl = new URL(docInfoURLString);
554

    
555
      String docInfoStr = ReplicationService.getURLContent(docinfoUrl);
556
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
557
      Hashtable<String, String> docinfoHash = dih.getDocInfo();
558
      // Get docid owner
559
      String user = docinfoHash.get("user_owner");
560
      // Get docid name (such as acl or dataset)
561
      String docName = docinfoHash.get("docname");
562
      // Get doc type (eml public id)
563
      String docType = docinfoHash.get("doctype");
564
      // Get docid home sever. it might be different to remoteserver
565
      // because of hub feature
566
      String docHomeServer = docinfoHash.get("home_server");
567
      String createdDate = docinfoHash.get("date_created");
568
      String updatedDate = docinfoHash.get("date_updated");
569
      //docid should include rev number too
570
      /*String accnum=docId+util.getProperty("document.accNumSeparator")+
571
                                              (String)docinfoHash.get("rev");*/
572

    
573

    
574
      String datafilePath = PropertyService.getProperty("application.datafilepath");
575
      // Get data file content
576
      String readDataURLString = "https://" + remoteserver + "?server="+
577
                                        MetacatUtil.getLocalReplicationServerName()+
578
                                            "&action=readdata&docid="+accNumber;
579
      readDataURLString = MetacatUtil.replaceWhiteSpaceForURL(readDataURLString);
580
      URL u = new URL(readDataURLString);
581
      InputStream input = u.openStream();
582
      //register data file into xml_documents table and wite data file
583
      //into file system
584
      if ( input != null)
585
      {
586
        DocumentImpl.writeDataFileInReplication(input,
587
                                                datafilePath,
588
                                                docName,docType,
589
                                                accNumber, user,
590
                                                docHomeServer,
591
                                                remoteserver,
592
                                                tableName,
593
                                                true, //true means timed replication
594
                                                createdDate,
595
                                                updatedDate);
596
                                         
597
        //process extra access rules
598
        Vector<XMLAccessDAO> xmlAccessDAOList = dih.getAccessControlList();
599
        if (xmlAccessDAOList != null) {
600
        	AccessControlForSingleFile acfsf = new AccessControlForSingleFile(accNumber);
601
        	for (XMLAccessDAO xmlAccessDAO : xmlAccessDAOList) {
602
        		if (!acfsf.accessControlExists(xmlAccessDAO)) {
603
        			acfsf.insertPermissions(xmlAccessDAO);
604
        		}
605
            }
606
        }
607
        
608
        logReplication.info("ReplicationHandler.handleSingleDataFile - Successfully to write datafile " + accNumber);
609
        /*MetacatReplication.replLog("wrote datafile " + accNumber + " from " +
610
                                    remote server);*/
611
        if (tableName.equals(DocumentImpl.DOCUMENTTABLE))
612
        {
613
          logReplication.info("ReplicationHandler.handleSingleDataFile - " + DOCINSERTNUMBER + " Wrote data file" + accNumber +
614
                                       " into "+tableName + " from " +
615
                                           remoteserver);
616
          DOCINSERTNUMBER++;
617
        }
618
        else
619
        {
620
            logReplication.info("ReplicationHandler.handleSingleDataFile - " + REVINSERTNUMBER + " Wrote data file" + accNumber +
621
                    " into "+tableName + " from " +
622
                        remoteserver);
623
            REVINSERTNUMBER++;
624
        }
625
        String ip = getIpFromURL(u);
626
        EventLog.getInstance().log(ip, ReplicationService.REPLICATIONUSER, accNumber, actions);
627
        
628
      }//if
629
      else
630
      {
631
         logReplication.info("ReplicationHandler.handleSingleDataFile - Couldn't open the data file: " + accNumber);
632
         throw new HandlerException("ReplicationHandler.handleSingleDataFile - Couldn't open the data file: " + accNumber);
633
      }//else
634

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

    
670

    
671

    
672
  /* Handle delete single document*/
673
  private void handleDeleteSingleDocument(String docId, String notifyServer)
674
               throws HandlerException
675
  {
676
    logReplication.info("ReplicationHandler.handleDeleteSingleDocument - Try delete doc: "+docId);
677
    DBConnection dbConn = null;
678
    int serialNumber = -1;
679
    try
680
    {
681
      // Get DBConnection from pool
682
      dbConn=DBConnectionPool.
683
                  getDBConnection("ReplicationHandler.handleDeleteSingleDoc");
684
      serialNumber=dbConn.getCheckOutSerialNumber();
685
      if(!alreadyDeleted(docId))
686
      {
687

    
688
         //because delete method docid should have rev number
689
         //so we just add one for it. This rev number is no sence.
690
         String accnum=docId+PropertyService.getProperty("document.accNumSeparator")+"1";
691
         //System.out.println("accnum: "+accnum);
692
         DocumentImpl.delete(accnum, null, null, notifyServer);
693
         logReplication.info("ReplicationHandler.handleDeleteSingleDocument - Successfully deleted doc " + docId);
694
         logReplication.info("ReplicationHandler.handleDeleteSingleDocument - Doc " + docId + " deleted");
695
         URL u = new URL("https://"+notifyServer);
696
         String ip = getIpFromURL(u);
697
         EventLog.getInstance().log(ip, ReplicationService.REPLICATIONUSER, docId, "delete");
698
      }
699

    
700
    }//try
701
    catch(Exception e)
702
    {
703
      logMetacat.error("ReplicationHandler.handleDeleteSingleDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
704
      logReplication.error("ReplicationHandler.handleDeleteSingleDocument - Failed to delete doc " + docId +
705
                                 " in db because because " + e.getMessage());
706
      throw new HandlerException("ReplicationHandler.handleDeleteSingleDocument - generic exception " 
707
    		  + "when handling document: " + e.getMessage());
708
    }
709
    finally
710
    {
711
       //return DBConnection
712
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
713
    }//finally
714
    logD1.info("replication.handleDeleteSingleDocument localId:" + docId);
715
  }
716

    
717
  /* Handle updateLastCheckTimForSingleServer*/
718
  private void updateLastCheckTimeForSingleServer(ReplicationServer repServer)
719
                                                  throws HandlerException
720
  {
721
    String server = repServer.getServerName();
722
    DBConnection dbConn = null;
723
    int serialNumber = -1;
724
    PreparedStatement pstmt = null;
725
    try
726
    {
727
      // Get DBConnection from pool
728
      dbConn=DBConnectionPool.
729
             getDBConnection("ReplicationHandler.updateLastCheckTimeForServer");
730
      serialNumber=dbConn.getCheckOutSerialNumber();
731

    
732
      logReplication.info("ReplicationHandler.updateLastCheckTimeForSingleServer - Try to update last_check for server: "+server);
733
      // Get time from remote server
734
      URL dateurl = new URL("https://" + server + "?server="+
735
      MetacatUtil.getLocalReplicationServerName()+"&action=gettime");
736
      String datexml = ReplicationService.getURLContent(dateurl);
737
      logReplication.info("ReplicationHandler.updateLastCheckTimeForSingleServer - datexml: "+datexml);
738
      if (datexml!=null && !datexml.equals(""))
739
      {
740
         String datestr = datexml.substring(11, datexml.indexOf('<', 11));
741
         StringBuffer sql = new StringBuffer();
742
         /*sql.append("update xml_replication set last_checked = to_date('");
743
         sql.append(datestr).append("', 'YY-MM-DD HH24:MI:SS') where ");
744
         sql.append("server like '").append(server).append("'");*/
745
         sql.append("update xml_replication set last_checked = ");
746
         sql.append(DatabaseService.getInstance().getDBAdapter().toDate(datestr, "MM/DD/YY HH24:MI:SS"));
747
         sql.append(" where server like '").append(server).append("'");
748
         pstmt = dbConn.prepareStatement(sql.toString());
749

    
750
         pstmt.executeUpdate();
751
         dbConn.commit();
752
         pstmt.close();
753
         logReplication.info("ReplicationHandler.updateLastCheckTimeForSingleServer - last_checked updated to "+datestr+" on "
754
                                      + server);
755
      }//if
756
      else
757
      {
758

    
759
         logReplication.info("ReplicationHandler.updateLastCheckTimeForSingleServer - Failed to update last_checked for server "  +
760
                                  server + " in db because couldn't get time "
761
                                  );
762
         throw new Exception("Couldn't get time for server "+ server);
763
      }
764

    
765
    }//try
766
    catch(Exception e)
767
    {
768
      logMetacat.error("ReplicationHandler.updateLastCheckTimeForSingleServer - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
769
      logReplication.error("ReplicationHandler.updateLastCheckTimeForSingleServer - Failed to update last_checked for server " +
770
                                server + " in db because because " + e.getMessage());
771
      throw new HandlerException("ReplicationHandler.updateLastCheckTimeForSingleServer - " 
772
    		  + "Error updating last checked time: " + e.getMessage());
773
    }
774
    finally
775
    {
776
       //return DBConnection
777
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
778
    }//finally
779
  }
780

    
781

    
782

    
783
  /**
784
   * updates xml_catalog with entries from other servers.
785
   */
786
  private void updateCatalog()
787
  {
788
    logReplication.info("ReplicationHandler.updateCatalog - Start of updateCatalog");
789
    // ReplicationServer object in server list
790
    ReplicationServer replServer = null;
791
    PreparedStatement pstmt = null;
792
    String server = null;
793

    
794

    
795
    // Go through each ReplicationServer object in sererlist
796
    for (int j=0; j<serverList.size(); j++)
797
    {
798
      Vector<Vector<String>> remoteCatalog = new Vector<Vector<String>>();
799
      Vector<String> publicId = new Vector<String>();
800
      try
801
      {
802
        // Get ReplicationServer object from server list
803
        replServer = serverList.serverAt(j);
804
        // Get server name from the ReplicationServer object
805
        server = replServer.getServerName();
806
        // Try to get catalog
807
        URL u = new URL("https://" + server + "?server="+
808
        MetacatUtil.getLocalReplicationServerName()+"&action=getcatalog");
809
        logReplication.info("ReplicationHandler.updateCatalog - sending message " + u.toString());
810
        String catxml = ReplicationService.getURLContent(u);
811

    
812
        // Make sure there are not error, no empty string
813
        if (catxml.indexOf("error")!=-1 || catxml==null||catxml.equals(""))
814
        {
815
          throw new Exception("Couldn't get catalog list form server " +server);
816
        }
817
        logReplication.debug("ReplicationHandler.updateCatalog - catxml: " + catxml);
818
        CatalogMessageHandler cmh = new CatalogMessageHandler();
819
        XMLReader catparser = initParser(cmh);
820
        catparser.parse(new InputSource(new StringReader(catxml)));
821
        //parse the returned catalog xml and put it into a vector
822
        remoteCatalog = cmh.getCatalogVect();
823

    
824
        // Make sure remoteCatalog is not empty
825
        if (remoteCatalog.isEmpty())
826
        {
827
          throw new Exception("Couldn't get catalog list form server " +server);
828
        }
829

    
830
        String localcatxml = ReplicationService.getCatalogXML();
831

    
832
        // Make sure local catalog is no empty
833
        if (localcatxml==null||localcatxml.equals(""))
834
        {
835
          throw new Exception("Couldn't get catalog list form server " +server);
836
        }
837

    
838
        cmh = new CatalogMessageHandler();
839
        catparser = initParser(cmh);
840
        catparser.parse(new InputSource(new StringReader(localcatxml)));
841
        Vector<Vector<String>> localCatalog = cmh.getCatalogVect();
842

    
843
        //now we have the catalog from the remote server and this local server
844
        //we now need to compare the two and merge the differences.
845
        //the comparison is base on the public_id fields which is the 4th
846
        //entry in each row vector.
847
        publicId = new Vector<String>();
848
        for(int i=0; i<localCatalog.size(); i++)
849
        {
850
          Vector<String> v = new Vector<String>(localCatalog.elementAt(i));
851
          logReplication.info("ReplicationHandler.updateCatalog - v1: " + v.toString());
852
          publicId.add(new String((String)v.elementAt(3)));
853
          //System.out.println("adding " + (String)v.elementAt(3));
854
        }
855
      }//try
856
      catch (Exception e)
857
      {
858
        logMetacat.error("ReplicationHandler.updateCatalog - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
859
        logReplication.error("ReplicationHandler.updateCatalog - Failed to update catalog for server "+
860
                                    server + " because " +e.getMessage());
861
      }//catch
862

    
863
      for(int i=0; i<remoteCatalog.size(); i++)
864
      {
865
         // DConnection
866
        DBConnection dbConn = null;
867
        // DBConnection checkout serial number
868
        int serialNumber = -1;
869
        try
870
        {
871
            dbConn=DBConnectionPool.
872
                  getDBConnection("ReplicationHandler.updateCatalog");
873
            serialNumber=dbConn.getCheckOutSerialNumber();
874
            Vector<String> v = remoteCatalog.elementAt(i);
875
            //System.out.println("v2: " + v.toString());
876
            //System.out.println("i: " + i);
877
            //System.out.println("remoteCatalog.size(): " + remoteCatalog.size());
878
            //System.out.println("publicID: " + publicId.toString());
879
            logReplication.info
880
                              ("ReplicationHandler.updateCatalog - v.elementAt(3): " + (String)v.elementAt(3));
881
           if(!publicId.contains(v.elementAt(3)))
882
           { //so we don't have this public id in our local table so we need to
883
             //add it.
884
             //System.out.println("in if");
885
             StringBuffer sql = new StringBuffer();
886
             sql.append("insert into xml_catalog (entry_type, source_doctype, ");
887
             sql.append("target_doctype, public_id, system_id) values (?,?,?,");
888
             sql.append("?,?)");
889
             //System.out.println("sql: " + sql.toString());
890
             pstmt = dbConn.prepareStatement(sql.toString());
891
             pstmt.setString(1, (String)v.elementAt(0));
892
             pstmt.setString(2, (String)v.elementAt(1));
893
             pstmt.setString(3, (String)v.elementAt(2));
894
             pstmt.setString(4, (String)v.elementAt(3));
895
             pstmt.setString(5, (String)v.elementAt(4));
896
             pstmt.execute();
897
             pstmt.close();
898
             logReplication.info("ReplicationHandler.updateCatalog - Success fully to insert new publicid "+
899
                               (String)v.elementAt(3) + " from server"+server);
900
           }
901
        }
902
        catch(Exception e)
903
        {
904
           logMetacat.error("ReplicationHandler.updateCatalog - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
905
           logReplication.error("ReplicationHandler.updateCatalog - Failed to update catalog for server "+
906
                                    server + " because " +e.getMessage());
907
        }//catch
908
        finally
909
        {
910
           DBConnectionPool.returnDBConnection(dbConn, serialNumber);
911
        }//finally
912
      }//for remote catalog
913
    }//for server list
914
    logReplication.info("End of updateCatalog");
915
  }
916

    
917
  /**
918
   * Method that returns true if docid has already been "deleted" from metacat.
919
   * This method really implements a truth table for deleted documents
920
   * The table is (a docid in one of the tables is represented by the X):
921
   * xml_docs      xml_revs      deleted?
922
   * ------------------------------------
923
   *   X             X             FALSE
924
   *   X             _             FALSE
925
   *   _             X             TRUE
926
   *   _             _             TRUE
927
   */
928
  private static boolean alreadyDeleted(String docid) throws HandlerException
929
  {
930
    DBConnection dbConn = null;
931
    int serialNumber = -1;
932
    PreparedStatement pstmt = null;
933
    try
934
    {
935
      dbConn=DBConnectionPool.
936
                  getDBConnection("ReplicationHandler.alreadyDeleted");
937
      serialNumber=dbConn.getCheckOutSerialNumber();
938
      boolean xml_docs = false;
939
      boolean xml_revs = false;
940

    
941
      StringBuffer sb = new StringBuffer();
942
      sb.append("select docid from xml_revisions where docid like '");
943
      sb.append(docid).append("'");
944
      pstmt = dbConn.prepareStatement(sb.toString());
945
      pstmt.execute();
946
      ResultSet rs = pstmt.getResultSet();
947
      boolean tablehasrows = rs.next();
948
      if(tablehasrows)
949
      {
950
        xml_revs = true;
951
      }
952

    
953
      sb = new StringBuffer();
954
      sb.append("select docid from xml_documents where docid like '");
955
      sb.append(docid).append("'");
956
      pstmt.close();
957
      pstmt = dbConn.prepareStatement(sb.toString());
958
      //increase usage count
959
      dbConn.increaseUsageCount(1);
960
      pstmt.execute();
961
      rs = pstmt.getResultSet();
962
      tablehasrows = rs.next();
963
      pstmt.close();
964
      if(tablehasrows)
965
      {
966
        xml_docs = true;
967
      }
968

    
969
      if(xml_docs && xml_revs)
970
      {
971
        return false;
972
      }
973
      else if(xml_docs && !xml_revs)
974
      {
975
        return false;
976
      }
977
      else if(!xml_docs && xml_revs)
978
      {
979
        return true;
980
      }
981
      else if(!xml_docs && !xml_revs)
982
      {
983
        return true;
984
      }
985
    }
986
    catch(Exception e)
987
    {
988
      logMetacat.error("ReplicationHandler.alreadyDeleted - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
989
      logReplication.error("ReplicationHandler.alreadyDeleted - general error in alreadyDeleted: " +
990
                          e.getMessage());
991
      throw new HandlerException("ReplicationHandler.alreadyDeleted - general error: " 
992
    		  + e.getMessage());
993
    }
994
    finally
995
    {
996
      try
997
      {
998
        pstmt.close();
999
      }//try
1000
      catch (SQLException ee)
1001
      {
1002
    	logMetacat.error("ReplicationHandler.alreadyDeleted - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1003
        logReplication.error("ReplicationHandler.alreadyDeleted - Error in replicationHandler.alreadyDeleted "+
1004
                          "to close pstmt: "+ee.getMessage());
1005
        throw new HandlerException("ReplicationHandler.alreadyDeleted - SQL error when closing prepared statement: " 
1006
      		  + ee.getMessage());
1007
      }//catch
1008
      finally
1009
      {
1010
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1011
      }//finally
1012
    }//finally
1013
    return false;
1014
  }
1015

    
1016

    
1017
  /**
1018
   * Method to initialize the message parser
1019
   */
1020
  public static XMLReader initParser(DefaultHandler dh)
1021
          throws HandlerException
1022
  {
1023
    XMLReader parser = null;
1024

    
1025
    try {
1026
      ContentHandler chandler = dh;
1027

    
1028
      // Get an instance of the parser
1029
      String parserName = PropertyService.getProperty("xml.saxparser");
1030
      parser = XMLReaderFactory.createXMLReader(parserName);
1031

    
1032
      // Turn off validation
1033
      parser.setFeature("http://xml.org/sax/features/validation", false);
1034

    
1035
      parser.setContentHandler((ContentHandler)chandler);
1036
      parser.setErrorHandler((ErrorHandler)chandler);
1037

    
1038
    } catch (SAXException se) {
1039
      throw new HandlerException("ReplicationHandler.initParser - Sax error when " 
1040
    		  + " initializing parser: " + se.getMessage());
1041
    } catch (PropertyNotFoundException pnfe) {
1042
        throw new HandlerException("ReplicationHandler.initParser - Property error when " 
1043
      		  + " getting parser name: " + pnfe.getMessage());
1044
    } 
1045

    
1046
    return parser;
1047
  }
1048

    
1049
  /**
1050
	 * This method will combine given time string(in short format) to current
1051
	 * date. If the given time (e.g 10:00 AM) passed the current time (e.g 2:00
1052
	 * PM Aug 21, 2005), then the time will set to second day, 10:00 AM Aug 22,
1053
	 * 2005. If the given time (e.g 10:00 AM) haven't passed the current time
1054
	 * (e.g 8:00 AM Aug 21, 2005) The time will set to be 10:00 AM Aug 21, 2005.
1055
	 * 
1056
	 * @param givenTime
1057
	 *            the format should be "10:00 AM " or "2:00 PM"
1058
	 * @return
1059
	 * @throws Exception
1060
	 */
1061
	public static Date combinateCurrentDateAndGivenTime(String givenTime) throws HandlerException
1062
  {
1063
	  try {
1064
     Date givenDate = parseTime(givenTime);
1065
     Date newDate = null;
1066
     Date now = new Date();
1067
     String currentTimeString = getTimeString(now);
1068
     Date currentTime = parseTime(currentTimeString); 
1069
     if ( currentTime.getTime() >= givenDate.getTime())
1070
     {
1071
        logReplication.info("ReplicationHandler.combinateCurrentDateAndGivenTime - Today already pass the given time, we should set it as tomorrow");
1072
        String dateAndTime = getDateString(now) + " " + givenTime;
1073
        Date combinationDate = parseDateTime(dateAndTime);
1074
        // new date should plus 24 hours to make is the second day
1075
        newDate = new Date(combinationDate.getTime()+24*3600*1000);
1076
     }
1077
     else
1078
     {
1079
         logReplication.info("ReplicationHandler.combinateCurrentDateAndGivenTime - Today haven't pass the given time, we should it as today");
1080
         String dateAndTime = getDateString(now) + " " + givenTime;
1081
         newDate = parseDateTime(dateAndTime);
1082
     }
1083
     logReplication.warn("ReplicationHandler.combinateCurrentDateAndGivenTime - final setting time is "+ newDate.toString());
1084
     return newDate;
1085
	  } catch (ParseException pe) {
1086
		  throw new HandlerException("ReplicationHandler.combinateCurrentDateAndGivenTime - "
1087
				  + "parsing error: "  + pe.getMessage());
1088
	  }
1089
  }
1090

    
1091
  /*
1092
	 * parse a given string to Time in short format. For example, given time is
1093
	 * 10:00 AM, the date will be return as Jan 1 1970, 10:00 AM
1094
	 */
1095
  private static Date parseTime(String timeString) throws ParseException
1096
  {
1097
    DateFormat format = DateFormat.getTimeInstance(DateFormat.SHORT);
1098
    Date time = format.parse(timeString); 
1099
    logReplication.info("ReplicationHandler.parseTime - Date string is after parse a time string "
1100
                              +time.toString());
1101
    return time;
1102

    
1103
  }
1104
  
1105
  /*
1106
   * Parse a given string to date and time. Date format is long and time
1107
   * format is short.
1108
   */
1109
  private static Date parseDateTime(String timeString) throws ParseException
1110
  {
1111
    DateFormat format = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT);
1112
    Date time = format.parse(timeString);
1113
    logReplication.info("ReplicationHandler.parseDateTime - Date string is after parse a time string "+
1114
                             time.toString());
1115
    return time;
1116
  }
1117
  
1118
  /*
1119
   * Get a date string from a Date object. The date format will be long
1120
   */
1121
  private static String getDateString(Date now)
1122
  {
1123
     DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
1124
     String s = df.format(now);
1125
     logReplication.info("ReplicationHandler.getDateString - Today is " + s);
1126
     return s;
1127
  }
1128
  
1129
  /*
1130
   * Get a time string from a Date object, the time format will be short
1131
   */
1132
  private static String getTimeString(Date now)
1133
  {
1134
     DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
1135
     String s = df.format(now);
1136
     logReplication.info("ReplicationHandler.getTimeString - Time is " + s);
1137
     return s;
1138
  }
1139
  
1140
  
1141
  /*
1142
	 * This method will go through the docid list both in xml_Documents table
1143
	 * and in xml_revisions table @author tao
1144
	 */
1145
	private void handleDocList(Vector<Vector<String>> docList, String tableName) {
1146
		boolean dataFile = false;
1147
		for (int j = 0; j < docList.size(); j++) {
1148
			// initial dataFile is false
1149
			dataFile = false;
1150
			// w is information for one document, information contain
1151
			// docid, rev, server or datafile.
1152
			Vector<String> w = new Vector<String>(docList.elementAt(j));
1153
			// Check if the vector w contain "datafile"
1154
			// If it has, this document is data file
1155
			try {
1156
				if (w.contains((String) PropertyService.getProperty("replication.datafileflag"))) {
1157
					dataFile = true;
1158
				}
1159
			} catch (PropertyNotFoundException pnfe) {
1160
				logMetacat.error("ReplicationHandler.handleDocList - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1161
				logReplication.error("ReplicationHandler.handleDocList - Could not retrieve data file flag property.  "
1162
						+ "Leaving as false: " + pnfe.getMessage());
1163
			}
1164
			// System.out.println("w: " + w.toString());
1165
			// Get docid
1166
			String docid = (String) w.elementAt(0);
1167
			logReplication.info("docid: " + docid);
1168
			// Get revision number
1169
			int rev = Integer.parseInt((String) w.elementAt(1));
1170
			logReplication.info("rev: " + rev);
1171
			// Get remote server name (it is may not be doc home server because
1172
			// the new hub feature
1173
			String remoteServer = (String) w.elementAt(2);
1174
			remoteServer = remoteServer.trim();
1175

    
1176
			try {
1177
				if (tableName.equals(DocumentImpl.DOCUMENTTABLE)) {
1178
					handleDocInXMLDocuments(docid, rev, remoteServer, dataFile);
1179
				} else if (tableName.equals(DocumentImpl.REVISIONTABLE)) {
1180
					handleDocInXMLRevisions(docid, rev, remoteServer, dataFile);
1181
				} else {
1182
					continue;
1183
				}
1184

    
1185
			} catch (Exception e) {
1186
				logMetacat.error("ReplicationHandler.handleDocList - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1187
				logReplication.error("ReplicationHandler.handleDocList - error to handle update doc in " + tableName
1188
						+ " in time replication" + e.getMessage());
1189
				continue;
1190
			}
1191
			
1192
	        if (_xmlDocQueryCount > 0 && (_xmlDocQueryCount % 100) == 0) {
1193
	        	logMetacat.debug("ReplicationHandler.update - xml_doc query count: " + _xmlDocQueryCount + 
1194
	        			", xml_doc avg query time: " + (_xmlDocQueryTime / _xmlDocQueryCount));
1195
	        }
1196
	        
1197
	        if (_xmlRevQueryCount > 0 && (_xmlRevQueryCount % 100) == 0) {
1198
	        	logMetacat.debug("ReplicationHandler.update - xml_rev query count: " + _xmlRevQueryCount + 
1199
	        			", xml_rev avg query time: " + (_xmlRevQueryTime / _xmlRevQueryCount));
1200
	        }
1201

    
1202
		}// for update docs
1203

    
1204
	}
1205
   
1206
   /*
1207
	 * This method will handle doc in xml_documents table.
1208
	 */
1209
   private void handleDocInXMLDocuments(String docid, int rev, String remoteServer, boolean dataFile) 
1210
                                        throws HandlerException
1211
   {
1212
       // compare the update rev and local rev to see what need happen
1213
       int localrev = -1;
1214
       String action = null;
1215
       boolean flag = false;
1216
       try
1217
       {
1218
    	 long docQueryStartTime = System.currentTimeMillis();
1219
         localrev = DBUtil.getLatestRevisionInDocumentTable(docid);
1220
         long docQueryEndTime = System.currentTimeMillis();
1221
         _xmlDocQueryTime += (docQueryEndTime - docQueryStartTime);
1222
         _xmlDocQueryCount++;
1223
       }
1224
       catch (SQLException e)
1225
       {
1226
    	 logMetacat.error("ReplicationHandler.handleDocInXMLDocuments - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1227
         logReplication.error("ReplicationHandler.handleDocInXMLDocuments - Local rev for docid "+ docid + " could not "+
1228
                                " be found because " + e.getMessage());
1229
         logReplication.error("ReplicationHandler.handleDocInXMLDocuments - " + DOCERRORNUMBER+"Docid "+ docid + " could not be "+
1230
                 "written because error happend to find it's local revision");
1231
         DOCERRORNUMBER++;
1232
         throw new HandlerException ("ReplicationHandler.handleDocInXMLDocuments - Local rev for docid "+ docid + " could not "+
1233
                 " be found: " + e.getMessage());
1234
       }
1235
       logReplication.info("ReplicationHandler.handleDocInXMLDocuments - Local rev for docid "+ docid + " is "+
1236
                               localrev);
1237

    
1238
       //check the revs for an update because this document is in the
1239
       //local DB, it might be out of date.
1240
       if (localrev == -1)
1241
       {
1242
          // check if the revision is in the revision table
1243
    	   Vector<Integer> localRevVector = null;
1244
    	 try {
1245
        	 long revQueryStartTime = System.currentTimeMillis();
1246
    		 localRevVector = DBUtil.getRevListFromRevisionTable(docid);
1247
             long revQueryEndTime = System.currentTimeMillis();
1248
             _xmlRevQueryTime += (revQueryEndTime - revQueryStartTime);
1249
             _xmlRevQueryCount++;
1250
    	 } catch (SQLException sqle) {
1251
    		 throw new HandlerException("ReplicationHandler.handleDocInXMLDocuments - SQL error " 
1252
    				 + " when getting rev list for docid: " + docid + " : " + sqle.getMessage());
1253
    	 }
1254
         if (localRevVector != null && localRevVector.contains(new Integer(rev)))
1255
         {
1256
             // this version was deleted, so don't need replicate
1257
             flag = false;
1258
         }
1259
         else
1260
         {
1261
           //insert this document as new because it is not in the local DB
1262
           action = "INSERT";
1263
           flag = true;
1264
         }
1265
       }
1266
       else
1267
       {
1268
         if(localrev == rev)
1269
         {
1270
           // Local meatacat has the same rev to remote host, don't need
1271
           // update and flag set false
1272
           flag = false;
1273
         }
1274
         else if(localrev < rev)
1275
         {
1276
           //this document needs to be updated so send an read request
1277
           action = "UPDATE";
1278
           flag = true;
1279
         }
1280
       }
1281
       
1282
       String accNumber = null;
1283
       try {
1284
    	   accNumber = docid + PropertyService.getProperty("document.accNumSeparator") + rev;
1285
       } catch (PropertyNotFoundException pnfe) {
1286
    	   throw new HandlerException("ReplicationHandler.handleDocInXMLDocuments - error getting " 
1287
    			   + "account number separator : " + pnfe.getMessage());
1288
       }
1289
       // this is non-data file
1290
       if(flag && !dataFile)
1291
       {
1292
         try
1293
         {
1294
           handleSingleXMLDocument(remoteServer, action, accNumber, DocumentImpl.DOCUMENTTABLE);
1295
         }
1296
         catch(HandlerException he)
1297
         {
1298
           // skip this document
1299
           throw he;
1300
         }
1301
       }//if for non-data file
1302

    
1303
        // this is for data file
1304
       if(flag && dataFile)
1305
       {
1306
         try
1307
         {
1308
           handleSingleDataFile(remoteServer, action, accNumber, DocumentImpl.DOCUMENTTABLE);
1309
         }
1310
         catch(HandlerException he)
1311
         {
1312
           // skip this data file
1313
           throw he;
1314
         }
1315

    
1316
       }//for data file
1317
   }
1318
   
1319
   /*
1320
    * This method will handle doc in xml_documents table.
1321
    */
1322
   private void handleDocInXMLRevisions(String docid, int rev, String remoteServer, boolean dataFile) 
1323
                                        throws HandlerException
1324
   {
1325
       // compare the update rev and local rev to see what need happen
1326
       logReplication.info("ReplicationHandler.handleDocInXMLRevisions - In handle repliation revsion table");
1327
       logReplication.info("ReplicationHandler.handleDocInXMLRevisions - the docid is "+ docid);
1328
       logReplication.info("ReplicationHandler.handleDocInXMLRevisions - The rev is "+rev);
1329
       Vector<Integer> localrev = null;
1330
       String action = "INSERT";
1331
       boolean flag = false;
1332
       try
1333
       {
1334
      	 long revQueryStartTime = System.currentTimeMillis();
1335
         localrev = DBUtil.getRevListFromRevisionTable(docid);
1336
         long revQueryEndTime = System.currentTimeMillis();
1337
         _xmlRevQueryTime += (revQueryEndTime - revQueryStartTime);
1338
         _xmlRevQueryCount++;
1339
       }
1340
       catch (SQLException sqle)
1341
       {
1342
    	 logMetacat.error("ReplicationHandler.handleDocInXMLDocuments - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1343
         logReplication.error("ReplicationHandler.handleDocInXMLRevisions - Local rev for docid "+ docid + " could not "+
1344
                                " be found because " + sqle.getMessage());
1345
         REVERRORNUMBER++;
1346
         throw new HandlerException ("ReplicationHandler.handleDocInXMLRevisions - SQL exception getting rev list: " 
1347
        		 + sqle.getMessage());
1348
       }
1349
       logReplication.info("ReplicationHandler.handleDocInXMLRevisions - rev list in xml_revision table for docid "+ docid + " is "+
1350
                               localrev.toString());
1351
       
1352
       // if the rev is not in the xml_revision, we need insert it
1353
       if (!localrev.contains(new Integer(rev)))
1354
       {
1355
           flag = true;    
1356
       }
1357
     
1358
       String accNumber = null;
1359
       try {
1360
    	   accNumber = docid + PropertyService.getProperty("document.accNumSeparator") + rev;
1361
       } catch (PropertyNotFoundException pnfe) {
1362
    	   throw new HandlerException("ReplicationHandler.handleDocInXMLRevisions - error getting " 
1363
    			   + "account number separator : " + pnfe.getMessage());
1364
       }
1365
       // this is non-data file
1366
       if(flag && !dataFile)
1367
       {
1368
         try
1369
         {
1370
           
1371
           handleSingleXMLDocument(remoteServer, action, accNumber, DocumentImpl.REVISIONTABLE);
1372
         }
1373
         catch(HandlerException he)
1374
         {
1375
           // skip this document
1376
           throw he;
1377
         }
1378
       }//if for non-data file
1379

    
1380
        // this is for data file
1381
       if(flag && dataFile)
1382
       {
1383
         try
1384
         {
1385
           handleSingleDataFile(remoteServer, action, accNumber, DocumentImpl.REVISIONTABLE);
1386
         }
1387
         catch(HandlerException he)
1388
         {
1389
           // skip this data file
1390
           throw he;
1391
         }
1392

    
1393
       }//for data file
1394
   }
1395
   
1396
   /*
1397
    * Return a ip address for given url
1398
    */
1399
   private String getIpFromURL(URL url)
1400
   {
1401
	   String ip = null;
1402
	   try
1403
	   {
1404
	      InetAddress address = InetAddress.getByName(url.getHost());
1405
	      ip = address.getHostAddress();
1406
	   }
1407
	   catch(UnknownHostException e)
1408
	   {
1409
		   logMetacat.error("ReplicationHandler.getIpFromURL - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1410
		   logReplication.error("ReplicationHandler.getIpFromURL - Error in get ip address for host: "
1411
                   +e.getMessage());
1412
	   }
1413

    
1414
	   return ip;
1415
   }
1416
  
1417
}
1418

    
(3-3/7)