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

    
27
package edu.ucsb.nceas.metacat;
28

    
29
import edu.ucsb.nceas.metacat.properties.PropertyService;
30
import edu.ucsb.nceas.metacat.util.MetacatUtil;
31
import edu.ucsb.nceas.utilities.HttpMessage;
32
import javax.servlet.ServletOutputStream;
33

    
34
import org.apache.log4j.Logger;
35

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

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

    
98
  }// Constructor
99

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

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

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

    
521
}//Class RemoteDocument
(58-58/64)