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: harris $'
7
 *     '$Date: 2006-01-25 16:42:52 -0800 (Wed, 25 Jan 2006) $'
8
 * '$Revision: 2904 $'
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.util.Hashtable;
36
import java.util.ResourceBundle;
37
import java.util.Enumeration;
38

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

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

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

    
55
import edu.ucsb.nceas.metacat.client.Metacat;
56
import edu.ucsb.nceas.metacat.client.MetacatFactory;
57
import edu.ucsb.nceas.metacat.client.MetacatInaccessibleException;
58

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

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

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

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

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

    
91
      try {
92

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

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

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

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

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

    
156
        if (input == null) { return false; }
157

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

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

    
184
        InputStream response = null;
185

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

    
190
        // create the query
191
        String theQuery = getMetaCatQuery(theLSID);
192

    
193
        // get the metacat record
194
        Reader metaCatResponse = getMetaCatResponse(theQuery);
195

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

    
199
        return response;
200

    
201
    }
202

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

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

    
230
        return theQuery;
231

    
232
    }
233

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

    
247
            Metacat m = MetacatFactory.createMetacatConnection(url);
248
            r = m.query(new StringReader(query));
249

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

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

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

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

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

    
301
        return new ByteArrayInputStream(result.getBytes());
302
    }
303

    
304
    /**
305
     * There's more than one metdata document
306
     */
307
    private ByteArrayInputStream metaDataList(String contents, LSID theLSID)
308
    {
309
        ResourceBundle rb = ResourceBundle.getBundle("metacat");
310
        String metadataLabels = rb.getString("metadatalabels");
311

    
312
        String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
313
                        + "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" \n"
314
                        + "	xmlns:dc=\"http://purl.org/dc/elements/1.1/\" \n"
315
                        + "	xmlns:pred=\"urn:lsid:i3c.org:predicates:\" xmlns=\"urn:lsid:"
316
                        + metadataLabels
317
                        + ":predicates:\"> \n"
318
                        + "<rdf:Description rdf:about=\""
319
                        + theLSID.getLsid()
320
                        + "\"> \n"
321
                        + "	<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"
322
                        + "</rdf:Description>\n" + "</rdf:RDF>\n";
323

    
324
        return new ByteArrayInputStream(result.getBytes());
325
    }
326

    
327
    /**
328
     * There's just one metadata document
329
     */
330
    private ByteArrayInputStream getMetaData(String contents, LSID theLSID)
331
    {
332
        String paramString = "<param name=\"dataset/title\">";
333
        ByteArrayInputStream result = null;
334

    
335
        if (contents.indexOf(paramString) == -1) {
336
            return noMetaDataResponse(theLSID);
337
        } else {
338
            String parts[] = contents.split(paramString);
339
            String parts2[] = parts[1].split("</param>");
340
            try {
341
                LSID newLSID = new LSID(parts2[0]);
342
                result = doMetadataRequest(newLSID);
343

    
344
            } catch (MalformedLSIDException e) {
345
                logger.error("problem generating LSID: " + e);
346
                e.printStackTrace();
347
            } catch (LSIDServerException e) {
348
                logger.error("problem generating LSID: " + e);
349
                e.printStackTrace();
350
            }
351
        }
352
        return result;
353
    }
354

    
355
    /**
356
     * Find out how many contents are in this metacat response I'm just using
357
     * string stuff for this - sort of lame, but does the trick more cool would
358
     * be to use xml stuff
359
     */
360
    private int numberDocuments(String contents)
361
    {
362

    
363
        String[] docSplit = contents.split("<document>");
364
        return (docSplit.length - 1);
365
    }
366

    
367
    /**
368
     * Given a reader, return a string
369
     */
370
    private String getStringFromReader(Reader reader)
371
    {
372
        StringBuffer response = new StringBuffer();
373

    
374
        try {
375
            BufferedReader bufReader = new BufferedReader(reader);
376

    
377
            String line = null;
378
            while ((line = bufReader.readLine()) != null) {
379
                response.append(line);
380
            }
381
            bufReader.close();
382

    
383
        } catch (IOException e) {
384
            logger.error("error getting string from reader " + e);
385
        }
386
        return response.toString();
387
    }
388

    
389
    /**
390
     * set the LSID for the current thread
391
     */
392
    static void setCurrentLSID(LSID lsid)
393
    {
394
        currentLSIDs.put(Thread.currentThread(), lsid);
395
    }
396

    
397
    static void clearState()
398
    {
399
        currentLSIDs.remove(Thread.currentThread());
400
    }
401

    
402
    /**
403
     * get the current LSID for the given thread, for use in XSLT so return a
404
     * string
405
     */
406
    public static String getLSID(
407
                         org.apache.xalan.extensions.XSLProcessorContext foo,
408
                         org.apache.xalan.templates.ElemExtensionCall bar)
409
                    throws MalformedLSIDException
410
    {
411
        return ((LSID) currentLSIDs.get(Thread.currentThread())).toString();
412
    }
413

    
414
    public static String getLSID() throws MalformedLSIDException
415
    {
416
        return ((LSID) currentLSIDs.get(Thread.currentThread())).toString();
417
    }
418
}
(3-3/4)