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-09-08 16:02:28 -0700 (Thu, 08 Sep 2005) $'
11
 * '$Revision: 2578 $'
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
  public ReplicationHandler()
66
  {
67
    //this.out = o;
68
    serverList = new ReplicationServerList();
69
  }
70

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

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

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

    
125
    ReplicationServer replServer = null; // Variable to store the
126
                                        // ReplicationServer got from
127
                                        // Server list
128
    String server = null; // Variable to store server name
129
    String update;
130
    ReplMessageHandler message = new ReplMessageHandler();
131
    Vector responses = new Vector();
132
    boolean flag=false; // If a document need to update
133
    boolean dataFile=false;
134
    String action = new String();
135
    XMLReader parser;
136
    URL u;
137

    
138

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

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

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

    
204

    
205
    MetaCatUtil.debugMessage("Responses from remote metacat about updated "+
206
                   "document information: "+ responses.toString(), 35);
207
    // go through response vector(it contains updated vector and delete vector
208
    for(int i=0; i<responses.size(); i++)
209
    {
210
        try
211
        {
212
          parser.parse(new InputSource(
213
                     new StringReader(
214
                     (String)(responses.elementAt(i)))));
215
        }
216
        catch(Exception e)
217
        {
218
          MetacatReplication.replErrorLog("Couldn't parse one responses "+
219
                           "because "+ e.getMessage());
220
          MetaCatUtil.debugMessage("Couldn't parse one responses "+
221
                                   "because "+ e.getMessage(), 30);
222
          continue;
223
        }
224
        //v is the list of updated documents
225
        Vector updateList = new Vector(message.getUpdatesVect());
226
        //System.out.println("v: " + v.toString());
227
        //d is the list of deleted documents
228
        Vector deleteList = new Vector(message.getDeletesVect());
229
        //System.out.println("d: " + d.toString());
230
        MetaCatUtil.debugMessage("Update vector size: "+ updateList.size(), 40);
231
        MetaCatUtil.debugMessage("Delete vector size: "+ deleteList.size(),40);
232
        // go though every element in updated document vector
233
        for(int j=0; j<updateList.size(); j++)
234
        {
235
          //initial dataFile is false
236
          dataFile=false;
237
          //w is information for one document, information contain
238
          //docid, rev, server or datafile.
239
          Vector w = new Vector((Vector)(updateList.elementAt(j)));
240
          //Check if the vector w contain "datafile"
241
          //If it has, this document is data file
242
          if (w.contains((String)util.getOption("datafileflag")))
243
          {
244
            dataFile=true;
245
          }
246
          //System.out.println("w: " + w.toString());
247
          // Get docid
248
          String docid = (String)w.elementAt(0);
249
          MetaCatUtil.debugMessage("docid: " + docid, 40);
250
          // Get revision number
251
          int rev = Integer.parseInt((String)w.elementAt(1));
252
          MetaCatUtil.debugMessage("rev: " + rev, 40);
253
          // Get remote server name (it is may not be doc homeserver because
254
          // the new hub feature
255
          String remoteServer = (String)w.elementAt(2);
256
          remoteServer = remoteServer.trim();
257

    
258

    
259
          // compare the update rev and local rev to see what need happen
260
          int localrev = -1;
261
          try
262
          {
263
            localrev = DocumentImpl.getLatestRevisionNumber(docid);
264
          }
265
          catch (SQLException e)
266
          {
267
            MetaCatUtil.debugMessage("Local rev for docid "+ docid + " could not "+
268
                                   " be found because " + e.getMessage(), 45);
269
            MetacatReplication.replErrorLog("Docid "+ docid + " could not be "+
270
                    "written because error happend to find it's local revision");
271
            continue;
272
          }
273
          MetaCatUtil.debugMessage("Local rev for docid "+ docid + " is "+
274
                                  localrev, 45);
275

    
276
          //check the revs for an update because this document is in the
277
          //local DB, it might be out of date.
278
          if (localrev == -1)
279
          {
280
            //insert this document as new because it is not in the local DB
281
            action = "INSERT";
282
            flag = true;
283
          }
284
          else
285
          {
286
            if(localrev == rev)
287
            {
288
              // Local meatacat has the same rev to remote host, don't need
289
              // update and flag set false
290
              flag = false;
291
            }
292
            else if(localrev < rev)
293
            {
294
              //this document needs to be updated so send an read request
295
              action = "UPDATE";
296
              flag = true;
297
            }
298
          }
299

    
300
          // this is non-data file
301
          if(flag && !dataFile)
302
          {
303
            try
304
            {
305
              handleSingleXMLDocument(remoteServer, action, docid);
306
            }
307
            catch(Exception e)
308
            {
309
              // skip this document
310
              continue;
311
            }
312
          }//if for non-data file
313

    
314
           // this is for data file
315
          if(flag && dataFile)
316
          {
317
            try
318
            {
319
              handleSingleDataFile(remoteServer, action, docid);
320
            }
321
            catch(Exception e)
322
            {
323
              // skip this datafile
324
              continue;
325
            }
326

    
327
          }//for datafile
328
        }//for update docs
329

    
330
        //handle deleted docs
331
        for(int k=0; k<deleteList.size(); k++)
332
        { //delete the deleted documents;
333
          Vector w = new Vector((Vector)deleteList.elementAt(k));
334
          String docId = (String)w.elementAt(0);
335
          try
336
          {
337
            handleDeleteSingleDocument(docId, server);
338
          }
339
          catch (Exception ee)
340
          {
341
            continue;
342
          }
343
        }//for delete docs
344
    }//for response
