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.client.ObjectFormatCache;
52
import org.dataone.service.exceptions.InsufficientResources;
53
import org.dataone.service.exceptions.InvalidRequest;
54
import org.dataone.service.exceptions.NotFound;
55
import org.dataone.service.exceptions.NotImplemented;
56
import org.dataone.service.exceptions.ServiceFailure;
57
import org.dataone.service.types.Identifier;
58
import org.dataone.service.types.ObjectFormat;
59
import org.dataone.service.types.ObjectFormatList;
60
//import org.dataone.service.types.ObjectFormatList;
61
import org.dataone.service.types.util.ServiceTypeUtil;
62
import org.jibx.runtime.JiBXException;
63

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

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

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

    
105
  /* The D1 node type for this instance of metacat */
106
  private String nodeType;
107
  
108
  /*
109
   * Constructor: Creates an instance of the object format service. Since
110
   * this uses a singleton pattern, use getInstance() to gain the instance.
111
   */
112
  private ObjectFormatService() {
113
    
114
    super();
115
    _serviceName="ObjectFormatService";
116
    
117
    try {
118
      doRefresh();
119
      
120
    } catch (ServiceException se) {
121
      logMetacat.debug("There was a problem creating the ObjectFormatService. " +
122
                       "The error message was: " + se.getMessage());
123
      
124
    }
125
    
126
  }
127
  
128
  /**
129
   *  Get the instance of the ObjectFormatService that has been instantiated,
130
   *  or instantiate one if it has not been already.
131
   *
132
   * @return objectFormatService - The instance of the object format service
133
   */
134
  public static ObjectFormatService getInstance(){
135
    
136
    if ( objectFormatService == null ) {
137
      
138
      objectFormatService = new ObjectFormatService();
139
      
140
    }
141
    return objectFormatService;
142
  }
143
  
144
  /**
145
   * Refreshes the object format service by manually updating the object
146
   * format document.
147
   */
148
  public void doRefresh() throws ServiceException {
149
    
150
    logMetacat.debug("ObjectFormatService.doRefresh() called.");
151
    logMetacat.info("Refreshing the object format list.");
152
    
153
    // create the in-memory list of object formats
154
    populateObjectFormatList();
155
    
156
    return;
157
  }
158
  
159
  /**
160
   * Populate the ObjectFormatService's objectFormatList. If this metacat
161
   * installation is a D1 Coordinating Node, object formats are populated
162
   * from a cached document in the Metacat database. Otherwise, if it is 
163
   * a Member Node, it attempts to get the authoritative list from the
164
   * defined Coordinating Node, failing back to a cached version.
165
   * 
166
   * @throws ServiceException
167
   */
168
  private void populateObjectFormatList() throws ServiceException {
169
    
170
    try {
171
      
172
      coordinatingNodeBaseURL = 
173
        PropertyService.getProperty("dataone.coordinatingNodeBaseURL");
174
      nodeType = 
175
        PropertyService.getProperty("dataone.nodeType");
176
      
177
      
178
    } catch ( PropertyNotFoundException pnfe ) {
179
      
180
      String message = "There was a problem finding the coordinating node " +
181
                       "URL in the properties file.  The message was: "     +
182
                       pnfe.getMessage();
183
      logMetacat.error(message);
184
      throw new ServiceException(message);
185
    }
186
    
187
    this.getCachedList();  
188
  }
189

    
190
  /**
191
   * Indicate whether or not this service is refreshable.  In this case it is,
192
   * where the ObjectFormatService can manually get the latest object format
193
   * document from Metacat.
194
   *
195
   * @return refreshable - the boolean refreshable status
196
   */
197
  public boolean refreshable() {
198
    return true;
199
    
200
  }
201
  
202
  /**
203
   * Stop the ObjectFormatService. When stopped, the service will no longer
204
   * respond to requests. Not implemented yet.
205
   */
206
  public void stop() throws ServiceException {
207
    
208
    // stub only 
209
    return;
210
  }
211
  
212
  /**
213
   * List the object formats registered with the object format service.
214
   * 
215
   * @return objectFormatList - the list of object formats
216
   */
217
  public ObjectFormatList listFormats() {
218
    
219
    return ObjectFormatService.objectFormatList;
220
    
221
  }
