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-30 12:48:59 -0700 (Fri, 30 Sep 2005) $'
11
 * '$Revision: 2608 $'
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
      else
168
      {
169
          // start, stop, getall and servercontrol need to check
170
          // if user is administor
171
          HttpSession sess = request.getSession(true);
172
          String sess_id = "";
173
          String username = "";
174
          String[] groupnames = {""};
175
          Hashtable sessionHash = MetaCatServlet.getSessionHash();
176
          if (params.containsKey("sessionid")) 
177
          {
178
             sess_id = ((String[]) params.get("sessionid"))[0];
179
             MetaCatUtil.debugMessage("in has sessionid "+ sess_id, 40);
180
             if (sessionHash.containsKey(sess_id)) 
181
             {
182
                  MetaCatUtil.debugMessage("find the id " + sess_id + " in hash table", 40);
183
                  sess = (HttpSession) sessionHash.get(sess_id);
184
             }
185
           } 
186
           username = (String) sess.getAttribute("username");
187
           MetaCatUtil.debugMessage("The user name from session is: "+ username, 20);
188
           groupnames = (String[]) sess.getAttribute("groupnames");
189
           if (!MetaCatUtil.isAdministrator(username, groupnames)) 
190
           {
191
               PrintWriter out = response.getWriter();
192
               out.print("<error>");
193
               out.print("The user \"" + username +
194
                       "\" is not authorized for this action.");
195
               out.print("</error>");
196
               out.close();
197
               MetaCatUtil.debugMessage("The user \"" + username +
198
                       "\" is not authorized for this action: " +action, 30);
199
               replErrorLog("The user \"" + username +
200
                       "\" is not authorized for this action: " +action);
201
               return;
202
           }
203
                        
204
      }// this is final else
205
    } catch (Exception e) {
206
      System.out.println("Error in MetacatReplication.handleGetOrPost: " +
207
                         e.getMessage() );
208
      return;
209
    }
210
    
211
    if ( action.equals("readdata") )
212
    {
213
      OutputStream outStream = response.getOutputStream();
214
      //to get the data file.
215
      handleGetDataFileRequest(outStream, params, response);
216
      outStream.close();
217
    }
218
    else if ( action.equals("forcereplicatedatafile") )
219
    {
220
      //read a specific docid from remote host, and store it into local host
221
      handleForceReplicateDataFileRequest(params);
222

    
223
    }
224
    else
225
    {
226
    PrintWriter out = response.getWriter();
227
    if ( action.equals("stop") ) {
228
      //stop the replication server
229
      replicationDaemon.cancel();
230
      replicationDaemon = new Timer(true);
231
      timedReplicationIsOn = false;
232
      MetaCatUtil.setOption(TIMEREPLICATION, (new Boolean(timedReplicationIsOn)).toString());
233
      out.println("Replication Handler Stopped");
234
      MetacatReplication.replLog("deltaT handler stopped");
235

    
236

    
237
    } else if ( action.equals("start") ) {
238
       String firstTimeStr = "";
239
      //start the replication server
240
       if ( params.containsKey("rate") ) {
241
        timeInterval = new Long(
242
               new String(((String[])params.get("rate"))[0])).longValue();
243
        if(timeInterval < TIMEINTERVALLIMIT) {
244
            out.println("Replication deltaT rate cannot be less than "+
245
                    TIMEINTERVALLIMIT + " millisecs and system automatically setup the rate to "+TIMEINTERVALLIMIT);
246
            //deltaT<30 is a timing mess!
247
            timeInterval = TIMEINTERVALLIMIT;
248
        }
249
      } else {
250
        timeInterval = TIMEINTERVALLIMIT ;
251
      }
252
      MetaCatUtil.debugMessage("New rate is: " + timeInterval + " mini seconds.", 30);
253
      if ( params.containsKey("firsttime"))
254
      {
255
         firstTimeStr = ((String[])params.get("firsttime"))[0];
256
         try
257
         {
258
           firstTime = ReplicationHandler.combinateCurrentDateAndGivenTime(firstTimeStr);
259
           MetaCatUtil.debugMessage("The first time setting is "+firstTime.toString(), 30);
260
         }
261
         catch (Exception e)
262
         {
263
            throw new ServletException(e.getMessage());
264
         }
265
         MetaCatUtil.debugMessage("After combine current time, the real first time is "
266
                                  +firstTime.toString()+" minisec", 20);
267
      }
268
      else
269
      {
270
          MetacatReplication.replErrorLog("You should specify the first time " +
271
                                          "to start a time replication");
272
          MetaCatUtil.debugMessage("You should specify the first time " +
273
                                  "to start a time replication", 30);
274
          return;
275
      }
276
      
277
      timedReplicationIsOn = true;
278
      // save settings to property file
279
      MetaCatUtil.setOption(TIMEREPLICATION, (new Boolean(timedReplicationIsOn)).toString());
280
      // note we couldn't use firstTime object because it has date info
281
      // we only need time info such as 10:00 PM
282
      MetaCatUtil.setOption(FIRSTTIME, firstTimeStr);
283
      MetaCatUtil.setOption(TIMEREPLICATIONINTERVAl, (new Long(timeInterval)).toString());
284
      replicationDaemon.cancel();
285
      replicationDaemon = new Timer(true);
286
      replicationDaemon.scheduleAtFixedRate(new ReplicationHandler(), firstTime,
287
                                            timeInterval);
288
      out.println("Replication Handler Started");
289
      MetacatReplication.replLog("deltaT handler started with rate=" +
290
                                    timeInterval + " milliseconds at " +firstTime.toString());
291

    
292

    
293
    } else if ( action.equals("getall") ) {
294
      //updates this server exactly once
295
      replicationDaemon.schedule(new ReplicationHandler(), 0);
296
      response.setContentType("text/html");
297
      out.println("<html><body>\"Get All\" Done</body></html>");
298

    
299
    } else if ( action.equals("forcereplicate") ) {
300
      //read a specific docid from remote host, and store it into local host
301
      handleForceReplicateRequest(out, params, response);
302

    
303
    } else if ( action.equals(FORCEREPLICATEDELETE) ) {
304
      //read a specific docid from remote host, and store it into local host
305
      handleForceReplicateDeleteRequest(out, params, response);
306

    
307
    } else if ( action.equals("update") ) {
308
      //request an update list from the server
309
      handleUpdateRequest(out, params, response);
310

    
311
    } else if ( action.equals("read") ) {
312
      //request a specific document from the server
313
      //note that this could be replaced by a call to metacatServlet
314
      //handleGetDocumentAction().
315
      handleGetDocumentRequest(out, params, response);
316
    } else if ( action.equals("getlock") ) {
317
      handleGetLockRequest(out, params, response);
318

    
319
    } else if ( action.equals("getdocumentinfo") ) {
320
      handleGetDocumentInfoRequest(out, params, response);
321

    
322
    } else if ( action.equals("gettime") ) {
323
      handleGetTimeRequest(out, params, response);
324

    
325
    } else if ( action.equals("getcatalog") ) {
326
      handleGetCatalogRequest(out, params, response, true);
327

    
328
    } else if ( action.equals("servercontrol") ) {
329
      handleServerControlRequest(out, params, response);
330
    } else if ( action.equals("test") ) {
331
      response.setContentType("text/html");
332
      out.println("<html><body>Test successfully</body></html>");
333
    }
334

    
335
    out.close();
336
    }//else
337
  }
338

    
339
  /**
340
   * This method can add, delete and list the servers currently included in
341
   * xml_replication.
342
   * action           subaction            other needed params
343
   * ---------------------------------------------------------
344
   * servercontrol    add                  server
345
   * servercontrol    delete               server
346
   * servercontrol    list
347
   */
348
  private void handleServerControlRequest(PrintWriter out, Hashtable params,
349
                                          HttpServletResponse response)
