Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2000-2005 Regents of the University of California and the
4
 *             National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author: leinfelder $'
7
 *     '$Date: 2010-12-27 14:47:01 -0800 (Mon, 27 Dec 2010) $'
8
 * '$Revision: 5760 $'
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
 */
24

    
25
package edu.ucsb.nceas.metacat.lsid;
26

    
27
import java.io.BufferedReader;
28
import java.io.ByteArrayInputStream;
29
import java.io.ByteArrayOutputStream;
30
import java.io.IOException;
31
import java.io.InputStream;
32
import java.io.InputStreamReader;
33
import java.io.Reader;
34
import java.io.StringReader;
35
import java.io.UnsupportedEncodingException;
36
import java.util.Hashtable;
37
import java.util.ResourceBundle;
38
import java.util.Enumeration;
39

    
40
import javax.xml.transform.Transformer;
41
import javax.xml.transform.TransformerFactory;
42
import javax.xml.transform.stream.StreamResult;
43
import javax.xml.transform.stream.StreamSource;
44

    
45
import org.apache.commons.logging.Log;
46
import org.apache.commons.logging.LogFactory;
47

    
48
import com.ibm.lsid.LSID;
49
import com.ibm.lsid.MalformedLSIDException;
50
import com.ibm.lsid.MetadataResponse;
51
import com.ibm.lsid.server.LSIDMetadataService;
52
import com.ibm.lsid.server.LSIDRequestContext;
53
import com.ibm.lsid.server.LSIDServerException;
54
import com.ibm.lsid.server.LSIDServiceConfig;
55

    
56
import edu.ucsb.nceas.metacat.MetaCatServlet;
57
import edu.ucsb.nceas.metacat.client.Metacat;
58
import edu.ucsb.nceas.metacat.client.MetacatFactory;
59
import edu.ucsb.nceas.metacat.client.MetacatInaccessibleException;
60

    
61
public class LSIDAuthorityMetaData implements LSIDMetadataService
62
{
63
    private LSIDDataLookup lookup = null;
64
    private static Hashtable currentLSIDs = new Hashtable();
65
    private static Log logger = LogFactory
66
                    .getLog("edu.ucsb.nceas.metacat.lsid");
67

    
68
    public void initService(LSIDServiceConfig cf) throws LSIDServerException
69
    {
70
        logger.info("Starting LSIDAuthorityMetadata.");
71
        lookup = new LSIDDataLookup();
72
    }
73

    
74
    private static final String RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
75
    private static final String DC_NS = "http://purl.org/dc/elements/1.1/";
76
    private static final String I3CP_NS = "urn:lsid:i3c.org:predicates:";
77
    private static final String I3C_CONTENT = "urn:lsid:i3c.org:types:content";
78
    private static final String DEFAULT_STYLESHEET = "default.xslt";
79

    
80
    public MetadataResponse getMetadata(LSIDRequestContext req, String[] formats)
81
                    throws LSIDServerException
82
    {
83
        LSID lsid = req.getLsid();
84
        ByteArrayInputStream theMetadata = doMetadataRequest(lsid);
85
        return new MetadataResponse(theMetadata, null,
86
                                    MetadataResponse.RDF_FORMAT);
87
    }
88

    
89
    private ByteArrayInputStream doMetadataRequest(LSID lsid) throws
90
        LSIDServerException {
91
      logger.debug("getting metadata for lsid " + lsid.getLsid());
92

    
93
      try {
94

    
95
        LSIDDataLookup myLookup = new LSIDDataLookup();
96
        InputStream content = myLookup.lsidData(lsid);
97
        InputStream content2 = myLookup.lsidData(lsid);
98
        if (!isEML(content2)) {
99
          content = getEML(lsid);
100
        }
101
        content2.close();
102
        setCurrentLSID(lsid);
103

    
104
        // based on the doctype choose the appropriate stylesheet
105
        String styleSheetName = null;
106
        String _docType = myLookup.getDocType(lsid);
107

    
108
        try {
109
          ResourceBundle rb = ResourceBundle.getBundle("metacat-lsid");
110
          styleSheetName = rb.getString(_docType.replaceAll(":", ""));
111
        }
112
        catch (java.util.MissingResourceException mre) {
113
          logger.warn("there is no style corresponding to: '" + _docType +
114
                      "' -- using default");
115
          styleSheetName = this.DEFAULT_STYLESHEET;
116
          mre.getMessage();
117
        }
118
        InputStream styleSheet = getClass()
119
            .getResourceAsStream(styleSheetName);
120
        TransformerFactory factory = TransformerFactory.newInstance();
121
        Transformer transformer = factory
122
            .newTransformer(new StreamSource(styleSheet));
123
        ByteArrayOutputStream out = new ByteArrayOutputStream();
124
        transformer.transform(new StreamSource(content),
125
                              new StreamResult(out));
126
        content.close();
127
        clearState();
128
        return new ByteArrayInputStream(out.toByteArray());
129
      }
130
      catch (Exception e) {
131
        throw new LSIDServerException(e, "Error transforming XML for: "
132
                                      + lsid);
133
      }
134
    }
135

    
136
    public static String getStringFromInputStream(InputStream input)
137
    {
138
        StringBuffer result = new StringBuffer();
139
        BufferedReader in = new BufferedReader(new InputStreamReader(input));
140
        String line;
141
        try {
142
            while ((line = in.readLine()) != null) {
143
                result.append(line);
144
            }
145
        } catch (IOException e) {
146
            logger.error("IOexception " + e);
147
        }
148
        return result.toString();
149
    }
150

    
151
    /**
152
     * figure out is this inputstream is an eml document or not
153
     * TODO: need a better way to figure out if this is an eml document
154
     */
155
    private boolean isEML(InputStream input)
156
    {
157

    
158
        if (input == null) { return false; }
159

    
160
        int loop = 0;
161
        boolean itIsEML = false;
162
        String line = "";
163
        try {
164
            BufferedReader in = new BufferedReader(new InputStreamReader(input));
165
            while ((loop < 20) && (line != null) && (!itIsEML)) {
166
                line = in.readLine();
167
                line = line.toLowerCase();
168
                if (line.indexOf("eml:eml") != -1) {
169
                    itIsEML = true;
170
                }
171
                loop++;
172
            }
173
        } catch (IOException e) {
174
            logger.error("ioerror in LSIDAuthorityMetadata: " + e);
175
        }
176
        return itIsEML;
177
    }
178

    
179
    /**
180
     * this lsid points to a data object - get the metadata objects which refer
181
     * to this document
182
     */
183
    private InputStream getEML(LSID theLSID)
184
    {
185

    
186
        InputStream response = null;
187

    
188
        // need to find things with this object in any of the elements
189
        // using the metacat api
190
        // get back dataset/docid and dataset/title
191

    
192
        // create the query
193
        String theQuery = getMetaCatQuery(theLSID);
194

    
195
        // get the metacat record
196
        Reader metaCatResponse = getMetaCatResponse(theQuery);
197

    
198
        // parse the metadata to get the applicable rdf information
199
        response = parseMetaCatResponse(metaCatResponse, theLSID);
200

    
201
        return response;
202

    
203
    }
204

    
205
    /**
206
     * given an LSID return a metacat query which will return docs mentioning
207
     * this LSID
208
     */
209
    private String getMetaCatQuery(LSID lsid)
210
    {
211
        logger.debug("getting Metacat Query for: " + lsid.toString());
212
        String ns = lsid.getNamespace();
213
        String id = lsid.getObject();
214
        String ver = lsid.getRevision();
215
        String theName = ns + "." + id + "." + ver;
216

    
217
        String theQuery = null;
218
        theQuery = "<?xml version=\"1.0\"?>\n"
219
                   + "<pathquery version=\"1.2\">\n"
220
                   + "  <querytitle>"
221
                   + theName
222
                   + " search</querytitle>\n"
223
                   + "  <returnfield>dataset/docid</returnfield>\n"
224
                   + "  <returnfield>dataset/title</returnfield>\n"
225
                   + "  <querygroup operator=\"UNION\">\n"
226
                   + "    <queryterm searchmode=\"contains\" casesensitive=\"false\">\n"
227
                   + "      <value>" + theName + "</value>\n"
228
                   + "      <pathexpr>anyfield</pathexpr>\n"
229
                   + "    </queryterm>\n" + "  </querygroup>\n"
230
                   + "<pathquery>\n";
231

    
232
        return theQuery;
233

    
234
    }
235

    
236
    /**
237
     * given a query string, query MetaCat and return the response
238
     */
239
    private Reader getMetaCatResponse(String query)
240
    {
241
        logger.debug("Querying the metacat server.");
242
        // get the metacat server from the configuration file
243
        //
244
        ResourceBundle rb = ResourceBundle.getBundle("metacat-lsid");
245
        String url = rb.getString("metacatserver");
246
        Reader r = null;
247
        try {
248

    
249
            Metacat m = MetacatFactory.createMetacatConnection(url);
250
            r = m.query(new StringReader(query));
251

    
252
        } catch (MetacatInaccessibleException mie) {
253
            logger.error("Metacat Inaccessible:\n" + mie.getMessage());
254
        } catch (Exception e) {
255
            logger.error("General exception:\n" + e.getMessage());
256
        }
257
        return r;
258
    }
259

    
260
    /**
261
     * Given a reader which is a metacat response, parse it and return the
262
     * appropriate rdf
263
     */
264
    private InputStream parseMetaCatResponse(Reader reader, LSID theLSID)
265
    {
266
        InputStream response = null;
267
        logger.debug("Parsing the metacat response.");
268
        // if there's more than one document, then return rdf listing the
269
        // documents
270
        // otherwise get the document and return rdf based on it
271

    
272
        String contents = getStringFromReader(reader);
273
        if (numberDocuments(contents) < 1) {
274
            response = noMetaDataResponse(theLSID);
275
        } else if (numberDocuments(contents) > 1) {
276
            response = metaDataList(contents, theLSID);
277
        } else {
278
            response = getMetaData(contents, theLSID);
279
        }
280
        return response;
281
    }
282

    
283
    /**
284
     * There's no metadata for this document
285
     */
286
    private ByteArrayInputStream noMetaDataResponse(LSID theLSID)
287
    {
288
        ResourceBundle rb = ResourceBundle.getBundle("metacat-lsid");
289
        String metadataLabels = rb.getString("metadatalabels");
290

    
291
        String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
292
                        + "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" \n"
293
                        + "	xmlns:dc=\"http://purl.org/dc/elements/1.1/\" \n"
294
                        + "	xmlns:pred=\"urn:lsid:i3c.org:predicates:\" xmlns=\"urn:lsid:"
295
                        + metadataLabels
296
                        + ":predicates:\"> \n"
297
                        + "<rdf:Description rdf:about=\""
298
                        + theLSID.getLsid()
299
                        + "\"> \n"
300
                        + "	<pred:title xmlns:pred=\"http://purl.org/dc/elements/1.1/\">There is no metadata for this LSID.</pred:title>\n"
301
                        + "</rdf:Description>\n" + "</rdf:RDF>\n";
302

    
303
        ByteArrayInputStream resultBytes = null;
304
        try {
305
        	resultBytes = new ByteArrayInputStream(result.getBytes(MetaCatServlet.DEFAULT_ENCODING));
306
		} catch (UnsupportedEncodingException e) {
307
			// TODO Auto-generated catch block
308
			e.printStackTrace();
309
		}
310
		return resultBytes;
311
    }
312

    
313
    /**
314
     * There's more than one metdata document
315
     */
316
    private ByteArrayInputStream metaDataList(String contents, LSID theLSID)
317
    {
318
        ResourceBundle rb = ResourceBundle.getBundle("metacat");
319
        String metadataLabels = rb.getString("metadatalabels");
320

    
321
        String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
322
                        + "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" \n"
323
                        + "	xmlns:dc=\"http://purl.org/dc/elements/1.1/\" \n"
324
                        + "	xmlns:pred=\"urn:lsid:i3c.org:predicates:\" xmlns=\"urn:lsid:"
325
                        + metadataLabels
326
                        + ":predicates:\"> \n"
327
                        + "<rdf:Description rdf:about=\""
328
                        + theLSID.getLsid()
329
                        + "\"> \n"
330
                        + "	<pred:title xmlns:pred=\"http://purl.org/dc/elements/1.1/\">There is more than one metadata document for this LSID - which confuses me right now.  Try again soon and I'll be less confused.</pred:title>\n"
331
                        + "</rdf:Description>\n" + "</rdf:RDF>\n";
332

    
333
        ByteArrayInputStream resultBytes = null;
334
        try {
335
        	resultBytes = new ByteArrayInputStream(result.getBytes(MetaCatServlet.DEFAULT_ENCODING));
336
		} catch (UnsupportedEncodingException e) {
337
			// TODO Auto-generated catch block
338
			e.printStackTrace();
339
		}
340
		return resultBytes;
341
    }
342

    
343
    /**
344
     * There's just one metadata document
345
     */
346
    private ByteArrayInputStream getMetaData(String contents, LSID theLSID)
347
    {
348
        String paramString = "<param name=\"dataset/title\">";
349
        ByteArrayInputStream result = null;
350

    
351
        if (contents.indexOf(paramString) == -1) {
352
            return noMetaDataResponse(theLSID);
353
        } else {
354
            String parts[] = contents.split(paramString);
355
            String parts2[] = parts[1].split("</param>");
356
            try {
357
                LSID newLSID = new LSID(parts2[0]);
358
                result = doMetadataRequest(newLSID);
359

    
360
            } catch (MalformedLSIDException e) {
361
                logger.error("problem generating LSID: " + e);
362
                e.printStackTrace();
363
            } catch (LSIDServerException e) {
364
                logger.error("problem generating LSID: " + e);
365
                e.printStackTrace();
366
            }
367
        }
368
        return result;
369
    }
370

    
371
    /**
372
     * Find out how many contents are in this metacat response I'm just using
373
     * string stuff for this - sort of lame, but does the trick more cool would
374
     * be to use xml stuff
375
     */
376
    private int numberDocuments(String contents)
377
    {
378

    
379
        String[] docSplit = contents.split("<document>");
380
        return (docSplit.length - 1);
381
    }
382

    
383
    /**
384
     * Given a reader, return a string
385
     */
386
    private String getStringFromReader(Reader reader)
387
    {
388
        StringBuffer response = new StringBuffer();
389

    
390
        try {
391
            BufferedReader bufReader = new BufferedReader(reader);
392

    
393
            String line = null;
394
            while ((line = bufReader.readLine()) != null) {
395
                response.append(line);
396
            }
397
            bufReader.close();
398

    
399
        } catch (IOException e) {
400
            logger.error("error getting string from reader " + e);
401
        }
402
        return response.toString();
403
    }
404

    
405
    /**
406
     * set the LSID for the current thread
407
     */
408
    static void setCurrentLSID(LSID lsid)
409
    {
410
        currentLSIDs.put(Thread.currentThread(), lsid);
411
    }
412

    
413
    static void clearState()
414
    {
415
        currentLSIDs.remove(Thread.currentThread());
416
    }
417

    
418
    /**
419
     * get the current LSID for the given thread, for use in XSLT so return a
420
     * string
421
     */
422
    public static String getLSID(
423
                         org.apache.xalan.extensions.XSLProcessorContext foo,
424
                         org.apache.xalan.templates.ElemExtensionCall bar)
425
                    throws MalformedLSIDException
426
    {
427
        return ((LSID) currentLSIDs.get(Thread.currentThread())).toString();
428
    }
429

    
430
    public static String getLSID() throws MalformedLSIDException
431
    {
432
        return ((LSID) currentLSIDs.get(Thread.currentThread())).toString();
433
    }
434
}
(3-3/4)