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: tao $'
10
 *     '$Date: 2004-09-15 20:25:46 -0700 (Wed, 15 Sep 2004) $'
11
 * '$Revision: 2286 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
31
import java.util.*;
32
import java.io.*;
33
import java.sql.*;
34
import java.net.*;
35
import java.lang.*;
36
import java.text.*;
37
import javax.servlet.*;
38
import javax.servlet.http.*;
39

    
40
import org.xml.sax.*;
41

    
42
public class MetacatReplication extends HttpServlet implements Runnable
43
{
44
  private String deltaT;
45
  Timer replicationDaemon;
46
  private static MetaCatUtil util = new MetaCatUtil();
47
  private Vector fileLocks = new Vector();
48
  private Thread lockThread = null;
49
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
50

    
51
  /**
52
   * Initialize the servlet by creating appropriate database connections
53
   */
54
  public void init(ServletConfig config) throws ServletException
55
  {
56
     //initialize db connections to handle any update requests
57
    MetaCatUtil util = new MetaCatUtil();
58
    deltaT = util.getOption("deltaT");
59
    //the default deltaT can be set from metacat.properties
60
    //create a thread to do the delta-T check but don't execute it yet
61
    replicationDaemon = new Timer(true);
62
    /*java.net.URL.setURLStreamHandlerFactory(
63
       new java.net.URLStreamHandlerFactory()
64
       {
65
          public java.net.URLStreamHandler createURLStreamHandler(
66
                        final String protocol)
67
          {
68
              if ("http".equals(protocol))
69
              {
70
                 try
71
                 {
72
                    URLStreamHandler urlsh = new HTTPClient.http.Handler();
73
                    MetaCatUtil.debugMessage("Using HttpClient Protocol Handler for http", 45);
74
                    return urlsh;
75
                  }
76
                  catch (Exception e)
77
                  {
78
                     MetaCatUtil.debugMessage(
79
                          "Error setting URL StreamHandler!", 30);
80
                     return null;
81
                  }
82
               }//if
83
               else if ("https".equals(protocol))
84
               {
85
                 try
86
                 {
87
                   URLStreamHandler urlsh = new HTTPClient.https.Handler();
88
                   MetaCatUtil.debugMessage("Using HttpClient Protocol Handler for https", 45);
89
                   return urlsh;
90
                 }
91
                 catch (Exception e)
92
                 {
93
                   MetaCatUtil.debugMessage(
94
                              "Error setting URL StreamHandler!", 30);
95
                   return null;
96
                 }
97
              }
98
              return null;
99
         }//createURLStreamHandler
100
     });*/
101

    
102
  }
103

    
104
  public void destroy()
105
  {
106
    replicationDaemon.cancel();
107
   // System.out.println("Replication daemon cancelled.");
108
  }
109

    
110
  public void doGet (HttpServletRequest request, HttpServletResponse response)
111
                     throws ServletException, IOException
112
  {
113
    // Process the data and send back the response
114
    handleGetOrPost(request, response);
115
  }
116

    
117
  public void doPost(HttpServletRequest request, HttpServletResponse response)
118
                     throws ServletException, IOException
119
  {
120
    // Process the data and send back the response
121
    handleGetOrPost(request, response);
122
  }
123

    
124
  private void handleGetOrPost(HttpServletRequest request,
125
                               HttpServletResponse response)
126
                               throws ServletException, IOException
127
  {
128
    //PrintWriter out = response.getWriter();
129
    //ServletOutputStream outPut = response.getOutputStream();
130
    Hashtable params = new Hashtable();
131
    Enumeration paramlist = request.getParameterNames();
132

    
133

    
134

    
135
// NOT NEEDED - doesn't provide enough security because of possible IP spoofing
136
// REPLACED with running replication comminications over HTTPS
137
//    String requestingServerIP = request.getRemoteAddr();
138
//    InetAddress iaddr = InetAddress.getByName(requestingServerIP);
139
//    String requestingServer = iaddr.getHostName();
140

    
141
    while (paramlist.hasMoreElements()) {
142
      String name = (String)paramlist.nextElement();
143
      String[] value = request.getParameterValues(name);
144
      params.put(name, value);
145
    }
146

    
147
    String action = ((String[])params.get("action"))[0];
148
    String server = null;
149

    
150
    try {
151
      // check if the server is included in the list of replicated servers
152
      if ( !action.equals("servercontrol") &&
153
           !action.equals("stop") &&
154
           !action.equals("start") &&
155
           !action.equals("getall") ) {
156

    
157
        server = ((String[])params.get("server"))[0];
158
        if ( getServerCodeForServerName(server) == 0 ) {
159
          System.out.println("Action \"" + action +
160
                             "\" rejected for server: " + server);
161
          return;
162
        } else {
163
          System.out.println("Action \"" + action +
164
                             "\" accepted for server: " + server);
165
        }
166
      }
167
    } catch (Exception e) {
168
      System.out.println("Error in MetacatReplication.handleGetOrPost: " +
169
                         e.getMessage() );
170
      return;
171
    }
172
    if ( action.equals("readdata") )
173
    {
174
      OutputStream out=response.getOutputStream();
175
      //to get the data file.
176
      handleGetDataFileRequest(out, params, response);
177
      out.close();
178
    }
179
    else if ( action.equals("forcereplicatedatafile") )
180
    {
181
      //read a specific docid from remote host, and store it into local host
182
      handleForceReplicateDataFileRequest(params);
183

    
184
    }
185
    else
186
    {
187
    PrintWriter out = response.getWriter();
188
    if ( action.equals("stop") ) {
189
      //stop the replication server
190
      replicationDaemon.cancel();
191
      replicationDaemon = new Timer(true);
192
      out.println("Replication Handler Stopped");
193
      MetacatReplication.replLog("deltaT handler stopped");
194

    
195

    
196
    } else if ( action.equals("start") ) {
197

    
198
      //start the replication server
199
      int rate;
200
      if ( params.containsKey("rate") ) {
201
        rate = new Integer(
202
               new String(((String[])params.get("rate"))[0])).intValue();
203
        if(rate < 30) {
204
            out.println("Replication deltaT rate cannot be less than 30!");
205
            //deltaT<30 is a timing mess!
206
            rate = 1000;
207
        }
208
      } else {
209
        rate = 1000;
210
      }
211
      out.println("New rate is: " + rate + " seconds.");
212
      replicationDaemon.cancel();
213
      replicationDaemon = new Timer(true);
214
      replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(out), 0,
215
                                            rate * 1000);
216
      out.println("Replication Handler Started");
217
      MetacatReplication.replLog("deltaT handler started with rate=" +
218
                                    rate + " seconds");
219

    
220

    
221
    } else if ( action.equals("getall") ) {
222
      //updates this server exactly once
223
      replicationDaemon.schedule(new ReplicationHandler(out), 0);
224
      response.setContentType("text/html");
225
      out.println("<html><body>\"Get All\" Done</body></html>");
226

    
227
    } else if ( action.equals("forcereplicate") ) {
228
      //read a specific docid from remote host, and store it into local host
229
      handleForceReplicateRequest(out, params, response);
230

    
231
    } else if ( action.equals("update") ) {
232
      //request an update list from the server
233
      handleUpdateRequest(out, params, response);
234

    
235
    } else if ( action.equals("read") ) {
236
      //request a specific document from the server
237
      //note that this could be replaced by a call to metacatServlet
238
      //handleGetDocumentAction().
239
      handleGetDocumentRequest(out, params, response);
240
    } else if ( action.equals("getlock") ) {
241
      handleGetLockRequest(out, params, response);
242

    
243
    } else if ( action.equals("getdocumentinfo") ) {
244
      handleGetDocumentInfoRequest(out, params, response);
245

    
246
    } else if ( action.equals("gettime") ) {
247
      handleGetTimeRequest(out, params, response);
248

    
249
    } else if ( action.equals("getcatalog") ) {
250
      handleGetCatalogRequest(out, params, response, true);
251

    
252
    } else if ( action.equals("servercontrol") ) {
253
      handleServerControlRequest(out, params, response);
254
    } else if ( action.equals("test") ) {
255
      response.setContentType("text/html");
256
      out.println("<html><body>Test successfully</body></html>");
257
    }
258

    
259
    out.close();
260
    }//else
261
  }
