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: 2005-09-08 10:48:34 -0700 (Thu, 08 Sep 2005) $'
11
 * '$Revision: 2572 $'
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.util.Date;
33
import java.io.*;
34
import java.sql.*;
35
import java.net.*;
36
import java.lang.*;
37
import java.text.*;
38
import javax.servlet.*;
39
import javax.servlet.http.*;
40

    
41
import org.xml.sax.*;
42

    
43
public class MetacatReplication extends HttpServlet implements Runnable
44
{
45
  private long timeInterval;
46
  private Date firstTime;
47
  private boolean timedReplicationIsOn = false;
48
  Timer replicationDaemon;
49
  private static MetaCatUtil util = new MetaCatUtil();
50
  private Vector fileLocks = new Vector();
51
  private Thread lockThread = null;
52
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
53
  public static final String FORCEREPLICATEDELETE = "forcereplicatedelete";
54
  private static final String TIMEREPLICATION = "timedreplication";
55
  private static final String TIMEREPLICATIONINTERVAl = "timedreplicationinterval";
56
  private static final String FIRSTTIME  = "firsttimedreplication";
57
  private static final int    TIMEINTERVALLIMIT = 7200000;
58
  
59
  /**
60
   * Initialize the servlet by creating appropriate database connections
61
   */
62
  public void init(ServletConfig config) throws ServletException
63
  {
64
     //initialize db connections to handle any update requests
65
    MetaCatUtil util = new MetaCatUtil();
66
    //deltaT = util.getOption("deltaT");
67
    //the default deltaT can be set from metacat.properties
68
    //create a thread to do the delta-T check but don't execute it yet
69
    replicationDaemon = new Timer(true);
70
    try
71
    {
72
       timedReplicationIsOn = (new Boolean(util.getOption(TIMEREPLICATION ).trim())).booleanValue();
73
       MetaCatUtil.debugMessage("The timed replication on is"+timedReplicationIsOn, 30);
74
       timeInterval = (new Long(util.getOption(TIMEREPLICATIONINTERVAl).trim())).longValue();
75
       MetaCatUtil.debugMessage("The timed replication time Inerval is "+ timeInterval, 20);
76
       String firstTimeStr = util.getOption(FIRSTTIME);
77
       MetaCatUtil.debugMessage("first replication time form property is "+firstTimeStr, 20);
78
       firstTime = ReplicationHandler.combinateCurrentDateAndGivenTime(firstTimeStr);
79
       MetaCatUtil.debugMessage("After combine current time, the real first time is "
80
                                +firstTime.toString()+" minisec", 20);
81
       // set up time replication if it is on
82
       if (timedReplicationIsOn)
83
       {
84
           replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(), firstTime, timeInterval);
85
           MetacatReplication.replLog("deltaT handler started with rate=" +
86
                   timeInterval + " mini seconds at " +firstTime.toString());
87
       }
88
    }
89
    catch (Exception e)
90
    {
91
        // the timed replication in Metacat.properties file has problem
92
        // so timed replication is setting to false;
93
        MetaCatUtil.debugMessage("Couldn't set up timed replication "+
94
                     " in Metacat replication servlet init because " +
95
                 e.getMessage(), 20);
96
        MetacatReplication.replErrorLog("Couldn't set up timed replication "+
97
                " in Metacat replication servlet init because " +
98
                e.getMessage());
99
        timedReplicationIsOn = false;
100
    }
101
    
102
  }
103

    
104
  public void destroy()
105
  {
106
    replicationDaemon.cancel();
107
   
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
      timedReplicationIsOn = false;
193
      MetaCatUtil.setOption(TIMEREPLICATION, (new Boolean(timedReplicationIsOn)).toString());
194
      out.println("Replication Handler Stopped");
195
      MetacatReplication.replLog("deltaT handler stopped");
196

    
197

    
198
    } else if ( action.equals("start") ) {
199
       String firstTimeStr = "";
200
      //start the replication server
201
       if ( params.containsKey("rate") ) {
202
        timeInterval = new Long(
203
               new String(((String[])params.get("rate"))[0])).longValue();
204
        if(timeInterval < TIMEINTERVALLIMIT) {
205
            out.println("Replication deltaT rate cannot be less than "+
206
                    TIMEINTERVALLIMIT + " millisecs and system automatically setup the rate to "+TIMEINTERVALLIMIT);
207
            //deltaT<30 is a timing mess!
208
            timeInterval = TIMEINTERVALLIMIT;
209
        }
210
      } else {
211
        timeInterval = TIMEINTERVALLIMIT ;
212
      }
213
      MetaCatUtil.debugMessage("New rate is: " + timeInterval + " mini seconds.", 30);
214
      if ( params.containsKey("firsttime"))
215
      {
216
         firstTimeStr = ((String[])params.get("firsttime"))[0];
217
         try
218
         {
219
           firstTime = ReplicationHandler.combinateCurrentDateAndGivenTime(firstTimeStr);
220
           MetaCatUtil.debugMessage("The first time setting is "+firstTime.toString(), 30);
221
         }
222
         catch (Exception e)
223
         {
224
            throw new ServletException(e.getMessage());
225
         }
226
         MetaCatUtil.debugMessage("After combine current time, the real first time is "
227
                                  +firstTime.toString()+" minisec", 20);
228
      }
229
      else
230
      {
231
          MetacatReplication.replErrorLog("You should specify the first time " +
232
                                          "to start a time replication");
233
          MetaCatUtil.debugMessage("You should specify the first time " +
234
                                  "to start a time replication", 30);
235
          return;
236
      }
237
      
238
      timedReplicationIsOn = true;
239
      // save settings to property file
240
      MetaCatUtil.setOption(TIMEREPLICATION, (new Boolean(timedReplicationIsOn)).toString());
241
      // note we couldn't use firstTime object because it has date info
242
      // we only need time info such as 10:00 PM
243
      MetaCatUtil.setOption(FIRSTTIME, firstTimeStr);
244
      MetaCatUtil.setOption(TIMEREPLICATIONINTERVAl, (new Long(timeInterval)).toString());
245
      replicationDaemon.cancel();
246
      replicationDaemon = new Timer(true);
247
      replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(), firstTime,
248
                                            timeInterval);
249
      out.println("Replication Handler Started");
250
      MetacatReplication.replLog("deltaT handler started with rate=" +
251
                                    timeInterval + " milliseconds at " +firstTime.toString());
252

    
253

    
254
    } else if ( action.equals("getall") ) {
255
      //updates this server exactly once
256
      replicationDaemon.schedule(new ReplicationHandler(), 0);
257
      response.setContentType("text/html");
258
      out.println("<html><body>\"Get All\" Done</body></html>");
259

    
260
    } else if ( action.equals("forcereplicate") ) {
261
      //read a specific docid from remote host, and store it into local host
262
      handleForceReplicateRequest(out, params, response);
263

    
264
    } else if ( action.equals(FORCEREPLICATEDELETE) ) {
265
      //read a specific docid from remote host, and store it into local host
266
      handleForceReplicateDeleteRequest(out, params, response);
267

    
268
    } else if ( action.equals("update") ) {
269
      //request an update list from the server
270
      handleUpdateRequest(out, params, response);
271

    
272
    } else if ( action.equals("read") ) {
273
      //request a specific document from the server
274
      //note that this could be replaced by a call to metacatServlet
275
      //handleGetDocumentAction().
276
      handleGetDocumentRequest(out, params, response);
277
    } else if ( action.equals("getlock") ) {
278
      handleGetLockRequest(out, params, response);
279

    
280
    } else if ( action.equals("getdocumentinfo") ) {
281
      handleGetDocumentInfoRequest(out, params, response);
282

    
283
    } else if ( action.equals("gettime") ) {
284
      handleGetTimeRequest(out, params, response);
285

    
286
    } else if ( action.equals("getcatalog") ) {
287
      handleGetCatalogRequest(out, params, response, true);
288

    
289
    } else if ( action.equals("servercontrol") ) {
290
      handleServerControlRequest(out, params, response);
291
    } else if ( action.equals("test") ) {
292
      response.setContentType("text/html");
293
      out.println("<html><body>Test successfully</body></html>");
294
    }
295

    
296
    out.close();
297
    }//else
298
  }