350
  {
351
    String subaction = ((String[])params.get("subaction"))[0];
352
    DBConnection dbConn = null;
353
    int serialNumber = -1;
354
    PreparedStatement pstmt = null;
355
    String replicate =null;
356
    String server = null;
357
    String dataReplicate = null;
358
    String hub = null;
359
    try {
360
      //conn = util.openDBConnection();
361
      dbConn=DBConnectionPool.
362
               getDBConnection("MetacatReplication.handleServerControlRequest");
363
      serialNumber=dbConn.getCheckOutSerialNumber();
364

    
365
      // add server to server list
366
      if ( subaction.equals("add") ) {
367
        replicate = ((String[])params.get("replicate"))[0];
368
        server = ((String[])params.get("server"))[0];
369

    
370
        //Get data replication value
371
        dataReplicate = ((String[])params.get("datareplicate"))[0];
372
        //Get hub value
373
        hub = ((String[])params.get("hub"))[0];
374

    
375
        /*pstmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
376
                  "(server, last_checked, replicate, datareplicate, hub) " +
377
                                      "VALUES ('" + server + "', to_date(" +
378
                                      "'01/01/00', 'MM/DD/YY'), '" +
379
                                      replicate +"', '" +dataReplicate+"', '"
380
                                      + hub +"')");*/
381
        pstmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
382
                  "(server, last_checked, replicate, datareplicate, hub) " +
383
                                      "VALUES ('" + server + "', "+
384
                                      dbAdapter.toDate("01/01/1980", "MM/DD/YYYY")
385
                                      + ", '" +
386
                                      replicate +"', '" +dataReplicate+"', '"
387
                                      + hub +"')");
388

    
389
        pstmt.execute();
390
        pstmt.close();
391
        dbConn.commit();
392
        out.println("Server " + server + " added");
393
        response.setContentType("text/html");
394
        out.println("<html><body><table border=\"1\">");
395
        out.println("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
396
        out.println("<b>replicate</b></td>");
397
        out.println("<td><b>datareplicate</b></td>");
398
        out.println("<td><b>hub</b></td></tr>");
399
        pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
400
        //increase dbconnection usage
401
        dbConn.increaseUsageCount(1);
402

    
403
        pstmt.execute();
404
        ResultSet rs = pstmt.getResultSet();
405
        boolean tablehasrows = rs.next();
406
        while(tablehasrows) {
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

    
413
          tablehasrows = rs.next();
414
        }
415
        out.println("</table></body></html>");
416

    
417
        // download certificate with the public key on this server
418
        // and import it as a trusted certificate
419
        String certURL = ((String[])params.get("certificate"))[0];
420
        downloadCertificate(certURL);
421

    
422
      // delete server from server list
423
      } else if ( subaction.equals("delete") ) {
424
        server = ((String[])params.get("server"))[0];
425
        pstmt = dbConn.prepareStatement("DELETE FROM xml_replication " +
426
                                      "WHERE server LIKE '" + server + "'");
427
        pstmt.execute();
428
        pstmt.close();
429
        dbConn.commit();
430
        out.println("Server " + server + " deleted");
431
        response.setContentType("text/html");
432
        out.println("<html><body><table border=\"1\">");
433
        out.println("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
434
        out.println("<b>replicate</b></td>");
435
        out.println("<td><b>datareplicate</b></td>");
436
        out.println("<td><b>hub</b></td></tr>");
437

    
438
        pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
439
        //increase dbconnection usage
440
        dbConn.increaseUsageCount(1);
441
        pstmt.execute();
442
        ResultSet rs = pstmt.getResultSet();
443
        boolean tablehasrows = rs.next();
444
        while(tablehasrows)
445
        {
446
          out.println("<tr><td>" + rs.getString(2) + "</td><td>");
447
          out.println(rs.getString(3) + "</td><td>");
448
          out.println(rs.getString(4) + "</td><td>");
449
          out.println(rs.getString(5) + "</td><td>");
450
          out.println(rs.getString(6) + "</td></tr>");
451
          tablehasrows = rs.next();
452
        }
453
        out.println("</table></body></html>");
454

    
455
      // list servers in server list
456
      } else if ( subaction.equals("list") ) {
457
        response.setContentType("text/html");
458
        out.println("<html><body><table border=\"1\">");
459
        out.println("<tr><td><b>server</b></td><td><b>last_checked</b></td><td>");
460
        out.println("<b>replicate</b></td>");
461
        out.println("<td><b>datareplicate</b></td>");
462
        out.println("<td><b>hub</b></td></tr>");
463
        pstmt = dbConn.prepareStatement("SELECT * FROM xml_replication");
464
        pstmt.execute();
465
        ResultSet rs = pstmt.getResultSet();
466
        boolean tablehasrows = rs.next();
467
        while(tablehasrows) {
468
          out.println("<tr><td>" + rs.getString(2) + "</td><td>");
469
          out.println(rs.getString(3) + "</td><td>");
470
          out.println(rs.getString(4) + "</td><td>");
471
          out.println(rs.getString(5) + "</td><td>");
472
          out.println(rs.getString(6) + "</td></tr>");
473
          tablehasrows = rs.next();
474
        }
475
        out.println("</table></body></html>");
476
      }
477
      else
478
      {
479

    
480
        out.println("<error>Unkonwn subaction</error>");
481

    
482
      }
483
      pstmt.close();
484
      //conn.close();
485

    
486
    } catch(Exception e) {
487
      System.out.println("Error in " +
488
                         "MetacatReplication.handleServerControlRequest " +
489
                         e.getMessage());
490
      e.printStackTrace(System.out);
491
    }
492
    finally
493
    {
494
      try
495
      {
496
        pstmt.close();
497
      }//try
498
      catch (SQLException ee)
499
      {
500
        MetaCatUtil.debugMessage("Error in " +
501
                "MetacatReplication.handleServerControlRequest to close pstmt "
502
                 + ee.getMessage(), 30);
503
      }//catch
504
      finally
505
      {
506
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
507
      }//finally
508
    }//finally
509

    
510
  }
511

    
512
  // download certificate with the public key from certURL and
513
  // upload it onto this server; it then must be imported as a
514
  // trusted certificate
515
  private void downloadCertificate (String certURL)
516
                throws FileNotFoundException, IOException, MalformedURLException
517
  {
518
    MetaCatUtil util = new MetaCatUtil();
519
    String certPath = util.getOption("certPath"); //the path to be uploaded to
520

    
521
    // get filename from the URL of the certificate
522
    String filename = certURL;
523
    int slash = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
524
    if ( slash > -1 ) {
525
      filename = filename.substring(slash + 1);
526
    }
527

    
528
    // open file output strem to write the input into it
529
    File f = new File(certPath, filename);
530
    synchronized (f) {
531
      try {
532
        if ( f.exists() ) {
533
          throw new IOException("File already exist: " + f.getCanonicalFile());
534
          //if ( f.exists() && !f.canWrite() ) {
535
          //  throw new IOException("Not writable: " + f.getCanonicalFile());
536
        }
537
      } catch (SecurityException se) {
538
        // if a security manager exists,
539
        // its checkRead method is called for f.exist()
540
        // or checkWrite method is called for f.canWrite()
541
        throw se;
542
      }
543

    
544
      // create a buffered byte output stream
545
      // that uses a default-sized output buffer
546
      FileOutputStream fos = new FileOutputStream(f);
547
      BufferedOutputStream out = new BufferedOutputStream(fos);
548

    
549
      // this should be http url
550
      URL url = new URL(certURL);
551
      BufferedInputStream bis = null;
552
      try {
553
        bis = new BufferedInputStream(url.openStream());
554
        byte[] buf = new byte[4 * 1024]; // 4K buffer
555
        int b = bis.read(buf);
556
        while (b != -1) {
557
          out.write(buf, 0, b);
558
          b = bis.read(buf);
559
        }
560
      } finally {
561
        if (bis != null) bis.close();
562
      }
563
      // the input and the output streams must be closed
564
      bis.close();
565
            out.flush();
566
            out.close();
567
            fos.close();
568
    } // end of synchronized(f)
569
  }
570

    
571
  /**
572
   * when a forcereplication request comes in, local host sends a read request
573
   * to the requesting server (remote server) for the specified docid.
574
   * Then store it in local database.
575
   */
576
  private void handleForceReplicateRequest(PrintWriter out, Hashtable params,
577
                                           HttpServletResponse response)
578
  {
579
    String server = ((String[])params.get("server"))[0]; // the server that
580
    String docid = ((String[])params.get("docid"))[0]; // sent the document
581
    String dbaction = "UPDATE"; // the default action is UPDATE
582
    boolean override = false;
583
    int serverCode = 1;
584
    DBConnection dbConn = null;
585
    int serialNumber = -1;
586

    
587
    try {
588
      //if the url contains a dbaction then the default action is overridden
589
      if(params.containsKey("dbaction")) {
590
        dbaction = ((String[])params.get("dbaction"))[0];
591
        //serverCode = MetacatReplication.getServerCode(server);
592
        //override = true; //we are now overriding the default action
593
      }
594
      MetacatReplication.replLog("force replication request from " + server);
595
      MetaCatUtil.debugMessage("Force replication request from: "+ server, 34);
596
      MetaCatUtil.debugMessage("Force replication docid: "+docid, 34);
597
      MetaCatUtil.debugMessage("Force replication action: "+dbaction, 34);
598
      // sending back read request to remote server
599
      URL u = new URL("https://" + server + "?server="
600
                +util.getLocalReplicationServerName()
601
                +"&action=read&docid=" + docid);
602
      String xmldoc = MetacatReplication.getURLContent(u);
603

    
604
      // get the document info from server
605
      URL docinfourl = new URL("https://" + server +
606
                               "?server="+util.getLocalReplicationServerName()
607
                               +"&action=getdocumentinfo&docid=" + docid);
608

    
609
      String docInfoStr = MetacatReplication.getURLContent(docinfourl);
610

    
611
      //dih is the parser for the docinfo xml format
612
      DocInfoHandler dih = new DocInfoHandler();
613
      XMLReader docinfoParser = ReplicationHandler.initParser(dih);
614
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
615
      Hashtable docinfoHash = dih.getDocInfo();
616

    
617
      // Get user owner of this docid
618
      String user = (String)docinfoHash.get("user_owner");
619
      // Get home server of this docid
620
      String homeServer=(String)docinfoHash.get("home_server");
621
      MetaCatUtil.debugMessage("homeServer: "+homeServer, 34);
622
      // Get Document type
623
      String docType = (String)docinfoHash.get("doctype");
624
      MetaCatUtil.debugMessage("docType: "+docType, 34);
625
      String parserBase = null;
626
      // this for eml2 and we need user eml2 parser
627
      if (docType != null &&
628
          (docType.trim()).equals(DocumentImpl.EML2_0_0NAMESPACE))
629
      {
630
         MetaCatUtil.debugMessage("This is an eml200 document!", 30);
631
         parserBase = DocumentImpl.EML200;
632
      }
633
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_0_1NAMESPACE))
634
      {
635
         MetaCatUtil.debugMessage("This is an eml2.0.1 document!", 30);
636
         parserBase = DocumentImpl.EML200;
637
      }
638
      else if (docType != null && (docType.trim()).equals(DocumentImpl.EML2_1_0NAMESPACE))
639
      {
640
         MetaCatUtil.debugMessage("This is an eml2.1.0 document!", 30);
641
         parserBase = DocumentImpl.EML210;
642
      }
643
      MetaCatUtil.debugMessage("The parserBase is: "+parserBase, 30);
644

    
645
      // Get DBConnection from pool
646
      dbConn=DBConnectionPool.
647
              getDBConnection("MetacatReplication.handleForceReplicateRequest");
648
      serialNumber=dbConn.getCheckOutSerialNumber();
649
      // write the document to local database
650
      DocumentImplWrapper wrapper = new DocumentImplWrapper(parserBase, false);
651
      wrapper.writeReplication(dbConn, new StringReader(xmldoc), null, null,
652
                               dbaction, docid, user, null, homeServer, server);
653

    
654
      MetacatReplication.replLog("document " + docid + " added to DB with " +
655
                                 "action " + dbaction);
656
    }//try
