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

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

    
29
import edu.ucsb.nceas.metacat.CatalogMessageHandler;
30
import edu.ucsb.nceas.metacat.DBUtil;
31
import edu.ucsb.nceas.metacat.DocInfoHandler;
32
import edu.ucsb.nceas.metacat.DocumentImpl;
33
import edu.ucsb.nceas.metacat.DocumentImplWrapper;
34
import edu.ucsb.nceas.metacat.EventLog;
35
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
36
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlForSingleFile;
37
import edu.ucsb.nceas.metacat.accesscontrol.XMLAccessDAO;
38
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
39
import edu.ucsb.nceas.metacat.database.DBConnection;
40
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
41
import edu.ucsb.nceas.metacat.database.DatabaseService;
42
import edu.ucsb.nceas.metacat.properties.PropertyService;
43
import edu.ucsb.nceas.metacat.shared.HandlerException;
44
import edu.ucsb.nceas.metacat.util.MetacatUtil;
45
import edu.ucsb.nceas.metacat.util.ReplicationUtil;
46
import edu.ucsb.nceas.metacat.IdentifierManager;
47
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
48

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

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

    
67

    
68

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

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

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

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

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

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

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

    
213

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

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

    
318
  }//update
319

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

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

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

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

    
464
    }//try
465
    catch(Exception e)