299

    
300
  /**
301
   * This method can add, delete and list the servers currently included in
302
   * xml_replication.
303
   * action           subaction            other needed params
304
   * ---------------------------------------------------------
305
   * servercontrol    add                  server
306
   * servercontrol    delete               server
307
   * servercontrol    list
308
   */
309
  private void handleServerControlRequest(PrintWriter out, Hashtable params,
310
                                          HttpServletResponse response)
311
  {
312
    String subaction = ((String[])params.get("subaction"))[0];
313
    DBConnection dbConn = null;
314
    int serialNumber = -1;
315
    PreparedStatement pstmt = null;
316
    String replicate =null;
317
    String server = null;
318
    String dataReplicate = null;
319
    String hub = null;
320
    try {
321
      //conn = util.openDBConnection();
322
      dbConn=DBConnectionPool.
323
               getDBConnection("MetacatReplication.handleServerControlRequest");
324
      serialNumber=dbConn.getCheckOutSerialNumber();
325

    
326
      // add server to server list
327
      if ( subaction.equals("add") ) {
328
        replicate = ((String[])params.get("replicate"))[0];
329
        server = ((String[])params.get("server"))[0];
330

    
331
        //Get data replication value
332
        dataReplicate = ((String[])params.get("datareplicate"))[0];
333
        //Get hub value
334
        hub = ((String[])params.get("hub"))[0];
335

    
336
        /*pstmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
337
                  "(server, last_checked, replicate, datareplicate, hub) " +
338
                                      "VALUES ('" + server + "', to_date(" +
339
                                      "'01/01/00', 'MM/DD/YY'), '" +
340
                                      replicate +"', '" +dataReplicate+"', '"
341
                                      + hub +"')");*/
342
        pstmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
343
                  "(server, last_checked, replicate, datareplicate, hub) " +
344
                                      "VALUES ('" + server + "', "+
345
                                      dbAdapter.toDate("01/01/1980", "MM/DD/YYYY")
346
                                      + ", '" +
347
                                      replicate +"', '" +dataReplicate+"', '"
348
                                      + hub +"')");
349

    
350
        pstmt.execute();
351
        pstmt.close();
352
        dbConn.commit();
353
        out.println("Server " + server + " added");
354
        response.setContentType("text/html");
355
        out.println("<html><body><table border=\"1\">");
356
        out.println("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
357
        out.println("<b>replicate</b></td>");
358
        out.println("<td><b>datareplicate</b></td>");
359
        out.println("<td><b>hub</b></td></tr>");
360
        pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
361
        //increase dbconnection usage
362
        dbConn.increaseUsageCount(1);
363

    
364
        pstmt.execute();
365
        ResultSet rs = pstmt.getResultSet();
366
        boolean tablehasrows = rs.next();
367
        while(tablehasrows) {
368
          out.println("<tr><td>" + rs.getString(2) + "</td><td>");
369
          out.println(rs.getString(3) + "</td><td>");
370
          out.println(rs.getString(4) + "</td><td>");
371
          out.println(rs.getString(5) + "</td><td>");
372
          out.println(rs.getString(6) + "</td></tr>");
373

    
374
          tablehasrows = rs.next();
375
        }
376
        out.println("</table></body></html>");
377

    
378
        // download certificate with the public key on this server
379
        // and import it as a trusted certificate
380
        String certURL = ((String[])params.get("certificate"))[0];
381
        downloadCertificate(certURL);
382

    
383
      // delete server from server list
384
      } else if ( subaction.equals("delete") ) {
385
        server = ((String[])params.get("server"))[0];
386
        pstmt = dbConn.prepareStatement("DELETE FROM xml_replication " +
387
                                      "WHERE server LIKE '" + server + "'");
388
        pstmt.execute();
389
        pstmt.close();
390
        dbConn.commit();
391
        out.println("Server " + server + " deleted");
392
        response.setContentType("text/html");
393
        out.println("<html><body><table border=\"1\">");
394
        out.println("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
395
        out.println("<b>replicate</b></td>");
396
        out.println("<td><b>datareplicate</b></td>");
397
        out.println("<td><b>hub</b></td></tr>");
398

    
399
        pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
400
        //increase dbconnection usage
401
        dbConn.increaseUsageCount(1);
402
        pstmt.execute();
403
        ResultSet rs = pstmt.getResultSet();
404
        boolean tablehasrows = rs.next();
405
        while(tablehasrows)
406
        {
407
          out.println("<tr><td>" + rs.getString(2) + "</td><td>");
408
          out.println(rs.getString(3) + "</td><td>");
409
          out.println(rs.getString(4) + "</td><td>");
410
          out.println(rs.getString(5) + "</td><td>");
411
          out.println(rs.getString(6) + "</td></tr>");
412
          tablehasrows = rs.next();
413
        }
414
        out.println("</table></body></html>");
415

    
416
      // list servers in server list
417
      } else if ( subaction.equals("list") ) {
418
        response.setContentType("text/html");
419
        out.println("<html><body><table border=\"1\">");
420
        out.println("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
421
        out.println("<b>replicate</b></td>");
422
        out.println("<td><b>datareplicate</b></td>");
423
        out.println("<td><b>hub</b></td></tr>");
424
        pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
425
        pstmt.execute();
426
        ResultSet rs = pstmt.getResultSet();
427
        boolean tablehasrows = rs.next();
428
        while(tablehasrows) {
429
          out.println("<tr><td>" + rs.getString(2) + "</td><td>");
430
          out.println(rs.getString(3) + "</td><td>");
431
          out.println(rs.getString(4) + "</td><td>");
432
          out.println(rs.getString(5) + "</td><td>");
433
          out.println(rs.getString(6) + "</td></tr>");
434
          tablehasrows = rs.next();
435
        }
436
        out.println("</table></body></html>");
437
      }
438
      else
439
      {
440

    
441
        out.println("<error>Unkonwn subaction</error>");
442

    
443
      }
444
      pstmt.close();
445
      //conn.close();
446

    
447
    } catch(Exception e) {
448
      System.out.println("Error in " +
449
                         "MetacatReplication.handleServerControlRequest " +
450
                         e.getMessage());
451
      e.printStackTrace(System.out);
452
    }
453
    finally
454
    {
455
      try
456
      {
457
        pstmt.close();
458
      }//try
459
      catch (SQLException ee)
460
      {
461
        MetaCatUtil.debugMessage("Error in " +
462
                "MetacatReplication.handleServerControlRequest to close pstmt "
463
                 + ee.getMessage(), 30);
464
      }//catch
465
      finally
466
      {
467
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
468
      }//finally
469
    }//finally
470

    
471
  }
472

    
473
  // download certificate with the public key from certURL and
474
  // upload it onto this server; it then must be imported as a
475
  // trusted certificate
476
  private void downloadCertificate (String certURL)
477
                throws FileNotFoundException, IOException, MalformedURLException
478
  {
479
    MetaCatUtil util = new MetaCatUtil();
480
    String certPath = util.getOption("certPath"); //the path to be uploaded to
481

    
482
    // get filename from the URL of the certificate
483
    String filename = certURL;
484
    int slash = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
485
    if ( slash > -1 ) {
486
      filename = filename.substring(slash + 1);
487
    }
488

    
489
    // open file output strem to write the input into it
490
    File f = new File(certPath, filename);
491
    synchronized (f) {
492
      try {
493
        if ( f.exists() ) {
494
          throw new IOException("File already exist: " + f.getCanonicalFile());
495
          //if ( f.exists() && !f.canWrite() ) {
496
          //  throw new IOException("Not writable: " + f.getCanonicalFile());
497
        }
498
      } catch (SecurityException se) {
499
        // if a security manager exists,
500
        // its checkRead method is called for f.exist()
501
        // or checkWrite method is called for f.canWrite()
502
        throw se;
503
      }
504

    
505
      // create a buffered byte output stream
506
      // that uses a default-sized output buffer
507
      FileOutputStream fos = new FileOutputStream(f);
508
      BufferedOutputStream out = new BufferedOutputStream(fos);
509

    
510
      // this should be http url
511
      URL url = new URL(certURL);
512
      BufferedInputStream bis = null;
513
      try {
514
        bis = new BufferedInputStream(url.openStream());
515
        byte[] buf = new byte[4 * 1024]; // 4K buffer
516
        int b = bis.read(buf);
517
        while (b != -1) {
518
          out.write(buf, 0, b);
519
          b = bis.read(buf);
520
        }
521
      } finally {
522
        if (bis != null) bis.close();
523
      }
524
      // the input and the output streams must be closed
525
      bis.close();
526
            out.flush();
527
            out.close();
528
            fos.close();
529
    } // end of synchronized(f)
530
  }
531

    
532
  /**
533
   * when a forcereplication request comes in, local host sends a read request
534
   * to the requesting server (remote server) for the specified docid.
535
   * Then store it in local database.
536
   */
537
  private void handleForceReplicateRequest(PrintWriter out, Hashtable params,
538
                                           HttpServletResponse response)
539
  {
540
    String server = ((String[])params.get("server"))[0]; // the server that
541
    String docid = ((String[])params.get("docid"))[0]; // sent the document
542
    String dbaction = "UPDATE"; // the default action is UPDATE
543
    boolean override = false;
544
    int serverCode = 1;
545
    DBConnection dbConn = null;
546
    int serialNumber = -1;
547

    
548
    try {
549
      //if the url contains a dbaction then the default action is overridden
550
      if(params.containsKey("dbaction")) {
551
        dbaction = ((String[])params.get("dbaction"))[0];
552
        //serverCode = MetacatReplication.getServerCode(server);
553
        //override = true; //we are now overriding the default action
554
      }
555
      MetacatReplication.replLog("force replication request from " + server);
556
      MetaCatUtil.debugMessage("Force replication request from: "+ server, 34);
557
      MetaCatUtil.debugMessage("Force replication docid: "+docid, 34);
558
      MetaCatUtil.debugMessage("Force replication action: "+dbaction, 34);
559
      // sending back read request to remote server
560
      URL u = new URL("https://" + server + "?server="
561
                +util.getLocalReplicationServerName()
562
                +"&action=read&docid=" + docid);
563
      String xmldoc = MetacatReplication.getURLContent(u);
564

    
565
      // get the document info from server
566
      URL docinfourl = new URL("https://" + server +
567
                               "?server="+util.getLocalReplicationServerName()
568
                               +"&action=getdocumentinfo&docid=" + docid);
569

    
570
      String docInfoStr = MetacatReplication.getURLContent(docinfourl);
571

    
572
      //dih is the parser for the docinfo xml format
573
      DocInfoHandler dih = new DocInfoHandler();
574
      XMLReader docinfoParser = ReplicationHandler.initParser(dih);
575
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
576
      Hashtable docinfoHash = dih.getDocInfo();
577

    
578
      // Get user owner of this docid
579
      String user = (String)docinfoHash.get("user_owner");
580
      // Get home server of this docid
581
      String homeServer=(String)docinfoHash.get("home_server");
582
      MetaCatUtil.debugMessage("homeServer: "+homeServer, 34);
583
      // Get Document type
584
      String docType = (String)docinfoHash.get("doctype");
585
      MetaCatUtil.debugMessage("docType: "+docType, 34);
586
      String parserBase = null;
587
      // this for eml2 and we need user eml2 parser
588
      if (docType != null &&
589
          (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE))
590
      {
591
         MetaCatUtil.debugMessage("This is an eml200 document!", 30);
592
         parserBase = DocumentImpl.EML200;
593
      }
594
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE))
595
      {
596
         MetaCatUtil.debugMessage("This is an eml2.0.1 document!", 30);
597
         parserBase = DocumentImpl.EML200;
598
      }
599
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE))
600
      {
601
         MetaCatUtil.debugMessage("This is an eml2.1.0 document!", 30);
602
         parserBase = DocumentImpl.EML210;
603
      }