345

    
346
    //updated last_checked
347
    for (int i=0;i<serverList.size(); i++)
348
    {
349
       // Get ReplicationServer object from server list
350
       replServer = serverList.serverAt(i);
351
       try
352
       {
353
         updateLastCheckTimeForSingleServer(replServer);
354
       }
355
       catch(Exception e)
356
       {
357
         continue;
358
       }
359
    }//for
360

    
361
  }//update
362

    
363
  /* Handle replicate single xml document*/
364
  private void handleSingleXMLDocument(String remoteserver, String actions,
365
                                       String docId)
366
               throws Exception
367
  {
368
    DBConnection dbConn = null;
369
    int serialNumber = -1;
370
    try
371
    {
372
      // Get DBConnection from pool
373
      dbConn=DBConnectionPool.
374
                  getDBConnection("ReplicationHandler.handleSingleXMLDocument");
375
      serialNumber=dbConn.getCheckOutSerialNumber();
376
      //if the document needs to be updated or inserted, this is executed
377
      String readDocURLString = "https://" + remoteserver + "?server="+
378
              util.getLocalReplicationServerName()+"&action=read&docid="+docId;
379
      readDocURLString = MetaCatUtil.replaceWhiteSpaceForURL(readDocURLString);
380
      URL u = new URL(readDocURLString);
381

    
382
      // Get docid content
383
      String newxmldoc = MetacatReplication.getURLContent(u);
384
      // If couldn't get skip it
385
      if ( newxmldoc.indexOf("<error>")!= -1 && newxmldoc.indexOf("</error>")!=-1)
386
      {
387
         throw new Exception(newxmldoc);
388
      }
389
      MetaCatUtil.debugMessage("xml documnet:", 45);
390
      MetaCatUtil.debugMessage(newxmldoc, 45);
391

    
392
      // Try get the docid info from remote server
393
      DocInfoHandler dih = new DocInfoHandler();
394
      XMLReader docinfoParser = initParser(dih);
395
      String docInfoURLStr = "https://" + remoteserver +
396
                       "?server="+util.getLocalReplicationServerName()+
397
                       "&action=getdocumentinfo&docid="+docId;
398
      docInfoURLStr = MetaCatUtil.replaceWhiteSpaceForURL(docInfoURLStr);
399
      URL docinfoUrl = new URL(docInfoURLStr);
400
      MetaCatUtil.debugMessage("Sending message: " +
401
                                                  docinfoUrl.toString(), 45);
402
      String docInfoStr = MetacatReplication.getURLContent(docinfoUrl);
403
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
404
      Hashtable docinfoHash = dih.getDocInfo();
405
      // Get home server of the docid
406
      String docHomeServer = (String)docinfoHash.get("home_server");
407
      MetaCatUtil.debugMessage("doc home server in repl: "+docHomeServer, 45);
408

    
409
      //docid should include rev number too
410
      String accnum=docId+util.getOption("accNumSeparator")+
411
                                              (String)docinfoHash.get("rev");
412
      MetaCatUtil.debugMessage("docid in repl: "+accnum, 45);
413
      String docType = (String)docinfoHash.get("doctype");
414
      MetaCatUtil.debugMessage("doctype in repl: "+docType, 45);
415

    
416
      String parserBase = null;
417
      // this for eml2 and we need user eml2 parser
418
      if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE))