466
    {
467
        
468
        if (tableName.equals(DocumentImpl.DOCUMENTTABLE))
469
        {
470
        	logMetacat.error("ReplicationHandler.handleSingleXMLDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
471
        	logReplication.error("ReplicationHandler.handleSingleXMLDocument - " +DOCERRORNUMBER + " Failed to write xml doc " + accNumber +
472
                                       " into "+tableName + " from " +
473
                                           remoteserver + " because "+e.getMessage());
474
          DOCERRORNUMBER++;
475
        }
476
        else
477
        {
478
        	logMetacat.error("ReplicationHandler.handleSingleXMLDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
479
        	logReplication.error("ReplicationHandler.handleSingleXMLDocument - " +REVERRORNUMBER + " Failed to write xml doc " + accNumber +
480
                    " into "+tableName + " from " +
481
                        remoteserver +" because "+e.getMessage());
482
            REVERRORNUMBER++;
483
        }
484
        logMetacat.error("ReplicationHandler.handleSingleXMLDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
485
        logReplication.error("ReplicationHandler.handleSingleXMLDocument - Failed to write doc " + accNumber +
486
                                      " into db because " +e.getMessage());
487
      throw new HandlerException("ReplicationHandler.handleSingleXMLDocument - generic exception " 
488
    		  + "writing Replication: " +e.getMessage());
489
    }
490
    finally
491
    {
492
       //return DBConnection
493
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
494
    }//finally
495
    logD1.info("replication.create localId:" + accNumber);
496
  }
497

    
498

    
499

    
500
  /* Handle replicate single xml document*/
501
  private void handleSingleDataFile(String remoteserver, String actions,
502
                                    String accNumber, String tableName)
503
               throws HandlerException
504
  {
505
    logReplication.info("ReplicationHandler.handleSingleDataFile - Try to replicate data file: " + accNumber);
506
    DBConnection dbConn = null;
507
    int serialNumber = -1;
508
    try
509
    {
510
      // Get DBConnection from pool
511
      dbConn=DBConnectionPool.
512
                  getDBConnection("ReplicationHandler.handleSinlgeDataFile");
513
      serialNumber=dbConn.getCheckOutSerialNumber();
514
      // Try get docid info from remote server
515
      DocInfoHandler dih = new DocInfoHandler();
516
      XMLReader docinfoParser = initParser(dih);
517
      String docInfoURLString = "https://" + remoteserver +
518
                  "?server="+MetacatUtil.getLocalReplicationServerName()+
519
                  "&action=getdocumentinfo&docid="+accNumber;
520
      docInfoURLString = MetacatUtil.replaceWhiteSpaceForURL(docInfoURLString);
521
      URL docinfoUrl = new URL(docInfoURLString);
522

    
523
      String docInfoStr = ReplicationService.getURLContent(docinfoUrl);
524
      
525
      // strip out the system metadata portion
526
      String systemMetadataXML = ReplicationUtil.getSystemMetadataContent(docInfoStr);
527
   	  docInfoStr = ReplicationUtil.getContentWithoutSystemMetadata(docInfoStr);  
528
   	  
529
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
530
      Hashtable<String, String> docinfoHash = dih.getDocInfo();
531
      
532
      // Get docid name (such as acl or dataset)
533
      String docName = docinfoHash.get("docname");
534
      // Get doc type (eml public id)
535
      String docType = docinfoHash.get("doctype");
536
      // Get docid home sever. it might be different to remoteserver
537
      // because of hub feature
538
      String docHomeServer = docinfoHash.get("home_server");
539
      String createdDate = docinfoHash.get("date_created");
540
      String updatedDate = docinfoHash.get("date_updated");
541
      //docid should include rev number too
542
      /*String accnum=docId+util.getProperty("document.accNumSeparator")+
543
                                              (String)docinfoHash.get("rev");*/
544

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

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

    
666

    
667

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

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

    
695
    }//try
696
    catch(McdbDocNotFoundException e)
697
    {
698
      logMetacat.error("ReplicationHandler.handleDeleteSingleDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
699
      logReplication.error("ReplicationHandler.handleDeleteSingleDocument - Failed to delete doc " + docId +
700
                                 " in db because because " + e.getMessage());
701
      throw new HandlerException("ReplicationHandler.handleDeleteSingleDocument - generic exception " 
702
    		  + "when handling document: " + e.getMessage());
703
    }
704
    catch(InsufficientKarmaException e)
705
    {
706
      logMetacat.error("ReplicationHandler.handleDeleteSingleDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
707
      logReplication.error("ReplicationHandler.handleDeleteSingleDocument - Failed to delete doc " + docId +
708
                                 " in db because because " + e.getMessage());
709
      throw new HandlerException("ReplicationHandler.handleDeleteSingleDocument - generic exception " 
710
    		  + "when handling document: " + e.getMessage());
711
    }
712
    catch(SQLException e)
713
    {
714
      logMetacat.error("ReplicationHandler.handleDeleteSingleDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
715
      logReplication.error("ReplicationHandler.handleDeleteSingleDocument - Failed to delete doc " + docId +
716
                                 " in db because because " + e.getMessage());
717
      throw new HandlerException("ReplicationHandler.handleDeleteSingleDocument - generic exception " 
718
    		  + "when handling document: " + e.getMessage());
719
    }
720
    catch(Exception e)
721
    {
722
      logMetacat.error("ReplicationHandler.handleDeleteSingleDocument - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
723
      logReplication.error("ReplicationHandler.handleDeleteSingleDocument - Failed to delete doc " + docId +
724
                                 " in db because because " + e.getMessage());
725
      throw new HandlerException("ReplicationHandler.handleDeleteSingleDocument - generic exception " 
726
    		  + "when handling document: " + e.getMessage());
727
    }
728
    finally
729
    {
730
       //return DBConnection
731
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
732
    }//finally
733
    logD1.info("replication.handleDeleteSingleDocument localId:" + docId);
734
  }
735

    
736
  /* Handle updateLastCheckTimForSingleServer*/
737
  private void updateLastCheckTimeForSingleServer(ReplicationServer repServer)
738
                                                  throws HandlerException
739
  {
740
    String server = repServer.getServerName();
741
    DBConnection dbConn = null;
742
    int serialNumber = -1;
743
    PreparedStatement pstmt = null;
744
    try
745
    {
746
      // Get DBConnection from pool
747
      dbConn=DBConnectionPool.
748
             getDBConnection("ReplicationHandler.updateLastCheckTimeForServer");
749
      serialNumber=dbConn.getCheckOutSerialNumber();
750

    
751
      logReplication.info("ReplicationHandler.updateLastCheckTimeForSingleServer - Try to update last_check for server: "+server);
752
      // Get time from remote server
753
      URL dateurl = new URL("https://" + server + "?server="+
754
      MetacatUtil.getLocalReplicationServerName()+"&action=gettime");
755
      String datexml = ReplicationService.getURLContent(dateurl);
756
      logReplication.info("ReplicationHandler.updateLastCheckTimeForSingleServer - datexml: "+datexml);
757
      if (datexml!=null && !datexml.equals(""))
758
      {
759
         String datestr = datexml.substring(11, datexml.indexOf('<', 11));
760
         StringBuffer sql = new StringBuffer();
761
         /*sql.append("update xml_replication set last_checked = to_date('");
762
         sql.append(datestr).append("', 'YY-MM-DD HH24:MI:SS') where ");
763
         sql.append("server like '").append(server).append("'");*/
764
         sql.append("update xml_replication set last_checked = ");
765
         sql.append(DatabaseService.getInstance().getDBAdapter().toDate(datestr, "MM/DD/YY HH24:MI:SS"));
766
         sql.append(" where server like '").append(server).append("'");
767
         pstmt = dbConn.prepareStatement(sql.toString());
768

    
769
         pstmt.executeUpdate();
770
         dbConn.commit();
771
         pstmt.close();
772
         logReplication.info("ReplicationHandler.updateLastCheckTimeForSingleServer - last_checked updated to "+datestr+" on "
773
                                      + server);
774
      }//if
775
      else
776
      {
777

    
778
         logReplication.info("ReplicationHandler.updateLastCheckTimeForSingleServer - Failed to update last_checked for server "  +
779
                                  server + " in db because couldn't get time "
780
                                  );
781
         throw new Exception("Couldn't get time for server "+ server);
782
      }
783

    
784
    }//try
785
    catch(Exception e)
786
    {
787
      logMetacat.error("ReplicationHandler.updateLastCheckTimeForSingleServer - " + ReplicationService.METACAT_REPL_ERROR_MSG); 
788
      logReplication.error("ReplicationHandler.updateLastCheckTimeForSingleServer - Failed to update last_checked for server " +
789
                                server + " in db because because " + e.getMessage());
790
      throw new HandlerException("ReplicationHandler.updateLastCheckTimeForSingleServer - " 
791
    		  + "Error updating last checked time: " + e.getMessage());
792
    }
793
    finally
794
    {
795
       //return DBConnection
796
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
797
    }//finally
798
  }
799

    
800

    
801

    
802
  /**
803
   * updates xml_catalog with entries from other servers.
804
   */
805
  private void updateCatalog()
806
  {
807
    logReplication.info("ReplicationHandler.updateCatalog - Start of updateCatalog");
808
    // ReplicationServer object in server list
809
    ReplicationServer replServer = null;
810
    PreparedStatement pstmt = null;
811
    String server = null;
812

    
813

    
814
    // Go through each ReplicationServer object in sererlist
815
    for (int j=0; j<serverList.size(); j++)
816
    {
817
      Vector<Vector<String>> remoteCatalog = new Vector<Vector<String>>();
818
      Vector<String> publicId = new Vector<String>();
819
      try
820
      {
821
        // Get ReplicationServer object from server list
822
        replServer = serverList.serverAt(j);
823
        // Get server name from the ReplicationServer object
824
        server = replServer.getServerName();
825
        // Try to get catalog
826
        URL u = new URL("https://" + server + "?server="+
827
        MetacatUtil.getLocalReplicationServerName()+"&action=getcatalog");
828
        logReplication.info("ReplicationHandler.updateCatalog - sending message " + u.toString());
829
        String catxml = ReplicationService.getURLContent(u);
830

    
831
        // Make sure there are not error, no empty string
832
        if (catxml.indexOf("error")!=-1 || catxml==null||catxml.equals(""))
833
        {
834
          throw new Exception("Couldn't get catalog list form server " +server);
835
        }
836
        logReplication.debug("ReplicationHandler.updateCatalog - catxml: " + catxml);
837
        CatalogMessageHandler cmh = new CatalogMessageHandler();
838
        XMLReader catparser = initParser(cmh);
839
        catparser.parse(new InputSource(new StringReader(catxml)));
840
        //parse the returned catalog xml and put it into a vector
841
        remoteCatalog = cmh.getCatalogVect();
842

    
843
        // Make sure remoteCatalog is not empty
844
        if (remoteCatalog.isEmpty())
845
        {
846
          throw new Exception("Couldn't get catalog list form server " +server);
847
        }
848

    
849
        String localcatxml = ReplicationService.getCatalogXML();
850

    
851
        // Make sure local catalog is no empty
852
        if (localcatxml==null||localcatxml.equals(""))
853
        {
854
          throw new Exception("Couldn't get catalog list form server " +server);
855
        }
856

    
857
        cmh = new CatalogMessageHandler();
858
        catparser = initParser(cmh);
859
        catparser.parse(new InputSource(new StringReader(localcatxml)));
860
        Vector<Vector<String>> localCatalog = cmh.getCatalogVect();
861

    
862
        //now we have the catalog from the remote server and this local server
863
        //we now need to compare the two and merge the differences.
864
        //the comparison is base on the public_id fields which is the 4th
865
        //entry in each row vector.
866
        publicId = new Vector<String>();
867
        for(int i=0; i<localCatalog.size(); i++)
868
        {
869
          Vector<String> v = new Vector<String>(localCatalog.elementAt(i));
870
          logReplication.info("ReplicationHandler.updateCatalog - v1: " + v.toString());
871
          publicId.add(new String((String)v.elementAt(3)));
872
        }
873
      }//try
874
      catch (Exception e)
875
      {
876
        logMetacat.error("ReplicationHandler.updateCatalog - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
877
        logReplication.error("ReplicationHandler.updateCatalog - Failed to update catalog for server "+
878
                                    server + " because " +e.getMessage());
879
      }//catch
880

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

    
935
  /**
936
   * Method that returns true if docid has already been "deleted" from metacat.
937
   * This method really implements a truth table for deleted documents
938
   * The table is (a docid in one of the tables is represented by the X):
939
   * xml_docs      xml_revs      deleted?
940
   * ------------------------------------
941
   *   X             X             FALSE
942
   *   X             _             FALSE
943
   *   _             X             TRUE
944
   *   _             _             TRUE
945
   */
946
  private static boolean alreadyDeleted(String docid) throws HandlerException
947
  {
948
    DBConnection dbConn = null;
949
    int serialNumber = -1;
950
    PreparedStatement pstmt = null;
951
    try
952
    {
953
      dbConn=DBConnectionPool.
954
                  getDBConnection("ReplicationHandler.alreadyDeleted");
955
      serialNumber=dbConn.getCheckOutSerialNumber();
956
      boolean xml_docs = false;
957
      boolean xml_revs = false;
958

    
959
      StringBuffer sb = new StringBuffer();
960
      sb.append("select docid from xml_revisions where docid like '");
961
      sb.append(docid).append("'");
962
      pstmt = dbConn.prepareStatement(sb.toString());
963
      pstmt.execute();
964
      ResultSet rs = pstmt.getResultSet();
965
      boolean tablehasrows = rs.next();
966
      if(tablehasrows)
967
      {
968
        xml_revs = true;
969
      }
970

    
971
      sb = new StringBuffer();
972
      sb.append("select docid from xml_documents where docid like '");
973
      sb.append(docid).append("'");
974
      pstmt.close();
975
      pstmt = dbConn.prepareStatement(sb.toString());
976
      //increase usage count
977
      dbConn.increaseUsageCount(1);
978
      pstmt.execute();
979
      rs = pstmt.getResultSet();
980
      tablehasrows = rs.next();
981
      pstmt.close();
982
      if(tablehasrows)
983
      {
984
        xml_docs = true;
985
      }
986

    
987
      if(xml_docs && xml_revs)
988
      {
989
        return false;
990
      }
991
      else if(xml_docs && !xml_revs)
992
      {
993
        return false;
994
      }
995
      else if(!xml_docs && xml_revs)
996
      {
997
        return true;
998
      }
999
      else if(!xml_docs && !xml_revs)
1000
      {
1001
        return true;
1002
      }
1003
    }
1004
    catch(Exception e)
1005
    {
1006
      logMetacat.error("ReplicationHandler.alreadyDeleted - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1007
      logReplication.error("ReplicationHandler.alreadyDeleted - general error in alreadyDeleted: " +
1008
                          e.getMessage());
1009
      throw new HandlerException("ReplicationHandler.alreadyDeleted - general error: " 
1010
    		  + e.getMessage());
1011
    }
1012
    finally
1013
    {
1014
      try
1015
      {
1016
        pstmt.close();
1017
      }//try
1018
      catch (SQLException ee)
1019
      {
1020
    	logMetacat.error("ReplicationHandler.alreadyDeleted - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1021
        logReplication.error("ReplicationHandler.alreadyDeleted - Error in replicationHandler.alreadyDeleted "+
1022
                          "to close pstmt: "+ee.getMessage());
1023
        throw new HandlerException("ReplicationHandler.alreadyDeleted - SQL error when closing prepared statement: " 
1024
      		  + ee.getMessage());
1025
      }//catch
1026
      finally
1027
      {
1028
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1029
      }//finally
1030
    }//finally
1031
    return false;
1032
  }
1033

    
1034

    
1035
  /**
1036
   * Method to initialize the message parser
1037
   */
1038
  public static XMLReader initParser(DefaultHandler dh)
1039
          throws HandlerException
1040
  {
1041
    XMLReader parser = null;
1042

    
1043
    try {
1044
      ContentHandler chandler = dh;
1045

    
1046
      // Get an instance of the parser
1047
      String parserName = PropertyService.getProperty("xml.saxparser");
1048
      parser = XMLReaderFactory.createXMLReader(parserName);
1049

    
1050
      // Turn off validation
1051
      parser.setFeature("http://xml.org/sax/features/validation", false);
1052

    
1053
      parser.setContentHandler((ContentHandler)chandler);
1054
      parser.setErrorHandler((ErrorHandler)chandler);
1055

    
1056
    } catch (SAXException se) {
1057
      throw new HandlerException("ReplicationHandler.initParser - Sax error when " 
1058
    		  + " initializing parser: " + se.getMessage());
1059
    } catch (PropertyNotFoundException pnfe) {
1060
        throw new HandlerException("ReplicationHandler.initParser - Property error when " 
1061
      		  + " getting parser name: " + pnfe.getMessage());
1062
    } 
1063

    
1064
    return parser;
1065
  }
1066

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

    
1109
  /*
1110
	 * parse a given string to Time in short format. For example, given time is
1111
	 * 10:00 AM, the date will be return as Jan 1 1970, 10:00 AM
1112
	 */
1113
  private static Date parseTime(String timeString) throws ParseException
1114
  {
1115
    DateFormat format = DateFormat.getTimeInstance(DateFormat.SHORT);
1116
    Date time = format.parse(timeString); 
1117
    logReplication.info("ReplicationHandler.parseTime - Date string is after parse a time string "
1118
                              +time.toString());
1119
    return time;
1120

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

    
1194
			try {
1195
				if (tableName.equals(DocumentImpl.DOCUMENTTABLE)) {
1196
					handleDocInXMLDocuments(docid, rev, remoteServer, dataFile);
1197
				} else if (tableName.equals(DocumentImpl.REVISIONTABLE)) {
1198
					handleDocInXMLRevisions(docid, rev, remoteServer, dataFile);
1199
				} else {
1200
					continue;
1201
				}
1202

    
1203
			} catch (Exception e) {
1204
				logMetacat.error("ReplicationHandler.handleDocList - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1205
				logReplication.error("ReplicationHandler.handleDocList - error to handle update doc in " + tableName
1206
						+ " in time replication" + e.getMessage());
1207
				continue;
1208
			}
1209
			
1210
	        if (_xmlDocQueryCount > 0 && (_xmlDocQueryCount % 100) == 0) {
1211
	        	logMetacat.debug("ReplicationHandler.update - xml_doc query count: " + _xmlDocQueryCount + 
1212
	        			", xml_doc avg query time: " + (_xmlDocQueryTime / _xmlDocQueryCount));
1213
	        }
1214
	        
1215
	        if (_xmlRevQueryCount > 0 && (_xmlRevQueryCount % 100) == 0) {
1216
	        	logMetacat.debug("ReplicationHandler.update - xml_rev query count: " + _xmlRevQueryCount + 
1217
	        			", xml_rev avg query time: " + (_xmlRevQueryTime / _xmlRevQueryCount));
1218
	        }
1219

    
1220
		}// for update docs
1221

    
1222
	}
1223
   
1224
   /*
1225
	 * This method will handle doc in xml_documents table.
1226
	 */
1227
   private void handleDocInXMLDocuments(String docid, int rev, String remoteServer, boolean dataFile) 
1228
                                        throws HandlerException
1229
   {
1230
       // compare the update rev and local rev to see what need happen
1231
       int localrev = -1;
1232
       String action = null;
1233
       boolean flag = false;
1234
       try
1235
       {
1236
    	 long docQueryStartTime = System.currentTimeMillis();
1237
         localrev = DBUtil.getLatestRevisionInDocumentTable(docid);
1238
         long docQueryEndTime = System.currentTimeMillis();
1239
         _xmlDocQueryTime += (docQueryEndTime - docQueryStartTime);
1240
         _xmlDocQueryCount++;
1241
       }
1242
       catch (SQLException e)
1243
       {
1244
    	 logMetacat.error("ReplicationHandler.handleDocInXMLDocuments - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1245
         logReplication.error("ReplicationHandler.handleDocInXMLDocuments - Local rev for docid "+ docid + " could not "+
1246
                                " be found because " + e.getMessage());
1247
         logReplication.error("ReplicationHandler.handleDocInXMLDocuments - " + DOCERRORNUMBER+"Docid "+ docid + " could not be "+
1248
                 "written because error happend to find it's local revision");
1249
         DOCERRORNUMBER++;
1250
         throw new HandlerException ("ReplicationHandler.handleDocInXMLDocuments - Local rev for docid "+ docid + " could not "+
1251
                 " be found: " + e.getMessage());
1252
       }
1253
       logReplication.info("ReplicationHandler.handleDocInXMLDocuments - Local rev for docid "+ docid + " is "+
1254
                               localrev);
1255

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

    
1321
        // this is for data file
1322
       if(flag && dataFile)
1323
       {
1324
         try
1325
         {
1326
           handleSingleDataFile(remoteServer, action, accNumber, DocumentImpl.DOCUMENTTABLE);
1327
         }
1328
         catch(HandlerException he)
1329
         {
1330
           // skip this data file
1331
           throw he;
1332
         }
1333

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

    
1398
        // this is for data file
1399
       if(flag && dataFile)
1400
       {
1401
         try
1402
         {
1403
           handleSingleDataFile(remoteServer, action, accNumber, DocumentImpl.REVISIONTABLE);
1404
         }
1405
         catch(HandlerException he)
1406
         {
1407
           // skip this data file
1408
           throw he;
1409
         }
1410

    
1411
       }//for data file
1412
   }
1413
   
1414
   /*
1415
    * Return a ip address for given url
1416
    */
1417
   private String getIpFromURL(URL url)
1418
   {
1419
	   String ip = null;
1420
	   try
1421
	   {
1422
	      InetAddress address = InetAddress.getByName(url.getHost());
1423
	      ip = address.getHostAddress();
1424
	   }
1425
	   catch(UnknownHostException e)
1426
	   {
1427
		   logMetacat.error("ReplicationHandler.getIpFromURL - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
1428
		   logReplication.error("ReplicationHandler.getIpFromURL - Error in get ip address for host: "
1429
                   +e.getMessage());
1430
	   }
1431

    
1432
	   return ip;
1433
   }
1434
  
1435
}
1436

    
(3-3/7)