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.InputStream;
31
import java.sql.SQLException;
32
import java.util.HashMap;
33

    
34
import org.apache.log4j.Logger;
35
import org.dataone.client.ObjectFormatCache;
36
import org.dataone.service.types.ObjectFormat;
37
import org.dataone.service.types.ObjectFormatList;
38
import org.dataone.service.types.util.ServiceTypeUtil;
39
import org.jibx.runtime.JiBXException;
40

    
41
import edu.ucsb.nceas.metacat.DBUtil;
42
import edu.ucsb.nceas.metacat.DocumentImpl;
43
import edu.ucsb.nceas.metacat.McdbException;
44
import edu.ucsb.nceas.metacat.properties.PropertyService;
45
import edu.ucsb.nceas.metacat.shared.BaseService;
46
import edu.ucsb.nceas.metacat.shared.ServiceException;
47
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
48

    
49
/**
50
 *  The ObjectFormatService manages the list of object formats registered
51
 *  within Metacat.  This includes schema types, mime types, and other
52
 *  information related to a particular format.  The service provides
53
 *  functionality for the DataONE MemberNode and CoordinatingNode components,
54
 *  with CoordinatingNodes providing the authoritative list of object formats.
55
 */
56
public class ObjectFormatService extends BaseService {
57
  
58
  /* The instance of the logging class */
59
  private static Logger logMetacat = Logger.getLogger(ObjectFormatService.class);
60
  
61
  /* The singleton instance of the object format service */
62
  private static ObjectFormatService objectFormatService = null;
63
  
64
  /* The scope of the object formats docid used as the metacat identifier */
65
  private final String OBJECT_FORMAT_DOCID = "OBJECT_FORMAT_LIST.103";
66
  
67
  /* The revision of the object formats document */
68
  private int rev;
69
  
70
  /* The separator of the object formats document */
71
  private String separator = ".";
72

    
73
  /* The accession number of the object formats document */
74
  private String accNumber = null;
75

    
76
  /* The list of object formats */
77
  private static ObjectFormatList objectFormatList = null;
78
  
79
  /* the searchable map of object formats */
80
  private static HashMap<String, ObjectFormat> objectFormatMap = 
81
    new HashMap<String, ObjectFormat>();
82
  
83
  /* A hash map of object format identifiers
84
  /* The D1 coordinating node reference object used for object format lookups */
85
  private String coordinatingNodeBaseURL = null;
86
  
87
  /* The D1 coordinating node reference object used for object format lookups */
88
  //private CNode cn = null;
89

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

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

    
295
  /**
296
   * Deserialize the object format list file to an object format list object
297
   * 
298
   * @param fileInputStream - the file input stream of the XML object format list file
299
   * @return objectFormatList - the ObjectFormatList object from the XML stream
300
   * @throws ServiceException
301
   */
302
  private ObjectFormatList deserializeObjectFormatList(InputStream inputStream) 
303
    throws ServiceException {
304
    
305
    ObjectFormatList objectFormatList;
306
    try {
307
      objectFormatList = (ObjectFormatList)
308
      ServiceTypeUtil.deserializeServiceType(ObjectFormatList.class, inputStream);
309
    
310
    } catch ( JiBXException jbxe ) {
311
      
312
      logMetacat.debug("There was an error deserializing the input stream. " +
313
        "The error was: " + jbxe.getMessage());
314
      jbxe.printStackTrace();
315
      throw new ServiceException(jbxe.getMessage());
316
    }
317
    
318
    return objectFormatList;
319
  }
320
  
321
}
(1-1/6)