Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: Implements a service for managing object formats
4
 *  Copyright: 2011 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Christopher Jones
7
 * 
8
 *   '$Author: $'
9
 *     '$Date: $'
10
 * '$Revision: $'
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.service;
28

    
29
import java.io.ByteArrayInputStream;
30
import java.io.FileInputStream;
31
import java.io.FileNotFoundException;
32
import java.io.InputStream;
33
import java.sql.SQLException;
34
import java.util.HashMap;
35
import java.util.List;
36

    
37
import edu.ucsb.nceas.metacat.DBUtil;
38
import edu.ucsb.nceas.metacat.DocumentImpl;
39
import edu.ucsb.nceas.metacat.McdbException;
40
import edu.ucsb.nceas.metacat.properties.PropertyService;
41
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
42
import edu.ucsb.nceas.metacat.shared.BaseService;
43
import edu.ucsb.nceas.metacat.shared.ServiceException;
44
import edu.ucsb.nceas.metacat.util.SystemUtil;
45
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
46

    
47
import org.apache.log4j.Logger;
48

    
49
import org.dataone.client.CNode;
50
import org.dataone.client.D1Client;
51
import org.dataone.service.exceptions.InsufficientResources;
52
import org.dataone.service.exceptions.InvalidRequest;
53
import org.dataone.service.exceptions.NotFound;
54
import org.dataone.service.exceptions.NotImplemented;
55
import org.dataone.service.exceptions.ServiceFailure;
56
import org.dataone.service.types.Identifier;
57
import org.dataone.service.types.ObjectFormat;
58
//import org.dataone.service.types.ObjectFormatList;
59
import org.dataone.service.types.util.ServiceTypeUtil;
60
import org.jibx.runtime.JiBXException;
61

    
62
/**
63
 *  The ObjectFormatService manages the list of object formats registered
64
 *  within Metacat.  This includes schema types, mime types, and other
65
 *  information related to a particular format.  The service provides
66
 *  functionality for the DataONE MemberNode and CoordinatingNode components,
67
 *  with CoordinatingNodes providing the authoritative list of object formats.
68
 */