657
    catch(Exception e)
658
    {
659
      MetacatReplication.replErrorLog("document " + docid +
660
                                      " failed to added to DB with " +
661
                                      "action " + dbaction + " because "+
662
                                       e.getMessage());
663
      MetaCatUtil.debugMessage("ERROR in MetacatReplication.handleForceReplicate" +
664
                         "Request(): " + e.getMessage(), 30);
665

    
666
    }//catch
667
    finally
668
    {
669
      // Return the checked out DBConnection
670
      DBConnectionPool.returnDBConnection(dbConn, serialNumber);
671
    }//finally
672
  }
673

    
674
/*
675
 * when a forcereplication delete request comes in, local host will delete this
676
 * document
677
 */
678
private void handleForceReplicateDeleteRequest(PrintWriter out, Hashtable params,
679
                                         HttpServletResponse response)
680
{
681
  String server = ((String[])params.get("server"))[0]; // the server that
682
  String docid = ((String[])params.get("docid"))[0]; // sent the document
683
  try
684
  {
685
    MetacatReplication.replLog("force replication delete request from " + server);
686
    MetacatReplication.replLog("force replication delete docid " + docid);
687
    MetaCatUtil.debugMessage("Force replication delete request from: "+ server, 34);
688
    MetaCatUtil.debugMessage("Force replication delete docid: "+docid, 34);
689
    DocumentImpl.delete(docid, null, null, server);
690
    MetacatReplication.replLog("document " + docid + " was successfully deleted ");
691
    MetaCatUtil.debugMessage("document " + docid + " was successfully deleted ", 34);
692
  }
693
  catch(Exception e)
694
  {
695
    MetacatReplication.replErrorLog("document " + docid +
696
                                    " failed to delete because "+
697
                                     e.getMessage());
698
    MetaCatUtil.debugMessage("ERROR in MetacatReplication.handleForceDeleteReplicate" +
699
                       "Request(): " + e.getMessage(), 30);
700

    
701
  }//catch
702

    
703
}
704

    
705

    
706
  /**
707
   * when a forcereplication data file request comes in, local host sends a
708
   * readdata request to the requesting server (remote server) for the specified
709
   * docid. Then store it in local database and file system
710
   */
711
  private void handleForceReplicateDataFileRequest(Hashtable params)
712
  {
713

    
714
    //make sure there is some parameters
715
    if(params.isEmpty())
716
    {
717
      return;
718
    }
719
    // Get remote server
720
    String server = ((String[])params.get("server"))[0];
721
    // the docid should include rev number
722
    String docid = ((String[])params.get("docid"))[0];
723
    // Make sure there is a docid and server
724
    if (docid==null || server==null || server.equals(""))
725
    {
726
      MetaCatUtil.debugMessage("Didn't specify docid or server for replication"
727
                              , 20);
728
      return;
729
    }
730

    
731
    // Overide or not
732
    boolean override = false;
733
    // dbaction - update or insert
734
    String dbaction=null;
735

    
736
    try
737
    {
738
      //docid was switch to two parts uinque code and rev
739
      String uniqueCode=MetaCatUtil.getDocIdFromString(docid);
740
      int rev=MetaCatUtil.getVersionFromString(docid);
741
      if(params.containsKey("dbaction"))
742
      {
743
        dbaction = ((String[])params.get("dbaction"))[0];
744
      }
745
      else//default value is update
746
      {
747
        dbaction = "update";
748
      }
749

    
750
      MetacatReplication.replLog("force replication request from " + server);
751
      MetaCatUtil.debugMessage("Force replication request from: "+ server, 34);
752
      MetaCatUtil.debugMessage("Force replication docid: "+docid, 34);
753
      MetaCatUtil.debugMessage("Force replication action: "+dbaction, 34);
754
      // get the document info from server
755
      URL docinfourl = new URL("https://" + server +
756
                               "?server="+util.getLocalReplicationServerName()
757
                               +"&action=getdocumentinfo&docid=" + uniqueCode);
758

    
759
      String docInfoStr = MetacatReplication.getURLContent(docinfourl);
760

    
761
      //dih is the parser for the docinfo xml format
762
      DocInfoHandler dih = new DocInfoHandler();
763
      XMLReader docinfoParser = ReplicationHandler.initParser(dih);
764
      docinfoParser.parse(new InputSource(new StringReader(docInfoStr)));
765
      Hashtable docinfoHash = dih.getDocInfo();
766
      String user = (String)docinfoHash.get("user_owner");
767

    
768
      String docName = (String)docinfoHash.get("docname");
769

    
770
      String docType = (String)docinfoHash.get("doctype");
771

    
772
      String docHomeServer= (String)docinfoHash.get("home_server");
773
      MetaCatUtil.debugMessage("docHomeServer of datafile: "+docHomeServer, 34);
774

    
775

    
776

    
777
      //if action is delete, we don't delete the data file. Just archieve
778
      //the xml_documents
779
      /*if (dbaction.equals("delete"))
780
      {
781
        //conn = util.getConnection();
782
        DocumentImpl.delete(docid,user,null);
783
        //util.returnConnection(conn);
784
      }*/
785
      //To data file insert or update is same
786
      if (dbaction.equals("insert")||dbaction.equals("update"))
787
      {
788
        //Get data file and store it into local file system.
789
        // sending back readdata request to server
790
        URL url = new URL("https://" + server + "?server="
791
                +util.getLocalReplicationServerName()
792
                +"&action=readdata&docid=" + docid);
793
        String datafilePath = util.getOption("datafilepath");
794
        //register data file into xml_documents table and wite data file
795
        //into file system
796
        DocumentImpl.writeDataFileInReplication(url.openStream(), datafilePath,
797
                            docName, docType, docid, user,docHomeServer,server, 
798
                            DocumentImpl.DOCUMENTTABLE, false);//false means non-timed replication
799
     }
800

    
801

    
802

    
803
    MetacatReplication.replLog("datafile " + docid + " added to DB with " +
804
                                 "action " + dbaction);
805
    }
806
    catch(Exception e)
807
    {
808

    
809
      MetacatReplication.replErrorLog("Datafile " + docid +
810
                                      " failed to added to DB with " +
811
                                      "action " + dbaction + " because "+
812
                                       e.getMessage());
813
      MetaCatUtil.debugMessage
814
              ("ERROR in MetacatReplication.handleForceDataFileReplicate" +
815
                         "Request(): " + e.getMessage(), 30);
816
    }
817
  }
