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

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
31
import java.sql.*;
32
import java.util.*;
33
import java.util.Date;
34
import java.lang.Thread;
35
import java.io.*;
36
import java.net.*;
37
import java.text.*;
38
import org.xml.sax.AttributeList;
39
import org.xml.sax.ContentHandler;
40
import org.xml.sax.DTDHandler;
41
import org.xml.sax.EntityResolver;
42
import org.xml.sax.ErrorHandler;
43
import org.xml.sax.InputSource;
44
import org.xml.sax.XMLReader;
45
import org.xml.sax.SAXException;
46
import org.xml.sax.SAXParseException;
47
import org.xml.sax.helpers.XMLReaderFactory;
48
import org.xml.sax.helpers.DefaultHandler;
49

    
50

    
51

    
52
/**
53
 * This class handles deltaT replication checking.  Whenever this TimerTask
54
 * is fired it checks each server in xml_replication for updates and updates
55
 * the local db as needed.
56
 */
57
public class ReplicationHandler extends TimerTask
58
{
59
  int serverCheckCode = 1;
60
  MetaCatUtil util = new MetaCatUtil();
61
  ReplicationServerList serverList = null;
62
  //PrintWriter out;
63
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
64

    
65
 
66
  
67
  public ReplicationHandler()
68
  {
69
    //this.out = o;
70
    serverList = new ReplicationServerList();
71
  }
72

    
73
  public ReplicationHandler(int serverCheckCode)
74
  {
75
    //this.out = o;
76
    this.serverCheckCode = serverCheckCode;
77
    serverList = new ReplicationServerList();
78
  }
79

    
80
  /**
81
   * Method that implements TimerTask.run().  It runs whenever the timer is
82
   * fired.
83
   */
84
  public void run()
85
  {
86
    //find out the last_checked time of each server in the server list and
87
    //send a query to each server to see if there are any documents in
88
    //xml_documents with an update_date > last_checked
89
    try
90
    {
91
      //if serverList is null, metacat don't need to replication
92
      if (serverList==null||serverList.isEmpty())
93
      {
94
        return;
95
      }
96
      updateCatalog();
97
      update();
98
      //conn.close();
99
    }//try
100
    catch (Exception e)
101
    {
102
      MetaCatUtil.debugMessage("Error in replicationHandler.run():"
103
                                                    +e.getMessage(), 30);
104
      e.printStackTrace();
105
    }//catch
106
  }
107

    
108
  /**
109
   * Method that uses revision taging for replication instead of update_date.
110
   */
111
  private void update()
112
  {
113
    /*
114
     Pseudo-algorithm
115
     - request a doc list from each server in xml_replication
116
     - check the rev number of each of those documents agains the
117
       documents in the local database
118
     - pull any documents that have a lesser rev number on the local server
119
       from the remote server
120
     - delete any documents that still exist in the local xml_documents but
121
       are in the deletedDocuments tag of the remote host response.
122
     - update last_checked to keep track of the last time it was checked.
123
       (this info is theoretically not needed using this system but probably
124
       should be kept anyway)
125
    */
126

    
127
    ReplicationServer replServer = null; // Variable to store the
128
                                        // ReplicationServer got from
129
                                        // Server list
130
    String server = null; // Variable to store server name
131
    String update;
132
    ReplMessageHandler message = new ReplMessageHandler();
133
    Vector responses = new Vector();
134
    XMLReader parser;
135
    URL u;
136

    
137

    
138
    try
139
    {
140
      parser = initParser(message);
141
    }
142
    catch (Exception e)
143
    {
144
      MetacatReplication.replErrorLog("Failed to replicate becaue couldn't "+
145
                                 " initParser for message and" +e.getMessage());
146
      MetaCatUtil.debugMessage("Failed to replicate becaue couldn't " +
147
                            " initParser for message and " +e.getMessage(), 30);
148
       // stop replication
149
       return;
150
    }
151
    //Check for every server in server list to get updated list and put
152
    // them in to response
153
    for (int i=0; i<serverList.size(); i++)
154
    {
155
        // Get ReplicationServer object from server list
156
        replServer = serverList.serverAt(i);
157
        // Get server name from ReplicationServer object
158
        server = replServer.getServerName().trim();
159
        String result = null;
160
        MetacatReplication.replLog("full update started to: " + server);
161
        // Send command to that server to get updated docid information
162
        try
163
        {
164
          u = new URL("https://" + server + "?server="
165
          +util.getLocalReplicationServerName()+"&action=update");
166
          MetaCatUtil.debugMessage("Sending infomation " +u.toString(), 50);
167
          result = MetacatReplication.getURLContent(u);
168
        }
169
        catch (Exception e)
170
        {
171
          MetacatReplication.replErrorLog("Failed to get updated doc list "+
172
                          "for server " + server + " because "+e.getMessage());
173
          MetaCatUtil.debugMessage( "Failed to get updated doc list "+
174
                       "for server " + server + " because "+e.getMessage(), 30);
175
          continue;
176
        }
177

    
178
        MetaCatUtil.debugMessage("docid: "+server+" "+result, 50);
179
        //check if result have error or not, if has skip it.
180
        if (result.indexOf("<error>")!=-1 && result.indexOf("</error>")!=-1)
181
        {
182
          MetacatReplication.replErrorLog("Failed to get updated doc list "+
183
                          "for server " + server + " because "+result);
184
          MetaCatUtil.debugMessage( "Failed to get updated doc list "+
185
                       "for server " + server + " because "+result, 30);
186
          continue;
187
        }
188
        //Add result to vector
189
        responses.add(result);
190
    }
191

    
192
    //make sure that there is updated file list
193
    //If response is null, metacat don't need do anything
194
    if (responses==null || responses.isEmpty())
195
    {
196
        MetacatReplication.replErrorLog("No updated doc list for "+
197
                           "every server and failed to replicate");
198
        MetaCatUtil.debugMessage( "No updated doc list for "+
199
                           "every server and failed to replicate", 30);
200
        return;
201
    }
202

    
203

    
204
    MetaCatUtil.debugMessage("Responses from remote metacat about updated "+
205
                   "document information: "+ responses.toString(), 35);
206
    // go through response vector(it contains updated vector and delete vector
207
    for(int i=0; i<responses.size(); i++)
208
    {
209
        try
210
        {
211
          parser.parse(new InputSource(
212
                     new StringReader(
213
                     (String)(responses.elementAt(i)))));
214
        }
215
        catch(Exception e)
216
        {
217
          MetacatReplication.replErrorLog("Couldn't parse one responses "+
218
                           "because "+ e.getMessage());
219
          MetaCatUtil.debugMessage("Couldn't parse one responses "+
220
                                   "because "+ e.getMessage(), 30);
221
          continue;
222
        }
223
        //v is the list of updated documents
224
        Vector updateList = new Vector(message.getUpdatesVect());
225
        //System.out.println("v: " + v.toString());
226
        //d is the list of deleted documents
227
        Vector deleteList = new Vector(message.getDeletesVect());
228
        //System.out.println("d: " + d.toString());
229
        MetaCatUtil.debugMessage("Update vector size: "+ updateList.size(), 40);
230
        MetaCatUtil.debugMessage("Delete vector size: "+ deleteList.size(),40);
231
        // go though every element in updated document vector
232
        handleDocList(updateList, DocumentImpl.DOCUMENTTABLE);
233
        //handle deleted docs
234
        for(int k=0; k<deleteList.size(); k++)
235
        { //delete the deleted documents;
236
          Vector w = new Vector((Vector)deleteList.elementAt(k));
237
          String docId = (String)w.elementAt(0);
238
          try
239
          {
240
            handleDeleteSingleDocument(docId, server);
241
          }
242
          catch (Exception ee)
243
          {
244
            continue;
245
          }
246
        }//for delete docs
247
        
248
        // handle replicate doc in xml_revision
249
        Vector revisionList = new Vector(message.getRevisionsVect());
250
        handleDocList(revisionList, DocumentImpl.REVISIONTABLE);
251
    }//for response
252

    
253
    //updated last_checked
254
    for (int i=0;i<serverList.size(); i++)
255
    {
256
       // Get ReplicationServer object from server list
257
       replServer = serverList.serverAt(i);
258
       try
259
       {
260
         updateLastCheckTimeForSingleServer(replServer);
261
       }
262
       catch(Exception e)
263
       {
264
         continue;
265
       }
266
    }//for
267

    
268
  }//update
269

    
270
  /* Handle replicate single xml document*/
271
  private void handleSingleXMLDocument(String remoteserver, String actions,
272
                                       String accNumber, String tableName)
273
               throws Exception
274
  {
275
    DBConnection dbConn = null;
276
    int serialNumber = -1;
277
    try
278
    {
279
      // Get DBConnection from pool
280
      dbConn=DBConnectionPool.
281
                  getDBConnection("ReplicationHandler.handleSingleXMLDocument");
282
      serialNumber=dbConn.getCheckOutSerialNumber();
283
      //if the document needs to be updated or inserted, this is executed
284
      String readDocURLString = "https://" + remoteserver + "?server="+
285
              util.getLocalReplicationServerName()+"&action=read&docid="+accNumber;
286
      readDocURLString = MetaCatUtil.replaceWhiteSpaceForURL(readDocURLString);
287
      URL u = new URL(readDocURLString);
288

    
289
      // Get docid content
290
      String newxmldoc = MetacatReplication.getURLContent(u);
291
      // If couldn't get skip it
292
      if ( newxmldoc.indexOf("<error>")!= -1 && newxmldoc.indexOf("</error>")!=-1)
293
      {
294
         throw new Exception(newxmldoc);
295
      }
296
      MetaCatUtil.debugMessage("xml documnet:", 45);
297
      MetaCatUtil.debugMessage(newxmldoc, 45);
298

    
299
      // Try get the docid info from remote server
300
      DocInfoHandler dih = new DocInfoHandler();
301
      XMLReader docinfoParser = initParser(dih);
302
      String docInfoURLStr = "https://" + remoteserver +
303
                       "?server="+util.getLocalReplicationServerName()+
304
                       "&action=getdocumentinfo&docid="+accNumber;
305
      docInfoURLStr = MetaCatUtil.replaceWhiteSpaceForURL(docInfoURLStr);
306
      URL docinfoUrl = new URL(docInfoURLStr);
307
      MetaCatUtil.debugMessage("Sending message: " +
308
                                                  docinfoUrl.toString(), 45);
309
      String docInfoStr = MetacatReplication.getURLContent(docinfoUrl);
310
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
311
      Hashtable docinfoHash = dih.getDocInfo();
312
      // Get home server of the docid
313
      String docHomeServer = (String)docinfoHash.get("home_server");
314
      MetaCatUtil.debugMessage("doc home server in repl: "+docHomeServer, 45);
315
      String createdDate = (String)docinfoHash.get("date_created");
316
      String updatedDate = (String)docinfoHash.get("date_updated");
317
      //docid should include rev number too
318
      /*String accnum=docId+util.getOption("accNumSeparator")+
319
                                              (String)docinfoHash.get("rev");*/
320
      MetaCatUtil.debugMessage("docid in repl: "+accNumber, 45);
321
      String docType = (String)docinfoHash.get("doctype");
322
      MetaCatUtil.debugMessage("doctype in repl: "+docType, 45);
323

    
324
      String parserBase = null;
325
      // this for eml2 and we need user eml2 parser
326
      if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE))
327
      {
328
         parserBase = DocumentImpl.EML200;
329
      }
330
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE))
331
      {
332
        parserBase = DocumentImpl.EML200;
333
      }
