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-06 15:09:01 -0800 (Tue, 06 Dec 2005) $'
8
 * '$Revision: 2818 $'
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.getLog( "edu.ucsb.nceas.metacat.lsid" );
63
    
64
	public void initService(LSIDServiceConfig cf) throws LSIDServerException {
65
        logger.info("Starting LSIDAuthorityMetadata.");
66
		lookup = new LSIDDataLookup();
67
	}
68

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

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

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

    
92
			String styleSheetName = null;
93
			styleSheetName = "metacat.xslt";
94
			LSIDDataLookup myLookup = new LSIDDataLookup();
95
			InputStream content = myLookup.lsidData(lsid);
96
			InputStream content2 = myLookup.lsidData(lsid);
97
			if (!isEML(content2)) {
98
				content = getEML(lsid);
99
			}
100
			content2.close();
101
			setCurrentLSID(lsid);
102
			InputStream styleSheet =
103
				getClass().getResourceAsStream(styleSheetName);
104
			TransformerFactory factory = TransformerFactory.newInstance();
105
			Transformer transformer =
106
				factory.newTransformer(new StreamSource(styleSheet));
107
			ByteArrayOutputStream out = new ByteArrayOutputStream();
108
			transformer.transform(
109
				new StreamSource(content),
110
				new StreamResult(out));
111
			content.close();
112
			clearState();
113
			return new ByteArrayInputStream(out.toByteArray());
114
		} catch (Exception e) {
115
			throw new LSIDServerException(
116
				e,
117
				"Error transforming XML for: " + lsid);
118
		}
119
	}
120

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

    
133
		return result.toString();
134

    
135
	}
136

    
137
	/**
138
	 * figure out is this inputstream is an eml document or not
139
		 */
140

    
141
	/* TODO: need a better way to figure out if this is an eml document */
142
	private boolean isEML(InputStream input) {
143

    
144
		if (input == null) {
145
			return false;
146
		}
147

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

    
168
	/**
169
	 *  this lsid points to a data object - get the
170
	     *  metadata objects which refer to this document
171
	     */
172

    
173
	private InputStream getEML(LSID theLSID) {
174

    
175
		InputStream response = null;
176

    
177
		// need to find things with this object in any of the elements
178
		// using the metacat api
179
		// get back dataset/docid and dataset/title
180

    
181
		// create the query
182
		String theQuery = getMetaCatQuery(theLSID);
183

    
184
		// get the metacat record
185
		Reader metaCatResponse = getMetaCatResponse(theQuery);
186

    
187
		// parse the metadata to get the applicable rdf information
188
		response = parseMetaCatResponse(metaCatResponse, theLSID);
189

    
190
		return response;
191

    
192
	}
193

    
194
	/** 
195
	 * given an LSID return a metacat query which will return docs mentioning this LSID
196
	 */
197

    
198
	private String getMetaCatQuery(LSID lsid) {
199
        logger.debug("getting Metacat Query for: " + lsid.toString());
200
		String ns = lsid.getNamespace();
201
		String id = lsid.getObject();
202
		String ver = lsid.getRevision();
203
		String theName = ns + "." + id + "." + ver;
204

    
205
		String theQuery = null;
206
		theQuery =
207
			"<?xml version=\"1.0\"?>\n"
208
				+ "<pathquery version=\"1.2\">\n"
209
				+ "  <querytitle>"
210
				+ theName
211
				+ " search</querytitle>\n"
212
				+ "  <returnfield>dataset/docid</returnfield>\n"
213
				+ "  <returnfield>dataset/title</returnfield>\n"
214
				+ "  <querygroup operator=\"UNION\">\n"
215
				+ "    <queryterm searchmode=\"contains\" casesensitive=\"false\">\n"
216
				+ "      <value>"
217
				+ theName
218
				+ "</value>\n"
219
				+ "      <pathexpr>anyfield</pathexpr>\n"
220
				+ "    </queryterm>\n"
221
				+ "  </querygroup>\n"
222
				+ "<pathquery>\n";
223

    
224
		return theQuery;
225

    
226
	}
227

    
228
	/* 
229
	 * given a query string, query MetaCat and return the response
230
	 */
231
	private Reader getMetaCatResponse(String query) {
232
        logger.debug("Querying the metacat server.");
233
		//  get the metacat server from the configuration file
234
		//
235
		ResourceBundle rb = ResourceBundle.getBundle("metacat-lsid");
236
		String url = rb.getString("metacatserver");
237
		Reader r = null;
238
		try {
239

    
240
			Metacat m = MetacatFactory.createMetacatConnection(url);
241
			r = m.query(new StringReader(query));
242

    
243
		} catch (MetacatInaccessibleException mie) {
244
            logger.error("Metacat Inaccessible:\n" + mie.getMessage());
245
		} catch (Exception e) {
246
			logger.error("General exception:\n" + e.getMessage());
247
		}
248
		return r;
249
	}
250

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

    
260
		String contents = getStringFromReader(reader);
261
		if (numberDocuments(contents) < 1) {
262
			response = noMetaDataResponse(theLSID);
263
		} else if (numberDocuments(contents) > 1) {
264
			response = metaDataList(contents, theLSID);
265
		} else {
266
			response = getMetaData(contents, theLSID);
267
		}
268
		return response;
269
	}