818
  /**
819
   * Grants or denies a lock to a requesting host.
820
   * The servlet parameters of interrest are:
821
   * docid: the docid of the file the lock is being requested for
822
   * currentdate: the timestamp of the document on the remote server
823
   *
824
   */
825
  private void handleGetLockRequest(PrintWriter out, Hashtable params,
826
                                    HttpServletResponse response)
827
  {
828

    
829
    try
830
    {
831

    
832
      String docid = ((String[])params.get("docid"))[0];
833
      String remoteRev = ((String[])params.get("updaterev"))[0];
834
      DocumentImpl requestDoc = new DocumentImpl(docid);
835
      MetacatReplication.replLog("lock request for " + docid);
836
      int localRevInt = requestDoc.getRev();
837
      int remoteRevInt = Integer.parseInt(remoteRev);
838

    
839
      if(remoteRevInt >= localRevInt)
840
      {
841
        if(!fileLocks.contains(docid))
842
        { //grant the lock if it is not already locked
843
          fileLocks.add(0, docid); //insert at the beginning of the queue Vector
844
          //send a message back to the the remote host authorizing the insert
845
          out.println("<lockgranted><docid>" +docid+ "</docid></lockgranted>");
846
          lockThread = new Thread(this);
847
          lockThread.setPriority(Thread.MIN_PRIORITY);
848
          lockThread.start();
849
          MetacatReplication.replLog("lock granted for " + docid);
850
        }
851
        else
852
        { //deny the lock
853
          out.println("<filelocked><docid>" + docid + "</docid></filelocked>");
854
          MetacatReplication.replLog("lock denied for " + docid +
855
                                     "reason: file already locked");
856
        }
857
      }
858
      else
859
      {//deny the lock.
860
        out.println("<outdatedfile><docid>" + docid + "</docid></filelocked>");
861
        MetacatReplication.replLog("lock denied for " + docid +
862
                                   "reason: client has outdated file");
863
      }
864
      //conn.close();
865
    }
866
    catch(Exception e)
867
    {
868
      System.out.println("error requesting file lock from MetacatReplication." +
869
                         "handleGetLockRequest: " + e.getMessage());
870
      e.printStackTrace(System.out);
871
    }
872
  }
873

    
874
  /**
875
   * Sends all of the xml_documents information encoded in xml to a requestor
876
   * the format is:
877
   * <!ELEMENT documentinfo (docid, docname, doctype, doctitle, user_owner,
878
   *                  user_updated, home_server, public_access, rev)/>
879
   * all of the subelements of document info are #PCDATA
880
   */
881
  private void handleGetDocumentInfoRequest(PrintWriter out, Hashtable params,
882
                                        HttpServletResponse response)
883
  {
884
    String docid = ((String[])(params.get("docid")))[0];
885
    StringBuffer sb = new StringBuffer();
886

    
887
    try
888
    {
889

    
890
      DocumentImpl doc = new DocumentImpl(docid);
891
      sb.append("<documentinfo><docid>").append(docid);
892
      sb.append("</docid><docname>").append(doc.getDocname());
893
      sb.append("</docname><doctype>").append(doc.getDoctype());
894
      sb.append("</doctype>");
895
      sb.append("<user_owner>").append(doc.getUserowner());
896
      sb.append("</user_owner><user_updated>").append(doc.getUserupdated());
897
      sb.append("</user_updated>");
898
      sb.append("<home_server>");
899
      sb.append(doc.getDocHomeServer());
900
      sb.append("</home_server>");
901
      sb.append("<public_access>").append(doc.getPublicaccess());
902
      sb.append("</public_access><rev>").append(doc.getRev());
903
      sb.append("</rev></documentinfo>");
904
      response.setContentType("text/xml");
905
      out.println(sb.toString());
906

    
907
    }
908
    catch (Exception e)
909
    {
910
      System.out.println("error in " +
911
                         "metacatReplication.handlegetdocumentinforequest: " +
912
                          e.getMessage());
913
    }
914

    
915
  }
916

    
917
  /**
918
   * Sends a datafile to a remote host
919
   */
920
  private void handleGetDataFileRequest(OutputStream outPut,
921
                            Hashtable params, HttpServletResponse response)
922

    
923
  {
924
    // File path for data file
925
    String filepath = util.getOption("datafilepath");
926
    // Request docid
927
    String docId = ((String[])(params.get("docid")))[0];
928
    //check if the doicd is null
929
    if (docId==null)
930
    {
931
      util.debugMessage("Didn't specify docid for replication", 20);
932
      return;
933
    }
934

    
935
    //try to open a https stream to test if the request server's public key
936
    //in the key store, this is security issue
937
    try
938
    {
939
      String server = ((String[])params.get("server"))[0];
940
      URL u = new URL("https://" + server + "?server="
941
                +util.getLocalReplicationServerName()
942
                +"&action=test");
943
      String test = MetacatReplication.getURLContent(u);
944
      //couldn't pass the test
945
      if (test.indexOf("successfully")==-1)
946
      {
947
        //response.setContentType("text/xml");
948
        //outPut.println("<error>Couldn't pass the trust test</error>");
949
        MetaCatUtil.debugMessage("Couldn't pass the trust test", 20);
950
        return;
951
      }
952
    }//try
953
    catch (Exception ee)
954
    {
955
      return;
956
    }//catch
957

    
958
    if(!filepath.endsWith("/"))
959
    {
960
          filepath += "/";
961
    }
962
    // Get file aboslute file name
963
    String filename = filepath + docId;
964

    
965
    //MIME type
966
    String contentType = null;
967
    if (filename.endsWith(".xml"))
968
    {
969
        contentType="text/xml";
970
    }
971
    else if (filename.endsWith(".css"))
972
    {
973
        contentType="text/css";
974
    }
975
    else if (filename.endsWith(".dtd"))
976
    {
977
        contentType="text/plain";
978
    }
979
    else if (filename.endsWith(".xsd"))
980
    {
981
        contentType="text/xml";
982
    }
983
    else if (filename.endsWith("/"))
984
    {
985
        contentType="text/html";
986
    }
987
    else
988
    {
989
        File f = new File(filename);
990
        if ( f.isDirectory() )
991
        {
992
           contentType="text/html";
993
        }
994
        else
995
        {
996
           contentType="application/octet-stream";
997
        }
998
     }
999

    
1000
   // Set the mime type
1001
   response.setContentType(contentType);
1002

    
1003
   // Get the content of the file
1004
   FileInputStream fin = null;
1005
   try
1006
   {
1007
      // FileInputStream to metacat
1008
      fin = new FileInputStream(filename);
1009
      // 4K buffer
1010
      byte[] buf = new byte[4 * 1024];
1011
      // Read data from file input stream to byte array
1012
      int b = fin.read(buf);
1013
      // Write to outStream from byte array
1014
      while (b != -1)
1015
      {
1016
        outPut.write(buf, 0, b);
1017
        b = fin.read(buf);
1018
      }
1019
      // close file input stream
1020
      fin.close();
1021

    
1022
   }//try
1023
   catch(Exception e)
1024
   {
1025
      System.out.println("error getting data file from MetacatReplication." +
1026
                         "handlGetDataFileRequest " + e.getMessage());
1027
      e.printStackTrace(System.out);
1028
   }//catch
1029

    
1030
}
1031

    
1032

    
1033
  /**
1034
   * Sends a document to a remote host
1035
   */
