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-11-11 12:09:01 -0800 (Fri, 11 Nov 2005) $'
8
 * '$Revision: 2737 $'
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.InputStream;
28
import java.io.ByteArrayInputStream;
29

    
30
import com.ibm.lsid.LSID;
31
import com.ibm.lsid.MetadataResponse;
32
import com.ibm.lsid.MalformedLSIDException;
33

    
34
import com.ibm.lsid.server.LSIDMetadataService;
35
import com.ibm.lsid.server.LSIDServerException;
36
import com.ibm.lsid.server.LSIDServiceConfig;
37

    
38
import com.ibm.lsid.server.LSIDRequestContext;
39

    
40
import java.io.ByteArrayOutputStream;
41
import java.io.IOException;
42
import java.io.Reader;
43
import java.io.StringReader;
44
import java.io.InputStreamReader;
45
import java.io.BufferedReader;
46

    
47
import javax.xml.transform.Transformer;
48
import javax.xml.transform.TransformerFactory;
49
import javax.xml.transform.stream.StreamResult;
50
import javax.xml.transform.stream.StreamSource;
51

    
52
import java.util.Hashtable;
53

    
54
import edu.ucsb.nceas.metacat.client.*;
55
import java.util.ResourceBundle;
56

    
57
public class LSIDAuthorityMetaData implements LSIDMetadataService {
58

    
59
	private LSIDDataLookup lookup = null;
60
	private static Hashtable currentLSIDs = new Hashtable();
61

    
62
	public void initService(LSIDServiceConfig cf) throws LSIDServerException {
63
        System.out.println("Starting LSIDAuthorityMetadata (Metacat).");
64
		lookup = new LSIDDataLookup();
65
	}
66

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

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

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

    
90
			String styleSheetName = null;
91
			styleSheetName = "metacat.xslt";
92
			LSIDDataLookup myLookup = new LSIDDataLookup();
93
			InputStream content = myLookup.lsidData(lsid);
94
			InputStream content2 = myLookup.lsidData(lsid);
95
			if (!isEML(content2)) {
96
				content = getEML(lsid);
97
			}
98
			content2.close();
99
			setCurrentLSID(lsid);
100
			InputStream styleSheet =
101
				getClass().getResourceAsStream(styleSheetName);
102
			TransformerFactory factory = TransformerFactory.newInstance();
103
			Transformer transformer =
104
				factory.newTransformer(new StreamSource(styleSheet));
105
			ByteArrayOutputStream out = new ByteArrayOutputStream();
106
			transformer.transform(
107
				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(
114
				e,
115
				"Error transforming XML for: " + lsid);
116
		}
117
	}
118

    
119
	private String getStringFromInputStream(InputStream input) {
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
			System.out.println("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
		 */
138

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

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

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

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

    
171
	private InputStream getEML(LSID theLSID) {
172

    
173
		InputStream response = null;
174

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

    
179
		// create the query
180
		String theQuery = getMetaCatQuery(theLSID);
181

    
182
		// get the metacat record
183
		Reader metaCatResponse = getMetaCatResponse(theQuery);
184

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

    
188
		return response;
189

    
190
	}
191

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

    
196
	private String getMetaCatQuery(LSID lsid) {
197
        System.out.println("getting Metacat Query for: " + lsid.toString());
198
		String ns = lsid.getNamespace();
199
		String id = lsid.getObject();
200
		String ver = lsid.getRevision();
201
		String theName = ns + "." + id + "." + ver;
202

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

    
222
		return theQuery;
223

    
224
	}
225

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

    
238
			Metacat m = MetacatFactory.createMetacatConnection(url);
239
			r = m.query(new StringReader(query));
240

    
241
		} catch (MetacatInaccessibleException mie) {
242
			System.out.println("Metacat Inaccessible:\n" + mie.getMessage());
243
		} catch (Exception e) {
244
			System.out.println("General exception:\n" + e.getMessage());
245
		}
246
		return r;
247
	}
248

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

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

    
269
	/**
270
	 *  There's no metadata for this document 
271
	*/
272

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

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

    
291
		return new ByteArrayInputStream(result.getBytes());
292
	}
293

    
294
	/**
295
	 *  There's more than one metdata document
296
	     */
297

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

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

    
315
		return new ByteArrayInputStream(result.getBytes());
316
	}
317

    
318
	/**
319
	 *  There's just one metadata document 
320
	     */
321

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

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

    
335
			} catch (MalformedLSIDException e) {
336
				System.out.println("problem generating LSID: " + e);
337
				e.printStackTrace();
338
			} catch (LSIDServerException e) {
339
				System.out.println("problem generating LSID: " + e);
340
				e.printStackTrace();
341
			}
342
		}
343
		return result;
344
	}
345

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

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

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

    
363
		try {
364
			BufferedReader bufReader = new BufferedReader(reader);
365

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

    
372
		} catch (IOException e) {
373
			System.out.println("error getting string from reader " + e);
374
		}
375
		return response.toString();
376
	}
377

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

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

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

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

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