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: 2004-09-16 17:04:08 -0700 (Thu, 16 Sep 2004) $'
11
 * '$Revision: 2298 $'
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.lang.Thread;
34
import java.io.*;
35
import java.net.*;
36
import java.text.*;
37
import org.xml.sax.AttributeList;
38
import org.xml.sax.ContentHandler;
39
import org.xml.sax.DTDHandler;
40
import org.xml.sax.EntityResolver;
41
import org.xml.sax.ErrorHandler;
42
import org.xml.sax.InputSource;
43
import org.xml.sax.XMLReader;
44
import org.xml.sax.SAXException;
45
import org.xml.sax.SAXParseException;
46
import org.xml.sax.helpers.XMLReaderFactory;
47
import org.xml.sax.helpers.DefaultHandler;
48

    
49

    
50

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

    
64
  public ReplicationHandler(PrintWriter o)
65
  {
66
    this.out = o;
67
    serverList = new ReplicationServerList();
68
  }
69

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

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

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

    
124
    ReplicationServer replServer = null; // Variable to store the
125
                                        // ReplicationServer got from
126
                                        // Server list
127
    String server = null; // Variable to store server name
128
    String update;
129
    ReplMessageHandler message = new ReplMessageHandler();
130
    Vector responses = new Vector();
131
    boolean flag=false; // If a document need to update
132
    boolean dataFile=false;
133
    String action = new String();
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();
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
        for(int j=0; j<updateList.size(); j++)
233
        {
234
          //initial dataFile is false
235
          dataFile=false;
236
          //w is information for one document, information contain
237
          //docid, rev, server or datafile.
238
          Vector w = new Vector((Vector)(updateList.elementAt(j)));
239
          //Check if the vector w contain "datafile"
240
          //If it has, this document is data file
241
          if (w.contains((String)util.getOption("datafileflag")))
242
          {
243
            dataFile=true;
244
          }
245
          //System.out.println("w: " + w.toString());
246
          // Get docid
247
          String docid = (String)w.elementAt(0);
248
          MetaCatUtil.debugMessage("docid: " + docid, 40);
249
          // Get revision number
250
          int rev = Integer.parseInt((String)w.elementAt(1));
251
          MetaCatUtil.debugMessage("rev: " + rev, 40);
252
          // Get remote server name (it is may not be doc homeserver because
253
          // the new hub feature
254
          String remoteServer = (String)w.elementAt(2);
255

    
256

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

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

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

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

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

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

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

    
359
  }//update
360

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

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

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

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

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

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

    
460

    
461

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

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

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

    
502

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

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

    
547

    
548

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

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

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

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

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

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

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

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

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

    
654

    
655

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

    
667

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

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

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

    
703
        String localcatxml = MetacatReplication.getCatalogXML();
704

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

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

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

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

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

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

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

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

    
889

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

    
898
    try {
899
      ContentHandler chandler = dh;
900

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

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

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

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

    
916
    return parser;
917
  }
918

    
919

    
920
}
921

    
(57-57/63)