222
  
223
  /**
224
   * Get the object format based on the given identifier as a string.
225
   * 
226
   * @param format - the object format as a string
227
   * @return objectFormat - the ObjectFormat represented by the format string
228
   */
229
  public static ObjectFormat getFormat(String format) {
230
    
231
    ObjectFormat objectFormat = null;
232
    objectFormat = ObjectFormatService.objectFormatMap.get(format);
233
    
234
    return objectFormat;
235
    
236
  }
237
  /**
238
   * Get the object format list cached in Metacat, or on failure, via a
239
   * cached file on disk
240
   * 
241
   * @return objectFormatList - the cached object format list
242
   */
243
  private void getCachedList()
244
    throws ServiceException {
245
          
246
    try {
247
      
248
      // reset the accession number separator in case it is 
249
      // different than the default
250
      try {
251
        
252
        this.separator = PropertyService.getProperty("document.accNumSeparator");
253
        
254
      } catch ( PropertyNotFoundException pnfe ) {
255
        
256
        // use the default separator, but log the issue
257
        logMetacat.debug("There was a problem finding the document " +
258
          "separator property. The error message was: " + pnfe.getMessage());
259
      }
260
      
261
      // get the latest accession number if it is in Metacat
262
      this.rev = 
263
        DBUtil.getLatestRevisionInDocumentTable(this.OBJECT_FORMAT_DOCID);
264
      
265
      if ( this.rev != -1 ) {
266
        this.accNumber = this.OBJECT_FORMAT_DOCID + 
267
                         this.separator + 
268
                         this.rev;
269
        DocumentImpl objectFormatsDocument = new DocumentImpl(accNumber, false);
270
        ByteArrayInputStream bais = 
271
          new ByteArrayInputStream(objectFormatsDocument.toString().getBytes());
272
        ObjectFormatService.objectFormatList = 
273
          this.deserializeObjectFormatList(bais);
274
  
275
      } else {
276
        
277
        logMetacat.info("The latest revision number of "   + 
278
          this.OBJECT_FORMAT_DOCID                         +
279
          " could not be found. Reverting to the on-disk " +
280
          "object format list");
281
          
282
        ObjectFormatService.objectFormatList = ObjectFormatCache.listFormats();
283
      }
284
      
285
    } catch ( SQLException sqle ) {
286
      
287
      // we either have a metacat error or the docid was not inserted yet
288
      logMetacat.info("The latest revision number of "   + 
289
        this.OBJECT_FORMAT_DOCID                         +
290
        " could not be found. Reverting to the on-disk " +
291
        "object format list");
292
        
293
      ObjectFormatService.objectFormatList = ObjectFormatCache.listFormats();
294
      
295
    } catch (McdbException mcdbe) {
296
      
297
      // we have a metacat doc not found error
298
      logMetacat.info( this.OBJECT_FORMAT_DOCID          +
299
        " could not be found. Reverting to the on-disk " +
300
        "object format list");
301
      
302
      ObjectFormatService.objectFormatList = ObjectFormatCache.listFormats();
303
  
304
    }
305
  
306
    return;
307
    
308
  }
309

    
310
  /**
311
   * Deserialize the object format list file to an object format list object
312
   * 
313
   * @param fileInputStream - the file input stream of the XML object format list file
314
   * @return objectFormatList - the ObjectFormatList object from the XML stream
315
   * @throws ServiceException
316
   */
317
  private ObjectFormatList deserializeObjectFormatList(InputStream inputStream) 
318
    throws ServiceException {
319
    
320
    ObjectFormatList objectFormatList;
321
    try {
322
      objectFormatList = (ObjectFormatList)
323
      ServiceTypeUtil.deserializeServiceType(ObjectFormatList.class, inputStream);
324
    
325
    } catch ( JiBXException jbxe ) {
326
      
327
      logMetacat.debug("There was an error deserializing the input stream. " +
328
        "The error was: " + jbxe.getMessage());
329
      jbxe.printStackTrace();
330
      throw new ServiceException(jbxe.getMessage());
331
    }
332
    
333
    return objectFormatList;
334
  }
335
  
336
}
(1-1/6)