419
      {
420
         parserBase = DocumentImpl.EML200;
421
      }
422
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE))
423
      {
424
        parserBase = DocumentImpl.EML200;
425
      }
426
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE))
427
      {
428
        parserBase = DocumentImpl.EML210;
429
      }
430
      // Write the document into local host
431
      DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false);
432
      String newDocid = wrapper.writeReplication(dbConn,
433
                              new StringReader(newxmldoc),
434
                              (String)docinfoHash.get("public_access"),
435
                              null,  /* the dtd text */
436
                              actions,
437
                              accnum,
438
                              (String)docinfoHash.get("user_owner"),
439
                              null, /* null for groups[] */
440
                              docHomeServer,
441
                              remoteserver);
442
      MetaCatUtil.debugMessage("Successfully replicated doc " + accnum, 35);
443
      MetacatReplication.replLog("wrote doc " + accnum + " from " +
444
                                         remoteserver);
445

    
446
    }//try
447
    catch(Exception e)
448
    {
449
      MetacatReplication.replErrorLog("Failed to write doc " + docId +
450
                                      " into db because " +e.getMessage());
451
      MetaCatUtil.debugMessage("Failed to write doc " + docId +
452
                                      " into db because " +e.getMessage(), 30);
453
      throw e;
454
    }
455
    finally
456
    {
457
       //return DBConnection
458
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
459
    }//finally
460
  }
461

    
462

    
463

    
464
  /* Handle replicate single xml document*/
465
  private void handleSingleDataFile(String remoteserver, String actions,
466
                                    String docId)
467
               throws Exception