262

    
263
  /**
264
   * This method can add, delete and list the servers currently included in
265
   * xml_replication.
266
   * action           subaction            other needed params
267
   * ---------------------------------------------------------
268
   * servercontrol    add                  server
269
   * servercontrol    delete               server
270
   * servercontrol    list
271
   */
272
  private void handleServerControlRequest(PrintWriter out, Hashtable params,
273
                                          HttpServletResponse response)
274
  {
275
    String subaction = ((String[])params.get("subaction"))[0];
276
    DBConnection dbConn = null;
277
    int serialNumber = -1;
278
    PreparedStatement pstmt = null;
279
    String replicate =null;
280
    String server = null;
281
    String dataReplicate = null;
282
    String hub = null;
283
    try {
284
      //conn = util.openDBConnection();
285
      dbConn=DBConnectionPool.
286
               getDBConnection("MetacatReplication.handleServerControlRequest");
287
      serialNumber=dbConn.getCheckOutSerialNumber();
288

    
289
      // add server to server list
290
      if ( subaction.equals("add") ) {
291
        replicate = ((String[])params.get("replicate"))[0];
292
        server = ((String[])params.get("server"))[0];
293

    
294
        //Get data replication value
295
        dataReplicate = ((String[])params.get("datareplicate"))[0];
296
        //Get hub value
297
        hub = ((String[])params.get("hub"))[0];
298

    
299
        /*pstmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
300
                  "(server, last_checked, replicate, datareplicate, hub) " +
301
                                      "VALUES ('" + server + "', to_date(" +
302
                                      "'01/01/00', 'MM/DD/YY'), '" +
303
                                      replicate +"', '" +dataReplicate+"', '"
304
                                      + hub +"')");*/
305
        pstmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
306
                  "(server, last_checked, replicate, datareplicate, hub) " +
307
                                      "VALUES ('" + server + "', "+
308
                                      dbAdapter.toDate("01/01/1980", "MM/DD/YYYY")
309
                                      + ", '" +
310
                                      replicate +"', '" +dataReplicate+"', '"
311
                                      + hub +"')");
312

    
313
        pstmt.execute();
314
        pstmt.close();
315
        dbConn.commit();
316
        out.println("Server " + server + " added");
317
        response.setContentType("text/html");
318
        out.println("<html><body><table border=\"1\">");
319
        out.println("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
320
        out.println("<b>replicate</b></td>");
321
        out.println("<td><b>datareplicate</b></td>");
322
        out.println("<td><b>hub</b></td></tr>");
323
        pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
324
        //increase dbconnection usage
325
        dbConn.increaseUsageCount(1);
326

    
327
        pstmt.execute();
328
        ResultSet rs = pstmt.getResultSet();
329
        boolean tablehasrows = rs.next();
330
        while(tablehasrows) {
331
          out.println("<tr><td>" + rs.getString(2) + "</td><td>");
332
          out.println(rs.getString(3) + "</td><td>");
333
          out.println(rs.getString(4) + "</td><td>");
334
          out.println(rs.getString(5) + "</td><td>");
335
          out.println(rs.getString(6) + "</td></tr>");
336

    
337
          tablehasrows = rs.next();
338
        }
339
        out.println("</table></body></html>");
340

    
341
        // download certificate with the public key on this server
342
        // and import it as a trusted certificate
343
        String certURL = ((String[])params.get("certificate"))[0];
344
        downloadCertificate(certURL);
345

    
346
      // delete server from server list
347
      } else if ( subaction.equals("delete") ) {
348
        server = ((String[])params.get("server"))[0];
349
        pstmt = dbConn.prepareStatement("DELETE FROM xml_replication " +
350
                                      "WHERE server LIKE '" + server + "'");
351
        pstmt.execute();
352
        pstmt.close();
353
        dbConn.commit();
354
        out.println("Server " + server + " deleted");
355
        response.setContentType("text/html");
356
        out.println("<html><body><table border=\"1\">");
357
        out.println("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
358
        out.println("<b>replicate</b></td>");
359
        out.println("<td><b>datareplicate</b></td>");
360
        out.println("<td><b>hub</b></td></tr>");
361

    
362
        pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
363
        //increase dbconnection usage
364
        dbConn.increaseUsageCount(1);
365
        pstmt.execute();
366
        ResultSet rs = pstmt.getResultSet();
367
        boolean tablehasrows = rs.next();
368
        while(tablehasrows)
369
        {
370
          out.println("<tr><td>" + rs.getString(2) + "</td><td>");
371
          out.println(rs.getString(3) + "</td><td>");
372
          out.println(rs.getString(4) + "</td><td>");
373
          out.println(rs.getString(5) + "</td><td>");
374
          out.println(rs.getString(6) + "</td></tr>");
375
          tablehasrows = rs.next();
376
        }
377
        out.println("</table></body></html>");
378

    
379
      // list servers in server list
380
      } else if ( subaction.equals("list") ) {
381
        response.setContentType("text/html");
382
        out.println("<html><body><table border=\"1\">");
383
        out.println("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
384
        out.println("<b>replicate</b></td>");
385
        out.println("<td><b>datareplicate</b></td>");
386
        out.println("<td><b>hub</b></td></tr>");
387
        pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
388
        pstmt.execute();
389
        ResultSet rs = pstmt.getResultSet();
390
        boolean tablehasrows = rs.next();
391
        while(tablehasrows) {
392
          out.println("<tr><td>" + rs.getString(2) + "</td><td>");
393
          out.println(rs.getString(3) + "</td><td>");
394
          out.println(rs.getString(4) + "</td><td>");
395
          out.println(rs.getString(5) + "</td><td>");
396
          out.println(rs.getString(6) + "</td></tr>");
397
          tablehasrows = rs.next();
398
        }
399
        out.println("</table></body></html>");
400
      }
401
      else
402
      {
403

    
404
        out.println("<error>Unkonwn subaction</error>");
405

    
406
      }
407
      pstmt.close();
408
      //conn.close();
409

    
410
    } catch(Exception e) {
411
      System.out.println("Error in " +
412
                         "MetacatReplication.handleServerControlRequest " +
413
                         e.getMessage());
414
      e.printStackTrace(System.out);
415
    }
416
    finally
417
    {
418
      try
419
      {
420
        pstmt.close();
421
      }//try
422
      catch (SQLException ee)
423
      {
424
        MetaCatUtil.debugMessage("Error in " +
425
                "MetacatReplication.handleServerControlRequest to close pstmt "
426
                 + ee.getMessage(), 30);
427
      }//catch
428
      finally
429
      {
430
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
431
      }//finally
432
    }//finally
433

    
434
  }
435

    
436
  // download certificate with the public key from certURL and
437
  // upload it onto this server; it then must be imported as a
438
  // trusted certificate
439
  private void downloadCertificate (String certURL)
440
                throws FileNotFoundException, IOException, MalformedURLException
441
  {
442
    MetaCatUtil util = new MetaCatUtil();
443
    String certPath = util.getOption("certPath"); //the path to be uploaded to
444

    
445
    // get filename from the URL of the certificate
446
    String filename = certURL;
447
    int slash = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
448
    if ( slash > -1 ) {
449
      filename = filename.substring(slash + 1);
450
    }
451

    
452
    // open file output strem to write the input into it
453
    File f = new File(certPath, filename);
454
    synchronized (f) {
455
      try {
456
        if ( f.exists() ) {
457
          throw new IOException("File already exist: " + f.getCanonicalFile());
458
          //if ( f.exists() && !f.canWrite() ) {
459
          //  throw new IOException("Not writable: " + f.getCanonicalFile());
460
        }
461
      } catch (SecurityException se) {
462
        // if a security manager exists,
463
        // its checkRead method is called for f.exist()
464
        // or checkWrite method is called for f.canWrite()
465
        throw se;
466
      }
467

    
468
      // create a buffered byte output stream
469
      // that uses a default-sized output buffer
470
      FileOutputStream fos = new FileOutputStream(f);
471
      BufferedOutputStream out = new BufferedOutputStream(fos);
472

    
473
      // this should be http url
474
      URL url = new URL(certURL);
475
      BufferedInputStream bis = null;
476
      try {
477
        bis = new BufferedInputStream(url.openStream());
478
        byte[] buf = new byte[4 * 1024]; // 4K buffer
479
        int b = bis.read(buf);
480
        while (b != -1) {
481
          out.write(buf, 0, b);
482
          b = bis.read(buf);
483
        }
484
      } finally {
485
        if (bis != null) bis.close();
486
      }
487
      // the input and the output streams must be closed
488
      bis.close();
489
            out.flush();
490
            out.close();
491
            fos.close();
492
    } // end of synchronized(f)
493
  }
494

    
495
  /**
496
   * when a forcereplication request comes in, local host sends a read request
497
   * to the requesting server (remote server) for the specified docid.
498
   * Then store it in local database.
499
   */
500
  private void handleForceReplicateRequest(PrintWriter out, Hashtable params,
501
                                           HttpServletResponse response)
502
  {
503
    String server = ((String[])params.get("server"))[0]; // the server that
504
    String docid = ((String[])params.get("docid"))[0]; // sent the document
505
    String dbaction = "UPDATE"; // the default action is UPDATE
506
    boolean override = false;
507
    int serverCode = 1;
508
    DBConnection dbConn = null;
509
    int serialNumber = -1;
510

    
511
    try {
512
      //if the url contains a dbaction then the default action is overridden
513
      if(params.containsKey("dbaction")) {
514
        dbaction = ((String[])params.get("dbaction"))[0];
515
        //serverCode = MetacatReplication.getServerCode(server);
516
        //override = true; //we are now overriding the default action
517
      }
518
      MetacatReplication.replLog("force replication request from " + server);
519
      MetaCatUtil.debugMessage("Force replication request from: "+ server, 34);
520
      MetaCatUtil.debugMessage("Force replication docid: "+docid, 34);
521
      MetaCatUtil.debugMessage("Force replication action: "+dbaction, 34);
522
      // sending back read request to remote server
523
      URL u = new URL("https://" + server + "?server="
524
                +util.getLocalReplicationServerName()
525
                +"&action=read&docid=" + docid);
526
      String xmldoc = MetacatReplication.getURLContent(u);
527

    
528
      // get the document info from server
529
      URL docinfourl = new URL("https://" + server +
530
                               "?server="+util.getLocalReplicationServerName()
531
                               +"&action=getdocumentinfo&docid=" + docid);
532

    
533
      String docInfoStr = MetacatReplication.getURLContent(docinfourl);
534

    
535
      //dih is the parser for the docinfo xml format
536
      DocInfoHandler dih = new DocInfoHandler();
537
      XMLReader docinfoParser = ReplicationHandler.initParser(dih);
538
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
539
      Hashtable docinfoHash = dih.getDocInfo();
540

    
541
      // Get user owner of this docid
542
      String user = (String)docinfoHash.get("user_owner");
543
      // Get home server of this docid
544
      String homeServer=(String)docinfoHash.get("home_server");
545
      MetaCatUtil.debugMessage("homeServer: "+homeServer, 34);
546
      // Get Document type
547
      String docType = (String)docinfoHash.get("doctype");
548
      MetaCatUtil.debugMessage("docType: "+docType, 34);
549
      String parserBase = null;
550
      // this for eml2 and we need user eml2 parser
551
      if (docType != null &&
552
          (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE))
553
      {
554
         MetaCatUtil.debugMessage("This is an eml200 document!", 30);
555
         parserBase = DocumentImpl.EML200;
556
      }
557
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE))
558
      {
559
         MetaCatUtil.debugMessage("This is an eml2.0.1 document!", 30);
560
         parserBase = DocumentImpl.EML200;
561
      }
562
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE))
563
      {
564
         MetaCatUtil.debugMessage("This is an eml2.1.0 document!", 30);
565
         parserBase = DocumentImpl.EML210;
566
      }
