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: tao $'
10
 *     '$Date: 2002-07-14 12:33:25 -0700 (Sun, 14 Jul 2002) $'
11
 * '$Revision: 1292 $'
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 javax.servlet.ServletOutputStream;
31
import java.io.*;
32
import java.net.*;
33
import java.util.*;
34
import java.util.zip.*;
35

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

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

    
93
  }// Constructor
94

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

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

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

    
514
}//Class RemoteDocument
(50-50/57)