468
  {
469
    MetaCatUtil.debugMessage("Try to replicate data file: "+docId, 40);
470
    DBConnection dbConn = null;
471
    int serialNumber = -1;
472
    try
473
    {
474
      // Get DBConnection from pool
475
      dbConn=DBConnectionPool.
476
                  getDBConnection("ReplicationHandler.handleSinlgeDataFile");
477
      serialNumber=dbConn.getCheckOutSerialNumber();
478
      // Try get docid info from remote server
479
      DocInfoHandler dih = new DocInfoHandler();
480
      XMLReader docinfoParser = initParser(dih);
481
      String docInfoURLString = "https://" + remoteserver +
482
                  "?server="+util.getLocalReplicationServerName()+
483
                  "&action=getdocumentinfo&docid="+docId;
484
      docInfoURLString = MetaCatUtil.replaceWhiteSpaceForURL(docInfoURLString);
485
      URL docinfoUrl = new URL(docInfoURLString);
486

    
487
      String docInfoStr = MetacatReplication.getURLContent(docinfoUrl);
488
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
489
      Hashtable docinfoHash = dih.getDocInfo();
490
      // Get doicd owner
491
      String user = (String)docinfoHash.get("user_owner");
492
      // Get docid name (such as acl or dataset)
493
      String docName = (String)docinfoHash.get("docname");
494
      // Get doc type (eml public id)
495
      String docType = (String)docinfoHash.get("doctype");
496
      // Get docid home sever. it might be different to remoteserver
497
      // becuause of hub feature
498
      String docHomeServer = (String)docinfoHash.get("home_server");
499

    
500
      //docid should include rev number too
501
      String accnum=docId+util.getOption("accNumSeparator")+
502
                                              (String)docinfoHash.get("rev");
503

    
504

    
505
      String datafilePath = util.getOption("datafilepath");
506
      // Get data file content
507
      String readDataURLString = "https://" + remoteserver + "?server="+
508
                                        util.getLocalReplicationServerName()+
509
                                            "&action=readdata&docid="+accnum;
510
      readDataURLString = MetaCatUtil.replaceWhiteSpaceForURL(readDataURLString);
511
      URL u = new URL(readDataURLString);
512
      InputStream input = u.openStream();
513
      //register data file into xml_documents table and wite data file
514
      //into file system
515
      if ( input != null)
516
      {
517
        DocumentImpl.writeDataFileInReplication(input,
518
                                                        datafilePath,
519
                                                        docName,docType,
520
                                                        accnum, user,
521
                                                        docHomeServer,
522
                                                        remoteserver);
523
        MetaCatUtil.debugMessage("Successfully to write datafile " + docId, 30);
524
        MetacatReplication.replLog("wrote datafile " + accnum + " from " +
525
                                    remoteserver);
526
      }//if
527
      else
528
      {
529
         MetaCatUtil.debugMessage("Couldn't open the data file: " + accnum, 30);
530
         throw new Exception("Couldn't open the data file: " + accnum);
531
      }//else
532

    
533
    }//try
534
    catch(Exception e)
535
    {
536
      MetacatReplication.replErrorLog("Failed to try wrote datafile " + docId +
537
                                      " because " +e.getMessage());
538
      MetaCatUtil.debugMessage("Failed to try wrote datafile " + docId +
539
                                      " because " +e.getMessage(), 30);
540
      throw e;
541
    }
542
    finally
543
    {
544
       //return DBConnection
545
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
546
    }//finally
547
  }
548

    
549

    
550

    
551
  /* Handle delete single document*/
552
  private void handleDeleteSingleDocument(String docId, String notifyServer)
553
               throws Exception
554
  {
555
    MetaCatUtil.debugMessage("Try delete doc: "+docId, 40);
556
    DBConnection dbConn = null;
557
    int serialNumber = -1;
558
    try
559
    {
560
      // Get DBConnection from pool
561
      dbConn=DBConnectionPool.
562
                  getDBConnection("ReplicationHandler.handleDeleteSingleDoc");
563
      serialNumber=dbConn.getCheckOutSerialNumber();
564
      if(!alreadyDeleted(docId))
565
      {
566

    
567
         //because delete method docid should have rev number
568
         //so we just add one for it. This rev number is no sence.
569
         String accnum=docId+util.getOption("accNumSeparator")+"1";
570
         //System.out.println("accnum: "+accnum);
571
         DocumentImpl.delete(accnum, null, null, notifyServer);
572
         MetaCatUtil.debugMessage("Successfully deleted doc " + docId, 30);
573
         MetacatReplication.replLog("Doc " + docId + " deleted");
574
      }
575

    
576
    }//try
577
    catch(Exception e)
578
    {
579
      MetacatReplication.replErrorLog("Failed to delete doc " + docId +
580
                                      " in db because " +e.getMessage());
581
      MetaCatUtil.debugMessage("Failed to delete doc " + docId +
582
                                 " in db because because " +e.getMessage(), 30);
583
      throw e;
584
    }
585
    finally
586
    {
587
       //return DBConnection
588
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
589
    }//finally
590
  }
591

    
592
  /* Handle updateLastCheckTimForSingleServer*/
593
  private void updateLastCheckTimeForSingleServer(ReplicationServer repServer)
594
                                                  throws Exception
