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: jones $'
7
 *     '$Date: 2005-12-07 10:59:03 -0800 (Wed, 07 Dec 2005) $'
8
 * '$Revision: 2819 $'
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

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

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

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

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

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

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

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

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

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

    
91
            String styleSheetName = null;
92
            styleSheetName = "metacat.xslt";
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
            InputStream styleSheet = getClass()
102
                            .getResourceAsStream(styleSheetName);
103
            TransformerFactory factory = TransformerFactory.newInstance();
104
            Transformer transformer = factory
105
                            .newTransformer(new StreamSource(styleSheet));
106
            ByteArrayOutputStream out = new ByteArrayOutputStream();
107
            transformer.transform(new StreamSource(content),
108
                                  new StreamResult(out));
109
            content.close();
110
            clearState();
111
            return new ByteArrayInputStream(out.toByteArray());
112
        } catch (Exception e) {
113
            throw new LSIDServerException(e, "Error transforming XML for: "
114
                                             + lsid);
115
        }
116
    }
117

    
118
    private String getStringFromInputStream(InputStream input)
119
    {
120
        StringBuffer result = new StringBuffer();
121
        BufferedReader in = new BufferedReader(new InputStreamReader(input));
122
        String line;
123
        try {
124
            while ((line = in.readLine()) != null) {
125
                result.append(line);
126
            }
127
        } catch (IOException e) {
128
            logger.error("IOexception " + e);
129
        }
130

    
131
        return result.toString();
132

    
133
    }
134

    
135
    /**
136
     * figure out is this inputstream is an eml document or not
137
     * TODO: need a better way to figure out if this is an eml document 
138
     */
139
    private boolean isEML(InputStream input)
140
    {
141

    
142
        if (input == null) { return false; }
143

    
144
        int loop = 0;
145
        boolean itIsEML = false;
146
        String line = "";
147
        try {
148
            BufferedReader in = new BufferedReader(new InputStreamReader(input));
149
            while ((loop < 20) && (line != null) && (!itIsEML)) {
150
                line = in.readLine();
151
                line = line.toLowerCase();
152
                if (line.indexOf("eml:eml") != -1) {
153
                    itIsEML = true;
154
                }
155
                loop++;
156
            }
157
        } catch (IOException e) {
158
            logger.error("ioerror in LSIDAuthorityMetadata: " + e);
159
        }
160
        return itIsEML;
161
    }
162

    
163
    /**
164
     * this lsid points to a data object - get the metadata objects which refer
165
     * to this document
166
     */
167
    private InputStream getEML(LSID theLSID)
168
    {
169

    
170
        InputStream response = null;
171

    
172
        // need to find things with this object in any of the elements
173
        // using the metacat api
174
        // get back dataset/docid and dataset/title
175

    
176
        // create the query
177
        String theQuery = getMetaCatQuery(theLSID);
178

    
179
        // get the metacat record
180
        Reader metaCatResponse = getMetaCatResponse(theQuery);
181

    
182
        // parse the metadata to get the applicable rdf information
183
        response = parseMetaCatResponse(metaCatResponse, theLSID);
184

    
185
        return response;
186

    
187
    }
188

    
189
    /**
190
     * given an LSID return a metacat query which will return docs mentioning
191
     * this LSID
192
     */
193
    private String getMetaCatQuery(LSID lsid)
194
    {
195
        logger.debug("getting Metacat Query for: " + lsid.toString());
196
        String ns = lsid.getNamespace();
197
        String id = lsid.getObject();
198
        String ver = lsid.getRevision();
199
        String theName = ns + "." + id + "." + ver;
200

    
201
        String theQuery = null;
202
        theQuery = "<?xml version=\"1.0\"?>\n"
203
                   + "<pathquery version=\"1.2\">\n"
204
                   + "  <querytitle>"
205
                   + theName
206
                   + " search</querytitle>\n"
207
                   + "  <returnfield>dataset/docid</returnfield>\n"
208
                   + "  <returnfield>dataset/title</returnfield>\n"
209
                   + "  <querygroup operator=\"UNION\">\n"
210
                   + "    <queryterm searchmode=\"contains\" casesensitive=\"false\">\n"
211
                   + "      <value>" + theName + "</value>\n"
212
                   + "      <pathexpr>anyfield</pathexpr>\n"
213
                   + "    </queryterm>\n" + "  </querygroup>\n"
214
                   + "<pathquery>\n";
215

    
216
        return theQuery;
217

    
218
    }
219

    
220
    /**
221
     * given a query string, query MetaCat and return the response
222
     */
223
    private Reader getMetaCatResponse(String query)
224
    {
225
        logger.debug("Querying the metacat server.");
226
        // get the metacat server from the configuration file
227
        //
228
        ResourceBundle rb = ResourceBundle.getBundle("metacat-lsid");
229
        String url = rb.getString("metacatserver");
230
        Reader r = null;
231
        try {
232

    
233
            Metacat m = MetacatFactory.createMetacatConnection(url);
234
            r = m.query(new StringReader(query));
235

    
236
        } catch (MetacatInaccessibleException mie) {
237
            logger.error("Metacat Inaccessible:\n" + mie.getMessage());
238
        } catch (Exception e) {
239
            logger.error("General exception:\n" + e.getMessage());
240
        }
241
        return r;
242
    }
243

    
244
    /**
245
     * Given a reader which is a metacat response, parse it and return the
246
     * appropriate rdf
247
     */
248
    private InputStream parseMetaCatResponse(Reader reader, LSID theLSID)