334
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE))
335
      {
336
        parserBase = DocumentImpl.EML210;
337
      }
338
      // Write the document into local host
339
      DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false);
340
      String newDocid = wrapper.writeReplication(dbConn,
341
                              new StringReader(newxmldoc),
342
                              (String)docinfoHash.get("public_access"),
343
                              null,  /* the dtd text */
344
                              actions,
345
                              accNumber,
346
                              (String)docinfoHash.get("user_owner"),
347
                              null, /* null for groups[] */
348
                              docHomeServer,
349
                              remoteserver, tableName, true,// true is for time replication 
350
                              createdDate,
351
                              updatedDate);
352
      MetaCatUtil.debugMessage("Successfully replicated doc " + accNumber, 35);
353
      MetacatReplication.replLog("wrote doc " + accNumber + " from " +
354
                                         remoteserver);
355

    
356
    }//try
357
    catch(Exception e)
358
    {
359
      MetacatReplication.replErrorLog("Failed to write doc " + accNumber +
360
                                      " into db because " +e.getMessage());
361
      MetaCatUtil.debugMessage("Failed to write doc " + accNumber +
362
                                      " into db because " +e.getMessage(), 30);
363
      throw e;
364
    }
365
    finally
366
    {
367
       //return DBConnection
368
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
369
    }//finally
