Project

General

Profile

1 522 berkley
/**
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$'
10
 *     '$Date$'
11
 * '$Revision$'
12 669 jones
 *
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 522 berkley
 */
27 2286 tao
28 522 berkley
package edu.ucsb.nceas.metacat;
29
30 1751 tao
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
31 522 berkley
import java.sql.*;
32
import java.util.*;
33 2555 tao
import java.util.Date;
34 2286 tao
import java.lang.Thread;
35 522 berkley
import java.io.*;
36
import java.net.*;
37 543 berkley
import java.text.*;
38 522 berkley
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 561 berkley
import org.xml.sax.helpers.DefaultHandler;
49 522 berkley
50 561 berkley
51
52 522 berkley
/**
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 573 berkley
  int serverCheckCode = 1;
60 522 berkley
  MetaCatUtil util = new MetaCatUtil();
61 2286 tao
  ReplicationServerList serverList = null;
62 522 berkley
  PrintWriter out;
63 1751 tao
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
64 2286 tao
65 522 berkley
  public ReplicationHandler(PrintWriter o)
66
  {
67
    this.out = o;
68 1292 tao
    serverList = new ReplicationServerList();
69 522 berkley
  }
70 2286 tao
71 573 berkley
  public ReplicationHandler(PrintWriter o, int serverCheckCode)
72
  {
73
    this.out = o;
74
    this.serverCheckCode = serverCheckCode;
75 1292 tao
    serverList = new ReplicationServerList();
76 573 berkley
  }
77 2286 tao
78 522 berkley
  /**
79 2286 tao
   * Method that implements TimerTask.run().  It runs whenever the timer is
80 522 berkley
   * fired.
81
   */
82
  public void run()
83
  {
84
    //find out the last_checked time of each server in the server list and
85 2286 tao
    //send a query to each server to see if there are any documents in
86 522 berkley
    //xml_documents with an update_date > last_checked
87
    try
88
    {
89 1032 tao
      //if serverList is null, metacat don't need to replication
90
      if (serverList==null||serverList.isEmpty())
91
      {
92
        return;
93
      }
94 1292 tao
      updateCatalog();
95
      update();
96 1217 tao
      //conn.close();
97
    }//try
98 522 berkley
    catch (Exception e)
99
    {
100 1217 tao
      MetaCatUtil.debugMessage("Error in replicationHandler.run():"
101
                                                    +e.getMessage(), 30);
102 1292 tao
      e.printStackTrace();
103 1217 tao
    }//catch
104 522 berkley
  }
105 2286 tao
106 522 berkley
  /**
107 577 berkley
   * Method that uses revision taging for replication instead of update_date.
108
   */
109 1292 tao
  private void update()
110 577 berkley
  {
111
    /*
112
     Pseudo-algorithm
113
     - request a doc list from each server in xml_replication
114 2286 tao
     - check the rev number of each of those documents agains the
115 577 berkley
       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 2286 tao
       (this info is theoretically not needed using this system but probably
122 577 berkley
       should be kept anyway)
123
    */
124 2286 tao
125
    ReplicationServer replServer = null; // Variable to store the
126
                                        // ReplicationServer got from
127 1292 tao
                                        // Server list
128 2298 tao
    String server = null; // Variable to store server name
129 577 berkley
    String update;
130
    ReplMessageHandler message = new ReplMessageHandler();
131
    Vector responses = new Vector();
132 1292 tao
    boolean flag=false; // If a document need to update
133 1037 tao
    boolean dataFile=false;
134 577 berkley
    String action = new String();
135
    XMLReader parser;
136
    URL u;
137 2286 tao
138
139 577 berkley
    try
140
    {
141
      parser = initParser(message);
142 1585 tao
    }
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 1292 tao
        // Get ReplicationServer object from server list
157
        replServer = serverList.serverAt(i);
158
        // Get server name from ReplicationServer object
159
        server = replServer.getServerName();
160 1585 tao
        String result = null;
161 584 berkley
        MetacatReplication.replLog("full update started to: " + server);
162 1292 tao
        // Send command to that server to get updated docid information
163
        try
164
        {
165 1585 tao
          u = new URL("https://" + server + "?server="
166
          +util.getLocalReplicationServerName()+"&action=update");
167
          MetaCatUtil.debugMessage("Sending infomation " +u.toString(), 50);
168 1292 tao
          result = MetacatReplication.getURLContent(u);
169 1585 tao
        }
170 1292 tao
        catch (Exception e)
171
        {
172 1585 tao
          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 1292 tao
          continue;
177 1585 tao
        }
178 2286 tao
179 1292 tao
        MetaCatUtil.debugMessage("docid: "+server+" "+result, 50);
180
        //check if result have error or not, if has skip it.
181 1609 tao
        if (result.indexOf("<error>")!=-1 && result.indexOf("</error>")!=-1)
182 1102 tao
        {
183 1585 tao
          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 1102 tao
          continue;
188
        }
189 1585 tao
        //Add result to vector
190 577 berkley
        responses.add(result);
191 1585 tao
    }