249
    {
250
        InputStream response = null;
251
        logger.debug("Parsing the metacat response.");
252
        // if there's more than one document, then return rdf listing the
253
        // documents
254
        // otherwise get the document and return rdf based on it
255

    
256
        String contents = getStringFromReader(reader);
257
        if (numberDocuments(contents) < 1) {
258
            response = noMetaDataResponse(theLSID);
259
        } else if (numberDocuments(contents) > 1) {
260
            response = metaDataList(contents, theLSID);
261
        } else {
262
            response = getMetaData(contents, theLSID);
263
        }
264
        return response;
265
    }
266

    
267
    /**
268
     * There's no metadata for this document
269
     */
270
    private ByteArrayInputStream noMetaDataResponse(LSID theLSID)
271
    {
272
        ResourceBundle rb = ResourceBundle.getBundle("metacat-lsid");
273
        String metadataLabels = rb.getString("metadatalabels");
274

    
275
        String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
276
                        + "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" \n"
277
                        + "	xmlns:dc=\"http://purl.org/dc/elements/1.1/\" \n"
278
                        + "	xmlns:pred=\"urn:lsid:i3c.org:predicates:\" xmlns=\"urn:lsid:"
279
                        + metadataLabels
280
                        + ":predicates:\"> \n"
281
                        + "<rdf:Description rdf:about=\""
282
                        + theLSID.getLsid()
283
                        + "\"> \n"
284
                        + "	<pred:title xmlns:pred=\"http://purl.org/dc/elements/1.1/\">There is no metadata for this LSID.</pred:title>\n"
285
                        + "</rdf:Description>\n" + "</rdf:RDF>\n";
286

    
287
        return new ByteArrayInputStream(result.getBytes());
288
    }
289

    
290
    /**
291
     * There's more than one metdata document
292
     */
293
    private ByteArrayInputStream metaDataList(String contents, LSID theLSID)
294
    {
295
        ResourceBundle rb = ResourceBundle.getBundle("metacat");
296
        String metadataLabels = rb.getString("metadatalabels");
297

    
298
        String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
299
                        + "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" \n"
300
                        + "	xmlns:dc=\"http://purl.org/dc/elements/1.1/\" \n"
301
                        + "	xmlns:pred=\"urn:lsid:i3c.org:predicates:\" xmlns=\"urn:lsid:"
302
                        + metadataLabels
303
                        + ":predicates:\"> \n"
304
                        + "<rdf:Description rdf:about=\""
305
                        + theLSID.getLsid()
306
                        + "\"> \n"
307
                        + "	<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"
308
                        + "</rdf:Description>\n" + "</rdf:RDF>\n";
309

    
310
        return new ByteArrayInputStream(result.getBytes());
311
    }
312

    
313
    /**
314
     * There's just one metadata document
315
     */
316
    private ByteArrayInputStream getMetaData(String contents, LSID theLSID)
317
    {
318
        String paramString = "<param name=\"dataset/title\">";
319
        ByteArrayInputStream result = null;
320

    
321
        if (contents.indexOf(paramString) == -1) {
322
            return noMetaDataResponse(theLSID);
323
        } else {
324
            String parts[] = contents.split(paramString);
325
            String parts2[] = parts[1].split("</param>");
326
            try {
327
                LSID newLSID = new LSID(parts2[0]);
328
                result = doMetadataRequest(newLSID);
329

    
330
            } catch (MalformedLSIDException e) {
331
                logger.error("problem generating LSID: " + e);
332
                e.printStackTrace();
333
            } catch (LSIDServerException e) {
334
                logger.error("problem generating LSID: " + e);
335
                e.printStackTrace();
336
            }
337
        }
338
        return result;
339
    }
340

    
341
    /**
342
     * Find out how many contents are in this metacat response I'm just using
343
     * string stuff for this - sort of lame, but does the trick more cool would
344
     * be to use xml stuff
345
     */
346
    private int numberDocuments(String contents)
347
    {
348

    
349
        String[] docSplit = contents.split("<document>");
350
        return (docSplit.length - 1);
351
    }
352

    
353
    /**
354
     * Given a reader, return a string
355
     */
356
    private String getStringFromReader(Reader reader)
357
    {
358
        StringBuffer response = new StringBuffer();
359

    
360
        try {
361
            BufferedReader bufReader = new BufferedReader(reader);
362

    
363
            String line = null;
364
            while ((line = bufReader.readLine()) != null) {
365
                response.append(line);
366
            }
367
            bufReader.close();
368

    
369
        } catch (IOException e) {
370
            logger.error("error getting string from reader " + e);
371
        }
372
        return response.toString();
373
    }
374

    
375
    /**
376
     * set the LSID for the current thread
377
     */
378
    static void setCurrentLSID(LSID lsid)
379
    {
380
        currentLSIDs.put(Thread.currentThread(), lsid);
381
    }
382

    
383
    static void clearState()
384
    {
385
        currentLSIDs.remove(Thread.currentThread());
386
    }
387

    
388
    /**
389
     * get the current LSID for the given thread, for use in XSLT so return a
390
     * string
391
     */
392
    public static String getLSID(
393
                         org.apache.xalan.extensions.XSLProcessorContext foo,
394
                         org.apache.xalan.templates.ElemExtensionCall bar)
395
                    throws MalformedLSIDException
396
    {
397
        return ((LSID) currentLSIDs.get(Thread.currentThread())).toString();
398
    }
399

    
400
    public static String getLSID() throws MalformedLSIDException
401
    {
402
        return ((LSID) currentLSIDs.get(Thread.currentThread())).toString();
403
    }
404
}
(3-3/4)