595
  {
596
    String server = repServer.getServerName();
597
    DBConnection dbConn = null;
598
    int serialNumber = -1;
599
    PreparedStatement pstmt = null;
600
    try
601
    {
602
      // Get DBConnection from pool
603
      dbConn=DBConnectionPool.
604
             getDBConnection("ReplicationHandler.updateLastCheckTimeForServer");
605
      serialNumber=dbConn.getCheckOutSerialNumber();
606

    
607
      MetaCatUtil.debugMessage("Try to update last_check for server: "+server, 40);
608
      // Get time from remote server
609
      URL dateurl = new URL("https://" + server + "?server="+
610
      util.getLocalReplicationServerName()+"&action=gettime");
611
      String datexml = MetacatReplication.getURLContent(dateurl);
612
      MetaCatUtil.debugMessage("datexml: "+datexml, 45);
613
      if (datexml!=null && !datexml.equals(""))
614
      {
615
         String datestr = datexml.substring(11, datexml.indexOf('<', 11));
616
         StringBuffer sql = new StringBuffer();
617
         /*sql.append("update xml_replication set last_checked = to_date('");
618
         sql.append(datestr).append("', 'YY-MM-DD HH24:MI:SS') where ");
619
         sql.append("server like '").append(server).append("'");*/
620
         sql.append("update xml_replication set last_checked = ");
621
         sql.append(dbAdapter.toDate(datestr, "MM/DD/YY HH24:MI:SS"));
622
         sql.append(" where server like '").append(server).append("'");
623
         pstmt = dbConn.prepareStatement(sql.toString());
624

    
625
         pstmt.executeUpdate();
626
         dbConn.commit();
627
         pstmt.close();
628
         MetaCatUtil.debugMessage("last_checked updated to "+datestr+" on "
629
                                      + server, 45);
630
      }//if
631
      else
632
      {
633

    
634
         MetaCatUtil.debugMessage("Failed to update last_checked for server "  +
635
                                  server + " in db because couldn't get time "
636
                                  , 30);
637
         throw new Exception("Couldn't get time for server "+ server);
638
      }
639

    
640
    }//try
641
    catch(Exception e)
642
    {
643

    
644
      MetaCatUtil.debugMessage("Failed to update last_checked for server " +
645
                                server + " in db because because " +
646
                                e.getMessage(), 30);
647
      throw e;
648
    }
649
    finally
650
    {
651
       //return DBConnection
652
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
653
    }//finally
654
  }
655

    
656

    
657

    
658
  /**
659
   * updates xml_catalog with entries from other servers.
660
   */
661
  private void updateCatalog()
