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: leinfelder $'
9
 *     '$Date: 2011-03-22 17:19:08 -0700 (Tue, 22 Mar 2011) $'
10
 * '$Revision: 6015 $'
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.IdentifierManager;
46
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
47

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

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

    
64

    
65

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

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

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

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

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

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

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

    
210

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

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

    
317
  }//update
318

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

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

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

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

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

    
534

    
535

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

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

    
576

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

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

    
679

    
680

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

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

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

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

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

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

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

    
798
    }//try
799
    catch(Exception e)
800
    {
801
      logMetacat.error("ReplicationHandler.updateLastCheckTimeForSingleServer - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
802
      logReplication.error("ReplicationHandler.updateLastCheckTimeForSingleServer - Failed to update last_checked for server " +
803
                                server + " in db because because " + e.getMessage());
804
      throw new HandlerException("ReplicationHandler.updateLastCheckTimeForSingleServer - " 
805
    		  + "Error updating last checked time: " + e.getMessage());
806
    }
807
    finally
808
    {
809
       //return DBConnection
810
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
811
    }//finally
812
  }
813

    
814

    
815

    
816
  /**
817
   * updates xml_catalog with entries from other servers.
818
   */
819
  private void updateCatalog()
820
  {
821
    logReplication.info("ReplicationHandler.updateCatalog - Start of updateCatalog");
822
    // ReplicationServer object in server list
823
    ReplicationServer replServer = null;
824
    PreparedStatement pstmt = null;
825
    String server = null;
826

    
827

    
828
    // Go through each ReplicationServer object in sererlist
829
    for (int j=0; j<serverList.size(); j++)
830
    {
831
      Vector<Vector<String>> remoteCatalog = new Vector<Vector<String>>();
832
      Vector<String> publicId = new Vector<String>();
833
      try
834
      {
835
        // Get ReplicationServer object from server list
836
        replServer = serverList.serverAt(j);
837
        // Get server name from the ReplicationServer object
838
        server = replServer.getServerName();
839
        // Try to get catalog
840
        URL u = new URL("https://" + server + "?server="+
841
        MetacatUtil.getLocalReplicationServerName()+"&action=getcatalog");
842
        logReplication.info("ReplicationHandler.updateCatalog - sending message " + u.toString());
843
        String catxml = ReplicationService.getURLContent(u);
844

    
845
        // Make sure there are not error, no empty string
846
        if (catxml.indexOf("error")!=-1 || catxml==null||catxml.equals(""))
847
        {
848
          throw new Exception("Couldn't get catalog list form server " +server);
849
        }
850
        logReplication.debug("ReplicationHandler.updateCatalog - catxml: " + catxml);
851
        CatalogMessageHandler cmh = new CatalogMessageHandler();
852
        XMLReader catparser = initParser(cmh);
853
        catparser.parse(new InputSource(new StringReader(catxml)));
854
        //parse the returned catalog xml and put it into a vector
855
        remoteCatalog = cmh.getCatalogVect();
856

    
857
        // Make sure remoteCatalog is not empty
858
        if (remoteCatalog.isEmpty())
859
        {
860
          throw new Exception("Couldn't get catalog list form server " +server);
861
        }
862

    
863
        String localcatxml = ReplicationService.getCatalogXML();
864

    
865
        // Make sure local catalog is no empty
866
        if (localcatxml==null||localcatxml.equals(""))
867
        {
868
          throw new Exception("Couldn't get catalog list form server " +server);
869
        }
870

    
871
        cmh = new CatalogMessageHandler();
872
        catparser = initParser(cmh);
873
        catparser.parse(new InputSource(new StringReader(localcatxml)));
874
        Vector<Vector<String>> localCatalog = cmh.getCatalogVect();
875

    
876
        //now we have the catalog from the remote server and this local server
877
        //we now need to compare the two and merge the differences.
878
        //the comparison is base on the public_id fields which is the 4th
879
        //entry in each row vector.
880
        publicId = new Vector<String>();
881
        for(int i=0; i<localCatalog.size(); i++)
882
        {
883
          Vector<String> v = new Vector<String>(localCatalog.elementAt(i));
884
          logReplication.info("ReplicationHandler.updateCatalog - v1: " + v.toString());
885
          publicId.add(new String((String)v.elementAt(3)));
886
          //System.out.println("adding " + (String)v.elementAt(3));
887
        }
888
      }//try
889
      catch (Exception e)
890
      {
891
        logMetacat.error("ReplicationHandler.updateCatalog - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
892
        logReplication.error("ReplicationHandler.updateCatalog - Failed to update catalog for server "+
893
                                    server + " because " +e.getMessage());
894
      }//catch
895

    
896
      for(int i=0; i<remoteCatalog.size(); i++)
897
      {
898
         // DConnection
899
        DBConnection dbConn = null;
900
        // DBConnection checkout serial number
901
        int serialNumber = -1;
902
        try
903
        {
904
            dbConn=DBConnectionPool.
905
                  getDBConnection("ReplicationHandler.updateCatalog");
906
            serialNumber=dbConn.getCheckOutSerialNumber();
907
            Vector<String> v = remoteCatalog.elementAt(i);
908
            //System.out.println("v2: " + v.toString());
909
            //System.out.println("i: " + i);
910
            //System.out.println("remoteCatalog.size(): " + remoteCatalog.size());
911
            //System.out.println("publicID: " + publicId.toString());
912
            logReplication.info
913
                              ("ReplicationHandler.updateCatalog - v.elementAt(3): " + (String)v.elementAt(3));
914
           if(!publicId.contains(v.elementAt(3)))
915
           { //so we don't have this public id in our local table so we need to
916
             //add it.
917
             //System.out.println("in if");
918
             StringBuffer sql = new StringBuffer();
919
             sql.append("insert into xml_catalog (entry_type, source_doctype, ");
920
             sql.append("target_doctype, public_id, system_id) values (?,?,?,");
921
             sql.append("?,?)");
922
             //System.out.println("sql: " + sql.toString());
923
             pstmt = dbConn.prepareStatement(sql.toString());
924
             pstmt.setString(1, (String)v.elementAt(0));
925
             pstmt.setString(2, (String)v.elementAt(1));
926
             pstmt.setString(3, (String)v.elementAt(2));
927
             pstmt.setString(4, (String)v.elementAt(3));
928
             pstmt.setString(5, (String)v.elementAt(4));
929
             pstmt.execute();
930
             pstmt.close();
931
             logReplication.info("ReplicationHandler.updateCatalog - Success fully to insert new publicid "+
932
                               (String)v.elementAt(3) + " from server"+server);
933
           }
934
        }
935
        catch(Exception e)
936
        {
937
           logMetacat.error("ReplicationHandler.updateCatalog - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
938
           logReplication.error("ReplicationHandler.updateCatalog - Failed to update catalog for server "+
939
                                    server + " because " +e.getMessage());
940
        }//catch
941
        finally
942
        {
943
           DBConnectionPool.returnDBConnection(dbConn, serialNumber);
944
        }//finally
945
      }//for remote catalog
946
    }//for server list
947
    logReplication.info("End of updateCatalog");
948
  }
949

    
950
  /**
951
   * Method that returns true if docid has already been "deleted" from metacat.
952
   * This method really implements a truth table for deleted documents
953
   * The table is (a docid in one of the tables is represented by the X):
954
   * xml_docs      xml_revs      deleted?
955
   * ------------------------------------
956
   *   X             X             FALSE
957
   *   X             _             FALSE
958
   *   _             X             TRUE
959
   *   _             _             TRUE
960
   */
961
  private static boolean alreadyDeleted(String docid) throws HandlerException
962
  {
963
    DBConnection dbConn = null;
964
    int serialNumber = -1;
965
    PreparedStatement pstmt = null;
966
    try
967
    {
968
      dbConn=DBConnectionPool.
969
                  getDBConnection("ReplicationHandler.alreadyDeleted");
970
      serialNumber=dbConn.getCheckOutSerialNumber();
971
      boolean xml_docs = false;
972
      boolean xml_revs = false;
973

    
974
      StringBuffer sb = new StringBuffer();
975
      sb.append("select docid from xml_revisions where docid like '");
976
      sb.append(docid).append("'");
977
      pstmt = dbConn.prepareStatement(sb.toString());
978
      pstmt.execute();
979
      ResultSet rs = pstmt.getResultSet();
980
      boolean tablehasrows = rs.next();
981
      if(tablehasrows)
982
      {
983
        xml_revs = true;
984
      }
985

    
986
      sb = new StringBuffer();
987
      sb.append("select docid from xml_documents where docid like '");
988
      sb.append(docid).append("'");
989
      pstmt.close();
990
      pstmt = dbConn.prepareStatement(sb.toString());
991
      //increase usage count
992
      dbConn.increaseUsageCount(1);
993
      pstmt.execute();
994
      rs = pstmt.getResultSet();
995
      tablehasrows = rs.next();
996
      pstmt.close();
997
      if(tablehasrows)
998
      {
999
        xml_docs = true;
1000
      }
1001

    
1002
      if(xml_docs && xml_revs)
1003
      {
1004
        return false;
1005
      }
1006
      else if(xml_docs && !xml_revs)
1007
      {
1008
        return false;
1009
      }
1010
      else if(!xml_docs && xml_revs)
1011
      {
1012
        return true;
1013
      }
1014
      else if(!xml_docs && !xml_revs)
1015
      {
1016
        return true;
1017
      }
1018
    }
1019
    catch(Exception e)
1020
    {
1021
      logMetacat.error("ReplicationHandler.alreadyDeleted - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1022
      logReplication.error("ReplicationHandler.alreadyDeleted - general error in alreadyDeleted: " +
1023
                          e.getMessage());
1024
      throw new HandlerException("ReplicationHandler.alreadyDeleted - general error: " 
1025
    		  + e.getMessage());
1026
    }
1027
    finally
1028
    {
1029
      try
1030
      {
1031
        pstmt.close();
1032
      }//try
1033
      catch (SQLException ee)
1034
      {
1035
    	logMetacat.error("ReplicationHandler.alreadyDeleted - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1036
        logReplication.error("ReplicationHandler.alreadyDeleted - Error in replicationHandler.alreadyDeleted "+
1037
                          "to close pstmt: "+ee.getMessage());
1038
        throw new HandlerException("ReplicationHandler.alreadyDeleted - SQL error when closing prepared statement: " 
1039
      		  + ee.getMessage());
1040
      }//catch
1041
      finally
1042
      {
1043
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1044
      }//finally
1045
    }//finally
1046
    return false;
1047
  }
1048

    
1049

    
1050
  /**
1051
   * Method to initialize the message parser
1052
   */
1053
  public static XMLReader initParser(DefaultHandler dh)
1054
          throws HandlerException
1055
  {
1056
    XMLReader parser = null;
1057

    
1058
    try {
1059
      ContentHandler chandler = dh;
1060

    
1061
      // Get an instance of the parser
1062
      String parserName = PropertyService.getProperty("xml.saxparser");
1063
      parser = XMLReaderFactory.createXMLReader(parserName);
1064

    
1065
      // Turn off validation
1066
      parser.setFeature("http://xml.org/sax/features/validation", false);
1067

    
1068
      parser.setContentHandler((ContentHandler)chandler);
1069
      parser.setErrorHandler((ErrorHandler)chandler);
1070

    
1071
    } catch (SAXException se) {
1072
      throw new HandlerException("ReplicationHandler.initParser - Sax error when " 
1073
    		  + " initializing parser: " + se.getMessage());
1074
    } catch (PropertyNotFoundException pnfe) {
1075
        throw new HandlerException("ReplicationHandler.initParser - Property error when " 
1076
      		  + " getting parser name: " + pnfe.getMessage());
1077
    } 
1078

    
1079
    return parser;
1080
  }
1081

    
1082
  /**
1083
	 * This method will combine given time string(in short format) to current
1084
	 * date. If the given time (e.g 10:00 AM) passed the current time (e.g 2:00
1085
	 * PM Aug 21, 2005), then the time will set to second day, 10:00 AM Aug 22,
1086
	 * 2005. If the given time (e.g 10:00 AM) haven't passed the current time
1087
	 * (e.g 8:00 AM Aug 21, 2005) The time will set to be 10:00 AM Aug 21, 2005.
1088
	 * 
1089
	 * @param givenTime
1090
	 *            the format should be "10:00 AM " or "2:00 PM"
1091
	 * @return
1092
	 * @throws Exception
1093
	 */
1094
	public static Date combinateCurrentDateAndGivenTime(String givenTime) throws HandlerException
1095
  {
1096
	  try {
1097
     Date givenDate = parseTime(givenTime);
1098
     Date newDate = null;
1099
     Date now = new Date();
1100
     String currentTimeString = getTimeString(now);
1101
     Date currentTime = parseTime(currentTimeString); 
1102
     if ( currentTime.getTime() >= givenDate.getTime())
1103
     {
1104
        logReplication.info("ReplicationHandler.combinateCurrentDateAndGivenTime - Today already pass the given time, we should set it as tomorrow");
1105
        String dateAndTime = getDateString(now) + " " + givenTime;
1106
        Date combinationDate = parseDateTime(dateAndTime);
1107
        // new date should plus 24 hours to make is the second day
1108
        newDate = new Date(combinationDate.getTime()+24*3600*1000);
1109
     }
1110
     else
1111
     {
1112
         logReplication.info("ReplicationHandler.combinateCurrentDateAndGivenTime - Today haven't pass the given time, we should it as today");
1113
         String dateAndTime = getDateString(now) + " " + givenTime;
1114
         newDate = parseDateTime(dateAndTime);
1115
     }
1116
     logReplication.warn("ReplicationHandler.combinateCurrentDateAndGivenTime - final setting time is "+ newDate.toString());
1117
     return newDate;
1118
	  } catch (ParseException pe) {
1119
		  throw new HandlerException("ReplicationHandler.combinateCurrentDateAndGivenTime - "
1120
				  + "parsing error: "  + pe.getMessage());
1121
	  }
1122
  }
1123

    
1124
  /*
1125
	 * parse a given string to Time in short format. For example, given time is
1126
	 * 10:00 AM, the date will be return as Jan 1 1970, 10:00 AM
1127
	 */
1128
  private static Date parseTime(String timeString) throws ParseException
1129
  {
1130
    DateFormat format = DateFormat.getTimeInstance(DateFormat.SHORT);
1131
    Date time = format.parse(timeString); 
1132
    logReplication.info("ReplicationHandler.parseTime - Date string is after parse a time string "
1133
                              +time.toString());
1134
    return time;
1135

    
1136
  }
1137
  
1138
  /*
1139
   * Parse a given string to date and time. Date format is long and time
1140
   * format is short.
1141
   */
1142
  private static Date parseDateTime(String timeString) throws ParseException
1143
  {
1144
    DateFormat format = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT);
1145
    Date time = format.parse(timeString);
1146
    logReplication.info("ReplicationHandler.parseDateTime - Date string is after parse a time string "+
1147
                             time.toString());
1148
    return time;
1149
  }
1150
  
1151
  /*
1152
   * Get a date string from a Date object. The date format will be long
1153
   */
1154
  private static String getDateString(Date now)
1155
  {
1156
     DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
1157
     String s = df.format(now);
1158
     logReplication.info("ReplicationHandler.getDateString - Today is " + s);
1159
     return s;
1160
  }
1161
  
1162
  /*
1163
   * Get a time string from a Date object, the time format will be short
1164
   */
1165
  private static String getTimeString(Date now)
1166
  {
1167
     DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
1168
     String s = df.format(now);
1169
     logReplication.info("ReplicationHandler.getTimeString - Time is " + s);
1170
     return s;
1171
  }
1172
  
1173
  
1174
  /*
1175
	 * This method will go through the docid list both in xml_Documents table
1176
	 * and in xml_revisions table @author tao
1177
	 */
1178
	private void handleDocList(Vector<Vector<String>> docList, String tableName) {
1179
		boolean dataFile = false;
1180
		for (int j = 0; j < docList.size(); j++) {
1181
			// initial dataFile is false
1182
			dataFile = false;
1183
			// w is information for one document, information contain
1184
			// docid, rev, server or datafile.
1185
			Vector<String> w = new Vector<String>(docList.elementAt(j));
1186
			// Check if the vector w contain "datafile"
1187
			// If it has, this document is data file
1188
			try {
1189
				if (w.contains((String) PropertyService.getProperty("replication.datafileflag"))) {
1190
					dataFile = true;
1191
				}
1192
			} catch (PropertyNotFoundException pnfe) {
1193
				logMetacat.error("ReplicationHandler.handleDocList - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1194
				logReplication.error("ReplicationHandler.handleDocList - Could not retrieve data file flag property.  "
1195
						+ "Leaving as false: " + pnfe.getMessage());
1196
			}
1197
			// System.out.println("w: " + w.toString());
1198
			// Get docid
1199
			String docid = (String) w.elementAt(0);
1200
			logReplication.info("docid: " + docid);
1201
			// Get revision number
1202
			int rev = Integer.parseInt((String) w.elementAt(1));
1203
			logReplication.info("rev: " + rev);
1204
			// Get remote server name (it is may not be doc home server because
1205
			// the new hub feature
1206
			String remoteServer = (String) w.elementAt(2);
1207
			remoteServer = remoteServer.trim();
1208

    
1209
			try {
1210
				if (tableName.equals(DocumentImpl.DOCUMENTTABLE)) {
1211
					handleDocInXMLDocuments(docid, rev, remoteServer, dataFile);
1212
				} else if (tableName.equals(DocumentImpl.REVISIONTABLE)) {
1213
					handleDocInXMLRevisions(docid, rev, remoteServer, dataFile);
1214
				} else {
1215
					continue;
1216
				}
1217

    
1218
			} catch (Exception e) {
1219
				logMetacat.error("ReplicationHandler.handleDocList - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1220
				logReplication.error("ReplicationHandler.handleDocList - error to handle update doc in " + tableName
1221
						+ " in time replication" + e.getMessage());
1222
				continue;
1223
			}
1224
			
1225
	        if (_xmlDocQueryCount > 0 && (_xmlDocQueryCount % 100) == 0) {
1226
	        	logMetacat.debug("ReplicationHandler.update - xml_doc query count: " + _xmlDocQueryCount + 
1227
	        			", xml_doc avg query time: " + (_xmlDocQueryTime / _xmlDocQueryCount));
1228
	        }
1229
	        
1230
	        if (_xmlRevQueryCount > 0 && (_xmlRevQueryCount % 100) == 0) {
1231
	        	logMetacat.debug("ReplicationHandler.update - xml_rev query count: " + _xmlRevQueryCount + 
1232
	        			", xml_rev avg query time: " + (_xmlRevQueryTime / _xmlRevQueryCount));
1233
	        }
1234

    
1235
		}// for update docs
1236

    
1237
	}
1238
   
1239
   /*
1240
	 * This method will handle doc in xml_documents table.
1241
	 */
1242
   private void handleDocInXMLDocuments(String docid, int rev, String remoteServer, boolean dataFile) 
1243
                                        throws HandlerException
1244
   {
1245
       // compare the update rev and local rev to see what need happen
1246
       int localrev = -1;
1247
       String action = null;
1248
       boolean flag = false;
1249
       try
1250
       {
1251
    	 long docQueryStartTime = System.currentTimeMillis();
1252
         localrev = DBUtil.getLatestRevisionInDocumentTable(docid);
1253
         long docQueryEndTime = System.currentTimeMillis();
1254
         _xmlDocQueryTime += (docQueryEndTime - docQueryStartTime);
1255
         _xmlDocQueryCount++;
1256
       }
1257
       catch (SQLException e)
1258
       {
1259
    	 logMetacat.error("ReplicationHandler.handleDocInXMLDocuments - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1260
         logReplication.error("ReplicationHandler.handleDocInXMLDocuments - Local rev for docid "+ docid + " could not "+
1261
                                " be found because " + e.getMessage());
1262
         logReplication.error("ReplicationHandler.handleDocInXMLDocuments - " + DOCERRORNUMBER+"Docid "+ docid + " could not be "+
1263
                 "written because error happend to find it's local revision");
1264
         DOCERRORNUMBER++;
1265
         throw new HandlerException ("ReplicationHandler.handleDocInXMLDocuments - Local rev for docid "+ docid + " could not "+
1266
                 " be found: " + e.getMessage());
1267
       }
1268
       logReplication.info("ReplicationHandler.handleDocInXMLDocuments - Local rev for docid "+ docid + " is "+
1269
                               localrev);
1270

    
1271
       //check the revs for an update because this document is in the
1272
       //local DB, it might be out of date.
1273
       if (localrev == -1)
1274
       {
1275
          // check if the revision is in the revision table
1276
    	   Vector<Integer> localRevVector = null;
1277
    	 try {
1278
        	 long revQueryStartTime = System.currentTimeMillis();
1279
    		 localRevVector = DBUtil.getRevListFromRevisionTable(docid);
1280
             long revQueryEndTime = System.currentTimeMillis();
1281
             _xmlRevQueryTime += (revQueryEndTime - revQueryStartTime);
1282
             _xmlRevQueryCount++;
1283
    	 } catch (SQLException sqle) {
1284
    		 throw new HandlerException("ReplicationHandler.handleDocInXMLDocuments - SQL error " 
1285
    				 + " when getting rev list for docid: " + docid + " : " + sqle.getMessage());
1286
    	 }
1287
         if (localRevVector != null && localRevVector.contains(new Integer(rev)))
1288
         {
1289
             // this version was deleted, so don't need replicate
1290
             flag = false;
1291
         }
1292
         else
1293
         {
1294
           //insert this document as new because it is not in the local DB
1295
           action = "INSERT";
1296
           flag = true;
1297
         }
1298
       }
1299
       else
1300
       {
1301
         if(localrev == rev)
1302
         {
1303
           // Local meatacat has the same rev to remote host, don't need
1304
           // update and flag set false
1305
           flag = false;
1306
         }
1307
         else if(localrev < rev)
1308
         {
1309
           //this document needs to be updated so send an read request
1310
           action = "UPDATE";
1311
           flag = true;
1312
         }
1313
       }
1314
       
1315
       String accNumber = null;
1316
       try {
1317
    	   accNumber = docid + PropertyService.getProperty("document.accNumSeparator") + rev;
1318
       } catch (PropertyNotFoundException pnfe) {
1319
    	   throw new HandlerException("ReplicationHandler.handleDocInXMLDocuments - error getting " 
1320
    			   + "account number separator : " + pnfe.getMessage());
1321
       }
1322
       // this is non-data file
1323
       if(flag && !dataFile)
1324
       {
1325
         try
1326
         {
1327
           handleSingleXMLDocument(remoteServer, action, accNumber, DocumentImpl.DOCUMENTTABLE);
1328
         }
1329
         catch(HandlerException he)
1330
         {
1331
           // skip this document
1332
           throw he;
1333
         }
1334
       }//if for non-data file
1335

    
1336
        // this is for data file
1337
       if(flag && dataFile)
1338
       {
1339
         try
1340
         {
1341
           handleSingleDataFile(remoteServer, action, accNumber, DocumentImpl.DOCUMENTTABLE);
1342
         }
1343
         catch(HandlerException he)
1344
         {
1345
           // skip this data file
1346
           throw he;
1347
         }
1348

    
1349
       }//for data file
1350
   }
1351
   
1352
   /*
1353
    * This method will handle doc in xml_documents table.
1354
    */
1355
   private void handleDocInXMLRevisions(String docid, int rev, String remoteServer, boolean dataFile) 
1356
                                        throws HandlerException
1357
   {
1358
       // compare the update rev and local rev to see what need happen
1359
       logReplication.info("ReplicationHandler.handleDocInXMLRevisions - In handle repliation revsion table");
1360
       logReplication.info("ReplicationHandler.handleDocInXMLRevisions - the docid is "+ docid);
1361
       logReplication.info("ReplicationHandler.handleDocInXMLRevisions - The rev is "+rev);
1362
       Vector<Integer> localrev = null;
1363
       String action = "INSERT";
1364
       boolean flag = false;
1365
       try
1366
       {
1367
      	 long revQueryStartTime = System.currentTimeMillis();
1368
         localrev = DBUtil.getRevListFromRevisionTable(docid);
1369
         long revQueryEndTime = System.currentTimeMillis();
1370
         _xmlRevQueryTime += (revQueryEndTime - revQueryStartTime);
1371
         _xmlRevQueryCount++;
1372
       }
1373
       catch (SQLException sqle)
1374
       {
1375
    	 logMetacat.error("ReplicationHandler.handleDocInXMLDocuments - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1376
         logReplication.error("ReplicationHandler.handleDocInXMLRevisions - Local rev for docid "+ docid + " could not "+
1377
                                " be found because " + sqle.getMessage());
1378
         REVERRORNUMBER++;
1379
         throw new HandlerException ("ReplicationHandler.handleDocInXMLRevisions - SQL exception getting rev list: " 
1380
        		 + sqle.getMessage());
1381
       }
1382
       logReplication.info("ReplicationHandler.handleDocInXMLRevisions - rev list in xml_revision table for docid "+ docid + " is "+
1383
                               localrev.toString());
1384
       
1385
       // if the rev is not in the xml_revision, we need insert it
1386
       if (!localrev.contains(new Integer(rev)))
1387
       {
1388
           flag = true;    
1389
       }
1390
     
1391
       String accNumber = null;
1392
       try {
1393
    	   accNumber = docid + PropertyService.getProperty("document.accNumSeparator") + rev;
1394
       } catch (PropertyNotFoundException pnfe) {
1395
    	   throw new HandlerException("ReplicationHandler.handleDocInXMLRevisions - error getting " 
1396
    			   + "account number separator : " + pnfe.getMessage());
1397
       }
1398
       // this is non-data file
1399
       if(flag && !dataFile)
1400
       {
1401
         try
1402
         {
1403
           
1404
           handleSingleXMLDocument(remoteServer, action, accNumber, DocumentImpl.REVISIONTABLE);
1405
         }
1406
         catch(HandlerException he)
1407
         {
1408
           // skip this document
1409
           throw he;
1410
         }
1411
       }//if for non-data file
1412

    
1413
        // this is for data file
1414
       if(flag && dataFile)
1415
       {
1416
         try
1417
         {
1418
           handleSingleDataFile(remoteServer, action, accNumber, DocumentImpl.REVISIONTABLE);
1419
         }
1420
         catch(HandlerException he)
1421
         {
1422
           // skip this data file
1423
           throw he;
1424
         }
1425

    
1426
       }//for data file
1427
   }
1428
   
1429
   /*
1430
    * Return a ip address for given url
1431
    */
1432
   private String getIpFromURL(URL url)
1433
   {
1434
	   String ip = null;
1435
	   try
1436
	   {
1437
	      InetAddress address = InetAddress.getByName(url.getHost());
1438
	      ip = address.getHostAddress();
1439
	   }
1440
	   catch(UnknownHostException e)
1441
	   {
1442
		   logMetacat.error("ReplicationHandler.getIpFromURL - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1443
		   logReplication.error("ReplicationHandler.getIpFromURL - Error in get ip address for host: "
1444
                   +e.getMessage());
1445
	   }
1446

    
1447
	   return ip;
1448
   }
1449
  
1450
}
1451

    
(3-3/7)