192 2286 tao
193 1585 tao
    //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 1032 tao
        return;
202 1585 tao
    }
203 2286 tao
204
205 1585 tao
    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 2286 tao
    {
210 1585 tao
        try
211
        {
212
          parser.parse(new InputSource(
213 577 berkley
                     new StringReader(
214
                     (String)(responses.elementAt(i)))));
215 1585 tao
        }
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 1037 tao
        //v is the list of updated documents
225 1585 tao
        Vector updateList = new Vector(message.getUpdatesVect());
226 577 berkley
        //System.out.println("v: " + v.toString());
227 1037 tao
        //d is the list of deleted documents
228 1585 tao
        Vector deleteList = new Vector(message.getDeletesVect());
229 1037 tao
        //System.out.println("d: " + d.toString());
230 1585 tao
        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 577 berkley
        {
235 1037 tao
          //initial dataFile is false
236
          dataFile=false;
237
          //w is information for one document, information contain
238
          //docid, rev, server or datafile.
239 1585 tao
          Vector w = new Vector((Vector)(updateList.elementAt(j)));
240 1037 tao
          //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 577 berkley
          //System.out.println("w: " + w.toString());
247 1292 tao
          // Get docid
248 577 berkley
          String docid = (String)w.elementAt(0);
249 1071 tao
          MetaCatUtil.debugMessage("docid: " + docid, 40);
250 1292 tao
          // Get revision number
251 577 berkley
          int rev = Integer.parseInt((String)w.elementAt(1));
252 1071 tao
          MetaCatUtil.debugMessage("rev: " + rev, 40);
253 1292 tao
          // 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 2286 tao
257
258 1585 tao
          // 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 2286 tao
            MetaCatUtil.debugMessage("Local rev for docid "+ docid + " could not "+
267 1585 tao
                                   " 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 2286 tao
          MetaCatUtil.debugMessage("Local rev for docid "+ docid + " is "+
273 1585 tao
                                  localrev, 45);
274 2286 tao
275 1585 tao
          //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 577 berkley
            if(localrev == rev)
286
            {
287 2286 tao
              // Local meatacat has the same rev to remote host, don't need
288 1292 tao
              // update and flag set false
289 577 berkley
              flag = false;
290
            }
291
            else if(localrev < rev)
292 1585 tao
            {
293
              //this document needs to be updated so send an read request
294 577 berkley
              action = "UPDATE";
295
              flag = true;
296
            }
297
          }
298 2286 tao
299 1037 tao
          // this is non-data file
300
          if(flag && !dataFile)
301 2286 tao
          {
302 625 berkley
            try
303
            {
304 1585 tao
              handleSingleXMLDocument(remoteServer, action, docid);
305 625 berkley
            }
306
            catch(Exception e)
307
            {
308 1585 tao
              // skip this document
309
              continue;
310 625 berkley
            }
311 1037 tao
          }//if for non-data file
312 2286 tao
313 1292 tao
           // this is for data file
314
          if(flag && dataFile)
315 2286 tao
          {
316 1037 tao
            try
317
            {
318 1585 tao
              handleSingleDataFile(remoteServer, action, docid);
319
            }
320 1037 tao
            catch(Exception e)
321
            {
322 1585 tao
              // skip this datafile
323
              continue;
324
            }
325 2286 tao
326 1037 tao
          }//for datafile
327
        }//for update docs
328 2286 tao
329 1037 tao
        //handle deleted docs
330 1585 tao
        for(int k=0; k<deleteList.size(); k++)
331 577 berkley
        { //delete the deleted documents;
332 1585 tao
          Vector w = new Vector((Vector)deleteList.elementAt(k));
333
          String docId = (String)w.elementAt(0);
334
          try
335 579 berkley
          {
336 2298 tao
            handleDeleteSingleDocument(docId, server);
337 579 berkley
          }
338 1585 tao
          catch (Exception ee)
339
          {
340
            continue;
341
          }
342 1037 tao
        }//for delete docs
343 1585 tao
    }//for response