1036
  private void handleGetDocumentRequest(PrintWriter out, Hashtable params,
1037
                                        HttpServletResponse response)
1038
  {
1039

    
1040
    try
1041
    {
1042
      //try to open a https stream to test if the request server's public key
1043
      //in the key store, this is security issue
1044
      String server = ((String[])params.get("server"))[0];
1045
      URL u = new URL("https://" + server + "?server="
1046
                +util.getLocalReplicationServerName()
1047
                +"&action=test");
1048
      String test = MetacatReplication.getURLContent(u);
1049
      //couldn't pass the test
1050
      if (test.indexOf("successfully")==-1)
1051
      {
1052
        response.setContentType("text/xml");
1053
        out.println("<error>Couldn't pass the trust test</error>");
1054
        out.close();
1055
        return;
1056
      }
1057

    
1058
      String docid = ((String[])(params.get("docid")))[0];
1059

    
1060
      DocumentImpl di = new DocumentImpl(docid);
1061
      response.setContentType("text/xml");
1062
      out.print(di.toString(null, null, true));
1063

    
1064
      MetacatReplication.replLog("document " + docid + " sent");
1065

    
1066
    }
1067
    catch(Exception e)
1068
    {
1069
      MetaCatUtil.debugMessage("error getting document from MetacatReplication."
1070
                          +"handlGetDocumentRequest " + e.getMessage(), 30);
1071
      //e.printStackTrace(System.out);
1072
      response.setContentType("text/xml");
1073
      out.println("<error>"+e.getMessage()+"</error>");
1074
    }
1075

    
1076
  }
1077

    
1078
  /**
1079
   * Sends a list of all of the documents on this sever along with their
1080
   * revision numbers.
1081
   * The format is:
1082
   * <!ELEMENT replication (server, updates)>
1083
   * <!ELEMENT server (#PCDATA)>
1084
   * <!ELEMENT updates ((updatedDocument | deleteDocument | revisionDocument)*)>
1085
   * <!ELEMENT updatedDocument (docid, rev, datafile*)>
1086
   * <!ELEMENT deletedDocument (docid, rev)>
1087
   * <!ELEMENT revisionDocument (docid, rev, datafile*)>
1088
   * <!ELEMENT docid (#PCDATA)>
1089
   * <!ELEMENT rev (#PCDATA)>
1090
   * <!ELEMENT datafile (#PCDATA)>
1091
   * note that the rev in deletedDocument is always empty.  I just left
1092
   * it in there to make the parser implementation easier.
1093
   */
1094
  private void handleUpdateRequest(PrintWriter out, Hashtable params,
1095
                                    HttpServletResponse response)
1096
  {
1097
    // Checked out DBConnection
1098
    DBConnection dbConn = null;
1099
    // DBConenction serial number when checked it out
1100
    int serialNumber = -1;
1101
    PreparedStatement pstmt = null;
1102
    // Server list to store server info of xml_replication table
1103
    ReplicationServerList serverList = null;
1104

    
1105
    try
1106
    {
1107
      // Check out a DBConnection from pool
1108
      dbConn=DBConnectionPool.
1109
                  getDBConnection("MetacatReplication.handleUpdateRequest");
1110
      serialNumber=dbConn.getCheckOutSerialNumber();
1111
      // Create a server list from xml_replication table
1112
      serverList = new ReplicationServerList();
1113

    
1114
      // Get remote server name from param
1115
      String server = ((String[])params.get("server"))[0];
1116
      // If no servr name in param, return a error
1117
      if ( server == null || server.equals(""))
1118
      {
1119
        response.setContentType("text/xml");
1120
        out.println("<error>Request didn't specify server name</error>");
1121
        out.close();
1122
        return;
1123
      }//if
1124

    
1125
      //try to open a https stream to test if the request server's public key
1126
      //in the key store, this is security issue
1127
      URL u = new URL("https://" + server + "?server="
1128
                +util.getLocalReplicationServerName()
1129
                +"&action=test");
1130
      String test = MetacatReplication.getURLContent(u);
1131
      //couldn't pass the test
1132
      if (test.indexOf("successfully")==-1)
1133
      {
1134
        response.setContentType("text/xml");
1135
        out.println("<error>Couldn't pass the trust test</error>");
1136
        out.close();
1137
        return;
1138
      }
1139

    
1140

    
1141
      // Check if local host configure to replicate xml documents to remote
1142
      // server. If not send back a error message
1143
      if (!serverList.getReplicationValue(server))
1144
      {
1145
        response.setContentType("text/xml");
1146
        out.println
1147
        ("<error>Configuration not allow to replicate document to you</error>");
1148
        out.close();
1149
        return;
1150
      }//if
1151

    
1152
      // Store the sql command
1153
      StringBuffer docsql = new StringBuffer();
1154
      StringBuffer revisionSql = new StringBuffer();
1155
      // Stroe the docid list
1156
      StringBuffer doclist = new StringBuffer();
1157
      // Store the deleted docid list
1158
      StringBuffer delsql = new StringBuffer();
1159
      // Store the data set file
1160
      Vector packageFiles = new Vector();
1161

    
1162
      // Append local server's name and replication servlet to doclist
1163
      doclist.append("<?xml version=\"1.0\"?><replication>");
1164
      doclist.append("<server>").append(util.getLocalReplicationServerName());
1165
      //doclist.append(util.getOption("replicationpath"));
1166
      doclist.append("</server><updates>");
1167

    
1168
      // Get correct docid that reside on this server according the requesting
1169
      // server's replicate and data replicate value in xml_replication table
1170
      docsql.append("select docid, rev, doctype from xml_documents ");
1171
      revisionSql.append("select docid, rev, doctype from xml_revisions ");
1172
      // If the localhost is not a hub to the remote server, only replicate
1173
      // the docid' which home server is local host (server_location =1)
1174
      if (!serverList.getHubValue(server))
1175
      {
1176
        String serverLocation = "where server_location = 1";
1177
        docsql.append(serverLocation);
1178
        revisionSql.append(serverLocation);
1179
      }
1180
      MetaCatUtil.debugMessage("Doc sql: "+docsql.toString(), 30);
1181

    
1182
      // Get any deleted documents
1183
      delsql.append("select distinct docid from ");
1184
      delsql.append("xml_revisions where docid not in (select docid from ");
1185
      delsql.append("xml_documents) ");
1186
      // If the localhost is not a hub to the remote server, only replicate
1187
      // the docid' which home server is local host (server_location =1)
1188
      if (!serverList.getHubValue(server))
1189
      {
1190
        delsql.append("and server_location = 1");
1191
      }
1192
      MetaCatUtil.debugMessage("Deleted sql: "+delsql.toString(), 30);
1193

    
1194

    
1195

    
1196
      // Get docid list of local host
1197
      pstmt = dbConn.prepareStatement(docsql.toString());
1198
      pstmt.execute();
1199
      ResultSet rs = pstmt.getResultSet();
1200
      boolean tablehasrows = rs.next();
1201
      //If metacat configed to replicate data file
1202
      //if ((util.getOption("replicationsenddata")).equals("on"))
1203
      boolean replicateData = serverList.getDataReplicationValue(server);
1204
      if (replicateData)
1205
      {
1206
        while(tablehasrows)
1207
        {
1208
          String recordDoctype = rs.getString(3);
1209
          Vector packagedoctypes = MetaCatUtil.getOptionList(
1210
                                     MetaCatUtil.getOption("packagedoctype"));
1211
          //if this is a package file, put it at the end
1212
          //because if a package file is read before all of the files it
1213
          //refers to are loaded then there is an error
1214
          if(recordDoctype != null && !packagedoctypes.contains(recordDoctype))
1215
          {
1216
              //If this is not data file
1217
              if (!recordDoctype.equals("BIN"))
1218
              {
1219
                //for non-data file document
1220
                doclist.append("<updatedDocument>");
1221
                doclist.append("<docid>").append(rs.getString(1));
1222
                doclist.append("</docid><rev>").append(rs.getInt(2));
1223
                doclist.append("</rev>");
1224
                doclist.append("</updatedDocument>");
1225
              }//if
1226
              else
1227
              {
1228
                //for data file document, in datafile attributes
1229
                //we put "datafile" value there
1230
                doclist.append("<updatedDocument>");
1231
                doclist.append("<docid>").append(rs.getString(1));
1232
                doclist.append("</docid><rev>").append(rs.getInt(2));
1233
                doclist.append("</rev>");
1234
                doclist.append("<datafile>");
1235
                doclist.append(MetaCatUtil.getOption("datafileflag"));
1236
                doclist.append("</datafile>");
1237
                doclist.append("</updatedDocument>");
1238
              }//else
1239
          }//if packagedoctpes
1240
          else
1241
          { //the package files are saved to be put into the xml later.
1242
              Vector v = new Vector();
1243
              v.add(new String(rs.getString(1)));
1244
              v.add(new Integer(rs.getInt(2)));
1245
              packageFiles.add(new Vector(v));
1246
          }//esle
1247
          tablehasrows = rs.next();
1248
        }//while
1249
      }//if
1250
      else //metacat was configured not to send data file
1251
      {
1252
        while(tablehasrows)
1253
        {
1254
          String recordDoctype = rs.getString(3);
1255
          if(!recordDoctype.equals("BIN"))
1256
          { //don't replicate data files
1257
            Vector packagedoctypes = MetaCatUtil.getOptionList(
1258
                                     MetaCatUtil.getOption("packagedoctype"));
1259
            if(recordDoctype != null && !packagedoctypes.contains(recordDoctype))
1260
            {   //if this is a package file, put it at the end
1261
              //because if a package file is read before all of the files it
1262
              //refers to are loaded then there is an error
1263
              doclist.append("<updatedDocument>");
1264
              doclist.append("<docid>").append(rs.getString(1));
1265
              doclist.append("</docid><rev>").append(rs.getInt(2));
1266
              doclist.append("</rev>");
1267
              doclist.append("</updatedDocument>");
1268
            }
1269
            else
1270
            { //the package files are saved to be put into the xml later.
1271
              Vector v = new Vector();
1272
              v.add(new String(rs.getString(1)));
1273
              v.add(new Integer(rs.getInt(2)));
1274
              packageFiles.add(new Vector(v));
1275
            }
1276
         }//if
1277
         tablehasrows = rs.next();
1278
        }//while
1279
      }//else
1280

    
1281
      pstmt = dbConn.prepareStatement(delsql.toString());
1282
      //usage count should increas 1
1283
      dbConn.increaseUsageCount(1);
1284

    
1285
      pstmt.execute();
1286
      rs = pstmt.getResultSet();
1287
      tablehasrows = rs.next();
1288
      while(tablehasrows)
1289
      { //handle the deleted documents
1290
        doclist.append("<deletedDocument><docid>").append(rs.getString(1));
1291
        doclist.append("</docid><rev></rev></deletedDocument>");
1292
        //note that rev is always empty for deleted docs
1293
        tablehasrows = rs.next();
1294
      }
1295

    
1296
      //now we can put the package files into the xml results
1297
      for(int i=0; i<packageFiles.size(); i++)
1298
      {
1299
        Vector v = (Vector)packageFiles.elementAt(i);
1300
        doclist.append("<updatedDocument>");
1301
        doclist.append("<docid>").append((String)v.elementAt(0));
1302
        doclist.append("</docid><rev>");
1303
        doclist.append(((Integer)v.elementAt(1)).intValue());
1304
        doclist.append("</rev>");
1305
        doclist.append("</updatedDocument>");
1306
      }
1307
      // add revision doc list  
1308
      doclist.append(prepareRevisionDoc(dbConn,revisionSql.toString(),replicateData));
1309
        
1310
      doclist.append("</updates></replication>");
1311
      MetaCatUtil.debugMessage("doclist: " + doclist.toString(), 40);
1312
      pstmt.close();
1313
      //conn.close();
1314
      response.setContentType("text/xml");
1315
      out.println(doclist.toString());
1316

    
1317
    }
1318
    catch(Exception e)
1319
    {
1320
      MetaCatUtil.debugMessage("error in MetacatReplication." +
1321
                         "handleupdaterequest: " + e.getMessage(), 30);
1322
      //e.printStackTrace(System.out);
1323
      response.setContentType("text/xml");
1324
      out.println("<error>"+e.getMessage()+"</error>");
1325
    }
1326
    finally
1327
    {
1328
      try
1329
      {
1330
        pstmt.close();
1331
      }//try
1332
      catch (SQLException ee)
1333
      {
1334
        MetaCatUtil.debugMessage("Error in MetacatReplication." +
1335
                "handleUpdaterequest to close pstmt: "+ee.getMessage(), 30);
1336
      }//catch
1337
      finally
1338
      {
1339
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1340
      }//finally
1341
    }//finally
1342

    
1343
  }//handlUpdateRequest