370
  }
371

    
372

    
373

    
374
  /* Handle replicate single xml document*/
375
  private void handleSingleDataFile(String remoteserver, String actions,
376
                                    String accNumber, String tableName)
377
               throws Exception
378
  {
379
    MetaCatUtil.debugMessage("Try to replicate data file: "+accNumber, 40);
380
    DBConnection dbConn = null;
381
    int serialNumber = -1;
382
    try
383
    {
384
      // Get DBConnection from pool
385
      dbConn=DBConnectionPool.
386
                  getDBConnection("ReplicationHandler.handleSinlgeDataFile");
387
      serialNumber=dbConn.getCheckOutSerialNumber();
388
      // Try get docid info from remote server
389
      DocInfoHandler dih = new DocInfoHandler();
390
      XMLReader docinfoParser = initParser(dih);
391
      String docInfoURLString = "https://" + remoteserver +
392
                  "?server="+util.getLocalReplicationServerName()+
393
                  "&action=getdocumentinfo&docid="+accNumber;
394
      docInfoURLString = MetaCatUtil.replaceWhiteSpaceForURL(docInfoURLString);
395
      URL docinfoUrl = new URL(docInfoURLString);
396

    
397
      String docInfoStr = MetacatReplication.getURLContent(docinfoUrl);
398
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
399
      Hashtable docinfoHash = dih.getDocInfo();
400
      // Get doicd owner
401
      String user = (String)docinfoHash.get("user_owner");
402
      // Get docid name (such as acl or dataset)
403
      String docName = (String)docinfoHash.get("docname");
404
      // Get doc type (eml public id)
405
      String docType = (String)docinfoHash.get("doctype");
406
      // Get docid home sever. it might be different to remoteserver
407
      // becuause of hub feature
408
      String docHomeServer = (String)docinfoHash.get("home_server");
409
      String createdDate = (String)docinfoHash.get("date_created");
410
      String updatedDate = (String)docinfoHash.get("date_updated");
411
      //docid should include rev number too
412
      /*String accnum=docId+util.getOption("accNumSeparator")+
413
                                              (String)docinfoHash.get("rev");*/
414

    
415

    
416
      String datafilePath = util.getOption("datafilepath");
417
      // Get data file content
418
      String readDataURLString = "https://" + remoteserver + "?server="+
419
                                        util.getLocalReplicationServerName()+
420
                                            "&action=readdata&docid="+accNumber;
421
      readDataURLString = MetaCatUtil.replaceWhiteSpaceForURL(readDataURLString);
422
      URL u = new URL(readDataURLString);
423
      InputStream input = u.openStream();
424
      //register data file into xml_documents table and wite data file
425
      //into file system
426
      if ( input != null)
427
      {
428
        DocumentImpl.writeDataFileInReplication(input,
429
                                                datafilePath,
430
                                                docName,docType,
431
                                                accNumber, user,
432
                                                docHomeServer,
433
                                                remoteserver,
434
                                                tableName,
435
                                                true, //true means timed replication
436
                                                createdDate,
437
                                                updatedDate);
438
                                         
439
        MetaCatUtil.debugMessage("Successfully to write datafile " + accNumber, 30);
440
        MetacatReplication.replLog("wrote datafile " + accNumber + " from " +
441
                                    remoteserver);
442
      }//if
443
      else
444
      {
445
         MetaCatUtil.debugMessage("Couldn't open the data file: " + accNumber, 30);
446
         throw new Exception("Couldn't open the data file: " + accNumber);
447
      }//else
448

    
449
    }//try
450
    catch(Exception e)
451
    {
452
      MetacatReplication.replErrorLog("Failed to try wrote datafile " + accNumber +
453
                                      " because " +e.getMessage());
454
      MetaCatUtil.debugMessage("Failed to try wrote datafile " + accNumber +
455
                                      " because " +e.getMessage(), 30);
456
      throw e;
457
    }
458
    finally
459
    {
460
       //return DBConnection
461
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
462
    }//finally
463
  }
