Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements replication for metacat
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: berkley $'
10
 *     '$Date: 2001-01-19 15:20:58 -0800 (Fri, 19 Jan 2001) $'
11
 * '$Revision: 683 $'
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 java.util.*;
31
import java.io.*;
32
import java.sql.*;
33
import java.net.*;
34
import java.lang.*;
35
import java.text.*;
36
import javax.servlet.*;
37
import javax.servlet.http.*;
38

    
39
import org.xml.sax.*;
40

    
41
public class MetacatReplication extends HttpServlet implements Runnable
42
{  
43
  private String deltaT;
44
  Timer replicationDaemon;
45
  private static MetaCatUtil util = new MetaCatUtil();
46
  private Vector fileLocks = new Vector();
47
  private Thread lockThread = null;
48
  
49
  /**
50
   * Initialize the servlet by creating appropriate database connections
51
   */
52
  public void init(ServletConfig config) throws ServletException 
53
  {
54
    //initialize db connections to handle any update requests
55
    MetaCatUtil util = new MetaCatUtil();
56
    deltaT = util.getOption("deltaT");
57
    //the default deltaT can be set from metacat.properties
58
    //create a thread to do the delta-T check but don't execute it yet
59
    replicationDaemon = new Timer(true);
60
  }
61
  
62
  public void destroy() 
63
  {
64
    replicationDaemon.cancel();
65
    System.out.println("Replication daemon cancelled.");
66
  }
67
  
68
  public void doGet (HttpServletRequest request, HttpServletResponse response)
69
                     throws ServletException, IOException 
70
  {
71
    // Process the data and send back the response
72
    handleGetOrPost(request, response);
73
  }
74

    
75
  public void doPost(HttpServletRequest request, HttpServletResponse response)
76
                     throws ServletException, IOException 
77
  {
78
    // Process the data and send back the response
79
    handleGetOrPost(request, response);
80
  }
81
  
82
  private void handleGetOrPost(HttpServletRequest request, 
83
                               HttpServletResponse response) 
84
                               throws ServletException, IOException 
85
  {
86
    PrintWriter out = response.getWriter();
87
    Hashtable params = new Hashtable();
88
    Enumeration paramlist = request.getParameterNames();
89
    
90
    while (paramlist.hasMoreElements()) 
91
    {
92
      String name = (String)paramlist.nextElement();
93
      String[] value = request.getParameterValues(name);
94
      params.put(name, value);  
95
    }
96
    
97
    if(params.containsKey("action"))
98
    {
99
      if(((String[])params.get("action"))[0].equals("stop"))
100
      { //stop the replication server
101
        replicationDaemon.cancel();
102
        replicationDaemon = new Timer(true);
103
        out.println("Replication Handler Stopped");
104
        System.out.println("Replication Handler Stopped");
105
        MetacatReplication.replLog("deltaT handler stopped");
106
      }
107
      else if(((String[])params.get("action"))[0].equals("start"))
108
      { //start the replication server
109
        int rate;
110
        if(params.containsKey("rate"))
111
        {
112
          rate = new Integer(
113
                 new String(((String[])params.get("rate"))[0])).intValue();
114
          if(rate < 30)
115
          {
116
            out.println("Replication deltaT rate cannot be less than 30!");
117
            //deltaT<30 is a timing mess!
118
            rate = 1000;
119
          }
120
        }
121
        else
122
        {
123
          rate = 1000;
124
        }
125
        
126
        out.println("New rate is: " + rate + " seconds.");
127
        replicationDaemon.cancel();
128
        replicationDaemon = new Timer(true);
129
        replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(out), 0, 
130
                                              rate * 1000);
131
        MetacatReplication.replLog("deltaT handler started with rate=" + 
132
                                    rate + " seconds");
133
        out.println("Replication Handler Started");
134
        System.out.println("Replication Handler Started");
135
      }
136
      else if(((String[])params.get("action"))[0].equals("getall"))
137
      { //updates this server exactly once
138
        replicationDaemon.schedule(new ReplicationHandler(out), 0);
139
        response.setContentType("text/html");
140
        out.println("<html><body>\"Get All\" Done</body></html>");
141
      }
142
      else if(((String[])params.get("action"))[0].equals("forcereplicate"))
143
      {
144
        handleForceReplicateRequest(out, params, response);
145
      }
146
      else if(((String[])params.get("action"))[0].equals("update"))
147
      { //request an update list from the server
148
        handleUpdateRequest(out, params, response);
149
      }
150
      else if(((String[])params.get("action"))[0].equals("read"))
151
      { //request a specific document from the server
152
        //note that this could be replaced by a call to metacatServlet
153
        //handleGetDocumentAction().
154
        handleGetDocumentRequest(out, params, response);
155
      }
156
      else if(((String[])params.get("action"))[0].equals("getlock"))
157
      {
158
        handleGetLockRequest(out, params, response);
159
      }
160
      else if(((String[])params.get("action"))[0].equals("getdocumentinfo"))
161
      {
162
        handleGetDocumentInfoRequest(out, params, response);
163
      }
164
      else if(((String[])params.get("action"))[0].equals("gettime"))
165
      {
166
        handleGetTimeRequest(out, params, response);
167
      }
168
      else if(((String[])params.get("action"))[0].equals("getcatalog"))
169
      {
170
        handleGetCatalogRequest(out, params, response, true);
171
      }
172
      else if(((String[])params.get("action"))[0].equals("servercontrol"))
173
      {
174
        handleServerControlRequest(out, params, response);
175
      }
176
      
177
    }
178
  }