604
      MetaCatUtil.debugMessage("The parserBase is: "+parserBase, 30);
605

    
606
      // Get DBConnection from pool
607
      dbConn=DBConnectionPool.
608
              getDBConnection("MetacatReplication.handleForceReplicateRequest");
609
      serialNumber=dbConn.getCheckOutSerialNumber();
610
      // write the document to local database
611
      DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false);
612
      wrapper.writeReplication(dbConn, new StringReader(xmldoc), null, null,
613
                               dbaction, docid, user, null, homeServer, server);
614

    
615
      MetacatReplication.replLog("document " + docid + " added to DB with " +
616
                                 "action " + dbaction);
617
    }//try
618
    catch(Exception e)
619
    {
620
      MetacatReplication.replErrorLog("document " + docid +
621
                                      " failed to added to DB with " +
622
                                      "action " + dbaction + " because "+
623
                                       e.getMessage());
624
      MetaCatUtil.debugMessage("ERROR in MetacatReplication.handleForceReplicate" +
625
                         "Request(): " + e.getMessage(), 30);
626

    
627
    }//catch
628
    finally
629
    {
630
      // Return the checked out DBConnection
631
      DBConnectionPool.returnDBConnection(dbConn, serialNumber);
632
    }//finally
633
  }
634

    
635
/*
636
 * when a forcereplication delete request comes in, local host will delete this
637
 * document
638
 */
639
private void handleForceReplicateDeleteRequest(PrintWriter out, Hashtable params,
640
                                         HttpServletResponse response)
641
{
642
  String server = ((String[])params.get("server"))[0]; // the server that
643
  String docid = ((String[])params.get("docid"))[0]; // sent the document
644
  try
645
  {
646
    MetacatReplication.replLog("force replication delete request from " + server);
647
    MetacatReplication.replLog("force replication delete docid " + docid);
648
    MetaCatUtil.debugMessage("Force replication delete request from: "+ server, 34);
649
    MetaCatUtil.debugMessage("Force replication delete docid: "+docid, 34);
650
    DocumentImpl.delete(docid, null, null, server);
651
    MetacatReplication.replLog("document " + docid + " was successfully deleted ");
652
    MetaCatUtil.debugMessage("document " + docid + " was successfully deleted ", 34);
653
  }
654
  catch(Exception e)
655
  {
656
    MetacatReplication.replErrorLog("document " + docid +
657
                                    " failed to delete because "+
658
                                     e.getMessage());
659
    MetaCatUtil.debugMessage("ERROR in MetacatReplication.handleForceDeleteReplicate" +
660
                       "Request(): " + e.getMessage(), 30);
661

    
662
  }//catch
663

    
664
}
665

    
666

    
667
  /**
668
   * when a forcereplication data file request comes in, local host sends a
669
   * readdata request to the requesting server (remote server) for the specified
670
   * docid. Then store it in local database and file system
671
   */
672
  private void handleForceReplicateDataFileRequest(Hashtable params)