567
      MetaCatUtil.debugMessage("The parserBase is: "+parserBase, 30);
568

    
569
      // Get DBConnection from pool
570
      dbConn=DBConnectionPool.
571
              getDBConnection("MetacatReplication.handleForceReplicateRequest");
572
      serialNumber=dbConn.getCheckOutSerialNumber();
573
      // write the document to local database
574
      DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false);
575
      wrapper.writeReplication(dbConn, new StringReader(xmldoc), null, null,
576
                               dbaction, docid, user, null, homeServer, server);
577

    
578
      MetacatReplication.replLog("document " + docid + " added to DB with " +
579
                                 "action " + dbaction);
580
    }//try
581
    catch(Exception e)
582
    {
583
      MetacatReplication.replErrorLog("document " + docid +
584
                                      " failed to added to DB with " +
585
                                      "action " + dbaction + " because "+
586
                                       e.getMessage());
587
      MetaCatUtil.debugMessage("ERROR in MetacatReplication.handleForceReplicate" +
588
                         "Request(): " + e.getMessage(), 30);
589

    
590
    }//catch
591
    finally
592
    {
593
      // Return the checked out DBConnection
594
      DBConnectionPool.returnDBConnection(dbConn, serialNumber);
595
    }//finally
596
  }
597

    
598
  /**
599
   * when a forcereplication data file request comes in, local host sends a
600
   * readdata request to the requesting server (remote server) for the specified
601
   * docid. Then store it in local database and file system
602
   */
603
  private void handleForceReplicateDataFileRequest(Hashtable params)
604
  {
605

    
606
    //make sure there is some parameters
607
    if(params.isEmpty())
608
    {
609
      return;
610
    }
611
    // Get remote server
612
    String server = ((String[])params.get("server"))[0];
613
    // the docid should include rev number
614
    String docid = ((String[])params.get("docid"))[0];
615
    // Make sure there is a docid and server
616
    if (docid==null || server==null || server.equals(""))
617
    {
618
      MetaCatUtil.debugMessage("Didn't specify docid or server for replication"
619
                              , 20);
620
      return;
621
    }
622

    
623
    // Overide or not
624
    boolean override = false;
625
    // dbaction - update or insert
626
    String dbaction=null;
627

    
628
    try
629
    {
630
      //docid was switch to two parts uinque code and rev
631
      String uniqueCode=MetaCatUtil.getDocIdFromString(docid);
632
      int rev=MetaCatUtil.getVersionFromString(docid);
633
      if(params.containsKey("dbaction"))
634
      {
635
        dbaction = ((String[])params.get("dbaction"))[0];
636
      }
637
      else//default value is update
638
      {
639
        dbaction = "update";
640
      }
641

    
642
      MetacatReplication.replLog("force replication request from " + server);
643
      MetaCatUtil.debugMessage("Force replication request from: "+ server, 34);
644
      MetaCatUtil.debugMessage("Force replication docid: "+docid, 34);
645
      MetaCatUtil.debugMessage("Force replication action: "+dbaction, 34);
646
      // get the document info from server
647
      URL docinfourl = new URL("https://" + server +
648
                               "?server="+util.getLocalReplicationServerName()
649
                               +"&action=getdocumentinfo&docid=" + uniqueCode);
650

    
651
      String docInfoStr = MetacatReplication.getURLContent(docinfourl);
652

    
653
      //dih is the parser for the docinfo xml format
654
      DocInfoHandler dih = new DocInfoHandler();
655
      XMLReader docinfoParser = ReplicationHandler.initParser(dih);
656
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
657
      Hashtable docinfoHash = dih.getDocInfo();
658
      String user = (String)docinfoHash.get("user_owner");
659

    
660
      String docName = (String)docinfoHash.get("docname");
661

    
662
      String docType = (String)docinfoHash.get("doctype");
663

    
664
      String docHomeServer= (String)docinfoHash.get("home_server");
665
      MetaCatUtil.debugMessage("docHomeServer of datafile: "+docHomeServer, 34);
666

    
667

    
668

    
669
      //if action is delete, we don't delete the data file. Just archieve
670
      //the xml_documents
671
      if (dbaction.equals("delete"))
672
      {
673
        //conn = util.getConnection();
674
        DocumentImpl.delete(docid,user,null);
675
        //util.returnConnection(conn);
676
      }
677
      //To data file insert or update is same
678
      else if (dbaction.equals("insert")||dbaction.equals("update"))
679
      {
680
        //Get data file and store it into local file system.
681
        // sending back readdata request to server
682
        URL url = new URL("https://" + server + "?server="
683
                +util.getLocalReplicationServerName()
684
                +"&action=readdata&docid=" + docid);
685
        String datafilePath = util.getOption("datafilepath");
686
        //register data file into xml_documents table and wite data file
687
        //into file system
688
        DocumentImpl.writeDataFileInReplication(url.openStream(), datafilePath,
689
                            docName, docType, docid, user,docHomeServer,server);
690
     }
691

    
692

    
693

    
694
    MetacatReplication.replLog("datafile " + docid + " added to DB with " +
695
                                 "action " + dbaction);
696
    }
697
    catch(Exception e)
698
    {
699

    
700
      MetacatReplication.replErrorLog("Datafile " + docid +
701
                                      " failed to added to DB with " +
702
                                      "action " + dbaction + " because "+
703
                                       e.getMessage());
704
      MetaCatUtil.debugMessage
705
              ("ERROR in MetacatReplication.handleForceDataFileReplicate" +
706
                         "Request(): " + e.getMessage(), 30);
707
    }
708
  }
