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: leinfelder $'
9
 *     '$Date: 2014-05-29 14:53:36 -0700 (Thu, 29 May 2014) $'
10
 * '$Revision: 8802 $'
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.client.MetacatClient;
30
import edu.ucsb.nceas.metacat.client.MetacatFactory;
31
import edu.ucsb.nceas.metacat.properties.PropertyService;
32
import edu.ucsb.nceas.metacat.util.MetacatUtil;
33
import javax.servlet.ServletOutputStream;
34

    
35
import org.apache.log4j.Logger;
36

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

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

    
107
  }// Constructor
108

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

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

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

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