673
  {
674

    
675
    //make sure there is some parameters
676
    if(params.isEmpty())
677
    {
678
      return;
679
    }
680
    // Get remote server
681
    String server = ((String[])params.get("server"))[0];
682
    // the docid should include rev number
683
    String docid = ((String[])params.get("docid"))[0];
684
    // Make sure there is a docid and server
685
    if (docid==null || server==null || server.equals(""))
686
    {
687
      MetaCatUtil.debugMessage("Didn't specify docid or server for replication"
688
                              , 20);
689
      return;
690
    }
691

    
692
    // Overide or not
693
    boolean override = false;
694
    // dbaction - update or insert
695
    String dbaction=null;
696

    
697
    try
698
    {
699
      //docid was switch to two parts uinque code and rev
700
      String uniqueCode=MetaCatUtil.getDocIdFromString(docid);
701
      int rev=MetaCatUtil.getVersionFromString(docid);
702
      if(params.containsKey("dbaction"))
703
      {
704
        dbaction = ((String[])params.get("dbaction"))[0];
705
      }
706
      else//default value is update
707
      {
708
        dbaction = "update";
709
      }
710

    
711
      MetacatReplication.replLog("force replication request from " + server);
712
      MetaCatUtil.debugMessage("Force replication request from: "+ server, 34);
713
      MetaCatUtil.debugMessage("Force replication docid: "+docid, 34);
714
      MetaCatUtil.debugMessage("Force replication action: "+dbaction, 34);
715
      // get the document info from server
716
      URL docinfourl = new URL("https://" + server +
717
                               "?server="+util.getLocalReplicationServerName()
718
                               +"&action=getdocumentinfo&docid=" + uniqueCode);
719

    
720
      String docInfoStr = MetacatReplication.getURLContent(docinfourl);
721

    
722
      //dih is the parser for the docinfo xml format
723
      DocInfoHandler dih = new DocInfoHandler();
724
      XMLReader docinfoParser = ReplicationHandler.initParser(dih);
725
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
726
      Hashtable docinfoHash = dih.getDocInfo();
727
      String user = (String)docinfoHash.get("user_owner");
728

    
729
      String docName = (String)docinfoHash.get("docname");
730

    
731
      String docType = (String)docinfoHash.get("doctype");
732

    
733
      String docHomeServer= (String)docinfoHash.get("home_server");
734
      MetaCatUtil.debugMessage("docHomeServer of datafile: "+docHomeServer, 34);
735

    
736

    
737

    
738
      //if action is delete, we don't delete the data file. Just archieve
739
      //the xml_documents
740
      /*if (dbaction.equals("delete"))
741
      {
742
        //conn = util.getConnection();
743
        DocumentImpl.delete(docid,user,null);
744
        //util.returnConnection(conn);
745
      }*/
746
      //To data file insert or update is same
747
      if (dbaction.equals("insert")||dbaction.equals("update"))
748
      {
749
        //Get data file and store it into local file system.
750
        // sending back readdata request to server
751
        URL url = new URL("https://" + server + "?server="
752
                +util.getLocalReplicationServerName()
753
                +"&action=readdata&docid=" + docid);
754
        String datafilePath = util.getOption("datafilepath");
755
        //register data file into xml_documents table and wite data file
756
        //into file system
757
        DocumentImpl.writeDataFileInReplication(url.openStream(), datafilePath,
758
                            docName, docType, docid, user,docHomeServer,server);
759
     }
760

    
761

    
762

    
763
    MetacatReplication.replLog("datafile " + docid + " added to DB with " +
764
                                 "action " + dbaction);
765
    }
766
    catch(Exception e)
767
    {
768

    
769
      MetacatReplication.replErrorLog("Datafile " + docid +
770
                                      " failed to added to DB with " +
771
                                      "action " + dbaction + " because "+
772
                                       e.getMessage());
773
      MetaCatUtil.debugMessage
774
              ("ERROR in MetacatReplication.handleForceDataFileReplicate" +
775
                         "Request(): " + e.getMessage(), 30);
776
    }
777
  }
778
  /**
779
   * Grants or denies a lock to a requesting host.
780
   * The servlet parameters of interrest are:
781
   * docid: the docid of the file the lock is being requested for
782
   * currentdate: the timestamp of the document on the remote server
783
   *
784
   */
785
  private void handleGetLockRequest(PrintWriter out, Hashtable params,
786
                                    HttpServletResponse response)
787
  {
788

    
789
    try
790
    {
791

    
792
      String docid = ((String[])params.get("docid"))[0];
793
      String remoteRev = ((String[])params.get("updaterev"))[0];
794
      DocumentImpl requestDoc = new DocumentImpl(docid);
795
      MetacatReplication.replLog("lock request for " + docid);
796
      int localRevInt = requestDoc.getRev();
797
      int remoteRevInt = Integer.parseInt(remoteRev);
798

    
799
      if(remoteRevInt >= localRevInt)
800
      {
801
        if(!fileLocks.contains(docid))
802
        { //grant the lock if it is not already locked
803
          fileLocks.add(0, docid); //insert at the beginning of the queue Vector
804
          //send a message back to the the remote host authorizing the insert
805
          out.println("<lockgranted><docid>" +docid+ "</docid></lockgranted>");
806
          lockThread = new Thread(this);
807
          lockThread.setPriority(Thread.MIN_PRIORITY);
808
          lockThread.start();
809
          MetacatReplication.replLog("lock granted for " + docid);
810
        }
811
        else
812
        { //deny the lock
813
          out.println("<filelocked><docid>" + docid + "</docid></filelocked>");
814
          MetacatReplication.replLog("lock denied for " + docid +
815
                                     "reason: file already locked");
816
        }
817
      }
818
      else
819
      {//deny the lock.
820
        out.println("<outdatedfile><docid>" + docid + "</docid></filelocked>");
821
        MetacatReplication.replLog("lock denied for " + docid +
822
                                   "reason: client has outdated file");
823
      }
824
      //conn.close();
825
    }
826
    catch(Exception e)
827
    {
828
      System.out.println("error requesting file lock from MetacatReplication." +
829
                         "handleGetLockRequest: " + e.getMessage());
830
      e.printStackTrace(System.out);
831
    }
832
  }
833

    
834
  /**
835
   * Sends all of the xml_documents information encoded in xml to a requestor
836
   * the format is:
837
   * <!ELEMENT documentinfo (docid, docname, doctype, doctitle, user_owner,
838
   *                  user_updated, home_server, public_access, rev)/>
839
   * all of the subelements of document info are #PCDATA
840
   */
841
  private void handleGetDocumentInfoRequest(PrintWriter out, Hashtable params,
842
                                        HttpServletResponse response)
843
  {
844
    String docid = ((String[])(params.get("docid")))[0];
845
    StringBuffer sb = new StringBuffer();
846

    
847
    try
848
    {
849

    
850
      DocumentImpl doc = new DocumentImpl(docid);
851
      sb.append("<documentinfo><docid>").append(docid);
852
      sb.append("</docid><docname>").append(doc.getDocname());
853
      sb.append("</docname><doctype>").append(doc.getDoctype());
854
      sb.append("</doctype>");
855
      sb.append("<user_owner>").append(doc.getUserowner());
856
      sb.append("</user_owner><user_updated>").append(doc.getUserupdated());
857
      sb.append("</user_updated>");
858
      sb.append("<home_server>");
859
      sb.append(doc.getDocHomeServer());
860
      sb.append("</home_server>");
861
      sb.append("<public_access>").append(doc.getPublicaccess());
862
      sb.append("</public_access><rev>").append(doc.getRev());
863
      sb.append("</rev></documentinfo>");
864
      response.setContentType("text/xml");
865
      out.println(sb.toString());
866

    
867
    }
868
    catch (Exception e)
869
    {
870
      System.out.println("error in " +
871
                         "metacatReplication.handlegetdocumentinforequest: " +
872
                          e.getMessage());
873
    }
874

    
875
  }
876

    
877
  /**
878
   * Sends a datafile to a remote host
879
   */
880
  private void handleGetDataFileRequest(OutputStream outPut,
881
                            Hashtable params, HttpServletResponse response)
882

    
883
  {
884
    // File path for data file
885
    String filepath = util.getOption("datafilepath");
886
    // Request docid
887
    String docId = ((String[])(params.get("docid")))[0];
888
    //check if the doicd is null
889
    if (docId==null)
890
    {
891
      util.debugMessage("Didn't specify docid for replication", 20);
892
      return;
893
    }
894

    
895
    //try to open a https stream to test if the request server's public key
896
    //in the key store, this is security issue
897
    try
898
    {
899
      String server = ((String[])params.get("server"))[0];
900
      URL u = new URL("https://" + server + "?server="
901
                +util.getLocalReplicationServerName()
902
                +"&action=test");
903
      String test = MetacatReplication.getURLContent(u);
904
      //couldn't pass the test
905
      if (test.indexOf("successfully")==-1)
906
      {
907
        //response.setContentType("text/xml");
908
        //outPut.println("<error>Couldn't pass the trust test</error>");
909
        MetaCatUtil.debugMessage("Couldn't pass the trust test", 20);
910
        return;
911
      }
912
    }//try
913
    catch (Exception ee)
914
    {
915
      return;
916
    }//catch
917

    
918
    if(!filepath.endsWith("/"))
919
    {
920
          filepath += "/";
921
    }
922
    // Get file aboslute file name
923
    String filename = filepath + docId;
924

    
925
    //MIME type
926
    String contentType = null;
927
    if (filename.endsWith(".xml"))
928
    {
929
        contentType="text/xml";
930
    }
931
    else if (filename.endsWith(".css"))
932
    {
933
        contentType="text/css";
934
    }
935
    else if (filename.endsWith(".dtd"))
936
    {
937
        contentType="text/plain";
938
    }
939
    else if (filename.endsWith(".xsd"))
940
    {
941
        contentType="text/xml";
942
    }
943
    else if (filename.endsWith("/"))
944
    {
945
        contentType="text/html";
946
    }
947
    else
948
    {
949
        File f = new File(filename);
950
        if ( f.isDirectory() )
951
        {
952
           contentType="text/html";
953
        }
954
        else
955
        {
956
           contentType="application/octet-stream";
957
        }
958
     }
959

    
960
   // Set the mime type
961
   response.setContentType(contentType);
962

    
963
   // Get the content of the file
964
   FileInputStream fin = null;
965
   try
966
   {
967
      // FileInputStream to metacat
968
      fin = new FileInputStream(filename);
969
      // 4K buffer
970
      byte[] buf = new byte[4 * 1024];
971
      // Read data from file input stream to byte array
972
      int b = fin.read(buf);
973
      // Write to outStream from byte array
974
      while (b != -1)
975
      {
976
        outPut.write(buf, 0, b);
977
        b = fin.read(buf);
978
      }
979
      // close file input stream
980
      fin.close();
981

    
982
   }//try
983
   catch(Exception e)
984
   {
985
      System.out.println("error getting data file from MetacatReplication." +
986
                         "handlGetDataFileRequest " + e.getMessage());
987
      e.printStackTrace(System.out);
988
   }//catch
989

    
990
}
991

    
992

    
993
  /**
994
   * Sends a document to a remote host
995
   */