270

    
271
	/**
272
	 *  There's no metadata for this document 
273
	*/
274

    
275
	private ByteArrayInputStream noMetaDataResponse(LSID theLSID) {
276
		ResourceBundle rb = ResourceBundle.getBundle("metacat-lsid");
277
		String metadataLabels = rb.getString("metadatalabels");
278

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

    
293
		return new ByteArrayInputStream(result.getBytes());
294
	}
295

    
296
	/**
297
	 *  There's more than one metdata document
298
	     */
299

    
300
	private ByteArrayInputStream metaDataList(String contents, LSID theLSID) {
301
		ResourceBundle rb = ResourceBundle.getBundle("metacat");
302
		String metadataLabels = rb.getString("metadatalabels");
303

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

    
317
		return new ByteArrayInputStream(result.getBytes());
318
	}
319

    
320
	/**
321
	 *  There's just one metadata document 
322
	     */
323

    
324
	private ByteArrayInputStream getMetaData(String contents, LSID theLSID) {
325
		String paramString = "<param name=\"dataset/title\">";
326
		ByteArrayInputStream result = null;
327

    
328
		if (contents.indexOf(paramString) == -1) {
329
			return noMetaDataResponse(theLSID);
330
		} else {
331
			String parts[] = contents.split(paramString);
332
			String parts2[] = parts[1].split("</param>");
333
			try {
334
				LSID newLSID = new LSID(parts2[0]);
335
				result = doMetadataRequest(newLSID);
336

    
337
			} catch (MalformedLSIDException e) {
338
                logger.error("problem generating LSID: " + e);
339
				e.printStackTrace();
340
			} catch (LSIDServerException e) {
341
                logger.error("problem generating LSID: " + e);
342
				e.printStackTrace();
343
			}
344
		}
345
		return result;
346
	}
347

    
348
	/**
349
	 *  Find out how many contents are in this metacat response
350
	 *  I'm just using string stuff for this - sort of lame, but does the trick
351
	 *  more cool would be to use xml stuff
352
	 */
353
	private int numberDocuments(String contents) {
354

    
355
		String[] docSplit = contents.split("<document>");
356
		return (docSplit.length - 1);
357
	}
358

    
359
	/**
360
	 * Given a reader, return a string
361
	 */
362
	private String getStringFromReader(Reader reader) {
363
		StringBuffer response = new StringBuffer();
364

    
365
		try {
366
			BufferedReader bufReader = new BufferedReader(reader);
367

    
368
			String line = null;
369
			while ((line = bufReader.readLine()) != null) {
370
				response.append(line);
371
			}
372
			bufReader.close();
373

    
374
		} catch (IOException e) {
375
			logger.error("error getting string from reader " + e);
376
		}
377
		return response.toString();
378
	}
379

    
380
	/**
381
	 * set the LSID for the current thread
382
	 */
383
	static void setCurrentLSID(LSID lsid) {
384
		currentLSIDs.put(Thread.currentThread(), lsid);
385
	}
386

    
387
	static void clearState() {
388
		currentLSIDs.remove(Thread.currentThread());
389
	}
390

    
391
	/**
392
	 * get the current LSID for the given thread, for use in XSLT so return a string
393
	 */
394
	//	public static String getLSID() throws MalformedLSIDException {
395
	//		return ((LSID)currentLSIDs.get(Thread.currentThread())).toString();
396
	//	}
397

    
398
	public static String getLSID(
399
		org.apache.xalan.extensions.XSLProcessorContext foo,
400
		org.apache.xalan.templates.ElemExtensionCall bar)
401
		throws MalformedLSIDException {
402
		return ((LSID) currentLSIDs.get(Thread.currentThread())).toString();
403
	}
404

    
405
	public static String getLSID() throws MalformedLSIDException {
406
		return ((LSID) currentLSIDs.get(Thread.currentThread())).toString();
407
	}
408
}
(3-3/4)