662
  {
663
    MetaCatUtil.debugMessage("Start of updateCatalog", 35 );
664
    // ReplicationServer object in server list
665
    ReplicationServer replServer = null;
666
    PreparedStatement pstmt = null;
667
    String server = null;
668

    
669

    
670
    // Go through each ReplicationServer object in sererlist
671
    for (int j=0; j<serverList.size(); j++)
672
    {
673
      Vector remoteCatalog = new Vector();
674
      Vector publicId = new Vector();
675
      try
676
      {
677
        // Get ReplicationServer object from server list
678
        replServer = serverList.serverAt(j);
679
        // Get server name from the ReplicationServer object
680
        server = replServer.getServerName();
681
        // Try to get catalog
682
        URL u = new URL("https://" + server + "?server="+
683
        util.getLocalReplicationServerName()+"&action=getcatalog");
684
        MetaCatUtil.debugMessage("sending message " + u.toString(), 50);
685
        String catxml = MetacatReplication.getURLContent(u);
686

    
687
        // Make sure there are not error, no empty string
688
        if (catxml.indexOf("error")!=-1 || catxml==null||catxml.equals(""))
689
        {
690
          throw new Exception("Couldn't get catalog list form server " +server);
691
        }
692
        MetaCatUtil.debugMessage("catxml: " + catxml, 40);
693
        CatalogMessageHandler cmh = new CatalogMessageHandler();
694
        XMLReader catparser = initParser(cmh);
695
        catparser.parse(new InputSource(new StringReader(catxml)));
696
        //parse the returned catalog xml and put it into a vector
697
        remoteCatalog = cmh.getCatalogVect();
698

    
699
        // Makse sure remoteCatalog is not empty
700
        if (remoteCatalog.isEmpty())
701
        {
702
          throw new Exception("Couldn't get catalog list form server " +server);
703
        }
704

    
705
        String localcatxml = MetacatReplication.getCatalogXML();
706

    
707
        // Make sure local catalog is no empty
708
        if (localcatxml==null||localcatxml.equals(""))
709
        {
710
          throw new Exception("Couldn't get catalog list form server " +server);
711
        }
712

    
713
        cmh = new CatalogMessageHandler();
714
        catparser = initParser(cmh);
715
        catparser.parse(new InputSource(new StringReader(localcatxml)));
716
        Vector localCatalog = cmh.getCatalogVect();
717

    
718
        //now we have the catalog from the remote server and this local server
719
        //we now need to compare the two and merge the differences.
720
        //the comparison is base on the public_id fields which is the 4th
721
        //entry in each row vector.
722
        publicId = new Vector();
723
        for(int i=0; i<localCatalog.size(); i++)
724
        {
725
          Vector v = new Vector((Vector)localCatalog.elementAt(i));
726
          MetaCatUtil.debugMessage("v1: " + v.toString(), 50);
727
          publicId.add(new String((String)v.elementAt(3)));
728
          //System.out.println("adding " + (String)v.elementAt(3));
729
        }
730
      }//try
731
      catch (Exception e)
732
      {
733
        MetacatReplication.replErrorLog("Failed to update catalog for server "+
734
                                    server + " because " +e.getMessage());
735
        MetaCatUtil.debugMessage("Failed to update catalog for server "+
736
                                    server + " because " +e.getMessage(), 30);
737
      }//catch
738

    
739
      for(int i=0; i<remoteCatalog.size(); i++)
740
      {
741
         // DConnection
742
        DBConnection dbConn = null;
743
        // DBConnection checkout serial number
744
        int serialNumber = -1;
745
        try
746
        {
747
            dbConn=DBConnectionPool.
748
                  getDBConnection("ReplicationHandler.updateCatalog");
749
            serialNumber=dbConn.getCheckOutSerialNumber();
750
            Vector v = (Vector)remoteCatalog.elementAt(i);
751
            //System.out.println("v2: " + v.toString());
752
            //System.out.println("i: " + i);
753
            //System.out.println("remoteCatalog.size(): " + remoteCatalog.size());
754
            //System.out.println("publicID: " + publicId.toString());
755
            MetaCatUtil.debugMessage
756
                              ("v.elementAt(3): " + (String)v.elementAt(3), 50);
757
           if(!publicId.contains(v.elementAt(3)))
758
           { //so we don't have this public id in our local table so we need to
759
             //add it.
760
             //System.out.println("in if");
761
             StringBuffer sql = new StringBuffer();
762
             sql.append("insert into xml_catalog (entry_type, source_doctype, ");
763
             sql.append("target_doctype, public_id, system_id) values (?,?,?,");
764
             sql.append("?,?)");
765
             //System.out.println("sql: " + sql.toString());
766
             pstmt = dbConn.prepareStatement(sql.toString());
767
             pstmt.setString(1, (String)v.elementAt(0));
768
             pstmt.setString(2, (String)v.elementAt(1));
769
             pstmt.setString(3, (String)v.elementAt(2));
770
             pstmt.setString(4, (String)v.elementAt(3));
771
             pstmt.setString(5, (String)v.elementAt(4));
772
             pstmt.execute();
773
             pstmt.close();
774
             MetacatReplication.replLog("Success fully to insert new publicid "+
775
                               (String)v.elementAt(3) + " from server"+server);
776
             MetaCatUtil.debugMessage("Success fully to insert new publicid "+
777
                             (String)v.elementAt(3) + " from server" +server, 30);
778
           }
779
        }
780
        catch(Exception e)
781
        {
782
           MetacatReplication.replErrorLog("Failed to update catalog for server "+
783
                                    server + " because " +e.getMessage());
784
           MetaCatUtil.debugMessage("Failed to update catalog for server "+
785
                                    server + " because " +e.getMessage(), 30);
786
        }//catch
787
        finally
788
        {
789
           DBConnectionPool.returnDBConnection(dbConn, serialNumber);
790
        }//finall
791
      }//for remote catalog
792
    }//for server list
793
    MetaCatUtil.debugMessage("End of updateCatalog", 35);
794
  }