179
  
180
  /** 
181
   * This method can add, delete and list the servers currently included in
182
   * xml_replication.
183
   * action           subaction            other needed params
184
   * ---------------------------------------------------------
185
   * servercontrol    add                  server
186
   * servercontrol    delete               server
187
   * servercontrol    list                 
188
   */
189
  private void handleServerControlRequest(PrintWriter out, Hashtable params,
190
                                          HttpServletResponse response)
191
  {
192
    String subaction = ((String[])params.get("subaction"))[0];
193
    Connection conn = null;
194
    try
195
    {
196
      conn = MetacatReplication.getDBConnection("MetacatReplication." + 
197
                                                "handleServerControlRequest");
198
      PreparedStatement pstmt = null;
199
      if(subaction.equals("add"))
200
      {
201
        String replicate = ((String[])params.get("replicate"))[0];
202
        String server = ((String[])params.get("server"))[0];
203
        pstmt = conn.prepareStatement("insert into xml_replication (server, " +
204
                "last_checked, replicate) values ('" + server + "', to_date(" +
205
                "'01/01/00', 'MM/DD/YY'), '" + replicate + "')");
206
        pstmt.execute();
207
        out.println("Server says: server " + server + " added"); 
208
        response.setContentType("text/html");
209
        out.println("<html><body><table border=\"1\">");
210
        out.println("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
211
        out.println("<b>replicate</b></td></tr>");
212
        pstmt = conn.prepareStatement("select * from xml_replication");
213
        pstmt.execute();
214
        ResultSet rs = pstmt.getResultSet();
215
        boolean tablehasrows = rs.next();
216
        while(tablehasrows)
217
        {
218
          out.println("<tr><td>" + rs.getString(2) + "</td><td>");
219
          out.println(rs.getString(3) + "</td><td>");
220
          out.println(rs.getString(4) + "</td></tr>");
221
          tablehasrows = rs.next();
222
        }
223
        out.println("</table></body></html>");
224
      }
225
      else if(subaction.equals("delete"))
226
      {
227
        String server = ((String[])params.get("server"))[0];
228
        pstmt = conn.prepareStatement("delete from xml_replication where " +
229
                "server like '" + server + "'");
230
        pstmt.execute();
231
        out.println("Server says: server " + server + " deleted");
232
        response.setContentType("text/html");
233
        out.println("<html><body><table border=\"1\">");
234
        out.println("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
235
        out.println("<b>replicate</b></td></tr>");
236
        pstmt = conn.prepareStatement("select * from xml_replication");
237
        pstmt.execute();
238
        ResultSet rs = pstmt.getResultSet();
239
        boolean tablehasrows = rs.next();
240
        while(tablehasrows)
241
        {
242
          out.println("<tr><td>" + rs.getString(2) + "</td><td>");
243
          out.println(rs.getString(3) + "</td><td>");
244
          out.println(rs.getString(4) + "</td></tr>");
245
          tablehasrows = rs.next();
246
        }
247
        out.println("</table></body></html>");
248
      }
249
      else if(subaction.equals("list"))
250
      {
251
        response.setContentType("text/html");
252
        out.println("<html><body><table border=\"1\">");
253
        out.println("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
254
        out.println("<b>replicate</b></td></tr>");
255
        pstmt = conn.prepareStatement("select * from xml_replication");
256
        pstmt.execute();
257
        ResultSet rs = pstmt.getResultSet();
258
        boolean tablehasrows = rs.next();
259
        while(tablehasrows)
260
        {
261
          out.println("<tr><td>" + rs.getString(2) + "</td><td>");
262
          out.println(rs.getString(3) + "</td><td>");
263
          out.println(rs.getString(4) + "</td></tr>");
264
          tablehasrows = rs.next();
265
        }
266
        out.println("</table></body></html>");
267
      }
268
      pstmt.close();
269
      conn.close();
270
    }
271
    catch(Exception e)
272
    {
273
      System.out.println("error in " + 
274
                         "MetacatReplication.handleServerControlRequest " + 
275
                         e.getMessage());
276
      e.printStackTrace(System.out);
277
    }
278
  }
279
  
280
  /**
281
   * when a forcereplication request comes in, this method sends a read request
282
   * to the requesting server for the specified docid.
283
   */
284
  private void handleForceReplicateRequest(PrintWriter out, Hashtable params,
285
                                           HttpServletResponse response)
286
  {
287
    //System.out.println("in handleforcereplicaterequest");
288
    String server = ((String[])params.get("server"))[0];
289
    if(!(replToServer(server)))
290
    { //do not get the server's new document if we are not replicating from there
291
      return;
292
    }
293
    
294
    //the server that the request came from
295
    String docid = ((String[])params.get("docid"))[0];
296
    //the docid of the document to get
297
    String dbaction = "UPDATE";
298
    //default action is update
299
    boolean override = false;
300
    int serverCode = 1;
301
    
302
    try
303
    {
304
      if(params.containsKey("dbaction"))
305
      { //if the url contains a dbaction then the default action is overridden
306
        dbaction = ((String[])params.get("dbaction"))[0];
307
        serverCode = MetacatReplication.getServerCode(server);
308
        override = true; //we are now overriding the default action
309
      }
310
      MetaCatUtil.debugMessage("action in forcereplicate is: " + dbaction);
311
      MetaCatUtil.debugMessage("serverCode in forcereplicate is: " + serverCode);
312
      MetacatReplication.replLog("force replication request from " + server); 
313
      
314
      int serverCheckCode = MetacatReplication.getServerCode(server);
315
      URL u = new URL("http://" + server + "?action=read&docid=" + docid);
316
      MetaCatUtil.debugMessage("sending message: " + u.toString());
317
      String xmldoc = MetacatReplication.getURLContent(u);
318
      MetaCatUtil.debugMessage("document: " + xmldoc);
319
      //get the document to write
320
      URL docinfourl = new URL("http://" + server + 
321
                               "?action=getdocumentinfo&docid=" +
322
                               docid);
323
      //we need to get the document's info so we can set the correct user
324
      //and group once we get the document and write it to our DB
325
      MetaCatUtil.debugMessage("sending message: " + docinfourl.toString());
326
      String docInfoStr = MetacatReplication.getURLContent(docinfourl);
327
      MetaCatUtil.debugMessage("docInfo: " + docInfoStr);
328
      DocInfoHandler dih = new DocInfoHandler();
329
      //dih is the parser for the docinfo xml format
330
      XMLReader docinfoParser = ReplicationHandler.initParser(dih);
331
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
332
      Hashtable docinfoHash = dih.getDocInfo();
333
      String user = (String)docinfoHash.get("user_owner");
334
      String group = new String(user);
335
      //right now the user and group are the same.
336
      Connection conn = null;
337
      
338
      conn = MetacatReplication.getDBConnection("MetacatReplication." +
339
                                                "handleForceReplicateRequest");
340
    
341
      DocumentImpl.write(conn, new StringReader(xmldoc), null, dbaction, docid, 
342
                         user, group, serverCode, override);
343
      MetacatReplication.replLog("document " + docid + " added to DB with " +
344
                                 "action " + dbaction);
345
      conn.close();
346
    }
347
    catch(Exception e)
348
    {
349
      System.out.println("error in metacatReplication.handleForceReplicate" +
350
                         "Request: " + e.getMessage());
351
    }
352
  }
353
  
354
  /**
355
   * Grants or denies a lock to a requesting host.
356
   * The servlet parameters of interrest are:
357
   * docid: the docid of the file the lock is being requested for
358
   * currentdate: the timestamp of the document on the remote server
359
   * 
360
   */
361
  private void handleGetLockRequest(PrintWriter out, Hashtable params,
362
                                    HttpServletResponse response)
363
  {
364
    Connection conn = null;
365
    try
366
    {
367
      conn = MetacatReplication.getDBConnection("MetacatReplication." +
368
                                                "handleGetLockRequest");
369
      String docid = ((String[])params.get("docid"))[0];
370
      String remoteRev = ((String[])params.get("updaterev"))[0];
371
      DocumentImpl requestDoc = new DocumentImpl(conn, docid);
372
      MetacatReplication.replLog("lock request for " + docid);
373
      int localRevInt = requestDoc.getRev();
374
      int remoteRevInt = Integer.parseInt(remoteRev);
375
      
376
      if(remoteRevInt >= localRevInt)
377
      {
378
        if(!fileLocks.contains(docid))
379
        { //grant the lock if it is not already locked
380
          fileLocks.add(0, docid); //insert at the beginning of the queue Vector
381
          //send a message back to the the remote host authorizing the insert
382
          out.println("<lockgranted><docid>" +docid+ "</docid></lockgranted>");
383
          lockThread = new Thread(this);
384
          lockThread.setPriority(Thread.MIN_PRIORITY);
385
          lockThread.start();
386
          System.out.println("lock granted for " + docid);
387
          MetacatReplication.replLog("lock granted for " + docid);
388
        }
389
        else
390
        { //deny the lock
391
          out.println("<filelocked><docid>" + docid + "</docid></filelocked>");
392
          MetacatReplication.replLog("lock denied for " + docid + 
393
                                     "reason: file already locked");
394
        }
395
      }
396
      else
397
      {//deny the lock.
398
        out.println("<outdatedfile><docid>" + docid + "</docid></filelocked>");
399
        MetacatReplication.replLog("lock denied for " + docid + 
400
                                   "reason: client has outdated file");
401
      }
402
      conn.close();
403
    }
404
    catch(Exception e)
405
    {
406
      System.out.println("error requesting file lock from MetacatReplication." +
407
                         "handleGetLockRequest: " + e.getMessage());
408
      e.printStackTrace(System.out);
409
    }
410
  }
411
  
412
  /**
413
   * Sends all of the xml_documents information encoded in xml to a requestor
414
   * the format is:
415
   * <!ELEMENT documentinfo (docid, docname, doctype, doctitle, user_owner,
416
   *                         user_updated, public_access, rev)
417
   * all of the subelements of document info are #PCDATA
418
   */
419
  private void handleGetDocumentInfoRequest(PrintWriter out, Hashtable params, 
420
                                        HttpServletResponse response)
421
  {
422
    String docid = ((String[])(params.get("docid")))[0];
423
    StringBuffer sb = new StringBuffer();
424
    Connection conn = null;
425
    try
426
    {
427
      conn = MetacatReplication.getDBConnection("MetacatReplication." +
428
                                                "handleGetDocumentInfoRequest");
429
      DocumentImpl doc = new DocumentImpl(conn, docid);
430
      sb.append("<documentinfo><docid>").append(docid);
431
      sb.append("</docid><docname>").append(doc.getDocname());
432
      sb.append("</docname><doctype>").append(doc.getDoctype());
433
      sb.append("</doctype><doctitle>").append(doc.getDocTitle());
434
      sb.append("</doctitle><user_owner>").append(doc.getUserowner());
435
      sb.append("</user_owner><user_updated>").append(doc.getUserupdated());
436
      sb.append("</user_updated><public_access>").append(doc.getPublicaccess());
437
      sb.append("</public_access><rev>").append(doc.getRev());
438
      sb.append("</rev></documentinfo>");
439
      response.setContentType("text/xml");
440
      out.println(sb.toString());
441
      conn.close();
442
    }
443
    catch (Exception e)
444
    {
445
      System.out.println("error in " +
446
                         "metacatReplication.handlegetdocumentinforequest: " + 
447
                          e.getMessage());
448
    }
449
    
450
  }
451
  
452
  /**
453
   * Sends a document to a remote host
454
   */
455
  private void handleGetDocumentRequest(PrintWriter out, Hashtable params, 
456
                                        HttpServletResponse response)
457
  {
458
    Connection conn = null;
459
    try
460
    {
461
      String docid = ((String[])(params.get("docid")))[0];
462
      System.out.println("incoming get request for document: " + docid);
463
      conn = MetacatReplication.getDBConnection("MetacatReplication." +
464
                                                "handleGetDocumentRequest");
465
      DocumentImpl di = new DocumentImpl(conn, docid);
466
      response.setContentType("text/xml");
467
      out.print(di.toString());
468
      conn.close();
469
      MetacatReplication.replLog("document " + docid + " sent");
470
      System.out.println("document " + docid + " sent");
471
    }
472
    catch(Exception e)
473
    {
474
      System.out.println("error getting document from MetacatReplication." +
475
                         "handlGetDocumentRequest " + e.getMessage());
476
      e.printStackTrace(System.out);
477
    }
478
    
479
  }
480
  
481
  /**
482
   * Sends a list of all of the documents on this sever along with their
483
   * revision numbers.  
484
   * The format is:
485
   * <!ELEMENT replication (server, updates)>
486
   * <!ELEMENT server (#PCDATA)>
487
   * <!ELEMENT updates ((updatedDocument | deleteDocument)*)>
488
   * <!ELEMENT updatedDocument (docid, rev)>
489
   * <!ELEMENT deletedDocument (docid, rev)>
490
   * <!ELEMENT docid (#PCDATA)>
491
   * <!ELEMENT rev (#PCDATA)>
492
   * note that the rev in deletedDocument is always empty.  I just left
493
   * it in there to make the parser implementation easier.
494
   */
495
  private void handleUpdateRequest(PrintWriter out, Hashtable params, 
496
                                    HttpServletResponse response)
497
  {
498
    Connection conn = null;
499
    try
500
    {
501
      System.out.println("received update request");
502
      StringBuffer docsql = new StringBuffer();
503
      StringBuffer doclist = new StringBuffer();
504
      Vector packageFiles = new Vector();
505
      
506
      //get all docs that reside on this server
507
      doclist.append("<?xml version=\"1.0\"?><replication>");
508
      doclist.append("<server>").append(util.getOption("server"));
509
      doclist.append(util.getOption("replicationpath"));
510
      doclist.append("</server><updates>");
511
      
512
      docsql.append("select docid, rev, doctype from xml_documents where "); 
513
      docsql.append("server_location = 1");
514
      
515
      //get any deleted documents
516
      StringBuffer delsql = new StringBuffer();
517
      delsql.append("select distinct docid from ");
518
      delsql.append("xml_revisions where docid not in (select docid from ");
519
      delsql.append("xml_documents) and server_location = 1");
520
      
521
      conn = MetacatReplication.getDBConnection("MetacatReplication." +
522
                                                "handleUpdateRequest");
523
      PreparedStatement pstmt = conn.prepareStatement(docsql.toString());
524
      pstmt.execute();
525
      ResultSet rs = pstmt.getResultSet();
526
      boolean tablehasrows = rs.next();
527
      while(tablehasrows)
528
      {
529
        String recordDoctype = rs.getString(3);
530
        if(!recordDoctype.equals("BIN"))
531
        { //don't replicate data files
532
          if(!recordDoctype.equals(util.getOption("packagedoctype")))
533
          { //if this is a package file, put it at the end
534
            //because if a package file is read before all of the files it
535
            //refers to are loaded then there is an error
536
            doclist.append("<updatedDocument>");
537
            doclist.append("<docid>").append(rs.getString(1));
538
            doclist.append("</docid><rev>").append(rs.getInt(2));
539
            doclist.append("</rev>");
540
            doclist.append("</updatedDocument>");
541
          }
542
          else
543
          { //the package files are saved to be put into the xml later.
544
            Vector v = new Vector();
545
            v.add(new String(rs.getString(1)));
546
            v.add(new Integer(rs.getInt(2)));
547
            packageFiles.add(new Vector(v));
548
          }
549
        }
550
        tablehasrows = rs.next();
551
      }
552
      
553
      pstmt = conn.prepareStatement(delsql.toString());
554
      pstmt.execute();
555
      rs = pstmt.getResultSet();
556
      tablehasrows = rs.next();
557
      while(tablehasrows)
558
      { //handle the deleted documents
559
        doclist.append("<deletedDocument><docid>").append(rs.getString(1));
560
        doclist.append("</docid><rev></rev></deletedDocument>");
561
        //note that rev is always empty for deleted docs
562
        tablehasrows = rs.next();
563
      }
564
      
565
      //now we can put the package files into the xml results
566
      for(int i=0; i<packageFiles.size(); i++)
567
      {
568
        Vector v = (Vector)packageFiles.elementAt(i);
569
        doclist.append("<updatedDocument>");
570
        doclist.append("<docid>").append((String)v.elementAt(0));
571
        doclist.append("</docid><rev>");
572
        doclist.append(((Integer)v.elementAt(1)).intValue());
573
        doclist.append("</rev>");
574
        doclist.append("</updatedDocument>");
575
      }
576
      
577
      doclist.append("</updates></replication>");
578
      MetaCatUtil.debugMessage("doclist: " + doclist.toString());
579
      pstmt.close();
580
      conn.close();
581
      response.setContentType("text/xml");
582
      out.println(doclist.toString());
583
      System.out.println("doclist: " + doclist.toString());
584
      System.out.println("update request handled");
585
    }
586
    catch(Exception e)
587
    {
588
      System.out.println("error in MetacatReplication.handleupdaterequest: " + 
589
                          e.getMessage());
590
      e.printStackTrace(System.out);
591
    }
592
    
593
  }
594
  
595
  /**
596
   * Returns the xml_catalog table encoded in xml
597
   */
598
  public static String getCatalogXML()
599
  {
600
    return handleGetCatalogRequest(null, null, null, false);
601
  }
602
  
603
  /**
604
   * Sends the contents of the xml_catalog table encoded in xml
605
   * The xml format is:
606
   * <!ELEMENT xml_catalog (row*)>
607
   * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
608
   *                system_id)>
609
   * All of the sub elements of row are #PCDATA
610
   
611
   * If printFlag == false then do not print to out.
612
   */
613
  private static String handleGetCatalogRequest(PrintWriter out, 
614
                                                Hashtable params,
615
                                                HttpServletResponse response,
616
                                                boolean printFlag)
617
  {
618
    Connection conn = null;
619
    PreparedStatement pstmt = null;
620
    try
621
    { 
622
      conn = MetacatReplication.getDBConnection("MetacatReplication." +
623
                                                "handleGetCatalogRequest");
624
      pstmt = conn.prepareStatement("select entry_type, " +
625
                              "source_doctype, target_doctype, public_id, " +
626
                              "system_id from xml_catalog");
627
      pstmt.execute();
628
      ResultSet rs = pstmt.getResultSet();
629
      boolean tablehasrows = rs.next();
630
      StringBuffer sb = new StringBuffer();
631
      sb.append("<?xml version=\"1.0\"?><xml_catalog>");
632
      while(tablehasrows)
633
      {
634
        sb.append("<row><entry_type>").append(rs.getString(1));
635
        sb.append("</entry_type><source_doctype>").append(rs.getString(2));
636
        sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
637
        sb.append("</target_doctype><public_id>").append(rs.getString(4));
638
        sb.append("</public_id><system_id>").append(rs.getString(5));
639
        sb.append("</system_id></row>");
640
      
641
        tablehasrows = rs.next();
642
      }
643
      sb.append("</xml_catalog>");
644
      conn.close();
645
      if(printFlag)
646
      {
647
        response.setContentType("text/xml");
648
        out.println(sb.toString());
649
      }
650
      pstmt.close();
651
      return sb.toString();
652
    }
653
    catch(Exception e)
654
    {
655
      try
656
      {
657
        pstmt.close();
658
        conn.close();
659
      }
660
      catch(Exception ee)
661
      {}
662
      System.out.println("error in MetacatReplication.handleGetCatalogRequest:"+ 
663
                          e.getMessage());
664
      e.printStackTrace(System.out);
665
    }
666
    return null;
667
  }
668
  
669
  /**
670
   * Sends the current system date to the remote server.  Using this action
671
   * for replication gets rid of any problems with syncronizing clocks 
672
   * because a time specific to a document is always kept on its home server.
673
   */
674
  private void handleGetTimeRequest(PrintWriter out, Hashtable params, 
675
                                    HttpServletResponse response)
676
  {
677
    SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
678
    java.util.Date localtime = new java.util.Date();
679
    String dateString = formatter.format(localtime);
680
    response.setContentType("text/xml");
681
    
682
    out.println("<timestamp>" + dateString + "</timestamp>");
683
  }
684
  
685
  /**
686
   * this method handles the timeout for a file lock.  when a lock is 
687
   * granted it is granted for 30 seconds.  When this thread runs out
688
   * it deletes the docid from the queue, thus eliminating the lock.
689
   */
690
  public void run()
691
  {
692
    try
693
    {
694
      MetaCatUtil.debugMessage("thread started for docid: " + 
695
                               (String)fileLocks.elementAt(0));
696
      System.out.println("thread started for docid: " + 
697
                               (String)fileLocks.elementAt(0));
698
      Thread.sleep(30000); //the lock will expire in 30 seconds
699
      MetaCatUtil.debugMessage("thread for docid: " + 
700
                             (String)fileLocks.elementAt(fileLocks.size() - 1) + 
701
                              " exiting.");
702
      System.out.println("thread for docid: " + 
703
                         (String)fileLocks.elementAt(fileLocks.size() - 1) + 
704
                         " exiting.");
705
      fileLocks.remove(fileLocks.size() - 1);
706
      //fileLocks is treated as a FIFO queue.  If there are more than one lock
707
      //in the vector, the first one inserted will be removed.
708
    }
709
    catch(Exception e)
710
    {
711
      System.out.println("error in file lock thread from MetacatReplication." + 
712
                         "run: " + e.getMessage());
713
    }
714
  }
715
  
716
  /**
717
   * Returns the name of a server given a serverCode
718
   * @param serverCode the serverid of the server
719
   * @return the servername or null if the specified serverCode does not
720
   *         exist.
721
   */
722
  public static String getServer(int serverCode)
723
  {
724
    //System.out.println("serverid: " + serverCode);
725
    Connection conn = null;
726
    try
727
    {
728
      conn = MetacatReplication.getDBConnection("MetacatReplication." +
729
                                                "getServer");
730
      String sql = new String("select server from " +
731
                              "xml_replication where serverid = " + 
732
                              serverCode);
733
      PreparedStatement pstmt = conn.prepareStatement(sql);
734
      //System.out.println("getserver sql: " + sql);
735
      pstmt.execute();
736
      ResultSet rs = pstmt.getResultSet();
737
      boolean tablehasrows = rs.next();
738
      if(tablehasrows)
739
      {
740
        //System.out.println("server: " + rs.getString(1));
741
        return rs.getString(1);
742
      }
743
      pstmt.close();
744
      conn.close();
745
    }
746
    catch(Exception e)
747
    {
748
      System.out.println("Error in MetacatReplication.getServer: " + 
749
                          e.getMessage());
750
    }
751
    return null;
752
      //return null if the server does not exist
753
  }
754
  
755
  /**
756
   * Returns a server code given a server name
757
   * @param server the name of the server
758
   * @return integer > 0 representing the code of the server, 0 if the server
759
   *  does not exist.
760
   */
761
  public static int getServerCode(String server) throws Exception
762
  {
763
    Connection conn = null;
764
    PreparedStatement pstmt = null;
765
    try
766
    {
767
      conn = MetacatReplication.getDBConnection("MetacatReplication.getServerCode");
768
      pstmt = conn.prepareStatement("select serverid from " +
769
                                         "xml_replication where server " +
770
                                         "like '" + server + "'");
771
      pstmt.execute();
772
      ResultSet rs = pstmt.getResultSet();
773
      boolean tablehasrows = rs.next();
774
      int serverCode = 0;
775
      if(tablehasrows)
776
      {  
777
        int ret = rs.getInt(1);
778
        pstmt.close();
779
        conn.close();
780
        return ret;
781
      }
782
      else
783
      {
784
        pstmt.close();
785
        conn.close();
786
        return 0;
787
      }
788
    }
789
    catch(Exception e)
790
    {
791
      throw e;
792
    }
793
    finally
794
    {
795
       try
796
       {
797
         pstmt.close();
798
         conn.close();
799
       }
800
       catch(Exception ee) {}
801
    }
802
  }
803
  
804
  /**
805
   * This method returns the content of a url
806
   * @param u the url to return the content from
807
   * @return a string representing the content of the url
808
   * @throws java.io.IOException
809
   */
810
  public static String getURLContent(URL u) throws java.io.IOException
811
  {
812
    //System.out.println("url: " + u.toString());
813
    char istreamChar;
814
    int istreamInt;
815
    InputStreamReader istream = new InputStreamReader(u.openStream());
816
    StringBuffer serverResponse = new StringBuffer();
817
    while((istreamInt = istream.read()) != -1)
818
    {
819
      istreamChar = (char)istreamInt;
820
      serverResponse.append(istreamChar);
821
    }
822
    
823
    return serverResponse.toString();
824
  }
825
  
826
  /**
827
   * Method for writing replication messages to a log file specified in 
828
   * metacat.properties
829
   */
830
  public static void replLog(String message)
831
  {
832
    try
833
    {
834
      FileOutputStream fos = new FileOutputStream(
835
                                 util.getOption("replicationlog"), true);
836
      PrintWriter pw = new PrintWriter(fos);
837
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
838
      java.util.Date localtime = new java.util.Date();
839
      String dateString = formatter.format(localtime);
840
      dateString += " :: " + message;
841
      //time stamp each entry
842
      pw.println(dateString);
843
      pw.flush();
844
    }
845
    catch(Exception e)
846
    {
847
      System.out.println("error writing to replication log from " +
848
                         "MetacatReplication.replLog: " + e.getMessage());
849
      //e.printStackTrace(System.out);
850
    }
851
  }
852
  
853
  /**
854
   * Returns true if the replicate field for server in xml_replication is 1.
855
   * Returns false otherwise
856
   */
857
  public static boolean replToServer(String server)
858
  {
859
    Connection conn = null;
860
    PreparedStatement pstmt = null;
861
    try
862
    {
863
      conn = MetacatReplication.getDBConnection("MetacatReplication.replToServer");
864
      pstmt = conn.prepareStatement("select replicate from " + 
865
                                    "xml_replication where server like '" +
866
                                     server + "'");
867
      pstmt.execute();
868
      ResultSet rs = pstmt.getResultSet();
869
      boolean tablehasrows = rs.next();
870
      if(tablehasrows)
871
      {
872
        int i = rs.getInt(1);
873
        if(i == 1)
874
        {
875
          pstmt.close();
876
          conn.close();
877
          return true;
878
        }
879
        else
880
        {
881
          pstmt.close();
882
          conn.close();
883
          return false;
884
        }
885
      }
886
    }
887
    catch(Exception e)
888
    {
889
      System.out.println("error in MetacatReplication.replToServer: " + 
890
                         e.getMessage());
891
    }
892
    finally
893
    {
894
      try
895
      {
896
        pstmt.close();
897
        conn.close();
898
      }
899
      catch(Exception ee)
900
      {}
901
    }
902
    return false;
903
    //the default if this server does not exist is to not replicate to it.
904
  }
905
  
906
  /**
907
   * A method for redundantly trying to connect.  this method will attempt to 
908
   * connect to the DB 3 times before failing.
909
   * @param methodname the methodname from which this method is called.
910
   */
911
  public static Connection getDBConnection(String methodname) throws Exception
912
  {
913
    Connection conn = null;
914
    try
915
    {
916
      try
917
      { //this connection is prone to error for some reason so we 
918
        //try to connect it three times before quiting.
919
        conn = util.openDBConnection();
920
        return conn;
921
      }
922
      catch(SQLException sqle)
923
      {
924
        try
925
        {
926
          conn = util.openDBConnection();
927
          return conn;
928
        }
929
        catch(SQLException sqlee)
930
        {
931
          try
932
          {
933
            conn = util.openDBConnection();
934
            return conn;
935
          }
936
          catch(SQLException sqleee)
937
          {
938
            System.out.println("error getting db connection in " + 
939
                               methodname +  ": " +
940
                               sqleee.getMessage());
941
            return conn;
942
          }
943
        }
944
      }
945
    }
946
    catch(Exception e)
947
    {
948
      throw new java.lang.Exception("error in " + methodname + ": " + 
949
                          e.getMessage());
950
    }
951
  }
952
}
(34-34/43)