Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that represents an document in remote metacat server
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Jing Tao
7
 *    Release: @release@
8
 *
9
 *   '$Author: sgarg $'
10
 *     '$Date: 2005-10-10 11:06:55 -0700 (Mon, 10 Oct 2005) $'
11
 * '$Revision: 2663 $'
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.utilities.HttpMessage;
31
import javax.servlet.ServletOutputStream;
32

    
33
import org.apache.log4j.Logger;
34

    
35
import java.io.*;
36
import java.net.*;
37
import java.util.*;
38
import java.util.zip.*;
39

    
40
/**
41
 * A class represents a document in remote metacat server. During the 
42
 * replication between two metacats, metadata (xml documents) might be 
43
 * replicated from Metacat A to Metacat B. But data file didn't. 
44
 * Sometime, user in Metacat B might query the data file which doesn't riside in
45
 * Metacat B. We need to download it from remote metacat server A and output it
46
 * to user. But it still doesn't reside in Metacat B.
47
 */
48
public class RemoteDocument
49
{
50
  private String docIdWithoutRevision = null; //Docid for this document
51
  private String revision = null; // Reviseion number for this document
52
  private String dataSetId = null; // Data set document Id which contains
53
                                   // this document
54
  private String documentHomeServerURL = null; // Home metacat server url
55
                                               // for this document
56
  private String docType = null; //String to store docType
57
  private String userName = null; // User name to require this document
58
  private String passWord = null; // The user's passwd
59
  private String zipEntry = null; // For zip entry
60
  private String revisionAndDocType; // String to store this info
61
  private Logger logMetacat = Logger.getLogger(RemoteDocument.class);
62
  
63
  /**
64
   * Constructor of RemoteDcoument
65
   * @param myDocIdWithoutRevision, Docid for this document
66
   * @param myRevision, revision number for this document
67
   * @param myUserName, the user who require this document
68
   * @param myGroup, the gourps the user belong to
69
   * @param myPassWord, the password of the user
70
   * @param myOutPut, the output stream the document will be put
71
   * @param myZipEntryPath, the base line for zip entry
72
   */
73
  public RemoteDocument ( String myDocIdWithoutRevision, String myRevision,
74
                    String myUserName, String myPassWord, String myZipEntryPath)
75
                          throws Exception
76
  {
77
    docIdWithoutRevision = myDocIdWithoutRevision;
78
    // Get data set id for the given docid
79
    dataSetId = DBUtil.findDataSetDocIdForGivenDocument(docIdWithoutRevision);
80
    documentHomeServerURL = getMetacatURLForGivenDocId(dataSetId);
81
    // Get revisionAndDocType
82
    getRevisionAndDocTypeString();
83
    revision = myRevision;
84
    // If rev is null or empty (user didn't specify it,
85
    // then set it current one in remote metacat
86
    if (revision == null ||revision.equals(""))
87
    {
88
      revision = setRevision();
89
    }
90
    docType = setDocType();
91
    userName = myUserName;
92
    passWord = myPassWord;
93
    zipEntry = myZipEntryPath+ docIdWithoutRevision + 
94
                MetaCatUtil.getOption("accNumSeparator") + revision;
95
   
96

    
97
  }// Constructor
98

    
99
  /**
100
   * Method to get docidWithout revision
101
   */
102
  public String getDocIdWithoutRevsion()
103
  {
104
    return docIdWithoutRevision;
105
  }//getDocIdWithoutRevsion
106
  
107
  /**
108
   * Method to get revsion
109
   */
110
  public String getRevision()
111
  {
112
    return revision;
113
  }//getRevision
114
  
115
  /**
116
   * Method to get docType
117
   */
118
  public String getDocType()
119
  {
120
    return docType;
121
  }//getDocType
122
  
123
  /**
124
   * Set revision if client didn't specify the revision number.
125
   * It come from revsionAndDocType String. This String look like "rev;doctype"
126
   * Rule: 
127
   *      1) Get current revision number from remote metacat
128
   *      2) If couldn't get, set revision number 1
129
   */
130
  private String setRevision()
131
  {
132
    // String to store the result
133
    String revision = null;
134
    // Int to store the index of ";" in revision
135
    int index = -1;
136
    // If String revisionAndDocType is null, revision set to 1
137
    if (revisionAndDocType == null || revisionAndDocType.equals(""))
138
    {
139
      revision = "1";
140
    }//if
141
    else
142
    {
143
      // Get the index of ";" in String revisionAndDocType
144
      index = revisionAndDocType.indexOf(";");
145
      // Get the subString about rev in String revisionAndDocType
146
      revision = revisionAndDocType.substring(0, index);
147
      // If revision is null or empty set revision 1
148
      if (revision == null || revision.equals(""))
149
      {
150
        revision = "1";
151
      }//if
152
    }//else
153
    return revision;
154
  }//setRevision
155
  
156
  /**
157
   * Set docType for this document base on the information from retmote metacat
158
   * It come from revsionAndDocType String. This String look like "rev;doctype"
159
   * If we couldn't get it from remote metacat, null will be set
160
   */
161
  private String setDocType()
162
  {
163
    // String to store the result
164
    String remoteDocType = null;
165
    // Int to store the index of ";" in revision
166
    int index = -1;
167
    
168
    // If String revisionAndDocType is null, revision set to 1
169
    if (revisionAndDocType == null || revisionAndDocType.equals(""))
170
    {
171
      remoteDocType = null;
172
    }//if
173
    else
174
    {
175
      // Get the index of ";" in String revisionAndDocType
176
      index = revisionAndDocType.indexOf(";");
177
      // Get the subString about doctype in String revisionAndDocType
178
      remoteDocType = revisionAndDocType.substring(index+1);
179
      
180
    }//else
181
    return remoteDocType;
182
  }//setDocType
183
  
184
  /**
185
   * Method to get a metacat url for dataset document id.
186
   * First, get replication document home server for dataset document.
187
   * Second, transfer a doc home server from replication servlet to metacat 
188
   * servlet. The reseaon is when we use read action to get the document, the
189
   * url is metacat servlet. Note: the protocol should be https. Because
190
   * replication is using https. If we use http and maybe access wrong port 
191
   * number.
192
   * @param dataSetId, the document id for which we need to find metacat url
193
   */
194
  private String getMetacatURLForGivenDocId( String givenDocId) throws Exception
195
  {
196
    // DocumentImpl object of this given docid
197
    DocumentImpl document = null;
198
    // Replication home server
199
    String replicationDocHomeServer = null;
200
    // String metacat url
201
    String metacatURL = null;
202
    
203
    // Check the given Docid is not null or empty
204
    if (givenDocId == null || givenDocId.equals(""))
205
    {
206
      throw new Exception ("Couldn't find a dataset docid for the required id");
207
    }
208
    // Create a documentImpl object
209
    String accNumber = givenDocId + MetaCatUtil.getOption("accNumSeparator") +
210
    DBUtil.getLatestRevisionInDocumentTable(givenDocId);
211
    document = new DocumentImpl(accNumber, false);
212
    // get the replication home server (it come from xml_replication table)
213
    replicationDocHomeServer = document.getDocHomeServer();
214
    
215
    // If replication doc home server is local host. throws a exception
216
    if (replicationDocHomeServer.
217
                           equals(MetaCatUtil.getLocalReplicationServerName()))
218
    {
219
      throw new Exception ("Couldn't find the docid: "
220
                                          +docIdWithoutRevision+"."+revision);
221
    }//if
222
    
223
    // replicationDocHomeServer looks like 
224
    // "pine.nceas.ucsb.edu:8443/tao/servlet/replication" and we should transfer
225
    // it to"https://pine.nceas.ucsb.edu:8443/tao/servlet/metacat"
226
    // get index of "replication" ocurrence
227
    int index = replicationDocHomeServer.indexOf("replication");
228
    // Get the subString from 0 to the index
229
    String subString = replicationDocHomeServer.substring(0, index);
230
    // Add https at head and append metacat 
231
    metacatURL = "https://" + subString +"metacat";
232
    logMetacat.info("metacatURL: "+metacatURL);
233
    
234
    return metacatURL;
235
    
236
  }//getMetacatURLForGivenDocId
237
  
238
  /**
239
   * Method to get revisionAndDocType String from remote metacat
240
   */
241
  private void getRevisionAndDocTypeString()
242
  {
243
    // Set property for login action
244
    Properties prop = new Properties();
245
    // Set action = getrevisionanddoctype
246
    prop.put("action", "getrevisionanddoctype");
247
    prop.put("docid", docIdWithoutRevision);
248
    // Now contact metacat and login.
249
    String response = getMetacatString(prop);
250
   
251
    // response contains error information
252
    if (response.indexOf("<error>")!=-1)
253
    {
254
      // Set response null
255
      response = null;
256
    }
257
    
258
    // Set revisionAndDocType equals reponse which get rid of white space
259
    if ( response != null)
260
    {
261
      revisionAndDocType = response.trim();
262
    }//if
263
    else
264
    {
265
      revisionAndDocType = response;
266
    }//else
267
   
268
    
269
  }//getRevisionAndDocTypeString
270
   
271
  
272
  /**
273
   * Method to read both xml and data file from remote server
274
   * and put the output into the given output stream
275
   * @param outPut, the serverlstoutputStream which the remote document or
276
   *                data file need to put.
277
   */
278
  public void readDocumentFromRemoteServer(ServletOutputStream outPut)
279
                                              throws Exception
280
  {
281
    // Set properties
282
    Properties prop = new Properties();
283
    // qformat set to be xml. Data file will be handle in MetaCatServlet class
284
    String qformat = "xml";
285
    // Action set to read
286
    String action = "read";
287
    // Input stream from remote metacat
288
    InputStream remoteResponse = null;
289
    
290
    // Check docIdWithoutRevision is not null or empty
291
    if (docIdWithoutRevision ==null || docIdWithoutRevision.equals(""))
292
    {
293
      throw new Exception("User didn't specify the required docid");
294
    }
295
    // User specified docid (including revision number
296
    String specifiedDocId = docIdWithoutRevision + 
297
                MetaCatUtil.getOption("accNumSeparator") +revision;
298
    logMetacat.info("The requried docid is: "+ specifiedDocId);
299
    
300
    // At first login to remote metacat server. 
301
    logIn(userName, passWord);
302
   
303
    // Set action  
304
    prop.put("action", action);
305
    // Set qformat xml
306
    prop.put("qformat", qformat);
307
    // Set the docid
308
    prop.put("docid", specifiedDocId);
309
    
310
    // Get remote metacat response
311
    try
312
    {
313
      remoteResponse = getMetacatInputStream(prop);
314
    }//try
315
    catch (Exception e)
316
    {
317
      // If has a exception throws it again
318
      throw e;
319
    }//catch
320
    
321
    // Read content from the remote input and write the content into
322
    // the given output
323
     byte[] buf = new byte[4 * 1024]; // 4K buffer
324
     // Read remote input into buffer
325
     int index = remoteResponse.read(buf);
326
     // If index is -1, this meams remote input ended
327
     while (index != -1) 
328
     {
329
        // Write the content of butter to given output
330
        outPut.write(buf, 0, index);
331
        // Read next bytes to the buffer from remote input stream
332
        index = remoteResponse.read(buf);
333
     }//while
334
     // Close remote reponse
335
     if (remoteResponse != null)
336
     {
337
       remoteResponse.close();
338
     }//if
339
    
340
  }//readDocumentFormRemoteServer
341
  
342
  
343
    /**
344
   * Method to read both xml and data file from remote server by zip output
345
   * and put the output into the given output stream
346
   * @param outPut, the serverlstoutputStream which the remote document or
347
   *                data file need to put.
348
   */
349
  public void readDocumentFromRemoteServerByZip(ZipOutputStream outPut)
350
                                              throws Exception
351
  {
352
    // Set properties
353
    Properties prop = new Properties();
354
    // qformat set to be xml. Data file will be handle in MetaCatServlet class
355
    String qformat = "xml";
356
    // Action set to read
357
    String action = "read";
358
    // Input stream from remote metacat
359
    InputStream remoteResponse = null;
360
    
361
    // Check docIdWithoutRevision is not null or empty
362
    if (docIdWithoutRevision ==null || docIdWithoutRevision.equals(""))
363
    {
364
      throw new Exception("User didn't specify the required docid");
365
    }
366
    // User specified docid (including revision number
367
    String specifiedDocId = docIdWithoutRevision + 
368
                MetaCatUtil.getOption("accNumSeparator") +revision;
369
    logMetacat.info("The requried docid is: "+ specifiedDocId);
370
    
371
    // At first login to remote metacat server.
372
    logIn(userName, passWord);
373
       
374
    // Set action  
375
    prop.put("action", action);
376
    // Set qformat xml
377
    prop.put("qformat", qformat);
378
    // Set the docid
379
    prop.put("docid", specifiedDocId);
380
    
381
    // Get remote metacat response
382
    try
383
    {
384
      remoteResponse = getMetacatInputStream(prop);
385
    }//try
386
    catch (Exception e)
387
    {
388
      // If has a exception throws it again
389
      throw e;
390
    }//catch
391
    
392
    // Create a zip entry
393
    ZipEntry zentry = new ZipEntry(zipEntry);
394
    outPut.putNextEntry(zentry);
395
    // Read content from the remote input and write the content into
396
    // the given output
397
     byte[] buf = new byte[4 * 1024]; // 4K buffer
398
     // Read remote input into buffer
399
     int index = remoteResponse.read(buf);
400
     // If index is -1, this meams remote input ended
401
     while (index != -1) 
402
     {
403
        // Write the content of butter to given output
404
        outPut.write(buf, 0, index);
405
        // Read next bytes to the buffer from remote input stream
406
        index = remoteResponse.read(buf);
407
     }//while
408
     // Close remote reponse
409
     if (remoteResponse != null)
410
     {
411
       remoteResponse.close();
412
     }//if
413
     // Close zip entry
414
     outPut.closeEntry();
415
    
416
  }//readDocumentFormRemoteServerByZip
417
  
418
  
419
  /**
420
   * Method to do login action. set cookie for it
421
   * @param usrerName, the DN name of the test method
422
   * @param passWord, the passwd of the user
423
   */
424
  private void logIn(String userName, String passWord)
425
  {
426
     // Make sure userName and password are not null 
427
    if ( userName == null || passWord == null || 
428
                                  userName.equals("") || passWord.equals(""))
429
    {
430
      return;
431
    }
432
    // Set property for login action
433
    Properties prop = new Properties();
434
    prop.put("action", "login");
435
    prop.put("qformat", "xml");
436
    prop.put("username", userName);
437
    prop.put("password", passWord);
438

    
439
    // Now contact metacat and login.
440
    String response = getMetacatString(prop);
441
    logMetacat.info("Login Message: "+response);
442
  }//login
443
  
444
  /**
445
   * Method to do logout action
446
   */
447
  private void logOut()
448
  {
449
    // Set property
450
    Properties prop = new Properties();
451
    prop.put("action", "logout");
452
    prop.put("qformat", "xml");
453
    // Send it to remote metacat
454
    String response = getMetacatString(prop);
455
    logMetacat.debug("Logout Message: "+response);
456
    // Set cookie to null
457
    HttpMessage.setCookie(null);
458
     
459
  }//logout
460
  
461
  /**
462
   * Send a request to Metacat and the return is a string from remote
463
   * Metacat.
464
   * @param prop the properties to be sent to Metacat
465
   */
466
  private String getMetacatString(Properties prop)
467
  {
468
    // Variable to store the response
469
    String response = null;
470

    
471
    // Now contact metacat and send the request
472
    try
473
    {
474
      InputStreamReader returnStream = 
475
                        new InputStreamReader(getMetacatInputStream(prop));
476
      StringWriter sw = new StringWriter();
477
      int len;
478
      char[] characters = new char[512];
479
      // Write inputstream into String
480
      while ((len = returnStream.read(characters, 0, 512)) != -1)
481
      {
482
        sw.write(characters, 0, len);
483
      }
484
      // Close the input stream reader
485
      returnStream.close();
486
      // Transfer string writer to String
487
      response = sw.toString();
488
      // close string wirter
489
      sw.close();
490
    }
491
    catch(Exception e)
492
    {
493
      logMetacat.error("Error in RemoteDocument.getMetacatString: "+
494
                               e.getMessage());
495
      // If there is some exception return null
496
      return null;
497
    }
498
  
499
    return response;
500
  }// getMetaCatString
501
  
502
  /**
503
   * Send a request to Metacat and the return is a input stream from remote
504
   * Metacat.
505
   * @param prop the properties to be sent to Metacat
506
   */
507
  private InputStream getMetacatInputStream(Properties prop) throws Exception
508
  {
509
    // Variable to store the returned input stream
510
    InputStream returnStream = null;
511
    // Create a URL for remtate
512
    URL url = new URL(documentHomeServerURL);
513
    HttpMessage msg = new HttpMessage(url);
514
    // Now contact metacat and send the request
515
    returnStream = msg.sendPostMessage(prop);
516
    return returnStream;
517
 
518
  }//getMetacatInputStream
519

    
520
}//Class RemoteDocument
(57-57/65)