464

    
465

    
466

    
467
  /* Handle delete single document*/
468
  private void handleDeleteSingleDocument(String docId, String notifyServer)
469
               throws Exception
470
  {
471
    MetaCatUtil.debugMessage("Try delete doc: "+docId, 40);
472
    DBConnection dbConn = null;
473
    int serialNumber = -1;
474
    try
475
    {
476
      // Get DBConnection from pool
477
      dbConn=DBConnectionPool.
478
                  getDBConnection("ReplicationHandler.handleDeleteSingleDoc");
479
      serialNumber=dbConn.getCheckOutSerialNumber();
480
      if(!alreadyDeleted(docId))
481
      {
482

    
483
         //because delete method docid should have rev number
484
         //so we just add one for it. This rev number is no sence.
485
         String accnum=docId+util.getOption("accNumSeparator")+"1";
486
         //System.out.println("accnum: "+accnum);
487
         DocumentImpl.delete(accnum, null, null, notifyServer);
488
         MetaCatUtil.debugMessage("Successfully deleted doc " + docId, 30);
489
         MetacatReplication.replLog("Doc " + docId + " deleted");
490
      }
491

    
492
    }//try
493
    catch(Exception e)
494
    {
495
      MetacatReplication.replErrorLog("Failed to delete doc " + docId +
496
                                      " in db because " +e.getMessage());
497
      MetaCatUtil.debugMessage("Failed to delete doc " + docId +
498
                                 " in db because because " +e.getMessage(), 30);
499
      throw e;
500
    }
501
    finally
502
    {
503
       //return DBConnection
504
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
505
    }//finally
506
  }
507

    
508
  /* Handle updateLastCheckTimForSingleServer*/
509
  private void updateLastCheckTimeForSingleServer(ReplicationServer repServer)
510
                                                  throws Exception
511
  {
512
    String server = repServer.getServerName();
513
    DBConnection dbConn = null;
514
    int serialNumber = -1;
515
    PreparedStatement pstmt = null;
516
    try
517
    {
518
      // Get DBConnection from pool
519
      dbConn=DBConnectionPool.
520
             getDBConnection("ReplicationHandler.updateLastCheckTimeForServer");
521
      serialNumber=dbConn.getCheckOutSerialNumber();
522

    
523
      MetaCatUtil.debugMessage("Try to update last_check for server: "+server, 40);
524
      // Get time from remote server
525
      URL dateurl = new URL("https://" + server + "?server="+
526
      util.getLocalReplicationServerName()+"&action=gettime");
527
      String datexml = MetacatReplication.getURLContent(dateurl);
528
      MetaCatUtil.debugMessage("datexml: "+datexml, 45);
529
      if (datexml!=null && !datexml.equals(""))
530
      {
531
         String datestr = datexml.substring(11, datexml.indexOf('<', 11));
532
         StringBuffer sql = new StringBuffer();
533
         /*sql.append("update xml_replication set last_checked = to_date('");
534
         sql.append(datestr).append("', 'YY-MM-DD HH24:MI:SS') where ");
535
         sql.append("server like '").append(server).append("'");*/
536
         sql.append("update xml_replication set last_checked = ");
537
         sql.append(dbAdapter.toDate(datestr, "MM/DD/YY HH24:MI:SS"));
538
         sql.append(" where server like '").append(server).append("'");
539
         pstmt = dbConn.prepareStatement(sql.toString());
540

    
541
         pstmt.executeUpdate();
542
         dbConn.commit();
543
         pstmt.close();
544
         MetaCatUtil.debugMessage("last_checked updated to "+datestr+" on "
545
                                      + server, 45);
546
      }//if
547
      else
548
      {
549

    
550
         MetaCatUtil.debugMessage("Failed to update last_checked for server "  +
551
                                  server + " in db because couldn't get time "
552
                                  , 30);
553
         throw new Exception("Couldn't get time for server "+ server);
554
      }
555

    
556
    }//try
557
    catch(Exception e)
558
    {
559

    
560
      MetaCatUtil.debugMessage("Failed to update last_checked for server " +
561
                                server + " in db because because " +
562
                                e.getMessage(), 30);
563
      throw e;
564
    }
565
    finally
566
    {
567
       //return DBConnection
568
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
569
    }//finally
570
  }