709
  /**
710
   * Grants or denies a lock to a requesting host.
711
   * The servlet parameters of interrest are:
712
   * docid: the docid of the file the lock is being requested for
713
   * currentdate: the timestamp of the document on the remote server
714
   *
715
   */
716
  private void handleGetLockRequest(PrintWriter out, Hashtable params,
717
                                    HttpServletResponse response)
718
  {
719

    
720
    try
721
    {
722

    
723
      String docid = ((String[])params.get("docid"))[0];
724
      String remoteRev = ((String[])params.get("updaterev"))[0];
725
      DocumentImpl requestDoc = new DocumentImpl(docid);
726
      MetacatReplication.replLog("lock request for " + docid);
727
      int localRevInt = requestDoc.getRev();
728
      int remoteRevInt = Integer.parseInt(remoteRev);
729

    
730
      if(remoteRevInt >= localRevInt)
731
      {
732
        if(!fileLocks.contains(docid))
733
        { //grant the lock if it is not already locked
734
          fileLocks.add(0, docid); //insert at the beginning of the queue Vector
735
          //send a message back to the the remote host authorizing the insert
736
          out.println("<lockgranted><docid>" +docid+ "</docid></lockgranted>");
737
          lockThread = new Thread(this);
738
          lockThread.setPriority(Thread.MIN_PRIORITY);
739
          lockThread.start();
740
          MetacatReplication.replLog("lock granted for " + docid);
741
        }
742
        else
743
        { //deny the lock
744
          out.println("<filelocked><docid>" + docid + "</docid></filelocked>");
745
          MetacatReplication.replLog("lock denied for " + docid +
746
                                     "reason: file already locked");
747
        }
748
      }
749
      else
750
      {//deny the lock.
751
        out.println("<outdatedfile><docid>" + docid + "</docid></filelocked>");
752
        MetacatReplication.replLog("lock denied for " + docid +
753
                                   "reason: client has outdated file");
754
      }
755
      //conn.close();
756
    }
757
    catch(Exception e)
758
    {
759
      System.out.println("error requesting file lock from MetacatReplication." +
760
                         "handleGetLockRequest: " + e.getMessage());
761
      e.printStackTrace(System.out);
762
    }
763
  }
764

    
765
  /**
766
   * Sends all of the xml_documents information encoded in xml to a requestor
767
   * the format is:
768
   * <!ELEMENT documentinfo (docid, docname, doctype, doctitle, user_owner,
769
   *                  user_updated, home_server, public_access, rev)/>
770
   * all of the subelements of document info are #PCDATA
771
   */
772
  private void handleGetDocumentInfoRequest(PrintWriter out, Hashtable params,
773
                                        HttpServletResponse response)
774
  {
775
    String docid = ((String[])(params.get("docid")))[0];
776
    StringBuffer sb = new StringBuffer();
777

    
778
    try
779
    {
780

    
781
      DocumentImpl doc = new DocumentImpl(docid);
782
      sb.append("<documentinfo><docid>").append(docid);
783
      sb.append("</docid><docname>").append(doc.getDocname());
784
      sb.append("</docname><doctype>").append(doc.getDoctype());
785
      sb.append("</doctype>");
786
      sb.append("<user_owner>").append(doc.getUserowner());
787
      sb.append("</user_owner><user_updated>").append(doc.getUserupdated());
788
      sb.append("</user_updated>");
789
      sb.append("<home_server>");
790
      sb.append(doc.getDocHomeServer());
791
      sb.append("</home_server>");
792
      sb.append("<public_access>").append(doc.getPublicaccess());
793
      sb.append("</public_access><rev>").append(doc.getRev());
794
      sb.append("</rev></documentinfo>");
795
      response.setContentType("text/xml");
796
      out.println(sb.toString());
797

    
798
    }
799
    catch (Exception e)
800
    {
801
      System.out.println("error in " +
802
                         "metacatReplication.handlegetdocumentinforequest: " +
803
                          e.getMessage());
804
    }
805

    
806
  }
807

    
808
  /**
809
   * Sends a datafile to a remote host
810
   */
811
  private void handleGetDataFileRequest(OutputStream outPut,
812
                            Hashtable params, HttpServletResponse response)
813

    
814
  {
815
    // File path for data file
816
    String filepath = util.getOption("datafilepath");
817
    // Request docid
818
    String docId = ((String[])(params.get("docid")))[0];
819
    //check if the doicd is null
820
    if (docId==null)
821
    {
822
      util.debugMessage("Didn't specify docid for replication", 20);
823
      return;
824
    }
825

    
826
    //try to open a https stream to test if the request server's public key
827
    //in the key store, this is security issue
828
    try
829
    {
830
      String server = ((String[])params.get("server"))[0];
831
      URL u = new URL("https://" + server + "?server="
832
                +util.getLocalReplicationServerName()
833
                +"&action=test");
834
      String test = MetacatReplication.getURLContent(u);
835
      //couldn't pass the test
836
      if (test.indexOf("successfully")==-1)
837
      {
838
        //response.setContentType("text/xml");
839
        //outPut.println("<error>Couldn't pass the trust test</error>");
840
        MetaCatUtil.debugMessage("Couldn't pass the trust test", 20);
841
        return;
842
      }
843
    }//try
844
    catch (Exception ee)
845
    {
846
      return;
847
    }//catch
848

    
849
    if(!filepath.endsWith("/"))
850
    {
851
          filepath += "/";
852
    }
853
    // Get file aboslute file name
854
    String filename = filepath + docId;
855

    
856
    //MIME type
857
    String contentType = null;
858
    if (filename.endsWith(".xml"))
859
    {
860
        contentType="text/xml";
861
    }
862
    else if (filename.endsWith(".css"))
863
    {
864
        contentType="text/css";
865
    }
866
    else if (filename.endsWith(".dtd"))
867
    {
868
        contentType="text/plain";
869
    }
870
    else if (filename.endsWith(".xsd"))
871
    {
872
        contentType="text/xml";
873
    }
874
    else if (filename.endsWith("/"))
875
    {
876
        contentType="text/html";
877
    }
878
    else
879
    {
880
        File f = new File(filename);
881
        if ( f.isDirectory() )
882
        {
883
           contentType="text/html";
884
        }
885
        else
886
        {
887
           contentType="application/octet-stream";
888
        }
889
     }
890

    
891
   // Set the mime type
892
   response.setContentType(contentType);
893

    
894
   // Get the content of the file
895
   FileInputStream fin = null;
896
   try
897
   {
898
      // FileInputStream to metacat
899
      fin = new FileInputStream(filename);
900
      // 4K buffer
901
      byte[] buf = new byte[4 * 1024];
902
      // Read data from file input stream to byte array
903
      int b = fin.read(buf);
904
      // Write to outStream from byte array
905
      while (b != -1)
906
      {
907
        outPut.write(buf, 0, b);
908
        b = fin.read(buf);
909
      }
910
      // close file input stream
911
      fin.close();
912

    
913
   }//try
914
   catch(Exception e)
915
   {
916
      System.out.println("error getting data file from MetacatReplication." +
917
                         "handlGetDataFileRequest " + e.getMessage());
918
      e.printStackTrace(System.out);
919
   }//catch
920

    
921
}
922

    
923

    
924
  /**
925
   * Sends a document to a remote host
926
   */