1344
  
1345
  /*
1346
   * This method will get the xml string for document in xml_revision
1347
   * The schema look like <!ELEMENT revisionDocument (docid, rev, datafile*)>
1348
   */
1349
  private String prepareRevisionDoc(DBConnection dbConn, String revSql, 
1350
                            boolean replicateData) throws Exception
1351
  {
1352
      StringBuffer revDocList = new StringBuffer();
1353
      PreparedStatement pstmt = dbConn.prepareStatement(revSql.toString());
1354
      //usage count should increas 1
1355
      dbConn.increaseUsageCount(1);
1356

    
1357
      pstmt.execute();
1358
      ResultSet rs = pstmt.getResultSet();
1359
      boolean tablehasrows = rs.next();
1360
      while(tablehasrows)
1361
      {
1362
        String recordDoctype = rs.getString(3);
1363
        
1364
        //If this is data file and it isn't configured to replicate data
1365
        if (recordDoctype.equals("BIN") && !replicateData)
1366
        {  
1367
            // do nothing
1368
            continue;
1369
        }
1370
        else
1371
        {  
1372
            
1373
            revDocList.append("<revisionDocument>");
1374
            revDocList.append("<docid>").append(rs.getString(1));
1375
            revDocList.append("</docid><rev>").append(rs.getInt(2));
1376
            revDocList.append("</rev>");
1377
            // data file
1378
            if (recordDoctype.equals("BIN"))
1379
            {
1380
                revDocList.append("<datafile>");
1381
                revDocList.append(MetaCatUtil.getOption("datafileflag"));
1382
                revDocList.append("</datafile>");
1383
            }
1384
            revDocList.append("</revsionDocument>");
1385
        
1386
         }//else
1387
      }
1388
      return revDocList.toString();
1389
  }
1390

    
1391
  /**
1392
   * Returns the xml_catalog table encoded in xml
1393
   */
1394
  public static String getCatalogXML()
1395
  {
1396
    return handleGetCatalogRequest(null, null, null, false);
1397
  }
1398

    
1399
  /**
1400
   * Sends the contents of the xml_catalog table encoded in xml
1401
   * The xml format is:
1402
   * <!ELEMENT xml_catalog (row*)>
1403
   * <!ELEMENT row (entry_type, source_doctype, target_doctype, public_id,
1404
   *                system_id)>
1405
   * All of the sub elements of row are #PCDATA
1406

    
1407
   * If printFlag == false then do not print to out.
1408
   */
1409
  private static String handleGetCatalogRequest(PrintWriter out,
1410
                                                Hashtable params,
1411
                                                HttpServletResponse response,
1412
                                                boolean printFlag)
1413
  {
1414
    DBConnection dbConn = null;
1415
    int serialNumber = -1;
1416
    PreparedStatement pstmt = null;
1417
    try
1418
    {
1419
      /*conn = MetacatReplication.getDBConnection("MetacatReplication." +
1420
                                                "handleGetCatalogRequest");*/
1421
      dbConn=DBConnectionPool.
1422
                 getDBConnection("MetacatReplication.handleGetCatalogRequest");
1423
      serialNumber=dbConn.getCheckOutSerialNumber();
1424
      pstmt = dbConn.prepareStatement("select entry_type, " +
1425
                              "source_doctype, target_doctype, public_id, " +
1426
                              "system_id from xml_catalog");
1427
      pstmt.execute();
1428
      ResultSet rs = pstmt.getResultSet();
1429
      boolean tablehasrows = rs.next();
1430
      StringBuffer sb = new StringBuffer();
1431
      sb.append("<?xml version=\"1.0\"?><xml_catalog>");
1432
      while(tablehasrows)
1433
      {
1434
        sb.append("<row><entry_type>").append(rs.getString(1));
1435
        sb.append("</entry_type><source_doctype>").append(rs.getString(2));
1436
        sb.append("</source_doctype><target_doctype>").append(rs.getString(3));
1437
        sb.append("</target_doctype><public_id>").append(rs.getString(4));
1438
        sb.append("</public_id><system_id>").append(rs.getString(5));
1439
        sb.append("</system_id></row>");
1440

    
1441
        tablehasrows = rs.next();
1442
      }
1443
      sb.append("</xml_catalog>");
1444
      //conn.close();
1445
      if(printFlag)
1446
      {
1447
        response.setContentType("text/xml");
1448
        out.println(sb.toString());
1449
      }
1450
      pstmt.close();
1451
      return sb.toString();
1452
    }
1453
    catch(Exception e)
1454
    {
1455

    
1456
      System.out.println("error in MetacatReplication.handleGetCatalogRequest:"+
1457
                          e.getMessage());
1458
      e.printStackTrace(System.out);
1459
      if(printFlag)
1460
      {
1461
        out.println("<error>"+e.getMessage()+"</error>");
1462
      }
1463
    }
1464
    finally
1465
    {
1466
      try
1467
      {
1468
        pstmt.close();
1469
      }//try
1470
      catch (SQLException ee)
1471
      {
1472
        MetaCatUtil.
1473
           debugMessage("Error in MetacatReplication.handleGetCatalogRequest: "
1474
           +ee.getMessage(), 30);
1475
      }//catch
1476
      finally
1477
      {
1478
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1479
      }//finally
1480
    }//finally
1481

    
1482
    return null;
1483
  }