571

    
572

    
573

    
574
  /**
575
   * updates xml_catalog with entries from other servers.
576
   */
577
  private void updateCatalog()
578
  {
579
    MetaCatUtil.debugMessage("Start of updateCatalog", 35 );
580
    // ReplicationServer object in server list
581
    ReplicationServer replServer = null;
582
    PreparedStatement pstmt = null;
583
    String server = null;
584

    
585

    
586
    // Go through each ReplicationServer object in sererlist
587
    for (int j=0; j<serverList.size(); j++)
588
    {
589
      Vector remoteCatalog = new Vector();
590
      Vector publicId = new Vector();
591
      try
592
      {
593
        // Get ReplicationServer object from server list
594
        replServer = serverList.serverAt(j);
595
        // Get server name from the ReplicationServer object
596
        server = replServer.getServerName();
597
        // Try to get catalog
598
        URL u = new URL("https://" + server + "?server="+
599
        util.getLocalReplicationServerName()+"&action=getcatalog");
600
        MetaCatUtil.debugMessage("sending message " + u.toString(), 50);
601
        String catxml = MetacatReplication.getURLContent(u);
602

    
603
        // Make sure there are not error, no empty string
604
        if (catxml.indexOf("error")!=-1 || catxml==null||catxml.equals(""))
605
        {
606
          throw new Exception("Couldn't get catalog list form server " +server);
607
        }
608
        MetaCatUtil.debugMessage("catxml: " + catxml, 40);
609
        CatalogMessageHandler cmh = new CatalogMessageHandler();
610
        XMLReader catparser = initParser(cmh);
611
        catparser.parse(new InputSource(new StringReader(catxml)));
612
        //parse the returned catalog xml and put it into a vector
613
        remoteCatalog = cmh.getCatalogVect();
614

    
615
        // Makse sure remoteCatalog is not empty
616
        if (remoteCatalog.isEmpty())
617
        {
618
          throw new Exception("Couldn't get catalog list form server " +server);
619
        }
620

    
621
        String localcatxml = MetacatReplication.getCatalogXML();
622

    
623
        // Make sure local catalog is no empty
624
        if (localcatxml==null||localcatxml.equals(""))
625
        {
626
          throw new Exception("Couldn't get catalog list form server " +server);
627
        }
628

    
629
        cmh = new CatalogMessageHandler();
630
        catparser = initParser(cmh);
631
        catparser.parse(new InputSource(new StringReader(localcatxml)));
632
        Vector localCatalog = cmh.getCatalogVect();
633

    
634
        //now we have the catalog from the remote server and this local server
635
        //we now need to compare the two and merge the differences.
636
        //the comparison is base on the public_id fields which is the 4th
637
        //entry in each row vector.
638
        publicId = new Vector();
639
        for(int i=0; i<localCatalog.size(); i++)
640
        {
641
          Vector v = new Vector((Vector)localCatalog.elementAt(i));
642
          MetaCatUtil.debugMessage("v1: " + v.toString(), 50);
643
          publicId.add(new String((String)v.elementAt(3)));
644
          //System.out.println("adding " + (String)v.elementAt(3));
645
        }
646
      }//try
647
      catch (Exception e)
648
      {
649
        MetacatReplication.replErrorLog("Failed to update catalog for server "+
650
                                    server + " because " +e.getMessage());
651
        MetaCatUtil.debugMessage("Failed to update catalog for server "+
652
                                    server + " because " +e.getMessage(), 30);
653
      }//catch
654

    
655
      for(int i=0; i<remoteCatalog.size(); i++)
656
      {
657
         // DConnection
658
        DBConnection dbConn = null;
659
        // DBConnection checkout serial number
660
        int serialNumber = -1;
661
        try
662
        {
663
            dbConn=DBConnectionPool.
664
                  getDBConnection("ReplicationHandler.updateCatalog");
665
            serialNumber=dbConn.getCheckOutSerialNumber();
666
            Vector v = (Vector)remoteCatalog.elementAt(i);
667
            //System.out.println("v2: " + v.toString());
668
            //System.out.println("i: " + i);
669
            //System.out.println("remoteCatalog.size(): " + remoteCatalog.size());
670
            //System.out.println("publicID: " + publicId.toString());
671
            MetaCatUtil.debugMessage
672
                              ("v.elementAt(3): " + (String)v.elementAt(3), 50);
673
           if(!publicId.contains(v.elementAt(3)))
674
           { //so we don't have this public id in our local table so we need to
675
             //add it.
676
             //System.out.println("in if");
677
             StringBuffer sql = new StringBuffer();
678
             sql.append("insert into xml_catalog (entry_type, source_doctype, ");
679
             sql.append("target_doctype, public_id, system_id) values (?,?,?,");
680
             sql.append("?,?)");
681
             //System.out.println("sql: " + sql.toString());
682
             pstmt = dbConn.prepareStatement(sql.toString());
683
             pstmt.setString(1, (String)v.elementAt(0));
684
             pstmt.setString(2, (String)v.elementAt(1));
685
             pstmt.setString(3, (String)v.elementAt(2));
686
             pstmt.setString(4, (String)v.elementAt(3));
687
             pstmt.setString(5, (String)v.elementAt(4));
688
             pstmt.execute();
689
             pstmt.close();
690
             MetacatReplication.replLog("Success fully to insert new publicid "+
691
                               (String)v.elementAt(3) + " from server"+server);
692
             MetaCatUtil.debugMessage("Success fully to insert new publicid "+
693
                             (String)v.elementAt(3) + " from server" +server, 30);
694
           }
695
        }
696
        catch(Exception e)
697
        {
698
           MetacatReplication.replErrorLog("Failed to update catalog for server "+
699
                                    server + " because " +e.getMessage());
700
           MetaCatUtil.debugMessage("Failed to update catalog for server "+
701
                                    server + " because " +e.getMessage(), 30);
702
        }//catch
703
        finally
704
        {
705
           DBConnectionPool.returnDBConnection(dbConn, serialNumber);
706
        }//finall
707
      }//for remote catalog
708
    }//for server list
709
    MetaCatUtil.debugMessage("End of updateCatalog", 35);
710
  }