927
  private void handleGetDocumentRequest(PrintWriter out, Hashtable params,
928
                                        HttpServletResponse response)
929
  {
930

    
931
    try
932
    {
933
      //try to open a https stream to test if the request server's public key
934
      //in the key store, this is security issue
935
      String server = ((String[])params.get("server"))[0];
936
      URL u = new URL("https://" + server + "?server="
937
                +util.getLocalReplicationServerName()
938
                +"&action=test");
939
      String test = MetacatReplication.getURLContent(u);
940
      //couldn't pass the test
941
      if (test.indexOf("successfully")==-1)
942
      {
943
        response.setContentType("text/xml");
944
        out.println("<error>Couldn't pass the trust test</error>");
945
        out.close();
946
        return;
947
      }
948

    
949
      String docid = ((String[])(params.get("docid")))[0];
950

    
951
      DocumentImpl di = new DocumentImpl(docid);
952
      response.setContentType("text/xml");
953
      out.print(di.toString(null, null, true));
954

    
955
      MetacatReplication.replLog("document " + docid + " sent");
956

    
957
    }
958
    catch(Exception e)
959
    {
960
      MetaCatUtil.debugMessage("error getting document from MetacatReplication."
961
                          +"handlGetDocumentRequest " + e.getMessage(), 30);
962
      //e.printStackTrace(System.out);
963
      response.setContentType("text/xml");
964
      out.println("<error>"+e.getMessage()+"</error>");
965
    }
966

    
967
  }
968

    
969
  /**
970
   * Sends a list of all of the documents on this sever along with their
971
   * revision numbers.
972
   * The format is:
973
   * <!ELEMENT replication (server, updates)>
974
   * <!ELEMENT server (#PCDATA)>
975
   * <!ELEMENT updates ((updatedDocument | deleteDocument)*)>
976
   * <!ELEMENT updatedDocument (docid, rev, datafile*)>
977
   * <!ELEMENT deletedDocument (docid, rev)>
978
   * <!ELEMENT docid (#PCDATA)>
979
   * <!ELEMENT rev (#PCDATA)>
980
   * <!ELEMENT datafile (#PCDATA)>
981
   * note that the rev in deletedDocument is always empty.  I just left
982
   * it in there to make the parser implementation easier.
983
   */
984
  private void handleUpdateRequest(PrintWriter out, Hashtable params,
985
                                    HttpServletResponse response)