1484

    
1485
  /**
1486
   * Sends the current system date to the remote server.  Using this action
1487
   * for replication gets rid of any problems with syncronizing clocks
1488
   * because a time specific to a document is always kept on its home server.
1489
   */
1490
  private void handleGetTimeRequest(PrintWriter out, Hashtable params,
1491
                                    HttpServletResponse response)
1492
  {
1493
    SimpleDateFormat formatter = new SimpleDateFormat ("MM/dd/yy HH:mm:ss");
1494
    java.util.Date localtime = new java.util.Date();
1495
    String dateString = formatter.format(localtime);
1496
    response.setContentType("text/xml");
1497

    
1498
    out.println("<timestamp>" + dateString + "</timestamp>");
1499
  }
1500

    
1501
  /**
1502
   * this method handles the timeout for a file lock.  when a lock is
1503
   * granted it is granted for 30 seconds.  When this thread runs out
1504
   * it deletes the docid from the queue, thus eliminating the lock.
1505
   */
1506
  public void run()
1507
  {
1508
    try
1509
    {
1510
      MetaCatUtil.debugMessage("thread started for docid: " +
1511
                               (String)fileLocks.elementAt(0), 45);
1512

    
1513
      Thread.sleep(30000); //the lock will expire in 30 seconds
1514
      MetaCatUtil.debugMessage("thread for docid: " +
1515
                             (String)fileLocks.elementAt(fileLocks.size() - 1) +
1516
                              " exiting.", 45);
1517

    
1518
      fileLocks.remove(fileLocks.size() - 1);
1519
      //fileLocks is treated as a FIFO queue.  If there are more than one lock
1520
      //in the vector, the first one inserted will be removed.
1521
    }
1522
    catch(Exception e)
1523
    {
1524
      MetaCatUtil.debugMessage("error in file lock thread from " +
1525
                                "MetacatReplication.run: " + e.getMessage(), 30);
1526
    }
1527
  }
1528

    
1529
  /**
1530
   * Returns the name of a server given a serverCode
1531
   * @param serverCode the serverid of the server
1532
   * @return the servername or null if the specified serverCode does not
1533
   *         exist.
1534
   */
1535
  public static String getServerNameForServerCode(int serverCode)
1536
  {
1537
    //System.out.println("serverid: " + serverCode);
1538
    DBConnection dbConn = null;
1539
    int serialNumber = -1;
1540
    PreparedStatement pstmt = null;
1541
    try
1542
    {
1543
      dbConn=DBConnectionPool.
1544
                  getDBConnection("MetacatReplication.getServer");
1545
      serialNumber=dbConn.getCheckOutSerialNumber();
1546
      String sql = new String("select server from " +
1547
                              "xml_replication where serverid = " +
1548
                              serverCode);
1549
      pstmt = dbConn.prepareStatement(sql);
1550
      //System.out.println("getserver sql: " + sql);
1551
      pstmt.execute();
1552
      ResultSet rs = pstmt.getResultSet();
1553
      boolean tablehasrows = rs.next();
1554
      if(tablehasrows)
1555
      {
1556
        //System.out.println("server: " + rs.getString(1));
1557
        return rs.getString(1);
1558
      }
1559

    
1560
      //conn.close();
1561
    }
1562
    catch(Exception e)
1563
    {
1564
      System.out.println("Error in MetacatReplication.getServer: " +
1565
                          e.getMessage());
1566
    }
1567
    finally
1568
    {
1569
      try
1570
      {
1571
        pstmt.close();
1572
      }//try
1573
      catch (SQLException ee)
1574
      {
1575
        MetaCatUtil.debugMessage("Error in MetacactReplication.getserver: "+
1576
                                    ee.getMessage(), 30);
1577
      }//catch
1578
      finally
1579
      {
1580
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1581
      }//fianlly
1582
    }//finally
1583

    
1584

    
1585

    
1586
    return null;
1587
      //return null if the server does not exist
1588
  }
1589

    
1590
  /**
1591
   * Returns a server code given a server name
1592
   * @param server the name of the server
1593
   * @return integer > 0 representing the code of the server, 0 if the server
1594
   *  does not exist.
1595
   */
1596
  public static int getServerCodeForServerName(String server) throws Exception
1597
  {
1598
    DBConnection dbConn = null;
1599
    int serialNumber = -1;
1600
    PreparedStatement pstmt = null;
1601
    int serverCode = 0;
1602

    
1603
    try {
1604

    
1605
      //conn = util.openDBConnection();
1606
      dbConn=DBConnectionPool.
1607
                  getDBConnection("MetacatReplication.getServerCode");
1608
      serialNumber=dbConn.getCheckOutSerialNumber();
1609
      pstmt = dbConn.prepareStatement("SELECT serverid FROM xml_replication " +
1610
                                    "WHERE server LIKE '" + server + "'");
1611
      pstmt.execute();
1612
      ResultSet rs = pstmt.getResultSet();
1613
      boolean tablehasrows = rs.next();
1614
      if ( tablehasrows ) {
1615
        serverCode = rs.getInt(1);
1616
        pstmt.close();
1617
        //conn.close();
1618
        return serverCode;
1619
      }
1620

    
1621
    } catch(Exception e) {
1622
      throw e;
1623

    
1624
    } finally {
1625
      try
1626
      {
1627
        pstmt.close();
1628
        //conn.close();
1629
       }//try
1630
       catch(Exception ee)
1631
       {
1632
         MetaCatUtil.debugMessage("Error in MetacatReplicatio.getServerCode: "
1633
                                  +ee.getMessage(), 30);
1634

    
1635
       }//catch
1636
       finally
1637
       {
1638
         DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1639
       }//finally
1640
    }//finally
1641

    
1642
    return serverCode;
1643
  }
1644

    
1645
  /**
1646
   * Method to get a host server information for given docid
1647
   * @param conn a connection to the database
1648
   */
1649
  public static Hashtable getHomeServerInfoForDocId(String docId)