711

    
712
  /**
713
   * Method that returns true if docid has already been "deleted" from metacat.
714
   * This method really implements a truth table for deleted documents
715
   * The table is (a docid in one of the tables is represented by the X):
716
   * xml_docs      xml_revs      deleted?
717
   * ------------------------------------
718
   *   X             X             FALSE
719
   *   X             _             FALSE
720
   *   _             X             TRUE
721
   *   _             _             TRUE
722
   */
723
  private static boolean alreadyDeleted(String docid) throws Exception
724
  {
725
    DBConnection dbConn = null;
726
    int serialNumber = -1;
727
    PreparedStatement pstmt = null;
728
    try
729
    {
730
      dbConn=DBConnectionPool.
731
                  getDBConnection("ReplicationHandler.alreadyDeleted");
732
      serialNumber=dbConn.getCheckOutSerialNumber();
733
      boolean xml_docs = false;
734
      boolean xml_revs = false;
735

    
736
      StringBuffer sb = new StringBuffer();
737
      sb.append("select docid from xml_revisions where docid like '");
738
      sb.append(docid).append("'");
739
      pstmt = dbConn.prepareStatement(sb.toString());
740
      pstmt.execute();
741
      ResultSet rs = pstmt.getResultSet();
742
      boolean tablehasrows = rs.next();
743
      if(tablehasrows)
744
      {
745
        xml_revs = true;
746
      }
747

    
748
      sb = new StringBuffer();
749
      sb.append("select docid from xml_documents where docid like '");
750
      sb.append(docid).append("'");
751
      pstmt.close();
752
      pstmt = dbConn.prepareStatement(sb.toString());
753
      //increase usage count
754
      dbConn.increaseUsageCount(1);
755
      pstmt.execute();
756
      rs = pstmt.getResultSet();
757
      tablehasrows = rs.next();
758
      pstmt.close();
759
      if(tablehasrows)
760
      {
761
        xml_docs = true;
762
      }
763

    
764
      if(xml_docs && xml_revs)
765
      {
766
        return false;
767
      }
768
      else if(xml_docs && !xml_revs)
769
      {
770
        return false;
771
      }
772
      else if(!xml_docs && xml_revs)
773
      {
774
        return true;
775
      }
776
      else if(!xml_docs && !xml_revs)
777
      {
778
        return true;
779
      }
780
    }
781
    catch(Exception e)
782
    {
783
      MetaCatUtil.debugMessage("error in ReplicationHandler.alreadyDeleted: " +
784
                          e.getMessage(), 30);
785
      throw e;
786
    }
787
    finally
788
    {
789
      try
790
      {
791
        pstmt.close();
792
      }//try
793
      catch (SQLException ee)
794
      {
795
        MetaCatUtil.debugMessage("Error in replicationHandler.alreadyDeleted "+
796
                          "to close pstmt: "+ee.getMessage(), 30);
797
        throw ee;
798
      }//catch
799
      finally
800
      {
801
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
802
      }//finally
803
    }//finally
804
    return false;
805
  }
806

    
807

    
808
  /**
809
   * Method to initialize the message parser
810
   */
811
  public static XMLReader initParser(DefaultHandler dh)
812
          throws Exception
813
  {
814
    XMLReader parser = null;
815

    
816
    try {
817
      ContentHandler chandler = dh;
818

    
819
      // Get an instance of the parser
820
      MetaCatUtil util = new MetaCatUtil();
821
      String parserName = util.getOption("saxparser");
822
      parser = XMLReaderFactory.createXMLReader(parserName);
823

    
824
      // Turn off validation
825
      parser.setFeature("http://xml.org/sax/features/validation", false);
826

    
827
      parser.setContentHandler((ContentHandler)chandler);
828
      parser.setErrorHandler((ErrorHandler)chandler);
829

    
830
    } catch (Exception e) {
831
      throw e;
832
    }
833

    
834
    return parser;
835
  }