344 2286 tao
345 1585 tao
    //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 2286 tao
360 1585 tao
  }//update
361 2286 tao
362 1585 tao
  /* Handle replicate single xml document*/
363 2286 tao
  private void handleSingleXMLDocument(String remoteserver, String actions,
364
                                       String docId)
365 1585 tao
               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 1600 tao
      String readDocURLString = "https://" + remoteserver + "?server="+
377
              util.getLocalReplicationServerName()+"&action=read&docid="+docId;
378
      readDocURLString = MetaCatUtil.replaceWhiteSpaceForURL(readDocURLString);
379
      URL u = new URL(readDocURLString);
380 2286 tao
381 1585 tao
      // Get docid content
382
      String newxmldoc = MetacatReplication.getURLContent(u);
383
      // If couldn't get skip it
384 1609 tao
      if ( newxmldoc.indexOf("<error>")!= -1 && newxmldoc.indexOf("</error>")!=-1)
385 1292 tao
      {
386 1585 tao
         throw new Exception(newxmldoc);
387
      }
388
      MetaCatUtil.debugMessage("xml documnet:", 45);
389
      MetaCatUtil.debugMessage(newxmldoc, 45);
390 2286 tao
391 1585 tao
      // Try get the docid info from remote server
392
      DocInfoHandler dih = new DocInfoHandler();
393
      XMLReader docinfoParser = initParser(dih);
394 2286 tao
      String docInfoURLStr = "https://" + remoteserver +
395 1585 tao
                       "?server="+util.getLocalReplicationServerName()+
396 1600 tao
                       "&action=getdocumentinfo&docid="+docId;
397
      docInfoURLStr = MetaCatUtil.replaceWhiteSpaceForURL(docInfoURLStr);
398
      URL docinfoUrl = new URL(docInfoURLStr);
399 2286 tao
      MetaCatUtil.debugMessage("Sending message: " +
400 1585 tao
                                                  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 2286 tao
408 1585 tao
      //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 2286 tao
415 1585 tao
      String parserBase = null;
416
      // this for eml2 and we need user eml2 parser
417 2169 sgarg
      if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE))
418 1585 tao
      {
419 2163 tao
         parserBase = DocumentImpl.EML200;
420 1585 tao
      }
421 2286 tao
      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 1585 tao
      // Write the document into local host
430
      DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false);
431 2286 tao
      String newDocid = wrapper.writeReplication(dbConn,
432 1585 tao
                              new StringReader(newxmldoc),
433
                              (String)docinfoHash.get("public_access"),
434
                              null,  /* the dtd text */
435 2286 tao
                              actions,
436
                              accnum,
437 1585 tao
                              (String)docinfoHash.get("user_owner"),
438
                              null, /* null for groups[] */
439 2286 tao
                              docHomeServer,
440 1585 tao
                              remoteserver);
441
      MetaCatUtil.debugMessage("Successfully replicated doc " + accnum, 35);
442 2286 tao
      MetacatReplication.replLog("wrote doc " + accnum + " from " +
443 1585 tao
                                         remoteserver);
444 2286 tao
445
    }//try
446 577 berkley
    catch(Exception e)
447
    {
448 1585 tao
      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 577 berkley
    }
