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: jones $'
9
 *     '$Date: 2006-11-10 10:25:38 -0800 (Fri, 10 Nov 2006) $'
10
 * '$Revision: 3077 $'
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.utilities.HttpMessage;
30
import javax.servlet.ServletOutputStream;
31

    
32
import org.apache.log4j.Logger;
33

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

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

    
96
  }// Constructor
97

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

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

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

    
519
}//Class RemoteDocument
(58-58/66)