986
  {
987
    // Checked out DBConnection
988
    DBConnection dbConn = null;
989
    // DBConenction serial number when checked it out
990
    int serialNumber = -1;
991
    PreparedStatement pstmt = null;
992
    // Server list to store server info of xml_replication table
993
    ReplicationServerList serverList = null;
994

    
995
    try
996
    {
997
      // Check out a DBConnection from pool
998
      dbConn=DBConnectionPool.
999
                  getDBConnection("MetacatReplication.handleUpdateRequest");
1000
      serialNumber=dbConn.getCheckOutSerialNumber();
1001
      // Create a server list from xml_replication table
1002
      serverList = new ReplicationServerList();
1003

    
1004
      // Get remote server name from param
1005
      String server = ((String[])params.get("server"))[0];
1006
      // If no servr name in param, return a error
1007
      if ( server == null || server.equals(""))
1008
      {
1009
        response.setContentType("text/xml");
1010
        out.println("<error>Request didn't specify server name</error>");
1011
        out.close();
1012
        return;
1013
      }//if
1014

    
1015
      //try to open a https stream to test if the request server's public key
1016
      //in the key store, this is security issue
1017
      URL u = new URL("https://" + server + "?server="
1018
                +util.getLocalReplicationServerName()
1019
                +"&action=test");
1020
      String test = MetacatReplication.getURLContent(u);
1021
      //couldn't pass the test
1022
      if (test.indexOf("successfully")==-1)
1023
      {
1024
        response.setContentType("text/xml");
1025
        out.println("<error>Couldn't pass the trust test</error>");
1026
        out.close();
1027
        return;
1028
      }
1029

    
1030

    
1031
      // Check if local host configure to replicate xml documents to remote
1032
      // server. If not send back a error message
1033
      if (!serverList.getReplicationValue(server))
1034
      {
1035
        response.setContentType("text/xml");
1036
        out.println
1037
        ("<error>Configuration not allow to replicate document to you</error>");
1038
        out.close();
1039
        return;
1040
      }//if
1041

    
1042
      // Store the sql command
1043
      StringBuffer docsql = new StringBuffer();
1044
      // Stroe the docid list
1045
      StringBuffer doclist = new StringBuffer();
1046
      // Store the deleted docid list
1047
      StringBuffer delsql = new StringBuffer();
1048
      // Store the data set file
1049
      Vector packageFiles = new Vector();
1050

    
1051
      // Append local server's name and replication servlet to doclist
1052
      doclist.append("<?xml version=\"1.0\"?><replication>");
1053
      doclist.append("<server>").append(util.getOption("server"));
1054
      doclist.append(util.getOption("replicationpath"));
1055
      doclist.append("</server><updates>");
1056

    
1057
      // Get correct docid that reside on this server according the requesting
1058
      // server's replicate and data replicate value in xml_replication table
1059
      docsql.append("select docid, rev, doctype from xml_documents ");
1060
      // If the localhost is not a hub to the remote server, only replicate
1061
      // the docid' which home server is local host (server_location =1)
1062
      if (!serverList.getHubValue(server))
1063
      {
1064
        docsql.append("where server_location = 1");
1065
      }
1066
      MetaCatUtil.debugMessage("Doc sql: "+docsql.toString(), 30);
1067

    
1068
      // Get any deleted documents
1069
      delsql.append("select distinct docid from ");
1070
      delsql.append("xml_revisions where docid not in (select docid from ");
1071
      delsql.append("xml_documents) ");
1072
      // If the localhost is not a hub to the remote server, only replicate
1073
      // the docid' which home server is local host (server_location =1)
1074
      if (!serverList.getHubValue(server))
1075
      {
1076
        delsql.append("and server_location = 1");
1077
      }
1078
      MetaCatUtil.debugMessage("Deleted sql: "+delsql.toString(), 30);
1079

    
1080

    
1081

    
1082
      // Get docid list of local host
1083
      pstmt = dbConn.prepareStatement(docsql.toString());
1084
      pstmt.execute();
1085
      ResultSet rs = pstmt.getResultSet();
1086
      boolean tablehasrows = rs.next();
1087
      //If metacat configed to replicate data file
1088
      //if ((util.getOption("replicationsenddata")).equals("on"))
1089
      if (serverList.getDataReplicationValue(server))
1090
      {
1091
        while(tablehasrows)
1092
        {
1093
          String recordDoctype = rs.getString(3);
1094
          Vector packagedoctypes = MetaCatUtil.getOptionList(
1095
                                     MetaCatUtil.getOption("packagedoctype"));
1096
          //if this is a package file, put it at the end
1097
          //because if a package file is read before all of the files it
1098
          //refers to are loaded then there is an error
1099
          if(recordDoctype != null && !packagedoctypes.contains(recordDoctype))
1100
          {
1101
              //If this is not data file
1102
              if (!recordDoctype.equals("BIN"))
1103
              {
1104
                //for non-data file document
1105
                doclist.append("<updatedDocument>");
1106
                doclist.append("<docid>").append(rs.getString(1));
1107
                doclist.append("</docid><rev>").append(rs.getInt(2));
1108
                doclist.append("</rev>");
1109
                doclist.append("</updatedDocument>");
1110
              }//if
1111
              else
1112
              {
1113
                //for data file document, in datafile attributes
1114
                //we put "datafile" value there
1115
                doclist.append("<updatedDocument>");
1116
                doclist.append("<docid>").append(rs.getString(1));
1117
                doclist.append("</docid><rev>").append(rs.getInt(2));
1118
                doclist.append("</rev>");
1119
                doclist.append("<datafile>");
1120
                doclist.append(MetaCatUtil.getOption("datafileflag"));
1121
                doclist.append("</datafile>");
1122
                doclist.append("</updatedDocument>");
1123
              }//else
1124
          }//if packagedoctpes
1125
          else
1126
          { //the package files are saved to be put into the xml later.
1127
              Vector v = new Vector();
1128
              v.add(new String(rs.getString(1)));
1129
              v.add(new Integer(rs.getInt(2)));
1130
              packageFiles.add(new Vector(v));
1131
          }//esle
1132
          tablehasrows = rs.next();
1133
        }//while
1134
      }//if
1135
      else //metacat was configured not to send data file
1136
      {
1137
        while(tablehasrows)
1138
        {
1139
          String recordDoctype = rs.getString(3);
1140
          if(!recordDoctype.equals("BIN"))
1141
          { //don't replicate data files
1142
            Vector packagedoctypes = MetaCatUtil.getOptionList(
1143
                                     MetaCatUtil.getOption("packagedoctype"));
1144
            if(recordDoctype != null && !packagedoctypes.contains(recordDoctype))
1145
            {   //if this is a package file, put it at the end
1146
              //because if a package file is read before all of the files it
1147
              //refers to are loaded then there is an error
1148
              doclist.append("<updatedDocument>");
1149
              doclist.append("<docid>").append(rs.getString(1));
1150
              doclist.append("</docid><rev>").append(rs.getInt(2));
1151
              doclist.append("</rev>");
1152
              doclist.append("</updatedDocument>");
1153
            }
1154
            else
1155
            { //the package files are saved to be put into the xml later.
1156
              Vector v = new Vector();
1157
              v.add(new String(rs.getString(1)));
1158
              v.add(new Integer(rs.getInt(2)));
1159
              packageFiles.add(new Vector(v));
1160
            }
1161
         }//if
1162
         tablehasrows = rs.next();
1163
        }//while
1164
      }//else
1165

    
1166
      pstmt = dbConn.prepareStatement(delsql.toString());
1167
      //usage count should increas 1
1168
      dbConn.increaseUsageCount(1);
1169

    
1170
      pstmt.execute();
1171
      rs = pstmt.getResultSet();
1172
      tablehasrows = rs.next();
1173
      while(tablehasrows)
1174
      { //handle the deleted documents
1175
        doclist.append("<deletedDocument><docid>").append(rs.getString(1));
1176
        doclist.append("</docid><rev></rev></deletedDocument>");
1177
        //note that rev is always empty for deleted docs
1178
        tablehasrows = rs.next();
1179
      }
1180

    
1181
      //now we can put the package files into the xml results
1182
      for(int i=0; i<packageFiles.size(); i++)
1183
      {
1184
        Vector v = (Vector)packageFiles.elementAt(i);
1185
        doclist.append("<updatedDocument>");
1186
        doclist.append("<docid>").append((String)v.elementAt(0));
1187
        doclist.append("</docid><rev>");
1188
        doclist.append(((Integer)v.elementAt(1)).intValue());
1189
        doclist.append("</rev>");
1190
        doclist.append("</updatedDocument>");
1191
      }
1192

    
1193
      doclist.append("</updates></replication>");
1194
      MetaCatUtil.debugMessage("doclist: " + doclist.toString(), 40);
1195
      pstmt.close();
1196
      //conn.close();
1197
      response.setContentType("text/xml");
1198
      out.println(doclist.toString());
1199

    
1200
    }
1201
    catch(Exception e)
1202
    {
1203
      MetaCatUtil.debugMessage("error in MetacatReplication." +
1204
                         "handleupdaterequest: " + e.getMessage(), 30);
1205
      //e.printStackTrace(System.out);
1206
      response.setContentType("text/xml");
1207
      out.println("<error>"+e.getMessage()+"</error>");
1208
    }
1209
    finally
1210
    {
1211
      try
1212
      {
1213
        pstmt.close();
1214
      }//try
1215
      catch (SQLException ee)
1216
      {
1217
        MetaCatUtil.debugMessage("Error in MetacatReplication." +
1218
                "handleUpdaterequest to close pstmt: "+ee.getMessage(), 30);
1219
      }//catch
1220
      finally
1221
      {
1222
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1223
      }//finally
1224
    }//finally
1225

    
1226
  }//handlUpdateRequest
1227

    
1228
  /**
1229
   * Returns the xml_catalog table encoded in xml
1230
   */
1231
  public static String getCatalogXML()
1232
  {
1233
    return handleGetCatalogRequest(null, null, null, false);
1234
  }
1235

    
1236
  /**
1237
   * Sends the contents of the xml_catalog table encoded in xml
1238
   * The xml format is:
1239
   * <!ELEMENT xml_catalog (row*)>
1240
   * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
1241
   *                system_id)>
1242
   * All of the sub elements of row are #PCDATA
1243

    
1244
   * If printFlag == false then do not print to out.
1245
   */
1246
  private static String handleGetCatalogRequest(PrintWriter out,
1247
                                                Hashtable params,
1248
                                                HttpServletResponse response,
1249
                                                boolean printFlag)
1250
  {
1251
    DBConnection dbConn = null;
1252
    int serialNumber = -1;
1253
    PreparedStatement pstmt = null;
1254
    try
1255
    {
1256
      /*conn = MetacatReplication.getDBConnection("MetacatReplication." +
1257
                                                "handleGetCatalogRequest");*/
1258
      dbConn=DBConnectionPool.
1259
                 getDBConnection("MetacatReplication.handleGetCatalogRequest");
1260
      serialNumber=dbConn.getCheckOutSerialNumber();
1261
      pstmt = dbConn.prepareStatement("select entry_type, " +
1262
                              "source_doctype, target_doctype, public_id, " +
1263
                              "system_id from xml_catalog");
1264
      pstmt.execute();
1265
      ResultSet rs = pstmt.getResultSet();
1266
      boolean tablehasrows = rs.next();
1267
      StringBuffer sb = new StringBuffer();
1268
      sb.append("<?xml version=\"1.0\"?><xml_catalog>");
1269
      while(tablehasrows)
1270
      {
1271
        sb.append("<row><entry_type>").append(rs.getString(1));
1272
        sb.append("</entry_type><source_doctype>").append(rs.getString(2));
1273
        sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
1274
        sb.append("</target_doctype><public_id>").append(rs.getString(4));
1275
        sb.append("</public_id><system_id>").append(rs.getString(5));
1276
        sb.append("</system_id></row>");
1277

    
1278
        tablehasrows = rs.next();
1279
      }
1280
      sb.append("</xml_catalog>");
1281
      //conn.close();
1282
      if(printFlag)
1283
      {
1284
        response.setContentType("text/xml");
1285
        out.println(sb.toString());
1286
      }
1287
      pstmt.close();
1288
      return sb.toString();
1289
    }
1290
    catch(Exception e)
1291
    {
1292

    
1293
      System.out.println("error in MetacatReplication.handleGetCatalogRequest:"+
1294
                          e.getMessage());
1295
      e.printStackTrace(System.out);
1296
      if(printFlag)
1297
      {
1298
        out.println("<error>"+e.getMessage()+"</error>");
1299
      }
1300
    }
1301
    finally
1302
    {
1303
      try
1304
      {
1305
        pstmt.close();
1306
      }//try
1307
      catch (SQLException ee)
1308
      {
1309
        MetaCatUtil.
1310
           debugMessage("Error in MetacatReplication.handleGetCatalogRequest: "
1311
           +ee.getMessage(), 30);
1312
      }//catch
1313
      finally
1314
      {
1315
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1316
      }//finally
1317
    }//finally
1318

    
1319
    return null;
1320
  }