996
  private void handleGetDocumentRequest(PrintWriter out, Hashtable params,
997
                                        HttpServletResponse response)
998
  {
999

    
1000
    try
1001
    {
1002
      //try to open a https stream to test if the request server's public key
1003
      //in the key store, this is security issue
1004
      String server = ((String[])params.get("server"))[0];
1005
      URL u = new URL("https://" + server + "?server="
1006
                +util.getLocalReplicationServerName()
1007
                +"&action=test");
1008
      String test = MetacatReplication.getURLContent(u);
1009
      //couldn't pass the test
1010
      if (test.indexOf("successfully")==-1)
1011
      {
1012
        response.setContentType("text/xml");
1013
        out.println("<error>Couldn't pass the trust test</error>");
1014
        out.close();
1015
        return;
1016
      }
1017

    
1018
      String docid = ((String[])(params.get("docid")))[0];
1019

    
1020
      DocumentImpl di = new DocumentImpl(docid);
1021
      response.setContentType("text/xml");
1022
      out.print(di.toString(null, null, true));
1023

    
1024
      MetacatReplication.replLog("document " + docid + " sent");
1025

    
1026
    }
1027
    catch(Exception e)
1028
    {
1029
      MetaCatUtil.debugMessage("error getting document from MetacatReplication."
1030
                          +"handlGetDocumentRequest " + e.getMessage(), 30);
1031
      //e.printStackTrace(System.out);
1032
      response.setContentType("text/xml");
1033
      out.println("<error>"+e.getMessage()+"</error>");
1034
    }
1035

    
1036
  }
1037

    
1038
  /**
1039
   * Sends a list of all of the documents on this sever along with their
1040
   * revision numbers.
1041
   * The format is:
1042
   * <!ELEMENT replication (server, updates)>
1043
   * <!ELEMENT server (#PCDATA)>
1044
   * <!ELEMENT updates ((updatedDocument | deleteDocument)*)>
1045
   * <!ELEMENT updatedDocument (docid, rev, datafile*)>
1046
   * <!ELEMENT deletedDocument (docid, rev)>
1047
   * <!ELEMENT docid (#PCDATA)>
1048
   * <!ELEMENT rev (#PCDATA)>
1049
   * <!ELEMENT datafile (#PCDATA)>
1050
   * note that the rev in deletedDocument is always empty.  I just left
1051
   * it in there to make the parser implementation easier.
1052
   */
1053
  private void handleUpdateRequest(PrintWriter out, Hashtable params,
1054
                                    HttpServletResponse response)