454 667 berkley
    finally
455
    {
456 1585 tao
       //return DBConnection
457
       DBConnectionPool.returnDBConnection(dbConn, serialNumber);
458
    }//finally
459
  }
460 2286 tao
461
462
463 1585 tao
  /* Handle replicate single xml document*/
464 2286 tao
  private void handleSingleDataFile(String remoteserver, String actions,
465
                                    String docId)
466 1585 tao
               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 2286 tao
      String docInfoURLString = "https://" + remoteserver +
481 1585 tao
                  "?server="+util.getLocalReplicationServerName()+
482 1600 tao
                  "&action=getdocumentinfo&docid="+docId;
483
      docInfoURLString = MetaCatUtil.replaceWhiteSpaceForURL(docInfoURLString);
484
      URL docinfoUrl = new URL(docInfoURLString);
485 2286 tao
486 1585 tao
      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 2286 tao
      // Get doc type (eml public id)
494 1585 tao
      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 2286 tao
499 1585 tao
      //docid should include rev number too
500
      String accnum=docId+util.getOption("accNumSeparator")+
501
                                              (String)docinfoHash.get("rev");
502 2286 tao
503
504 1585 tao
      String datafilePath = util.getOption("datafilepath");
505
      // Get data file content
506 1600 tao
      String readDataURLString = "https://" + remoteserver + "?server="+
507 1585 tao
                                        util.getLocalReplicationServerName()+
508 1600 tao
                                            "&action=readdata&docid="+accnum;
509
      readDataURLString = MetaCatUtil.replaceWhiteSpaceForURL(readDataURLString);
510
      URL u = new URL(readDataURLString);
511 2286 tao
      InputStream input = u.openStream();
512 1585 tao
      //register data file into xml_documents table and wite data file
513
      //into file system
514 1600 tao
      if ( input != null)
515 667 berkley
      {
516 2286 tao
        DocumentImpl.writeDataFileInReplication(input,
517
                                                        datafilePath,
518
                                                        docName,docType,
519 1585 tao
                                                        accnum, user,
520
                                                        docHomeServer,
521
                                                        remoteserver);
522 2286 tao
        MetaCatUtil.debugMessage("Successfully to write datafile " + docId, 30);
523
        MetacatReplication.replLog("wrote datafile " + accnum + " from " +
524 1585 tao
                                    remoteserver);
525
      }//if
526
      else
527 1217 tao
      {
528 1600 tao
         MetaCatUtil.debugMessage("Couldn't open the data file: " + accnum, 30);
529 1585 tao
         throw new Exception("Couldn't open the data file: " + accnum);
530
      }//else
531 2286 tao
532
    }//try
533 1585 tao
    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 2286 tao
548
549
550 1585 tao
  /* Handle delete single document*/
551 2298 tao
  private void handleDeleteSingleDocument(String docId, String notifyServer)
552 1585 tao
               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 1217 tao
      {
565 2286 tao
566 1585 tao
         //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 2298 tao
         DocumentImpl.delete(accnum, null, null, notifyServer);
571 2286 tao
         MetaCatUtil.debugMessage("Successfully deleted doc " + docId, 30);
572 1585 tao
         MetacatReplication.replLog("Doc " + docId + " deleted");
573
      }
574 2286 tao
575
    }//try
576 1585 tao
    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 1037 tao
    }//finally
589 1585 tao
  }
590 2286 tao
591 1585 tao
  /* Handle updateLastCheckTimForSingleServer*/
592 2286 tao
  private void updateLastCheckTimeForSingleServer(ReplicationServer repServer)
593 1585 tao
                                                  throws Exception