836

    
837
  /**
838
   * This method will combinate given time string(in short format) to
839
   * current date. If the given time (e.g 10:00 AM) passed the current time
840
   * (e.g 2:00 PM Aug 21, 2005), then the time will set to second day,
841
   * 10:00 AM Aug 22, 2005. If the given time (e.g 10:00 AM) haven't passed
842
   * the current time (e.g 8:00 AM Aug 21, 2005) The time will set to be
843
   * 10:00 AM Aug 21, 2005.
844
   * @param givenTime  the format should be "10:00 AM " or "2:00 PM"
845
   * @return
846
   * @throws Exception
847
   */
848
  public static Date combinateCurrentDateAndGivenTime(String givenTime) throws Exception
849
  {
850
     Date givenDate = parseTime(givenTime);
851
     Date newDate = null;
852
     Date now = new Date();
853
     String currentTimeString = getTimeString(now);
854
     Date currentTime = parseTime(currentTimeString); 
855
     if ( currentTime.getTime() >= givenDate.getTime())
856
     {
857
        MetaCatUtil.debugMessage("Today already pass the given time, we should set it as tomorrow", 30);
858
        String dateAndTime = getDateString(now) + " " + givenTime;
859
        Date combinationDate = parseDateTime(dateAndTime);
860
        // new date should plus 24 hours to make is the second day
861
        newDate = new Date(combinationDate.getTime()+24*3600*1000);
862
     }
863
     else
864
     {
865
         MetaCatUtil.debugMessage("Today haven't pass the given time, we should it as today", 2);
866
         String dateAndTime = getDateString(now) + " " + givenTime;
867
         newDate = parseDateTime(dateAndTime);
868
     }
869
     MetaCatUtil.debugMessage("final setting time is "+ newDate.toString(), 20);
870
     return newDate;
871
  }
872

    
873
  /*
874
   * parse a given string to Time in short format.
875
   * For example, given time is 10:00 AM, the date will be return as
876
   * Jan 1 1970, 10:00 AM
877
   */
878
  private static Date parseTime(String timeString) throws Exception
879
  {
880
    DateFormat format = DateFormat.getTimeInstance(DateFormat.SHORT);
881
    Date time = format.parse(timeString); 
882
    System.out.println("Date string is after parse a time string "+time.toString());
883
    return time;
884

    
885
  }
886
  
887
  /*
888
   * Pasre a given string to date and time. Date format is long and time
889
   * format is short.
890
   */
891
  private static Date parseDateTime(String timeString) throws Exception
892
  {
893
    DateFormat format = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT);
894
    Date time = format.parse(timeString);
895
    System.out.println("Date string is after parse a time string "+time.toString());
896
    return time;
897
  }
898
  
899
  /*
900
   * Get a date string from a Date object. The date format will be long
901
   */
902
  private static String getDateString(Date now)
903
  {
904
     DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
905
     String s = df.format(now);
906
     System.out.println("Today is " + s);
907
     return s;
908
  }
909
  
910
  /*
911
   * Get a time string from a Date object, the time format will be short
912
   */
913
  private static String getTimeString(Date now)
914
  {
915
     DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
916
     String s = df.format(now);
917
     System.out.println("Time is " + s);
918
     return s;
919
  }
920
  
921
  
922
  /*
923
   * This method will go through the docid list both in xml_Documents table
924
   * and in xml_revisions table
925
   * @author tao
926
   */
927
   private void handleDocList(Vector docList, String tableName)
928
   {
929
       boolean dataFile=false;
930
       for(int j=0; j<docList.size(); j++)
931
       {
932
         //initial dataFile is false
933
         dataFile=false;
934
         //w is information for one document, information contain
935
         //docid, rev, server or datafile.
936
         Vector w = new Vector((Vector)(docList.elementAt(j)));
937
         //Check if the vector w contain "datafile"
938
         //If it has, this document is data file
939
         if (w.contains((String)util.getOption("datafileflag")))
940
         {
941
           dataFile=true;
942
         }
943
         //System.out.println("w: " + w.toString());
944
         // Get docid
945
         String docid = (String)w.elementAt(0);
946
         MetaCatUtil.debugMessage("docid: " + docid, 40);
947
         // Get revision number
948
         int rev = Integer.parseInt((String)w.elementAt(1));
949
         MetaCatUtil.debugMessage("rev: " + rev, 40);
950
         // Get remote server name (it is may not be doc homeserver because
951
         // the new hub feature
952
         String remoteServer = (String)w.elementAt(2);
953
         remoteServer = remoteServer.trim();
954

    
955
         try
956
         {
957
             if (tableName.equals(DocumentImpl.DOCUMENTTABLE))
958
             {
959
                 handleDocInXMLDocuments(docid, rev, remoteServer, dataFile);
960
             }
961
             else if (tableName.equals(DocumentImpl.REVISIONTABLE))
962
             {
963
                 handleDocInXMLRevisions(docid, rev, remoteServer, dataFile);
964
             }
965
             else
966
             {
967
                 continue;
968
             }
969
                 
970
         }
971
         catch (Exception e)
972
         {
973
             MetaCatUtil.debugMessage("error to handle update doc in "+ 
974
                     tableName +" in time replication"+e.getMessage(), 30);
975
             continue;
976
         }
977
        
978
       }//for update docs
979

    
980
   }