795

    
796
  /**
797
   * Method that returns true if docid has already been "deleted" from metacat.
798
   * This method really implements a truth table for deleted documents
799
   * The table is (a docid in one of the tables is represented by the X):
800
   * xml_docs      xml_revs      deleted?
801
   * ------------------------------------
802
   *   X             X             FALSE
803
   *   X             _             FALSE
804
   *   _             X             TRUE
805
   *   _             _             TRUE
806
   */
807
  private static boolean alreadyDeleted(String docid) throws Exception
808
  {
809
    DBConnection dbConn = null;
810
    int serialNumber = -1;
811
    PreparedStatement pstmt = null;
812
    try
813
    {
814
      dbConn=DBConnectionPool.
815
                  getDBConnection("ReplicationHandler.alreadyDeleted");
816
      serialNumber=dbConn.getCheckOutSerialNumber();
817
      boolean xml_docs = false;
818
      boolean xml_revs = false;
819

    
820
      StringBuffer sb = new StringBuffer();
821
      sb.append("select docid from xml_revisions where docid like '");
822
      sb.append(docid).append("'");
823
      pstmt = dbConn.prepareStatement(sb.toString());
824
      pstmt.execute();
825
      ResultSet rs = pstmt.getResultSet();
826
      boolean tablehasrows = rs.next();
827
      if(tablehasrows)
828
      {
829
        xml_revs = true;
830
      }
831

    
832
      sb = new StringBuffer();
833
      sb.append("select docid from xml_documents where docid like '");
834
      sb.append(docid).append("'");
835
      pstmt.close();
836
      pstmt = dbConn.prepareStatement(sb.toString());
837
      //increase usage count
838
      dbConn.increaseUsageCount(1);
839
      pstmt.execute();
840
      rs = pstmt.getResultSet();
841
      tablehasrows = rs.next();
842
      pstmt.close();
843
      if(tablehasrows)
844
      {
845
        xml_docs = true;
846
      }
847

    
848
      if(xml_docs && xml_revs)
849
      {
850
        return false;
851
      }
852
      else if(xml_docs && !xml_revs)
853
      {
854
        return false;
855
      }
856
      else if(!xml_docs && xml_revs)
857
      {
858
        return true;
859
      }
860
      else if(!xml_docs && !xml_revs)
861
      {
862
        return true;
863
      }
864
    }
865
    catch(Exception e)
866
    {
867
      MetaCatUtil.debugMessage("error in ReplicationHandler.alreadyDeleted: " +
868
                          e.getMessage(), 30);
869
      throw e;
870
    }
871
    finally
872
    {
873
      try
874
      {
875
        pstmt.close();
876
      }//try
877
      catch (SQLException ee)
878
      {
879
        MetaCatUtil.debugMessage("Error in replicationHandler.alreadyDeleted "+
880
                          "to close pstmt: "+ee.getMessage(), 30);
881
        throw ee;
882
      }//catch
883
      finally
884
      {
885
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
886
      }//finally
887
    }//finally
888
    return false;
889
  }
890

    
891

    
892
  /**
893
   * Method to initialize the message parser
894
   */
895
  public static XMLReader initParser(DefaultHandler dh)
896
          throws Exception