1321

    
1322
  /**
1323
   * Sends the current system date to the remote server.  Using this action
1324
   * for replication gets rid of any problems with syncronizing clocks
1325
   * because a time specific to a document is always kept on its home server.
1326
   */
1327
  private void handleGetTimeRequest(PrintWriter out, Hashtable params,
1328
                                    HttpServletResponse response)
1329
  {
1330
    SimpleDateFormat formatter = new SimpleDateFormat ("MM/dd/yy HH:mm:ss");
1331
    java.util.Date localtime = new java.util.Date();
1332
    String dateString = formatter.format(localtime);
1333
    response.setContentType("text/xml");
1334

    
1335
    out.println("<timestamp>" + dateString + "</timestamp>");
1336
  }
1337

    
1338
  /**
1339
   * this method handles the timeout for a file lock.  when a lock is
1340
   * granted it is granted for 30 seconds.  When this thread runs out
1341
   * it deletes the docid from the queue, thus eliminating the lock.
1342
   */
1343
  public void run()
1344
  {
1345
    try
1346
    {
1347
      MetaCatUtil.debugMessage("thread started for docid: " +
1348
                               (String)fileLocks.elementAt(0), 45);
1349

    
1350
      Thread.sleep(30000); //the lock will expire in 30 seconds
1351
      MetaCatUtil.debugMessage("thread for docid: " +
1352
                             (String)fileLocks.elementAt(fileLocks.size() - 1) +
1353
                              " exiting.", 45);
1354

    
1355
      fileLocks.remove(fileLocks.size() - 1);
1356
      //fileLocks is treated as a FIFO queue.  If there are more than one lock
1357
      //in the vector, the first one inserted will be removed.
1358
    }
1359
    catch(Exception e)
1360
    {
1361
      MetaCatUtil.debugMessage("error in file lock thread from " +
1362
                                "MetacatReplication.run: " + e.getMessage(), 30);
1363
    }
1364
  }
1365

    
1366
  /**
1367
   * Returns the name of a server given a serverCode
1368
   * @param serverCode the serverid of the server
1369
   * @return the servername or null if the specified serverCode does not
1370
   *         exist.
1371
   */
1372
  public static String getServerNameForServerCode(int serverCode)
1373
  {
1374
    //System.out.println("serverid: " + serverCode);
1375
    DBConnection dbConn = null;
1376
    int serialNumber = -1;
1377
    PreparedStatement pstmt = null;
1378
    try
1379
    {
1380
      dbConn=DBConnectionPool.
1381
                  getDBConnection("MetacatReplication.getServer");
1382
      serialNumber=dbConn.getCheckOutSerialNumber();
1383
      String sql = new String("select server from " +
1384
                              "xml_replication where serverid = " +
1385
                              serverCode);
1386
      pstmt = dbConn.prepareStatement(sql);
1387
      //System.out.println("getserver sql: " + sql);
1388
      pstmt.execute();
1389
      ResultSet rs = pstmt.getResultSet();
1390
      boolean tablehasrows = rs.next();
1391
      if(tablehasrows)
1392
      {
1393
        //System.out.println("server: " + rs.getString(1));
1394
        return rs.getString(1);
1395
      }
1396

    
1397
      //conn.close();
1398
    }
1399
    catch(Exception e)
1400
    {
1401
      System.out.println("Error in MetacatReplication.getServer: " +
1402
                          e.getMessage());
1403
    }
1404
    finally
1405
    {
1406
      try
1407
      {
1408
        pstmt.close();
1409
      }//try
1410
      catch (SQLException ee)
1411
      {
1412
        MetaCatUtil.debugMessage("Error in MetacactReplication.getserver: "+
1413
                                    ee.getMessage(), 30);
1414
      }//catch
1415
      finally
1416
      {
1417
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1418
      }//fianlly
1419
    }//finally
1420

    
1421

    
1422

    
1423
    return null;
1424
      //return null if the server does not exist
1425
  }
1426

    
1427
  /**
1428
   * Returns a server code given a server name
1429
   * @param server the name of the server
1430
   * @return integer > 0 representing the code of the server, 0 if the server
1431
   *  does not exist.
1432
   */
1433
  public static int getServerCodeForServerName(String server) throws Exception
1434
  {
1435
    DBConnection dbConn = null;
1436
    int serialNumber = -1;
1437
    PreparedStatement pstmt = null;
1438
    int serverCode = 0;
1439

    
1440
    try {
1441

    
1442
      //conn = util.openDBConnection();
1443
      dbConn=DBConnectionPool.
1444
                  getDBConnection("MetacatReplication.getServerCode");
1445
      serialNumber=dbConn.getCheckOutSerialNumber();
1446
      pstmt = dbConn.prepareStatement("SELECT serverid FROM xml_replication " +
1447
                                    "WHERE server LIKE '" + server + "'");
1448
      pstmt.execute();
1449
      ResultSet rs = pstmt.getResultSet();
1450
      boolean tablehasrows = rs.next();
1451
      if ( tablehasrows ) {
1452
        serverCode = rs.getInt(1);
1453
        pstmt.close();
1454
        //conn.close();
1455
        return serverCode;
1456
      }
1457

    
1458
    } catch(Exception e) {
1459
      throw e;
1460

    
1461
    } finally {
1462
      try
1463
      {
1464
        pstmt.close();
1465
        //conn.close();
1466
       }//try
1467
       catch(Exception ee)
1468
       {
1469
         MetaCatUtil.debugMessage("Error in MetacatReplicatio.getServerCode: "
1470
                                  +ee.getMessage(), 30);
1471

    
1472
       }//catch
1473
       finally
1474
       {
1475
         DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1476
       }//finally
1477
    }//finally
1478

    
1479
    return serverCode;
1480
  }
1481

    
1482
  /**
1483
   * Method to get a host server information for given docid
1484
   * @param conn a connection to the database
1485
   */
1486
  public static Hashtable getHomeServerInfoForDocId(String docId)
1487
  {
1488
    Hashtable sl = new Hashtable();
1489
    DBConnection dbConn = null;
1490
    int serialNumber = -1;
1491
    //MetaCatUtil ut=new MetaCatUtil();
1492
    docId=MetaCatUtil.getDocIdFromString(docId);
1493
    PreparedStatement pstmt=null;
1494
    int serverLocation;
1495
    try
1496
    {
1497
      //get conection
1498
      dbConn=DBConnectionPool.
1499
                  getDBConnection("ReplicationHandler.getHomeServer");
1500
      serialNumber=dbConn.getCheckOutSerialNumber();
1501
      //get a server location from xml_document table
1502
      pstmt=dbConn.prepareStatement("select server_location from xml_documents "
1503
                                            +"where docid = ?");
1504
      pstmt.setString(1, docId);
1505
      pstmt.execute();
1506
      ResultSet serverName = pstmt.getResultSet();
1507
      //get a server location
1508
      if(serverName.next())
1509
      {
1510
        serverLocation=serverName.getInt(1);
1511
        pstmt.close();
1512
      }
1513
      else
1514
      {
1515
        pstmt.close();
1516
        //ut.returnConnection(conn);
1517
        return null;
1518
      }
1519
      pstmt=dbConn.prepareStatement("select server, last_checked, replicate " +
1520
                        "from xml_replication where serverid = ?");
1521
      //increase usage count
1522
      dbConn.increaseUsageCount(1);
1523
      pstmt.setInt(1, serverLocation);
1524
      pstmt.execute();
1525
      ResultSet rs = pstmt.getResultSet();
1526
      boolean tableHasRows = rs.next();
1527
      if (tableHasRows)
1528
      {
1529

    
1530
          String server = rs.getString(1);
1531
          String last_checked = rs.getString(2);
1532
          if(!server.equals("localhost"))
1533
          {
1534
            sl.put(server, last_checked);
1535
          }
1536

    
1537
      }
1538
      else
1539
      {
1540
        pstmt.close();
1541
        //ut.returnConnection(conn);
1542
        return null;
1543
      }
1544
      pstmt.close();
1545
    }
1546
    catch(Exception e)
1547
    {
1548
      System.out.println("error in replicationHandler.getHomeServer(): " +
1549
                         e.getMessage());
1550
    }
1551
    finally
1552
    {
1553
      try
1554
      {
1555
        pstmt.close();
1556
        //ut.returnConnection(conn);
1557
      }
1558
      catch (Exception ee)
1559
      {
1560
        MetaCatUtil.debugMessage("Eror irn rplicationHandler.getHomeServer() "+
1561
                          "to close pstmt: "+ee.getMessage(), 30);
1562
      }
1563
      finally
1564
      {
1565
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1566
      }
1567

    
1568
    }//finally
1569
    return sl;
1570
  }