981
   
982
   /*
983
    * This method will handle doc in xml_documents table.
984
    */
985
   private void handleDocInXMLDocuments(String docid, int rev, String remoteServer, boolean dataFile) 
986
                                        throws Exception
987
   {
988
       // compare the update rev and local rev to see what need happen
989
       int localrev = -1;
990
       String action = null;
991
       boolean flag = false;
992
       try
993
       {
994
         localrev = DBUtil.getLatestRevisionInDocumentTable(docid);
995
       }
996
       catch (SQLException e)
997
       {
998
         MetaCatUtil.debugMessage("Local rev for docid "+ docid + " could not "+
999
                                " be found because " + e.getMessage(), 45);
1000
         MetacatReplication.replErrorLog("Docid "+ docid + " could not be "+
1001
                 "written because error happend to find it's local revision");
1002
         throw new Exception (e.getMessage());
1003
       }
1004
       MetaCatUtil.debugMessage("Local rev for docid "+ docid + " is "+
1005
                               localrev, 45);
1006

    
1007
       //check the revs for an update because this document is in the
1008
       //local DB, it might be out of date.
1009
       if (localrev == -1)
1010
       {
1011
         //insert this document as new because it is not in the local DB
1012
         action = "INSERT";
1013
         flag = true;
1014
       }
1015
       else
1016
       {
1017
         if(localrev == rev)
1018
         {
1019
           // Local meatacat has the same rev to remote host, don't need
1020
           // update and flag set false
1021
           flag = false;
1022
         }
1023
         else if(localrev < rev)
1024
         {
1025
           //this document needs to be updated so send an read request
1026
           action = "UPDATE";
1027
           flag = true;
1028
         }
1029
       }
1030
       
1031
       String accNumber = docid + MetaCatUtil.getOption("accNumSeparator") + rev;
1032
       // this is non-data file
1033
       if(flag && !dataFile)
1034
       {
1035
         try
1036
         {
1037
           handleSingleXMLDocument(remoteServer, action, accNumber, DocumentImpl.DOCUMENTTABLE);
1038
         }
1039
         catch(Exception e)
1040
         {
1041
           // skip this document
1042
           throw e;
1043
         }
1044
       }//if for non-data file
1045

    
1046
        // this is for data file
1047
       if(flag && dataFile)
1048
       {
1049
         try
1050
         {
1051
           handleSingleDataFile(remoteServer, action, accNumber, DocumentImpl.DOCUMENTTABLE);
1052
         }
1053
         catch(Exception e)
1054
         {
1055
           // skip this datafile
1056
           throw e;
1057
         }
1058

    
1059
       }//for datafile
1060
   }
1061
   
1062
   /*
1063
    * This method will handle doc in xml_documents table.
1064
    */
1065
   private void handleDocInXMLRevisions(String docid, int rev, String remoteServer, boolean dataFile) 
1066
                                        throws Exception
1067
   {
1068
       // compare the update rev and local rev to see what need happen
1069
       System.out.println("In handle repliation revsion table");
1070
       System.out.println("the docid is "+ docid);
1071
       System.out.println("The rev is "+rev);
1072
       Vector localrev = null;
1073
       String action = "INSERT";
1074
       boolean flag = false;
1075
       try
1076
       {
1077
         localrev = DBUtil.getRevListFromRevisionTable(docid);
1078
       }
1079
       catch (SQLException e)
1080
       {
1081
         MetaCatUtil.debugMessage("Local rev for docid "+ docid + " could not "+
1082
                                " be found because " + e.getMessage(), 45);
1083
         MetacatReplication.replErrorLog("Docid "+ docid + " could not be "+
1084
                 "written because error happend to find it's local revision");
1085
         throw new Exception (e.getMessage());
1086
       }
1087
       MetaCatUtil.debugMessage("rev list in xml_revision table for docid "+ docid + " is "+
1088
                               localrev.toString(), 45);
1089
       
1090
       // if the rev is not in the xml_revision, we need insert it
1091
       if (!localrev.contains(new Integer(rev)))
1092
       {
1093
           flag = true;    
1094
       }
1095
     
1096
       String accNumber = docid + MetaCatUtil.getOption("accNumSeparator") + rev;
1097
       // this is non-data file
1098
       if(flag && !dataFile)
1099
       {
1100
         try
1101
         {
1102
           
1103
           handleSingleXMLDocument(remoteServer, action, accNumber, DocumentImpl.REVISIONTABLE);
1104
         }
1105
         catch(Exception e)
1106
         {
1107
           // skip this document
1108
           throw e;
1109
         }
1110
       }//if for non-data file
1111

    
1112
        // this is for data file
1113
       if(flag && dataFile)
1114
       {
1115
         try
1116
         {
1117
           handleSingleDataFile(remoteServer, action, accNumber, DocumentImpl.REVISIONTABLE);
1118
         }
1119
         catch(Exception e)
1120
         {
1121
           // skip this datafile
1122
           throw e;
1123
         }
1124

    
1125
       }//for datafile
1126
   }
1127
  
1128
}
1129

    
(57-57/63)