1650
  {
1651
    Hashtable sl = new Hashtable();
1652
    DBConnection dbConn = null;
1653
    int serialNumber = -1;
1654
    //MetaCatUtil ut=new MetaCatUtil();
1655
    docId=MetaCatUtil.getDocIdFromString(docId);
1656
    PreparedStatement pstmt=null;
1657
    int serverLocation;
1658
    try
1659
    {
1660
      //get conection
1661
      dbConn=DBConnectionPool.
1662
                  getDBConnection("ReplicationHandler.getHomeServer");
1663
      serialNumber=dbConn.getCheckOutSerialNumber();
1664
      //get a server location from xml_document table
1665
      pstmt=dbConn.prepareStatement("select server_location from xml_documents "
1666
                                            +"where docid = ?");
1667
      pstmt.setString(1, docId);
1668
      pstmt.execute();
1669
      ResultSet serverName = pstmt.getResultSet();
1670
      //get a server location
1671
      if(serverName.next())
1672
      {
1673
        serverLocation=serverName.getInt(1);
1674
        pstmt.close();
1675
      }
1676
      else
1677
      {
1678
        pstmt.close();
1679
        //ut.returnConnection(conn);
1680
        return null;
1681
      }
1682
      pstmt=dbConn.prepareStatement("select server, last_checked, replicate " +
1683
                        "from xml_replication where serverid = ?");
1684
      //increase usage count
1685
      dbConn.increaseUsageCount(1);
1686
      pstmt.setInt(1, serverLocation);
1687
      pstmt.execute();
1688
      ResultSet rs = pstmt.getResultSet();
1689
      boolean tableHasRows = rs.next();
1690
      if (tableHasRows)
1691
      {
1692

    
1693
          String server = rs.getString(1);
1694
          String last_checked = rs.getString(2);
1695
          if(!server.equals("localhost"))
1696
          {
1697
            sl.put(server, last_checked);
1698
          }
1699

    
1700
      }
1701
      else
1702
      {
1703
        pstmt.close();
1704
        //ut.returnConnection(conn);
1705
        return null;
1706
      }
1707
      pstmt.close();
1708
    }
1709
    catch(Exception e)
1710
    {
1711
      System.out.println("error in replicationHandler.getHomeServer(): " +
1712
                         e.getMessage());
1713
    }
1714
    finally
1715
    {
1716
      try
1717
      {
1718
        pstmt.close();
1719
        //ut.returnConnection(conn);
1720
      }
1721
      catch (Exception ee)
1722
      {
1723
        MetaCatUtil.debugMessage("Eror irn rplicationHandler.getHomeServer() "+
1724
                          "to close pstmt: "+ee.getMessage(), 30);
1725
      }
1726
      finally
1727
      {
1728
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1729
      }
1730

    
1731
    }//finally
1732
    return sl;
1733
  }
1734

    
1735
  /**
1736
   * Returns a home server location  given a accnum
1737
   * @param accNum , given accNum for a document
1738
   *
1739
   */
1740
  public static int getHomeServerCodeForDocId(String accNum) throws Exception
1741
  {
1742
    DBConnection dbConn = null;
1743
    int serialNumber = -1;
1744
    PreparedStatement pstmt = null;
1745
    int serverCode = 1;
1746
    //MetaCatUtil ut = new MetaCatUtil();
1747
    String docId=MetaCatUtil.getDocIdFromString(accNum);
1748

    
1749
    try
1750
    {
1751

    
1752
      // Get DBConnection
1753
      dbConn=DBConnectionPool.
1754
                  getDBConnection("ReplicationHandler.getServerLocation");
1755
      serialNumber=dbConn.getCheckOutSerialNumber();
1756
      pstmt=dbConn.prepareStatement("SELECT server_location FROM xml_documents "
1757
                              + "WHERE docid LIKE '" + docId + "'");
1758
      pstmt.execute();
1759
      ResultSet rs = pstmt.getResultSet();
1760
      boolean tablehasrows = rs.next();
1761
      //If a document is find, return the server location for it
1762
      if ( tablehasrows )
1763
      {
1764
        serverCode = rs.getInt(1);
1765
        pstmt.close();
1766
        //conn.close();
1767
        return serverCode;
1768
      }
1769
      //if couldn't find in xml_documents table, we think server code is 1
1770
      //(this is new document)
1771
      else
1772
      {
1773
        pstmt.close();
1774
        //conn.close();
1775
        return serverCode;
1776
      }
1777

    
1778
    }
1779
    catch(Exception e)
1780
    {
1781

    
1782
      throw e;
1783

    
1784
    }
1785
    finally
1786
    {
1787
      try
1788
      {
1789
        pstmt.close();
1790
        //conn.close();
1791

    
1792
      }
1793
      catch(Exception ee)
1794
      {
1795
        MetaCatUtil.debugMessage("Erorr in Replication.getServerLocation "+
1796
                     "to close pstmt"+ee.getMessage(), 30);
1797
      }
1798
      finally
1799
      {
1800
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1801
      }//finally
1802
    }//finally
1803
   //return serverCode;
1804
  }
1805

    
1806

    
1807

    
1808
  /**
1809
   * This method returns the content of a url
1810
   * @param u the url to return the content from
1811
   * @return a string representing the content of the url
1812
   * @throws java.io.IOException
1813
   */
1814
  public static String getURLContent(URL u) throws java.io.IOException
1815
  {
1816
    char istreamChar;
1817
    int istreamInt;
1818
    MetaCatUtil.debugMessage("Before open the stream"+u.toString(), 50);
1819
    InputStream input = u.openStream();
1820
    MetaCatUtil.debugMessage("Afetr open the stream"+u.toString(), 50);
1821
    InputStreamReader istream = new InputStreamReader(input);
1822
    StringBuffer serverResponse = new StringBuffer();
1823
    while((istreamInt = istream.read()) != -1)
1824
    {
1825
      istreamChar = (char)istreamInt;
1826
      serverResponse.append(istreamChar);
1827
    }
1828
    istream.close();
1829
    input.close();
1830

    
1831
    return serverResponse.toString();
1832
  }
1833

    
1834
  /**
1835
   * Method for writing replication messages to a log file specified in
1836
   * metacat.properties
1837
   */
1838
  public static void replLog(String message)
1839
  {
1840
    try
1841
    {
1842
      FileOutputStream fos = new FileOutputStream(
1843
                                 util.getOption("replicationlog"), true);
1844
      PrintWriter pw = new PrintWriter(fos);
1845
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
1846
      java.util.Date localtime = new java.util.Date();
1847
      String dateString = formatter.format(localtime);
1848
      dateString += " :: " + message;
1849
      //time stamp each entry
1850
      pw.println(dateString);
1851
      pw.flush();
1852
    }
1853
    catch(Exception e)
1854
    {
1855
      System.out.println("error writing to replication log from " +
1856
                         "MetacatReplication.replLog: " + e.getMessage());
1857
      //e.printStackTrace(System.out);
1858
    }
1859
  }
1860

    
1861
  /**
1862
   * Method for writing replication messages to a log file specified in
1863
   * metacat.properties
1864
   */
1865
  public static void replErrorLog(String message)
1866
  {
1867
    try
1868
    {
1869
      FileOutputStream fos = new FileOutputStream(
1870
                                 util.getOption("replicationerrorlog"), true);
1871
      PrintWriter pw = new PrintWriter(fos);
1872
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
1873
      java.util.Date localtime = new java.util.Date();
1874
      String dateString = formatter.format(localtime);
1875
      dateString += " :: " + message;
1876
      //time stamp each entry
1877
      pw.println(dateString);
1878
      pw.flush();
1879
    }
1880
    catch(Exception e)
1881
    {
1882
      System.out.println("error writing to replication log from " +
1883
                         "MetacatReplication.replLog: " + e.getMessage());
1884
      //e.printStackTrace(System.out);
1885
    }
1886
  }
1887

    
1888
  /**
1889
   * Returns true if the replicate field for server in xml_replication is 1.
1890
   * Returns false otherwise
1891
   */
1892
  public static boolean replToServer(String server)
1893
  {
1894
    DBConnection dbConn = null;
1895
    int serialNumber = -1;
1896
    PreparedStatement pstmt = null;
1897
    try
1898
    {
1899
      dbConn=DBConnectionPool.
1900
                  getDBConnection("MetacatReplication.repltoServer");
1901
      serialNumber=dbConn.getCheckOutSerialNumber();
1902
      pstmt = dbConn.prepareStatement("select replicate from " +
1903
                                    "xml_replication where server like '" +
1904
                                     server + "'");
1905
      pstmt.execute();
1906
      ResultSet rs = pstmt.getResultSet();
1907
      boolean tablehasrows = rs.next();
1908
      if(tablehasrows)
1909
      {
1910
        int i = rs.getInt(1);
1911
        if(i == 1)
1912
        {
1913
          pstmt.close();
1914
          //conn.close();
1915
          return true;
1916
        }
1917
        else
1918
        {
1919
          pstmt.close();
1920
          //conn.close();
1921
          return false;
1922
        }
1923
      }
1924
    }
1925
    catch(Exception e)
1926
    {
1927
      System.out.println("error in MetacatReplication.replToServer: " +
1928
                         e.getMessage());
1929
    }
1930
    finally
1931
    {
1932
      try
1933
      {
1934
        pstmt.close();
1935
        //conn.close();
1936
      }//try
1937
      catch(Exception ee)
1938
      {
1939
        MetaCatUtil.debugMessage("Error in MetacatReplication.replToServer: "
1940
                                  +ee.getMessage(), 30);
1941
      }//catch
1942
      finally
1943
      {
1944
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1945
      }//finally
1946
    }//finally
1947
    return false;
1948
    //the default if this server does not exist is to not replicate to it.
1949
  }
1950

    
1951

    
1952
}
(45-45/64)