69
public class ObjectFormatService extends BaseService {
70
  
71
  /* The instance of the logging class */
72
  private static Logger logMetacat = Logger.getLogger(ObjectFormatService.class);
73
  
74
  /* The singleton instance of the object format service */
75
  private static ObjectFormatService objectFormatService = null;
76
  
77
  /* The scope of the object formats docid used as the metacat identifier */
78
  private final String OBJECT_FORMAT_DOCID = "OBJECT_FORMAT_LIST.103";
79
  
80
  /* The revision of the object formats document */
81
  private int rev;
82
  
83
  /* The separator of the object formats document */
84
  private String separator = ".";
85

    
86
  /* The accession number of the object formats document */
87
  private String accNumber = null;
88

    
89
  /* The list of object formats */
90
  //private static ObjectFormatList objectFormatList = null;
91
  
92
  /* the searchable map of object formats */
93
  private static HashMap<String, ObjectFormat> objectFormatMap = 
94
    new HashMap<String, ObjectFormat>();
95
  
96
  /* A hash map of object format identifiers
97
  /* The D1 coordinating node reference object used for object format lookups */
98
  private String coordinatingNodeBaseURL = null;
99
  
100
  /* The D1 coordinating node reference object used for object format lookups */
101
  private CNode cn = null;
102

    
103
  /* The D1 node type for this instance of metacat */
104
  private String nodeType;
105
  
106
  /*
107
   * Constructor: Creates an instance of the object format service. Since
108
   * this uses a singleton pattern, use getInstance() to gain the instance.
109
   */
110
  private ObjectFormatService() {
111
    
112
    super();
113
    _serviceName="ObjectFormatService";
114
    
115
    try {
116
      doRefresh();
117
      
118
    } catch (ServiceException se) {
119
      logMetacat.debug("There was a problem creating the ObjectFormatService. " +
120
                       "The error message was: " + se.getMessage());
121
      
122
    }
123
    
124
  }
125
  
126
  /**
127
   *  Get the instance of the ObjectFormatService that has been instantiated,
128
   *  or instantiate one if it has not been already.
129
   *
130
   * @return objectFormatService - The instance of the object format service
131
   */
132
  public static ObjectFormatService getInstance(){
133
    
134
    if ( objectFormatService == null ) {
135
      
136
      objectFormatService = new ObjectFormatService();
137
      
138
    }
139
    return objectFormatService;
140
  }
141
  
142
  /**
143
   * Refreshes the object format service by manually updating the object
144
   * format document.
145
   */
146
  public void doRefresh() throws ServiceException {
147
    
148
    logMetacat.debug("ObjectFormatService.doRefresh() called.");
149
    logMetacat.info("Refreshing the object format list.");
150
    
151
    // create the in-memory list of object formats
152
    populateObjectFormatList();
153
    
154
    return;
155
  }
156
  
157
  /**
158
   * Populate the ObjectFormatService's objectFormatList. If this metacat
159
   * installation is a D1 Coordinating Node, object formats are populated
160
   * from a cached document in the Metacat database. Otherwise, if it is 
161
   * a Member Node, it attempts to get the authoritative list from the
162
   * defined Coordinating Node, failing back to a cached version.
163
   * 
164
   * @throws ServiceException
165
   */
166
  private void populateObjectFormatList() throws ServiceException {
167
    
168
    try {
169
      
170
      coordinatingNodeBaseURL = 
171
        PropertyService.getProperty("dataone.coordinatingNodeBaseURL");
172
      nodeType = 
173
        PropertyService.getProperty("dataone.nodeType");
174
      
175
      
176
    } catch ( PropertyNotFoundException pnfe ) {
177
      
178
      String message = "There was a problem finding the coordinating node " +
179
                       "URL in the properties file.  The message was: "     +
180
                       pnfe.getMessage();
181
      logMetacat.error(message);
182
      throw new ServiceException(message);
183
    }
184
    
185
    // For DataONE Member Nodes, get the authoritative list from the 
186
    // Coordinating Node, otherwise, get the cached list
187
    if ( this.nodeType.equals("mn") ) {
188
      
189
      /*
190
       *try {
191
       *  
192
       *  // try to get the authoritative list remotely
193
       *  D1Client d1Client = new D1Client(coordinatingNodeBaseURL);
194
       *  this.cn = D1Client.getCN();
195
       *  this.objectFormatList = cn.listFormats();
196
       *
197
       *} catch (ServiceFailure e) {
198
       *  
199
       *  logMetacat.debug("There was a getting the object format list from " +
200
       *    "the coordinating node. The message was: " +
201
       *    e.getMessage());
202
       *  this.getCachedList();  
203
       *  
204
       *} catch (NotImplemented e) {
205
       *  
206
       *  logMetacat.debug("There was a getting the object format list from " +
207
       *    "the coordinating node. The message was: " + e.getMessage());
208
       *  this.getCachedList();  
209
       *  
210
       *} catch (InvalidRequest e) {
211
       *  
212
       *  logMetacat.debug("There was a getting the object format list from " +
213
       *    "the coordinating node. The message was: " + e.getMessage());
214
       *  this.getCachedList();  
215
       *  
216
       *} catch (NotFound e) {
217
       *  
218
       *  logMetacat.debug("There was a getting the object format list from " +
219
       *    "the coordinating node. The message was: " + e.getMessage());
220
       *  this.getCachedList();  
221
       *  
222
       *} catch (InsufficientResources e) {
223
       *  
224
       *  logMetacat.debug("There was a getting the object format list from " +
225
       *    "the coordinating node. The message was: " + e.getMessage());
226
       *  this.getCachedList();  
227
       *  
228
       *}
229
       */
230
      
231
      // this will be replaced with external lookup code above
232
      //this.getCachedList();
233
      
234
    } else if ( this.nodeType.equals("cn") ) {
235
      
236
      // get the list from the local metacat database
237
      //this.getCachedList();  
238

    
239
    } else {
240
      
241
      // the node type is not recognized
242
      throw new ServiceException("An error occurred in initializing the " +
243
        "ObjectFormatService. The DataONE node type needs to be either "  +
244
        "'cn' or 'mn', but instead was: " + this.nodeType);
245
    }
246
    
247
    // index the object format list based on the format identifier
248
    //int listSize = ObjectFormatService.objectFormatList.sizeObjectFormats();
249
    //
250
    //for (int i = 0; i < listSize; i++ ) {
251
    //  
252
    //  ObjectFormat objectFormat = 
253
    //    ObjectFormatService.objectFormatList.getObjectFormat(i);
254
    //  String identifier = objectFormat.getFmtid();
255
    //  ObjectFormatService.objectFormatMap.put(identifier, objectFormat);
256
    //  
257
    //}
258
        
259

    
260
    
261
  }
262

    
263
  /**
264
   * Indicate whether or not this service is refreshable.  In this case it is,
265
   * where the ObjectFormatService can manually get the latest object format
266
   * document from Metacat.
267
   *
268
   * @return refreshable - the boolean refreshable status
269
   */
270
  public boolean refreshable() {
271
    return true;
272
    
273
  }
274
  
275
  /**
276
   * Stop the ObjectFormatService. When stopped, the service will no longer
277
   * respond to requests. Not implemented yet.
278
   */
279
  public void stop() throws ServiceException {
280
    
281
    // stub only 
282
    return;
283
  }
284
  
285
  /**
286
   * List the object formats registered with the object format service.
287
   * 
288
   * @return objectFormatList - the list of object formats
289
   */
290
  //public ObjectFormatList listFormats() {
291
  //  
292
  //  return ObjectFormatService.objectFormatList;
293
  //  
294
  //}
295
  
296
  /**
297
   * Get the object format based on the given identifier as a string.
298
   * 
299
   * @param format - the object format as a string
300
   * @return objectFormat - the ObjectFormat represented by the format string
301
   */
302
  //public static ObjectFormat getFormat(String format) {
303
  //  
304
  //  ObjectFormat objectFormat = null;
305
  //  objectFormat = ObjectFormatService.objectFormatMap.get(format);
306
  //  
307
  //  return objectFormat;
308
  //  
309
  //}
310
  /**
311
   * Get the object format list cached in Metacat, or on failure, via a
312
   * cached file on disk
313
   * 
314
   * @return objectFormatList - the cached object format list
315
   */
316
  //private void getCachedList()
317
  //  throws ServiceException {
318
  //        
319
  //  try {
320
  //    
321
  //    // reset the accession number separator in case it is 
322
  //    // different than the default
323
  //    try {
324
  //      
325
  //      this.separator = PropertyService.getProperty("document.accNumSeparator");
326
  //      
327
  //    } catch ( PropertyNotFoundException pnfe ) {
328
  //      
329
  //      // use the default separator, but log the issue
330
  //      logMetacat.debug("There was a problem finding the document " +
331
  //        "separator property. The error message was: " + pnfe.getMessage());
332
  //    }
333
  //    
334
  //    // get the latest accession number if it is in Metacat
335
  //    this.rev = 
336
  //      DBUtil.getLatestRevisionInDocumentTable(this.OBJECT_FORMAT_DOCID);
337
  //    
338
  //    if ( this.rev != -1 ) {
339
  //      this.accNumber = this.OBJECT_FORMAT_DOCID + 
340
  //                       this.separator + 
341
  //                       this.rev;
342
  //      DocumentImpl objectFormatsDocument = new DocumentImpl(accNumber, false);
343
  //      ByteArrayInputStream bais = 
344
  //        new ByteArrayInputStream(objectFormatsDocument.toString().getBytes());
345
  //      ObjectFormatService.objectFormatList = 
346
  //        this.deserializeObjectFormatList(bais);
347
  //
348
  //    } else {
349
  //      
350
  //      logMetacat.info("The latest revision number of "   + 
351
  //        this.OBJECT_FORMAT_DOCID                         +
352
  //        " could not be found. Reverting to the on-disk " +
353
  //        "object format list");
354
  //      try {
355
  //        
356
  //        ObjectFormatService.objectFormatList = this.getListFromDisk();
357
  //      
358
  //      } catch (ServiceException se) {
359
  //        
360
  //        throw new ServiceException(se.getMessage());
361
  //      
362
  //      }
363
  //
364
  //    }
365
  //    
366
  //  } catch ( SQLException sqle ) {
367
  //    
368
  //    // we either have a metacat error or the docid was not inserted yet
369
  //    logMetacat.info("The latest revision number of "   + 
370
  //      this.OBJECT_FORMAT_DOCID                         +
371
  //      " could not be found. Reverting to the on-disk " +
372
  //      "object format list");
373
  //    
374
  //    try {
375
  //      
376
  //      ObjectFormatService.objectFormatList = this.getListFromDisk();
377
  //    
378
  //    } catch (ServiceException se) {
379
  //      
380
  //      throw se; 
381
  //      
382
  //    }
383
  //    
384
  //  } catch (McdbException mcdbe) {
385
  //    
386
  //    // we have a metacat doc not found error
387
  //    logMetacat.info( this.OBJECT_FORMAT_DOCID          +
388
  //      " could not be found. Reverting to the on-disk " +
389
  //      "object format list");
390
  //    
391
  //    try {
392
  //      
393
  //      ObjectFormatService.objectFormatList = this.getListFromDisk();
394
  //    
395
  //    } catch (ServiceException se) {
396
  //      
397
  //      throw se; 
398
  //      
399
  //    }
400
  //    
401
  //
402
  //  }
403
  //
404
  //  return;
405
  //  
406
  //}
407

    
408
  /**
409
   * Get the object format list cached on disk as stated in the metacat
410
   * properties file.
411
   * 
412
   * @return objectFormatList - the on-disk object format list
413
   * @throws ServiceException
414
   */
415
  //private ObjectFormatList getListFromDisk() 
416
  //  throws ServiceException {
417
  //  
418
  //  // the filesystem location of the object format list xml file
419
  //  String objectFormatFilePath = null;
420
  //  
421
  //  // get the object format list from disk and parse it
422
  //  try {
423
  //    objectFormatFilePath = SystemUtil.getContextDir() + "/WEB-INF/" +
424
  //      PropertyService.getProperty("dataone.objectFormatListName");
425
  //          
426
  //    FileInputStream fileInputStream = new FileInputStream(objectFormatFilePath);         
427
  //
428
  //    ObjectFormatService.objectFormatList = 
429
  //      this.deserializeObjectFormatList(fileInputStream);
430
  //
431
  //  } catch (PropertyNotFoundException pnfe) {
432
  //    
433
  //    logMetacat.error("The object format list file could not be parsed. " +
434
  //      "The error message was: " + pnfe.getMessage());
435
  //    throw new ServiceException(pnfe.getMessage());
436
  //    
437
  //  } catch ( FileNotFoundException fnfe ) {
438
  //    
439
  //    logMetacat.debug("There was an error reading the file " +
440
  //      objectFormatFilePath + ". The error was: "            +
441
  //      fnfe.getMessage());
442
  //    throw new ServiceException(fnfe.getMessage());
443
  //        
444
  //  }
445
  //  
446
  //  return ObjectFormatService.objectFormatList;
447
  //}
448

    
449
  /**
450
   * Deserialize the object format list file to an object format list object
451
   * 
452
   * @param fileInputStream - the file input stream of the XML object format list file
453
   * @return objectFormatList - the ObjectFormatList object from the XML stream
454
   * @throws ServiceException
455
   */
456
  //private ObjectFormatList deserializeObjectFormatList(InputStream inputStream) 
457
  //  throws ServiceException {
458
  //  
459
  //  ObjectFormatList objectFormatList;
460
  //  try {
461
  //    objectFormatList = (ObjectFormatList)
462
  //    ServiceTypeUtil.deserializeServiceType(ObjectFormatList.class, inputStream);
463
  //  
464
  //  } catch ( JiBXException jbxe ) {
465
  //    
466
  //    logMetacat.debug("There was an error deserializing the input stream. " +
467
  //      "The error was: " + jbxe.getMessage());
468
  //    jbxe.printStackTrace();
469
  //    throw new ServiceException(jbxe.getMessage());
470
  //  }
471
  //  
472
  //  return objectFormatList;
473
  //}
474
  
475
}
(1-1/6)