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 10:49:20 -0700 (Thu, 08 Sep 2005) $'
11
 * '$Revision: 2573 $'
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();
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

    
257

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

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

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

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

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

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

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

    
360
  }//update
361

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

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

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

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

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

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

    
461

    
462

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

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

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

    
503

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

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

    
548

    
549

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

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

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

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

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

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

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

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

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

    
655

    
656

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

    
668

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

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

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

    
704
        String localcatxml = MetacatReplication.getCatalogXML();
705

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

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

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

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

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

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

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

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

    
890

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

    
899
    try {
900
      ContentHandler chandler = dh;
901

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

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

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

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

    
917
    return parser;
918
  }
919

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

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

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

    
(57-57/63)