1055
  {
1056
    // Checked out DBConnection
1057
    DBConnection dbConn = null;
1058
    // DBConenction serial number when checked it out
1059
    int serialNumber = -1;
1060
    PreparedStatement pstmt = null;
1061
    // Server list to store server info of xml_replication table
1062
    ReplicationServerList serverList = null;
1063

    
1064
    try
1065
    {
1066
      // Check out a DBConnection from pool
1067
      dbConn=DBConnectionPool.
1068
                  getDBConnection("MetacatReplication.handleUpdateRequest");
1069
      serialNumber=dbConn.getCheckOutSerialNumber();
1070
      // Create a server list from xml_replication table
1071
      serverList = new ReplicationServerList();
1072

    
1073
      // Get remote server name from param
1074
      String server = ((String[])params.get("server"))[0];
1075
      // If no servr name in param, return a error
1076
      if ( server == null || server.equals(""))
1077
      {
1078
        response.setContentType("text/xml");
1079
        out.println("<error>Request didn't specify server name</error>");
1080
        out.close();
1081
        return;
1082
      }//if
1083

    
1084
      //try to open a https stream to test if the request server's public key
1085
      //in the key store, this is security issue
1086
      URL u = new URL("https://" + server + "?server="
1087
                +util.getLocalReplicationServerName()
1088
                +"&action=test");
1089
      String test = MetacatReplication.getURLContent(u);
1090
      //couldn't pass the test
1091
      if (test.indexOf("successfully")==-1)
1092
      {
1093
        response.setContentType("text/xml");
1094
        out.println("<error>Couldn't pass the trust test</error>");
1095
        out.close();
1096
        return;
1097
      }
1098

    
1099

    
1100
      // Check if local host configure to replicate xml documents to remote
1101
      // server. If not send back a error message
1102
      if (!serverList.getReplicationValue(server))
1103
      {
1104
        response.setContentType("text/xml");
1105
        out.println
1106
        ("<error>Configuration not allow to replicate document to you</error>");
1107
        out.close();
1108
        return;
1109
      }//if
1110

    
1111
      // Store the sql command
1112
      StringBuffer docsql = new StringBuffer();
1113
      // Stroe the docid list
1114
      StringBuffer doclist = new StringBuffer();
1115
      // Store the deleted docid list
1116
      StringBuffer delsql = new StringBuffer();
1117
      // Store the data set file
1118
      Vector packageFiles = new Vector();
1119

    
1120
      // Append local server's name and replication servlet to doclist
1121
      doclist.append("<?xml version=\"1.0\"?><replication>");
1122
      doclist.append("<server>").append(util.getOption("server"));
1123
      doclist.append(util.getOption("replicationpath"));
1124
      doclist.append("</server><updates>");
1125

    
1126
      // Get correct docid that reside on this server according the requesting
1127
      // server's replicate and data replicate value in xml_replication table
1128
      docsql.append("select docid, rev, doctype from xml_documents ");
1129
      // If the localhost is not a hub to the remote server, only replicate
1130
      // the docid' which home server is local host (server_location =1)
1131
      if (!serverList.getHubValue(server))
1132
      {
1133
        docsql.append("where server_location = 1");
1134
      }
1135
      MetaCatUtil.debugMessage("Doc sql: "+docsql.toString(), 30);
1136

    
1137
      // Get any deleted documents
1138
      delsql.append("select distinct docid from ");
1139
      delsql.append("xml_revisions where docid not in (select docid from ");
1140
      delsql.append("xml_documents) ");
1141
      // If the localhost is not a hub to the remote server, only replicate
1142
      // the docid' which home server is local host (server_location =1)
1143
      if (!serverList.getHubValue(server))
1144
      {
1145
        delsql.append("and server_location = 1");
1146
      }
1147
      MetaCatUtil.debugMessage("Deleted sql: "+delsql.toString(), 30);
1148

    
1149

    
1150

    
1151
      // Get docid list of local host
1152
      pstmt = dbConn.prepareStatement(docsql.toString());
1153
      pstmt.execute();
1154
      ResultSet rs = pstmt.getResultSet();
1155
      boolean tablehasrows = rs.next();
1156
      //If metacat configed to replicate data file
1157
      //if ((util.getOption("replicationsenddata")).equals("on"))
1158
      if (serverList.getDataReplicationValue(server))
1159
      {
1160
        while(tablehasrows)
1161
        {
1162
          String recordDoctype = rs.getString(3);
1163
          Vector packagedoctypes = MetaCatUtil.getOptionList(
1164
                                     MetaCatUtil.getOption("packagedoctype"));
1165
          //if this is a package file, put it at the end
1166
          //because if a package file is read before all of the files it
1167
          //refers to are loaded then there is an error
1168
          if(recordDoctype != null && !packagedoctypes.contains(recordDoctype))
1169
          {
1170
              //If this is not data file
1171
              if (!recordDoctype.equals("BIN"))
1172
              {
1173
                //for non-data file document
1174
                doclist.append("<updatedDocument>");
1175
                doclist.append("<docid>").append(rs.getString(1));
1176
                doclist.append("</docid><rev>").append(rs.getInt(2));
1177
                doclist.append("</rev>");
1178
                doclist.append("</updatedDocument>");
1179
              }//if
1180
              else
1181
              {
1182
                //for data file document, in datafile attributes
1183
                //we put "datafile" value there
1184
                doclist.append("<updatedDocument>");
1185
                doclist.append("<docid>").append(rs.getString(1));
1186
                doclist.append("</docid><rev>").append(rs.getInt(2));
1187
                doclist.append("</rev>");
1188
                doclist.append("<datafile>");
1189
                doclist.append(MetaCatUtil.getOption("datafileflag"));
1190
                doclist.append("</datafile>");
1191
                doclist.append("</updatedDocument>");
1192
              }//else
1193
          }//if packagedoctpes
1194
          else
1195
          { //the package files are saved to be put into the xml later.
1196
              Vector v = new Vector();
1197
              v.add(new String(rs.getString(1)));
1198
              v.add(new Integer(rs.getInt(2)));
1199
              packageFiles.add(new Vector(v));
1200
          }//esle
1201
          tablehasrows = rs.next();
1202
        }//while
1203
      }//if
1204
      else //metacat was configured not to send data file
1205
      {
1206
        while(tablehasrows)
1207
        {
1208
          String recordDoctype = rs.getString(3);
1209
          if(!recordDoctype.equals("BIN"))
1210
          { //don't replicate data files
1211
            Vector packagedoctypes = MetaCatUtil.getOptionList(
1212
                                     MetaCatUtil.getOption("packagedoctype"));
1213
            if(recordDoctype != null && !packagedoctypes.contains(recordDoctype))
1214
            {   //if this is a package file, put it at the end
1215
              //because if a package file is read before all of the files it
1216
              //refers to are loaded then there is an error
1217
              doclist.append("<updatedDocument>");
1218
              doclist.append("<docid>").append(rs.getString(1));
1219
              doclist.append("</docid><rev>").append(rs.getInt(2));
1220
              doclist.append("</rev>");
1221
              doclist.append("</updatedDocument>");
1222
            }
1223
            else
1224
            { //the package files are saved to be put into the xml later.
1225
              Vector v = new Vector();
1226
              v.add(new String(rs.getString(1)));
1227
              v.add(new Integer(rs.getInt(2)));
1228
              packageFiles.add(new Vector(v));
1229
            }
1230
         }//if
1231
         tablehasrows = rs.next();
1232
        }//while
1233
      }//else
1234

    
1235
      pstmt = dbConn.prepareStatement(delsql.toString());
1236
      //usage count should increas 1
1237
      dbConn.increaseUsageCount(1);
1238

    
1239
      pstmt.execute();
1240
      rs = pstmt.getResultSet();
1241
      tablehasrows = rs.next();
1242
      while(tablehasrows)
1243
      { //handle the deleted documents
1244
        doclist.append("<deletedDocument><docid>").append(rs.getString(1));
1245
        doclist.append("</docid><rev></rev></deletedDocument>");
1246
        //note that rev is always empty for deleted docs
1247
        tablehasrows = rs.next();
1248
      }
1249

    
1250
      //now we can put the package files into the xml results
1251
      for(int i=0; i<packageFiles.size(); i++)
1252
      {
1253
        Vector v = (Vector)packageFiles.elementAt(i);
1254
        doclist.append("<updatedDocument>");
1255
        doclist.append("<docid>").append((String)v.elementAt(0));
1256
        doclist.append("</docid><rev>");
1257
        doclist.append(((Integer)v.elementAt(1)).intValue());
1258
        doclist.append("</rev>");
1259
        doclist.append("</updatedDocument>");
1260
      }
1261

    
1262
      doclist.append("</updates></replication>");
1263
      MetaCatUtil.debugMessage("doclist: " + doclist.toString(), 40);
1264
      pstmt.close();
1265
      //conn.close();
1266
      response.setContentType("text/xml");
1267
      out.println(doclist.toString());
1268

    
1269
    }
1270
    catch(Exception e)
1271
    {
1272
      MetaCatUtil.debugMessage("error in MetacatReplication." +
1273
                         "handleupdaterequest: " + e.getMessage(), 30);
1274
      //e.printStackTrace(System.out);
1275
      response.setContentType("text/xml");
1276
      out.println("<error>"+e.getMessage()+"</error>");
1277
    }
1278
    finally
1279
    {
1280
      try
1281
      {
1282
        pstmt.close();
1283
      }//try
1284
      catch (SQLException ee)
1285
      {
1286
        MetaCatUtil.debugMessage("Error in MetacatReplication." +
1287
                "handleUpdaterequest to close pstmt: "+ee.getMessage(), 30);
1288
      }//catch
1289
      finally
1290
      {
1291
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1292
      }//finally
1293
    }//finally
1294

    
1295
  }//handlUpdateRequest
1296

    
1297
  /**
1298
   * Returns the xml_catalog table encoded in xml
1299
   */
1300
  public static String getCatalogXML()
1301
  {
1302
    return handleGetCatalogRequest(null, null, null, false);
1303
  }
1304

    
1305
  /**
1306
   * Sends the contents of the xml_catalog table encoded in xml
1307
   * The xml format is:
1308
   * <!ELEMENT xml_catalog (row*)>
1309
   * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
1310
   *                system_id)>
1311
   * All of the sub elements of row are #PCDATA
1312

    
1313
   * If printFlag == false then do not print to out.
1314
   */
1315
  private static String handleGetCatalogRequest(PrintWriter out,
1316
                                                Hashtable params,
1317
                                                HttpServletResponse response,
1318
                                                boolean printFlag)
1319
  {
1320
    DBConnection dbConn = null;
1321
    int serialNumber = -1;
1322
    PreparedStatement pstmt = null;
1323
    try
1324
    {
1325
      /*conn = MetacatReplication.getDBConnection("MetacatReplication." +
1326
                                                "handleGetCatalogRequest");*/
1327
      dbConn=DBConnectionPool.
1328
                 getDBConnection("MetacatReplication.handleGetCatalogRequest");
1329
      serialNumber=dbConn.getCheckOutSerialNumber();
1330
      pstmt = dbConn.prepareStatement("select entry_type, " +
1331
                              "source_doctype, target_doctype, public_id, " +
1332
                              "system_id from xml_catalog");
1333
      pstmt.execute();
1334
      ResultSet rs = pstmt.getResultSet();
1335
      boolean tablehasrows = rs.next();
1336
      StringBuffer sb = new StringBuffer();
1337
      sb.append("<?xml version=\"1.0\"?><xml_catalog>");
1338
      while(tablehasrows)
1339
      {
1340
        sb.append("<row><entry_type>").append(rs.getString(1));
1341
        sb.append("</entry_type><source_doctype>").append(rs.getString(2));
1342
        sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
1343
        sb.append("</target_doctype><public_id>").append(rs.getString(4));
1344
        sb.append("</public_id><system_id>").append(rs.getString(5));
1345
        sb.append("</system_id></row>");
1346

    
1347
        tablehasrows = rs.next();
1348
      }
1349
      sb.append("</xml_catalog>");
1350
      //conn.close();
1351
      if(printFlag)
1352
      {
1353
        response.setContentType("text/xml");
1354
        out.println(sb.toString());
1355
      }
1356
      pstmt.close();
1357
      return sb.toString();
1358
    }
1359
    catch(Exception e)
1360
    {
1361

    
1362
      System.out.println("error in MetacatReplication.handleGetCatalogRequest:"+
1363
                          e.getMessage());
1364
      e.printStackTrace(System.out);
1365
      if(printFlag)
1366
      {
1367
        out.println("<error>"+e.getMessage()+"</error>");
1368
      }
1369
    }
1370
    finally
1371
    {
1372
      try
1373
      {
1374
        pstmt.close();
1375
      }//try
1376
      catch (SQLException ee)
1377
      {
1378
        MetaCatUtil.
1379
           debugMessage("Error in MetacatReplication.handleGetCatalogRequest: "
1380
           +ee.getMessage(), 30);
1381
      }//catch
1382
      finally
1383
      {
1384
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1385
      }//finally
1386
    }//finally
1387

    
1388
    return null;
1389
  }
