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