594 590 berkley
  {
595 1585 tao
    String server = repServer.getServerName();
596 1217 tao
    DBConnection dbConn = null;
597
    int serialNumber = -1;
598
    PreparedStatement pstmt = null;
599 590 berkley
    try
600
    {
601 1585 tao
      // Get DBConnection from pool
602 1217 tao
      dbConn=DBConnectionPool.
603 1585 tao
             getDBConnection("ReplicationHandler.updateLastCheckTimeForServer");
604 1217 tao
      serialNumber=dbConn.getCheckOutSerialNumber();
605 2286 tao
606 1585 tao
      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 1751 tao
         /*sql.append("update xml_replication set last_checked = to_date('");
617 1585 tao
         sql.append(datestr).append("', 'YY-MM-DD HH24:MI:SS') where ");
618 1751 tao
         sql.append("server like '").append(server).append("'");*/
619
         sql.append("update xml_replication set last_checked = ");
620 1753 tao
         sql.append(dbAdapter.toDate(datestr, "MM/DD/YY HH24:MI:SS"));
621 1751 tao
         sql.append(" where server like '").append(server).append("'");
622 1585 tao
         pstmt = dbConn.prepareStatement(sql.toString());
623 2286 tao
624 1585 tao
         pstmt.executeUpdate();
625
         dbConn.commit();
626
         pstmt.close();
627 2286 tao
         MetaCatUtil.debugMessage("last_checked updated to "+datestr+" on "
628 1585 tao
                                      + server, 45);
629
      }//if
630
      else
631
      {
632 2286 tao
633
         MetaCatUtil.debugMessage("Failed to update last_checked for server "  +
634
                                  server + " in db because couldn't get time "
635 1585 tao
                                  , 30);
636
         throw new Exception("Couldn't get time for server "+ server);
637
      }
638 2286 tao
639
    }//try
640 1585 tao
    catch(Exception e)