1390

    
1391
  /**
1392
   * Sends the current system date to the remote server.  Using this action
1393
   * for replication gets rid of any problems with syncronizing clocks
1394
   * because a time specific to a document is always kept on its home server.
1395
   */
1396
  private void handleGetTimeRequest(PrintWriter out, Hashtable params,
1397
                                    HttpServletResponse response)
1398
  {
1399
    SimpleDateFormat formatter = new SimpleDateFormat ("MM/dd/yy HH:mm:ss");
1400
    java.util.Date localtime = new java.util.Date();
1401
    String dateString = formatter.format(localtime);
1402
    response.setContentType("text/xml");
1403

    
1404
    out.println("<timestamp>" + dateString + "</timestamp>");
1405
  }
1406

    
1407
  /**
1408
   * this method handles the timeout for a file lock.  when a lock is
1409
   * granted it is granted for 30 seconds.  When this thread runs out
1410
   * it deletes the docid from the queue, thus eliminating the lock.
1411
   */
1412
  public void run()
1413
  {
1414
    try
1415
    {
1416
      MetaCatUtil.debugMessage("thread started for docid: " +
1417
                               (String)fileLocks.elementAt(0), 45);
1418

    
1419
      Thread.sleep(30000); //the lock will expire in 30 seconds
1420
      MetaCatUtil.debugMessage("thread for docid: " +
1421
                             (String)fileLocks.elementAt(fileLocks.size() - 1) +
1422
                              " exiting.", 45);
1423

    
1424
      fileLocks.remove(fileLocks.size() - 1);
1425
      //fileLocks is treated as a FIFO queue.  If there are more than one lock
1426
      //in the vector, the first one inserted will be removed.
1427
    }
1428
    catch(Exception e)
1429
    {
1430
      MetaCatUtil.debugMessage("error in file lock thread from " +
1431
                                "MetacatReplication.run: " + e.getMessage(), 30);
1432
    }
1433
  }
1434

    
1435
  /**
1436
   * Returns the name of a server given a serverCode
1437
   * @param serverCode the serverid of the server
1438
   * @return the servername or null if the specified serverCode does not
1439
   *         exist.
1440
   */
1441
  public static String getServerNameForServerCode(int serverCode)
1442
  {
1443
    //System.out.println("serverid: " + serverCode);
1444
    DBConnection dbConn = null;
1445
    int serialNumber = -1;
1446
    PreparedStatement pstmt = null;
1447
    try
1448
    {
1449
      dbConn=DBConnectionPool.
1450
                  getDBConnection("MetacatReplication.getServer");
1451
      serialNumber=dbConn.getCheckOutSerialNumber();
1452
      String sql = new String("select server from " +
1453
                              "xml_replication where serverid = " +
1454
                              serverCode);
1455
      pstmt = dbConn.prepareStatement(sql);
1456
      //System.out.println("getserver sql: " + sql);
1457
      pstmt.execute();
1458
      ResultSet rs = pstmt.getResultSet();
1459
      boolean tablehasrows = rs.next();
1460
      if(tablehasrows)
1461
      {
1462
        //System.out.println("server: " + rs.getString(1));
1463
        return rs.getString(1);
1464
      }
1465

    
1466
      //conn.close();
1467
    }
1468
    catch(Exception e)
1469
    {
1470
      System.out.println("Error in MetacatReplication.getServer: " +
1471
                          e.getMessage());
1472
    }
1473
    finally
1474
    {
1475
      try
1476
      {
1477
        pstmt.close();
1478
      }//try
1479
      catch (SQLException ee)
1480
      {
1481
        MetaCatUtil.debugMessage("Error in MetacactReplication.getserver: "+
1482
                                    ee.getMessage(), 30);
1483
      }//catch
1484
      finally
1485
      {
1486
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1487
      }//fianlly
1488
    }//finally
1489

    
1490

    
1491

    
1492
    return null;
1493
      //return null if the server does not exist
1494
  }
1495

    
1496
  /**
1497
   * Returns a server code given a server name
1498
   * @param server the name of the server
1499
   * @return integer > 0 representing the code of the server, 0 if the server
1500
   *  does not exist.
1501
   */
1502
  public static int getServerCodeForServerName(String server) throws Exception
1503
  {
1504
    DBConnection dbConn = null;
1505
    int serialNumber = -1;
1506
    PreparedStatement pstmt = null;
1507
    int serverCode = 0;
1508

    
1509
    try {
1510

    
1511
      //conn = util.openDBConnection();
1512
      dbConn=DBConnectionPool.
1513
                  getDBConnection("MetacatReplication.getServerCode");
1514
      serialNumber=dbConn.getCheckOutSerialNumber();
1515
      pstmt = dbConn.prepareStatement("SELECT serverid FROM xml_replication " +
1516
                                    "WHERE server LIKE '" + server + "'");
1517
      pstmt.execute();
1518
      ResultSet rs = pstmt.getResultSet();
1519
      boolean tablehasrows = rs.next();
1520
      if ( tablehasrows ) {
1521
        serverCode = rs.getInt(1);
1522
        pstmt.close();
1523
        //conn.close();
1524
        return serverCode;
1525
      }
1526

    
1527
    } catch(Exception e) {
1528
      throw e;
1529

    
1530
    } finally {
1531
      try
1532
      {
1533
        pstmt.close();
1534
        //conn.close();
1535
       }//try
1536
       catch(Exception ee)
1537
       {
1538
         MetaCatUtil.debugMessage("Error in MetacatReplicatio.getServerCode: "
1539
                                  +ee.getMessage(), 30);
1540

    
1541
       }//catch
1542
       finally
1543
       {
1544
         DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1545
       }//finally
1546
    }//finally
1547

    
1548
    return serverCode;
1549
  }
1550

    
1551
  /**
1552
   * Method to get a host server information for given docid
1553
   * @param conn a connection to the database
1554
   */
1555
  public static Hashtable getHomeServerInfoForDocId(String docId)
1556
  {
1557
    Hashtable sl = new Hashtable();
1558
    DBConnection dbConn = null;
1559
    int serialNumber = -1;
1560
    //MetaCatUtil ut=new MetaCatUtil();
1561
    docId=MetaCatUtil.getDocIdFromString(docId);
1562
    PreparedStatement pstmt=null;
1563
    int serverLocation;
1564
    try
1565
    {
1566
      //get conection
1567
      dbConn=DBConnectionPool.
1568
                  getDBConnection("ReplicationHandler.getHomeServer");
1569
      serialNumber=dbConn.getCheckOutSerialNumber();
1570
      //get a server location from xml_document table
1571
      pstmt=dbConn.prepareStatement("select server_location from xml_documents "
1572
                                            +"where docid = ?");
1573
      pstmt.setString(1, docId);
1574
      pstmt.execute();
1575
      ResultSet serverName = pstmt.getResultSet();
1576
      //get a server location
1577
      if(serverName.next())
1578
      {
1579
        serverLocation=serverName.getInt(1);
1580
        pstmt.close();
1581
      }
1582
      else
1583
      {
1584
        pstmt.close();
1585
        //ut.returnConnection(conn);
1586
        return null;
1587
      }
1588
      pstmt=dbConn.prepareStatement("select server, last_checked, replicate " +
1589
                        "from xml_replication where serverid = ?");
1590
      //increase usage count
1591
      dbConn.increaseUsageCount(1);
1592
      pstmt.setInt(1, serverLocation);
1593
      pstmt.execute();
1594
      ResultSet rs = pstmt.getResultSet();
1595
      boolean tableHasRows = rs.next();
1596
      if (tableHasRows)
1597
      {
1598

    
1599
          String server = rs.getString(1);
1600
          String last_checked = rs.getString(2);
1601
          if(!server.equals("localhost"))
1602
          {
1603
            sl.put(server, last_checked);
1604
          }
1605

    
1606
      }
1607
      else
1608
      {
1609
        pstmt.close();
1610
        //ut.returnConnection(conn);
1611
        return null;
1612
      }
1613
      pstmt.close();
1614
    }
1615
    catch(Exception e)
1616
    {
1617
      System.out.println("error in replicationHandler.getHomeServer(): " +
1618
                         e.getMessage());
1619
    }
1620
    finally
1621
    {
1622
      try
1623
      {
1624
        pstmt.close();
1625
        //ut.returnConnection(conn);
1626
      }
1627
      catch (Exception ee)
1628
      {
1629
        MetaCatUtil.debugMessage("Eror irn rplicationHandler.getHomeServer() "+
1630
                          "to close pstmt: "+ee.getMessage(), 30);
1631
      }
1632
      finally
1633
      {
1634
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1635
      }
1636

    
1637
    }//finally
1638
    return sl;
1639
  }
