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: jones $'
10
 *     '$Date: 2003-09-17 12:42:42 -0700 (Wed, 17 Sep 2003) $'
11
 * '$Revision: 1822 $'
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
import java.io.*;
33
import java.net.*;
34
import java.util.*;
35
import java.util.zip.*;
36

    
37
/**
38
 * A class represents a document in remote metacat server. During the 
39
 * replication between two metacats, metadata (xml documents) might be 
40
 * replicated from Metacat A to Metacat B. But data file didn't. 
41
 * Sometime, user in Metacat B might query the data file which doesn't riside in
42
 * Metacat B. We need to download it from remote metacat server A and output it
43
 * to user. But it still doesn't reside in Metacat B.
44
 */
45
public class RemoteDocument
46
{
47
  private String docIdWithoutRevision = null; //Docid for this document
48
  private String revision = null; // Reviseion number for this document
49
  private String dataSetId = null; // Data set document Id which contains
50
                                   // this document
51
  private String documentHomeServerURL = null; // Home metacat server url
52
                                               // for this document
53
  private String docType = null; //String to store docType
54
  private String userName = null; // User name to require this document
55
  private String passWord = null; // The user's passwd
56
  private String zipEntry = null; // For zip entry
57
  private String revisionAndDocType; // String to store this info
58

    
59
  
60
  /**
61
   * Constructor of RemoteDcoument
62
   * @param myDocIdWithoutRevision, Docid for this document
63
   * @param myRevision, revision number for this document
64
   * @param myUserName, the user who require this document
65
   * @param myGroup, the gourps the user belong to
66
   * @param myPassWord, the password of the user
67
   * @param myOutPut, the output stream the document will be put
68
   * @param myZipEntryPath, the base line for zip entry
69
   */
70
  public RemoteDocument ( String myDocIdWithoutRevision, String myRevision,
71
                    String myUserName, String myPassWord, String myZipEntryPath)
72
                          throws Exception
73
  {
74
    docIdWithoutRevision = myDocIdWithoutRevision;
75
    // Get data set id for the given docid
76
    dataSetId = DBUtil.findDataSetDocIdForGivenDocument(docIdWithoutRevision);
77
    documentHomeServerURL = getMetacatURLForGivenDocId(dataSetId);
78
    // Get revisionAndDocType
79
    getRevisionAndDocTypeString();
80
    revision = myRevision;
81
    // If rev is null or empty (user didn't specify it,
82
    // then set it current one in remote metacat
83
    if (revision == null ||revision.equals(""))
84
    {
85
      revision = setRevision();
86
    }
87
    docType = setDocType();
88
    userName = myUserName;
89
    passWord = myPassWord;
90
    zipEntry = myZipEntryPath+ docIdWithoutRevision + 
91
                MetaCatUtil.getOption("accNumSeparator") + revision;
92
   
93

    
94
  }// Constructor
95

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

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

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

    
515
}//Class RemoteDocument
(49-49/56)