897
  {
898
    XMLReader parser = null;
899

    
900
    try {
901
      ContentHandler chandler = dh;
902

    
903
      // Get an instance of the parser
904
      MetaCatUtil util = new MetaCatUtil();
905
      String parserName = util.getOption("saxparser");
906
      parser = XMLReaderFactory.createXMLReader(parserName);
907

    
908
      // Turn off validation
909
      parser.setFeature("http://xml.org/sax/features/validation", false);
910

    
911
      parser.setContentHandler((ContentHandler)chandler);
912
      parser.setErrorHandler((ErrorHandler)chandler);
913

    
914
    } catch (Exception e) {
915
      throw e;
916
    }
917

    
918
    return parser;
919
  }
920

    
921
  /**
922
   * This method will combinate given time string(in short format) to
923
   * current date. If the given time (e.g 10:00 AM) passed the current time
924
   * (e.g 2:00 PM Aug 21, 2005), then the time will set to second day,
925
   * 10:00 AM Aug 22, 2005. If the given time (e.g 10:00 AM) haven't passed
926
   * the current time (e.g 8:00 AM Aug 21, 2005) The time will set to be
927
   * 10:00 AM Aug 21, 2005.
928
   * @param givenTime  the format should be "10:00 AM " or "2:00 PM"
929
   * @return
930
   * @throws Exception
931
   */
932
  public static Date combinateCurrentDateAndGivenTime(String givenTime) throws Exception
933
  {
934
     Date givenDate = parseTime(givenTime);
935
     Date newDate = null;
936
     Date now = new Date();
937
     String currentTimeString = getTimeString(now);
938
     Date currentTime = parseTime(currentTimeString); 
939
     if ( currentTime.getTime() >= givenDate.getTime())
940
     {
941
        MetaCatUtil.debugMessage("Today already pass the given time, we should set it as tomorrow", 30);
942
        String dateAndTime = getDateString(now) + " " + givenTime;
943
        Date combinationDate = parseDateTime(dateAndTime);
944
        // new date should plus 24 hours to make is the second day
945
        newDate = new Date(combinationDate.getTime()+24*3600*1000);
946
     }
947
     else
948
     {
949
         MetaCatUtil.debugMessage("Today haven't pass the given time, we should it as today", 2);
950
         String dateAndTime = getDateString(now) + " " + givenTime;
951
         newDate = parseDateTime(dateAndTime);
952
     }
953
     MetaCatUtil.debugMessage("final setting time is "+ newDate.toString(), 20);
954
     return newDate;
955
  }
956

    
957
  /*
958
   * parse a given string to Time in short format.
959
   * For example, given time is 10:00 AM, the date will be return as
960
   * Jan 1 1970, 10:00 AM
961
   */
962
  private static Date parseTime(String timeString) throws Exception
963
  {
964
    DateFormat format = DateFormat.getTimeInstance(DateFormat.SHORT);
965
    Date time = format.parse(timeString); 
966
    System.out.println("Date string is after parse a time string "+time.toString());
967
    return time;
968

    
969
  }
970
  
971
  /*
972
   * Pasre a given string to date and time. Date format is long and time
973
   * format is short.
974
   */
975
  private static Date parseDateTime(String timeString) throws Exception
976
  {
977
    DateFormat format = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT);
978
    Date time = format.parse(timeString);
979
    System.out.println("Date string is after parse a time string "+time.toString());
980
    return time;
981
  }
982
  
983
  /*
984
   * Get a date string from a Date object. The date format will be long
985
   */
986
  private static String getDateString(Date now)
987
  {
988
     DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
989
     String s = df.format(now);
990
     System.out.println("Today is " + s);
991
     return s;
992
  }
993
  
994
  /*
995
   * Get a time string from a Date object, the time format will be short
996
   */
997
  private static String getTimeString(Date now)
998
  {
999
     DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
1000
     String s = df.format(now);
1001
     System.out.println("Time is " + s);
1002
     return s;
1003
  }
1004
}
1005

    
(57-57/63)