1571

    
1572
  /**
1573
   * Returns a home server location  given a accnum
1574
   * @param accNum , given accNum for a document
1575
   *
1576
   */
1577
  public static int getHomeServerCodeForDocId(String accNum) throws Exception
1578
  {
1579
    DBConnection dbConn = null;
1580
    int serialNumber = -1;
1581
    PreparedStatement pstmt = null;
1582
    int serverCode = 1;
1583
    //MetaCatUtil ut = new MetaCatUtil();
1584
    String docId=MetaCatUtil.getDocIdFromString(accNum);
1585

    
1586
    try
1587
    {
1588

    
1589
      // Get DBConnection
1590
      dbConn=DBConnectionPool.
1591
                  getDBConnection("ReplicationHandler.getServerLocation");
1592
      serialNumber=dbConn.getCheckOutSerialNumber();
1593
      pstmt=dbConn.prepareStatement("SELECT server_location FROM xml_documents "
1594
                              + "WHERE docid LIKE '" + docId + "'");
1595
      pstmt.execute();
1596
      ResultSet rs = pstmt.getResultSet();
1597
      boolean tablehasrows = rs.next();
1598
      //If a document is find, return the server location for it
1599
      if ( tablehasrows )
1600
      {
1601
        serverCode = rs.getInt(1);
1602
        pstmt.close();
1603
        //conn.close();
1604
        return serverCode;
1605
      }
1606
      //if couldn't find in xml_documents table, we think server code is 1
1607
      //(this is new document)
1608
      else
1609
      {
1610
        pstmt.close();
1611
        //conn.close();
1612
        return serverCode;
1613
      }
1614

    
1615
    }
1616
    catch(Exception e)
1617
    {
1618

    
1619
      throw e;
1620

    
1621
    }
1622
    finally
1623
    {
1624
      try
1625
      {
1626
        pstmt.close();
1627
        //conn.close();
1628

    
1629
      }
1630
      catch(Exception ee)
1631
      {
1632
        MetaCatUtil.debugMessage("Erorr in Replication.getServerLocation "+
1633
                     "to close pstmt"+ee.getMessage(), 30);
1634
      }
1635
      finally
1636
      {
1637
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1638
      }//finally
1639
    }//finally
1640
   //return serverCode;
1641
  }
1642

    
1643

    
1644

    
1645
  /**
1646
   * This method returns the content of a url
1647
   * @param u the url to return the content from
1648
   * @return a string representing the content of the url
1649
   * @throws java.io.IOException
1650
   */
1651
  public static String getURLContent(URL u) throws java.io.IOException
1652
  {
1653
    char istreamChar;
1654
    int istreamInt;
1655
    MetaCatUtil.debugMessage("Before open the stream"+u.toString(), 50);
1656
    InputStream input = u.openStream();
1657
    MetaCatUtil.debugMessage("Afetr open the stream"+u.toString(), 50);
1658
    InputStreamReader istream = new InputStreamReader(input);
1659
    StringBuffer serverResponse = new StringBuffer();
1660
    while((istreamInt = istream.read()) != -1)
1661
    {
1662
      istreamChar = (char)istreamInt;
1663
      serverResponse.append(istreamChar);
1664
    }
1665
    istream.close();
1666
    input.close();
1667

    
1668
    return serverResponse.toString();
1669
  }
1670

    
1671
  /**
1672
   * Method for writing replication messages to a log file specified in
1673
   * metacat.properties
1674
   */
1675
  public static void replLog(String message)
1676
  {
1677
    try
1678
    {
1679
      FileOutputStream fos = new FileOutputStream(
1680
                                 util.getOption("replicationlog"), true);
1681
      PrintWriter pw = new PrintWriter(fos);
1682
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
1683
      java.util.Date localtime = new java.util.Date();
1684
      String dateString = formatter.format(localtime);
1685
      dateString += " :: " + message;
1686
      //time stamp each entry
1687
      pw.println(dateString);
1688
      pw.flush();
1689
    }
1690
    catch(Exception e)
1691
    {
1692
      System.out.println("error writing to replication log from " +
1693
                         "MetacatReplication.replLog: " + e.getMessage());
1694
      //e.printStackTrace(System.out);
1695
    }
1696
  }
1697

    
1698
  /**
1699
   * Method for writing replication messages to a log file specified in
1700
   * metacat.properties
1701
   */
1702
  public static void replErrorLog(String message)
1703
  {
1704
    try
1705
    {
1706
      FileOutputStream fos = new FileOutputStream(
1707
                                 util.getOption("replicationerrorlog"), true);
1708
      PrintWriter pw = new PrintWriter(fos);
1709
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
1710
      java.util.Date localtime = new java.util.Date();
1711
      String dateString = formatter.format(localtime);
1712
      dateString += " :: " + message;
1713
      //time stamp each entry
1714
      pw.println(dateString);
1715
      pw.flush();
1716
    }
1717
    catch(Exception e)
1718
    {
1719
      System.out.println("error writing to replication log from " +
1720
                         "MetacatReplication.replLog: " + e.getMessage());
1721
      //e.printStackTrace(System.out);
1722
    }
1723
  }
1724

    
1725
  /**
1726
   * Returns true if the replicate field for server in xml_replication is 1.
1727
   * Returns false otherwise
1728
   */
1729
  public static boolean replToServer(String server)
1730
  {
1731
    DBConnection dbConn = null;
1732
    int serialNumber = -1;
1733
    PreparedStatement pstmt = null;
1734
    try
1735
    {
1736
      dbConn=DBConnectionPool.
1737
                  getDBConnection("MetacatReplication.repltoServer");
1738
      serialNumber=dbConn.getCheckOutSerialNumber();
1739
      pstmt = dbConn.prepareStatement("select replicate from " +
1740
                                    "xml_replication where server like '" +
1741
                                     server + "'");
1742
      pstmt.execute();
1743
      ResultSet rs = pstmt.getResultSet();
1744
      boolean tablehasrows = rs.next();
1745
      if(tablehasrows)
1746
      {
1747
        int i = rs.getInt(1);
1748
        if(i == 1)
1749
        {
1750
          pstmt.close();
1751
          //conn.close();
1752
          return true;
1753
        }
1754
        else
1755
        {
1756
          pstmt.close();
1757
          //conn.close();
1758
          return false;
1759
        }
1760
      }
1761
    }
1762
    catch(Exception e)
1763
    {
1764
      System.out.println("error in MetacatReplication.replToServer: " +
1765
                         e.getMessage());
1766
    }
1767
    finally
1768
    {
1769
      try
1770
      {
1771
        pstmt.close();
1772
        //conn.close();
1773
      }//try
1774
      catch(Exception ee)
1775
      {
1776
        MetaCatUtil.debugMessage("Error in MetacatReplication.replToServer: "
1777
                                  +ee.getMessage(), 30);
1778
      }//catch
1779
      finally
1780
      {
1781
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1782
      }//finally
1783
    }//finally
1784
    return false;
1785
    //the default if this server does not exist is to not replicate to it.
1786
  }
1787

    
1788

    
1789
}
(44-44/63)