641
    {
642 2286 tao
643
      MetaCatUtil.debugMessage("Failed to update last_checked for server " +
644 1585 tao
                                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 2286 tao
655
656
657 1585 tao
  /**
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 2286 tao
668
669 1585 tao
    // Go through each ReplicationServer object in sererlist
670
    for (int j=0; j<serverList.size(); j++)
671 2286 tao
    {
672 1585 tao
      Vector remoteCatalog = new Vector();
673
      Vector publicId = new Vector();
674
      try
675
      {
676 1292 tao
        // 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 1011 tao
        URL u = new URL("https://" + server + "?server="+
682 1015 tao
        util.getLocalReplicationServerName()+"&action=getcatalog");
683 1292 tao
        MetaCatUtil.debugMessage("sending message " + u.toString(), 50);
684 590 berkley
        String catxml = MetacatReplication.getURLContent(u);
685 2286 tao
686 1292 tao
        // Make sure there are not error, no empty string
687
        if (catxml.indexOf("error")!=-1 || catxml==null||catxml.equals(""))
688
        {
689 1585 tao
          throw new Exception("Couldn't get catalog list form server " +server);
690 1292 tao
        }
691 1585 tao
        MetaCatUtil.debugMessage("catxml: " + catxml, 40);
692 590 berkley
        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 1585 tao
        remoteCatalog = cmh.getCatalogVect();
697 2286 tao
698 1292 tao
        // Makse sure remoteCatalog is not empty
699
        if (remoteCatalog.isEmpty())
700
        {
701 1585 tao
          throw new Exception("Couldn't get catalog list form server " +server);
702 1292 tao
        }
703 2286 tao
704 590 berkley
        String localcatxml = MetacatReplication.getCatalogXML();
705 2286 tao
706 1292 tao
        // Make sure local catalog is no empty
707
        if (localcatxml==null||localcatxml.equals(""))
708
        {
709 1585 tao
          throw new Exception("Couldn't get catalog list form server " +server);
710 1292 tao
        }
711 2286 tao
712 590 berkley
        cmh = new CatalogMessageHandler();
713
        catparser = initParser(cmh);
714
        catparser.parse(new InputSource(new StringReader(localcatxml)));
715
        Vector localCatalog = cmh.getCatalogVect();
716 2286 tao
717 590 berkley
        //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 1585 tao
        publicId = new Vector();
722 590 berkley
        for(int i=0; i<localCatalog.size(); i++)
723
        {
724
          Vector v = new Vector((Vector)localCatalog.elementAt(i));
725 1292 tao
          MetaCatUtil.debugMessage("v1: " + v.toString(), 50);
726 590 berkley
          publicId.add(new String((String)v.elementAt(3)));
727 595 berkley
          //System.out.println("adding " + (String)v.elementAt(3));
728 590 berkley
        }
729 1585 tao
      }//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 2286 tao
738 1585 tao
      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 590 berkley
        {
746 1585 tao
            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 1292 tao
                              ("v.elementAt(3): " + (String)v.elementAt(3), 50);
756 1585 tao
           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 590 berkley
        }
779 1585 tao
        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 590 berkley
  }
794 2286 tao
795 590 berkley
  /**
796 579 berkley
   * Method that returns true if docid has already been "deleted" from metacat.
797 582 berkley
   * This method really implements a truth table for deleted documents
798 590 berkley
   * The table is (a docid in one of the tables is represented by the X):
799 582 berkley
   * xml_docs      xml_revs      deleted?
800
   * ------------------------------------
801
   *   X             X             FALSE
802
   *   X             _             FALSE
803
   *   _             X             TRUE
804
   *   _             _             TRUE
805 579 berkley
   */
806 1585 tao
  private static boolean alreadyDeleted(String docid) throws Exception
807 579 berkley
  {
808 1217 tao
    DBConnection dbConn = null;
809
    int serialNumber = -1;
810
    PreparedStatement pstmt = null;
811 579 berkley
    try
812
    {
813 1217 tao
      dbConn=DBConnectionPool.
814
                  getDBConnection("ReplicationHandler.alreadyDeleted");
815
      serialNumber=dbConn.getCheckOutSerialNumber();
816 582 berkley
      boolean xml_docs = false;
817
      boolean xml_revs = false;
818 2286 tao
819 579 berkley
      StringBuffer sb = new StringBuffer();
820 582 berkley
      sb.append("select docid from xml_revisions where docid like '");
821 579 berkley
      sb.append(docid).append("'");
822 1217 tao
      pstmt = dbConn.prepareStatement(sb.toString());
823 579 berkley
      pstmt.execute();
824
      ResultSet rs = pstmt.getResultSet();
825
      boolean tablehasrows = rs.next();
826
      if(tablehasrows)
827
      {
828 582 berkley
        xml_revs = true;
829
      }
830 2286 tao
831 582 berkley
      sb = new StringBuffer();
832
      sb.append("select docid from xml_documents where docid like '");
833
      sb.append(docid).append("'");
834 667 berkley
      pstmt.close();
835 1217 tao
      pstmt = dbConn.prepareStatement(sb.toString());
836
      //increase usage count
837
      dbConn.increaseUsageCount(1);
838 582 berkley
      pstmt.execute();
839
      rs = pstmt.getResultSet();
840
      tablehasrows = rs.next();
841 667 berkley
      pstmt.close();
842 582 berkley
      if(tablehasrows)
843
      {
844
        xml_docs = true;
845
      }
846 2286 tao
847 582 berkley
      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 579 berkley
        return true;
858
      }
859 582 berkley
      else if(!xml_docs && !xml_revs)
860
      {
861
        return true;
862
      }
863 579 berkley
    }
864
    catch(Exception e)
865
    {
866 2286 tao
      MetaCatUtil.debugMessage("error in ReplicationHandler.alreadyDeleted: " +
867 1585 tao
                          e.getMessage(), 30);
868
      throw e;
869 579 berkley
    }
870 667 berkley
    finally
871
    {
872 1217 tao
      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 1585 tao
        throw ee;
881 1217 tao
      }//catch
882
      finally
883
      {
884
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
885
      }//finally
886
    }//finally
887 579 berkley
    return false;
888
  }
889 533 berkley
890 2286 tao
891 533 berkley
  /**
892 574 berkley
   * 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 2286 tao
910 574 berkley
      parser.setContentHandler((ContentHandler)chandler);
911
      parser.setErrorHandler((ErrorHandler)chandler);
912
913
    } catch (Exception e) {
914
      throw e;
915
    }
916
917
    return parser;
918
  }
919 2286 tao
920 2555 tao
  /**
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 2286 tao
956 2555 tao
  /*
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 522 berkley
}