1640

    
1641
  /**
1642
   * Returns a home server location  given a accnum
1643
   * @param accNum , given accNum for a document
1644
   *
1645
   */
1646
  public static int getHomeServerCodeForDocId(String accNum) throws Exception
1647
  {
1648
    DBConnection dbConn = null;
1649
    int serialNumber = -1;
1650
    PreparedStatement pstmt = null;
1651
    int serverCode = 1;
1652
    //MetaCatUtil ut = new MetaCatUtil();
1653
    String docId=MetaCatUtil.getDocIdFromString(accNum);
1654

    
1655
    try
1656
    {
1657

    
1658
      // Get DBConnection
1659
      dbConn=DBConnectionPool.
1660
                  getDBConnection("ReplicationHandler.getServerLocation");
1661
      serialNumber=dbConn.getCheckOutSerialNumber();
1662
      pstmt=dbConn.prepareStatement("SELECT server_location FROM xml_documents "
1663
                              + "WHERE docid LIKE '" + docId + "'");
1664
      pstmt.execute();
1665
      ResultSet rs = pstmt.getResultSet();
1666
      boolean tablehasrows = rs.next();
1667
      //If a document is find, return the server location for it
1668
      if ( tablehasrows )
1669
      {
1670
        serverCode = rs.getInt(1);
1671
        pstmt.close();
1672
        //conn.close();
1673
        return serverCode;
1674
      }
1675
      //if couldn't find in xml_documents table, we think server code is 1
1676
      //(this is new document)
1677
      else
1678
      {
1679
        pstmt.close();
1680
        //conn.close();
1681
        return serverCode;
1682
      }
1683

    
1684
    }
1685
    catch(Exception e)
1686
    {
1687

    
1688
      throw e;
1689

    
1690
    }
1691
    finally
1692
    {
1693
      try
1694
      {
1695
        pstmt.close();
1696
        //conn.close();
1697

    
1698
      }
1699
      catch(Exception ee)
1700
      {
1701
        MetaCatUtil.debugMessage("Erorr in Replication.getServerLocation "+
1702
                     "to close pstmt"+ee.getMessage(), 30);
1703
      }
1704
      finally
1705
      {
1706
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1707
      }//finally
1708
    }//finally
1709
   //return serverCode;
1710
  }
1711

    
1712

    
1713

    
1714
  /**
1715
   * This method returns the content of a url
1716
   * @param u the url to return the content from
1717
   * @return a string representing the content of the url
1718
   * @throws java.io.IOException
1719
   */
1720
  public static String getURLContent(URL u) throws java.io.IOException
1721
  {
1722
    char istreamChar;
1723
    int istreamInt;
1724
    MetaCatUtil.debugMessage("Before open the stream"+u.toString(), 50);
1725
    InputStream input = u.openStream();
1726
    MetaCatUtil.debugMessage("Afetr open the stream"+u.toString(), 50);
1727
    InputStreamReader istream = new InputStreamReader(input);
1728
    StringBuffer serverResponse = new StringBuffer();
1729
    while((istreamInt = istream.read()) != -1)
1730
    {
1731
      istreamChar = (char)istreamInt;
1732
      serverResponse.append(istreamChar);
1733
    }
1734
    istream.close();
1735
    input.close();
1736

    
1737
    return serverResponse.toString();
1738
  }
1739

    
1740
  /**
1741
   * Method for writing replication messages to a log file specified in
1742
   * metacat.properties
1743
   */
1744
  public static void replLog(String message)
1745
  {
1746
    try
1747
    {
1748
      FileOutputStream fos = new FileOutputStream(
1749
                                 util.getOption("replicationlog"), true);
1750
      PrintWriter pw = new PrintWriter(fos);
1751
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
1752
      java.util.Date localtime = new java.util.Date();
1753
      String dateString = formatter.format(localtime);
1754
      dateString += " :: " + message;
1755
      //time stamp each entry
1756
      pw.println(dateString);
1757
      pw.flush();
1758
    }
1759
    catch(Exception e)
1760
    {
1761
      System.out.println("error writing to replication log from " +
1762
                         "MetacatReplication.replLog: " + e.getMessage());
1763
      //e.printStackTrace(System.out);
1764
    }
1765
  }
1766

    
1767
  /**
1768
   * Method for writing replication messages to a log file specified in
1769
   * metacat.properties
1770
   */
1771
  public static void replErrorLog(String message)
1772
  {
1773
    try
1774
    {
1775
      FileOutputStream fos = new FileOutputStream(
1776
                                 util.getOption("replicationerrorlog"), true);
1777
      PrintWriter pw = new PrintWriter(fos);
1778
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
1779
      java.util.Date localtime = new java.util.Date();
1780
      String dateString = formatter.format(localtime);
1781
      dateString += " :: " + message;
1782
      //time stamp each entry
1783
      pw.println(dateString);
1784
      pw.flush();
1785
    }
1786
    catch(Exception e)
1787
    {
1788
      System.out.println("error writing to replication log from " +
1789
                         "MetacatReplication.replLog: " + e.getMessage());
1790
      //e.printStackTrace(System.out);
1791
    }
1792
  }
1793

    
1794
  /**
1795
   * Returns true if the replicate field for server in xml_replication is 1.
1796
   * Returns false otherwise
1797
   */
1798
  public static boolean replToServer(String server)
1799
  {
1800
    DBConnection dbConn = null;
1801
    int serialNumber = -1;
1802
    PreparedStatement pstmt = null;
1803
    try
1804
    {
1805
      dbConn=DBConnectionPool.
1806
                  getDBConnection("MetacatReplication.repltoServer");
1807
      serialNumber=dbConn.getCheckOutSerialNumber();
1808
      pstmt = dbConn.prepareStatement("select replicate from " +
1809
                                    "xml_replication where server like '" +
1810
                                     server + "'");
1811
      pstmt.execute();
1812
      ResultSet rs = pstmt.getResultSet();
1813
      boolean tablehasrows = rs.next();
1814
      if(tablehasrows)
1815
      {
1816
        int i = rs.getInt(1);
1817
        if(i == 1)
1818
        {
1819
          pstmt.close();
1820
          //conn.close();
1821
          return true;
1822
        }
1823
        else
1824
        {
1825
          pstmt.close();
1826
          //conn.close();
1827
          return false;
1828
        }
1829
      }
1830
    }
1831
    catch(Exception e)
1832
    {
1833
      System.out.println("error in MetacatReplication.replToServer: " +
1834
                         e.getMessage());
1835
    }
1836
    finally
1837
    {
1838
      try
1839
      {
1840
        pstmt.close();
1841
        //conn.close();
1842
      }//try
1843
      catch(Exception ee)
1844
      {
1845
        MetaCatUtil.debugMessage("Error in MetacatReplication.replToServer: "
1846
                                  +ee.getMessage(), 30);
1847
      }//catch
1848
      finally
1849
      {
1850
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1851
      }//finally
1852
    }//finally
1853
    return false;
1854
    //the default if this server does not exist is to not replicate to it.
1855
  }
1856

    
1857

    
1858
}
(44-44/63)