source: other-projects/trunk/gs3-webservices-democlient/src/GS3Fedora/org/greenstone/fedora/services/FedoraGS3Connection.java@ 15222

Last change on this file since 15222 was 15222, checked in by ak19, 16 years ago

Greenstone3 web services demo-clientadded to GS3's other-projects

File size: 89.5 KB
Line 
1/**
2 *#########################################################################
3 * FedoraGS3Connection.java - works with the demo-client for Greenstone 3,
4 * of the Greenstone digital library suite from the New Zealand Digital
5 * Library Project at the * University of Waikato, New Zealand.
6 * <BR><BR>
7 * Copyright (C) 2008 New Zealand Digital Library Project
8 * <BR><BR>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 * <BR><BR>
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *########################################################################
19 */
20
21package org.greenstone.fedora.services;
22
23
24import java.io.StringReader;
25
26import org.apache.log4j.Logger;
27import org.greenstone.fedora.services.FedoraGS3Exception.AuthenticationFailedException;
28import org.greenstone.fedora.services.FedoraGS3Exception.CancelledException;
29import org.greenstone.fedora.services.FedoraGS3Exception.FedoraGS3RunException;
30import org.greenstone.fedora.services.FedoraGS3Exception.NotAFedoraServerException;
31import org.greenstone.fedora.services.FedoraToGS3Interface.Constants;
32import org.greenstone.gsdl3.util.GSXML;
33import org.w3c.dom.Document;
34import org.w3c.dom.Element;
35import org.w3c.dom.Attr;
36import org.w3c.dom.Text;
37import org.w3c.dom.NodeList;
38import org.w3c.dom.Node;
39import org.xml.sax.InputSource;
40
41import java.io.File;
42import java.util.HashMap;
43import java.util.Properties;
44import java.util.Map;
45
46import javax.swing.JOptionPane;
47
48import org.xml.sax.SAXException;
49import java.io.UnsupportedEncodingException;
50import java.io.IOException;
51import javax.net.ssl.SSLHandshakeException;
52import java.net.ConnectException;
53import java.net.MalformedURLException;
54import java.rmi.RemoteException;
55import javax.xml.parsers.ParserConfigurationException;
56import javax.xml.transform.TransformerException;
57
58/**
59 * Class that extends FedoraConnection in order to be able to use
60 * Fedora's web services to retrieve the specific datastreams of
61 * Greenstone documents stored in Fedora's repository. This class
62 * provides methods that convert those datastreams into Greenstone3
63 * XML response messages which are returned.
64 * @author ak19
65*/
66public class FedoraGS3Connection
67 extends FedoraConnection implements FedoraToGS3Interface,
68 FedoraToGS3Interface.Constants
69{
70 /** The logging instance for this class */
71 private static final Logger LOG = Logger.getLogger(
72 FedoraGS3Connection.class.getName());
73
74 /** The last part of the gSearchWSDL URL. The first part is
75 * the same as the fedora server's base url. */
76 protected static final String gSearchWSDLSuffix
77 = "gsearch/services/FgsOperations?wsdl";
78
79 /** Complete list of services that are supported our FedoraGS3 would
80 * support if everything goes well. If a connection to FedoraGSearch
81 * cannot be established, the query services will no longer be
82 * available. The actual services supported are given by member
83 * variable serviceNames. */
84 protected static final String[] SERVICES = {
85 "DocumentContentRetrieve", "DocumentMetadataRetrieve",
86 "DocumentStructureRetrieve",
87 "TextQuery", "FieldQuery",
88 "ClassifierBrowse", "ClassifierBrowseMetadataRetrieve"
89 };
90
91 /** List of services actually supported by our FedoraGS3 repository
92 * after construction. If FedoraGenericSearch can't be connected to,
93 * then query services will not be offered */
94 protected String[] serviceNames;
95
96 /** constant CHILDREN indicates that a DocumentStructureRetrieve is to
97 * return only the child nodes of a section, not any further descendants */
98 protected static final int CHILDREN = 0;
99
100 /** constant DESCENDANTS indicates that a DocumentStructureRetrieve is to
101 * return all descendants of a section */
102 protected static final int DESCENDANTS = 1;
103
104 /** The object used to connect to FedoraGenericSearch, which is used
105 * for doing full-text searching */
106 protected GSearchConnection fedoraGSearch;
107
108 /** The url for the wsdl file of FedoraGSearch's web services
109 * by default this will be the Fedora server's base URL
110 * concatenated to "gsearch/services/FgsOperations?wsdl" */
111 protected String gSearchWSDLURL;
112
113 /** 5 argument constructor is the same as that of superclass FedoraConnection:
114 * @param protocol can be either http or https
115 * @param host is the host where the fedora server is listening
116 * @param port is the port where the fedora server is listening
117 * @param fedoraServerUsername is the username for administrative
118 * authentication required to access the fedora server.
119 * @param fedoraServerPassword is the password for administrative
120 * authentication required to access the fedora server. If no password was set
121 * when installing Fedora, leave the field "".
122 * Instantiates a FedoraGS3Connection object which connects to Fedora's
123 * web services through stub classes and tries to connect to FedoraGSearch's
124 * web services through the default WSDL location for it
125 * ("gsearch/services/FgsOperations?wsdl"). If another url is to be used,
126 * call setGSearchWSDLURL(url) after the constructor instead.
127 */
128 public FedoraGS3Connection(String protocol, String host, int port,
129 String fedoraServerUsername, String fedoraServerPassword)
130 throws ParserConfigurationException, MalformedURLException,
131 SSLHandshakeException, RemoteException, AuthenticationFailedException,
132 NotAFedoraServerException, ConnectException, Exception
133 {
134 super(protocol, host, port, fedoraServerUsername, fedoraServerPassword);
135 // super() will call setInitialisationProperties(properties)
136 // And that will try to instantiate the GSearchConnection.
137 }
138
139 /** No-argument constructor which is the same as that of superclass
140 * FedoraConnection: it displays a small dialog requesting input for the
141 * host, port, administrative password and username of the fedora server.
142 * If no password was set on the fedora repository when installing it,
143 * the user can leave the password field blank. */
144 public FedoraGS3Connection()
145 throws ParserConfigurationException, MalformedURLException,
146 CancelledException, ConnectException, RemoteException,
147 SSLHandshakeException, Exception
148 {
149 super();
150 // super() will call setInitialisationProperties(properties)
151 // And that will try to instantiate the GSearchConnection.
152 }
153
154 /** Single-argument constructor which is the same as that of superclass
155 * FedoraConnection: it takes the name of the properties file where
156 * connection initialisation values may already be provided and then
157 * displays a small dialog requesting input for the host, port,
158 * administrative password and username of the fedora server showing
159 * the values in the properties file as default. If the necessary
160 * initialisation are not present in the file, they corresponding fields
161 * in the dialog will be blank.
162 * If no password was set on the fedora repository when installing it,
163 * the user can leave the password field blank. */
164 public FedoraGS3Connection(File propertiesFilename)
165 throws ParserConfigurationException, MalformedURLException,
166 CancelledException, ConnectException, RemoteException,
167 SSLHandshakeException, Exception
168 {
169 super(propertiesFilename);
170 // super() will call setInitialisationProperties(properties)
171 // And that will try to instantiate the GSearchConnection.
172 }
173
174 /** The superclass constructor calls this method passing any preset
175 * properties loaded from a propertiesFile. This method is overridden
176 * here in order to instantiate the gSearchConnection based on the
177 * gSearchWSDLURL. (If one was not provided in the properties file,
178 * gSearchWSDLURL defaults to something of the form
179 * "http://localhost:8080/fedoragsearch/services/FgsOperations?wsdl"
180 * where http://localhost:8080/fedora is the baseURL of fedora and
181 * "gsearch/services/FgsOperations?wsdl" is the default gSearchWSDLSuffix.)
182 * @param properties is the Properties Map loaded from a properties file
183 * (if there was any) which specifies such things as host and port of the
184 * FedoraServer, but can also specify the property "gSearchWsdlURL".
185 * At the end of this method, properties' "gSearchWsdlURL" will be set
186 * to whatever the final value of this.gSearchWSDLURL is.
187 */
188 protected void setInitialisationProperties(Properties properties)
189 throws ParserConfigurationException, MalformedURLException,
190 CancelledException, ConnectException, RemoteException,
191 SSLHandshakeException, Exception
192 {
193 super.setInitialisationProperties(properties);
194 // gsearchWSDL URL, if not specified, defaults to something of the form:
195 // "http://localhost:8080/fedoragsearch/services/FgsOperations?wsdl"
196 // where http://localhost:8080/fedora is the baseURL of fedora
197 this.gSearchWSDLURL = properties.getProperty(
198 "gSearchWsdlURL", this.baseURL+gSearchWSDLSuffix);
199 // Set the property to whatever this.gSearchWSDLURL is now,
200 // so that it will be written out to the properties file again
201 properties.setProperty("gSearchWsdlURL", this.gSearchWSDLURL);
202 // Create a connection to FedoraGSearch's web services:
203 initSearchFunctionality();
204 }
205
206 /** Init method that instantiates a GSearchConnection object used
207 * to work with the separate FedoraGSearch web services.
208 * The url of the WSDL for FedoraGSearch's web services is worked out
209 * from the baseURL of the Fedora server.
210 */
211 protected void initSearchFunctionality()
212 {
213 try {
214 this.fedoraGSearch = new GSearchConnection(gSearchWSDLURL);
215 this.serviceNames = SERVICES;
216 } catch(Exception e){
217 LOG.error("Cannot connect to FedoraGSearch's web services at "
218 + gSearchWSDLURL + "\nQuery services will not be available.");
219 // If an exception occurs, something has gone wrong when
220 // trying to connect to FedoraGSearch's web services. This
221 // means, we can't offer query services, as that's provided
222 // by FedoraGSearch
223 serviceNames = null;
224 int countOfNonQueryServices = 0;
225 for(int i = 0; i < SERVICES.length; i++) {
226 // do not count query services
227 if(!SERVICES[i].toLowerCase().contains("query")) {
228 countOfNonQueryServices++;
229 }
230 }
231 // Services now supported are everything except Query services
232 serviceNames = new String[countOfNonQueryServices];
233 for(int i = 0; i < SERVICES.length; i++) {
234 if(!SERVICES[i].toLowerCase().contains("query")) {
235 serviceNames[i] = SERVICES[i];
236 }
237
238 }
239 }
240 }
241
242 /** @return the gSearchWSDLURL, the url of the WSDL for the
243 * FedoraGSearch web services */
244 public String getGSearchWSDLURL() { return gSearchWSDLURL; }
245
246 /** Sets the member variable gSearchWSDLURL that specify the location of
247 * the WSDL file of FedoraGSearch's web services. Then it attempts
248 * to instantiate a connection to those web services.
249 * @param url is the new url of the GSearch web services WSDL file */
250 public void setGSearchWSDLURL(String url) {
251 gSearchWSDLURL = url;
252 initSearchFunctionality();
253 }
254
255 /** @return the array of the services actually supported by FedoraGS3 */
256 protected String[] getServiceNames() { return this.serviceNames;}
257
258 /**
259 * For finding out if the sectionNumber is given as part of the docID.
260 * @param docID is the String that contains the docPID and may also
261 * contain the section number.
262 * @return true if the document identifier docID contains a section-
263 * number, and false if it consists solely of the docPID.
264 * That is, true is returned if
265 * <pre>docID = "greenstone:colName-&lt;docPID&gt;-&lt;sectionNum&gt;"</pre>
266 * and false is returned if
267 * <pre>docID = "greenstone:colName-&lt;docPID&gt;"</pre>
268 * */
269 protected boolean containsSectionNumber(String docID) {
270 // if there are two hyphens in the docID, then there are sections
271 // (and the section number is appended at end of docID)
272 // docID = "greenstone:colName-<docPID>-<sectionNum>"
273 return (docID.lastIndexOf(HYPHEN) != docID.indexOf(HYPHEN));
274 }
275
276 /** This method will extract the docPID from docID and return it.
277 * (If a sectionNumber is suffixed to the docID, the docPID which is
278 * the prefix is returned; otherwise the docID is the docPID and is
279 * returned)
280 * @param docID is the String that contains the docPID and may also
281 * contain the section number.
282 * @return only the docPID portion of the docID.
283 */
284 protected String getDocPIDFromDocID(String docID) {
285 if(containsSectionNumber(docID))
286 return docID.substring(0, docID.lastIndexOf(HYPHEN));
287 // else (if there's no sectionNumber), docID is the docPID
288 return docID;
289 }
290
291 /** This method will return the section Number, if there's any
292 * suffixed to the docID. Otherwise it will return the empty string
293 * @param docID is the String that contains the docPID and may also
294 * contain the section number.
295 * @return only the sectionID portion of the docID - if any, else "".
296 */
297 protected String getSectionIDFromDocID(String docID) {
298 if(containsSectionNumber(docID))
299 return docID.substring(
300 docID.lastIndexOf(HYPHEN)+1, docID.length());
301 return "";
302 }
303
304 /** Given a list of collectionIDs, returns a GS3 DocumentMetadataRetrieve
305 * response message that gives the metadata for each collection identified
306 * @param collIDs is an array of fedora pids identifying collections in the
307 * fedora repository
308 * @return a GS3 DocumentMetadataRetrieve response message containing the
309 * EX metadata for all the requested collections */
310 public String getCollectionMetadata(String[] collIDs) {
311 return getMetadata(collIDs);
312 }
313
314 /** Given a list of document identifiers, a GS3 DocumentMetadataRetrieve
315 * response message is returned containing the metadata for each document.
316 * @param docIDs is an array of document identifiers (docID can either be
317 * &lt;pid&gt;s items (documents) in the fedora repository, or
318 * "&lt;pid&gt;-sectionNumber".
319 * @return a GS3 DocumentMetadataRetrieve response message containing the
320 * EX, DC, DLS metadata for all the requested documents */
321 public String getDocumentMetadata(String[] docIDs) {
322 return getMetadata(docIDs);
323 }
324
325 /** Given a collectionID, returns a GS3 DocumentMetadataRetrieve
326 * response message that gives the metadata for the collection identified
327 * @param collID is a fedora pid identifying a collection in its repository
328 * @return a GS3 DocumentMetadataRetrieve response message containing the
329 * EX metadata for the requested collection */
330 public String getCollectionMetadata(String collID) {
331 return getMetadata(new String[] {collID});
332 }
333
334 /** Given a document identifier, returns a GS3 DocumentMetadataRetrieve
335 * response message containing the metadata for the document.
336 * @param docID is a document identifier (docID can either be a &lt;pid&gt;
337 * of an item (document) in the fedora repository, or it can be
338 * "&lt;pid&gt;-sectionNumber".
339 * @return a GS3 DocumentMetadataRetrieve response message containing the
340 * EX, DC, DLS metadata for the requested document */
341 public String getDocumentMetadata(String docID) {
342 return getMetadata(new String[] {docID});
343 }
344
345 /** @return a greenstone DocumentMetadataRetrieve response for the
346 * documents or collections indicated by the docIDsOrCollIDs.
347 * @param docIDsOrCollIDs is an array of identifiers which may be either the
348 * fedora pids for collections, or otherwise may be a document identifier.
349 * In the last case, the document ID may consist of either
350 * "documentPID-sectionNumber" or may just be just fedora documentPID */
351 public String getMetadata(String[] docIDsOrCollIDs)
352 {
353 Document doc = builder.newDocument();
354 FedoraGS3RunException ex = null;
355
356 Element docNodeList = doc.createElement(
357 GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
358
359 try{
360 for(int i = 0; i < docIDsOrCollIDs.length; i++) {
361 // create the <documentNode> containing the metadata
362 // for each document docID
363 Element docNode = getMetadata(doc, docIDsOrCollIDs[i]);
364 docNodeList.appendChild(docNode);
365 }
366 } catch(Exception e) {
367 ex = new FedoraGS3RunException(e);
368 ex.setSpecifics("EX (and/or DC, DLS) metadata datastream");
369 }
370
371 Element responseMsg = createResponseMessage(doc, docNodeList, ex,
372 GSXML.REQUEST_TYPE_PROCESS, "DocumentMetadataRetrieve");
373 try{
374 return FedoraCommons.elementToFormattedString(responseMsg);
375 } catch(TransformerException e) {
376 return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
377 + " " + e;
378 }
379 }
380
381 /** Method that takes a new DOM document, as well as an identifier of either
382 * a collection or document (which may be a fedora pid for the collection
383 * or document, or may be the documentPid-sectionNumber for a document) and
384 * returns a documentNode element for it:
385 * &lt;documentNode&gt;&lt;metadataList&gt;
386 * &lt;metadata name=""&gt;value&lt;/metadata&gt;
387 * ...
388 * &lt;/metadataList&gt;&lt;/documentNode&gt;
389 * @return documentNode containing the metadata for the collection or
390 * document given by parameter ID
391 * @param id denotes a collection pid, a document pid or a docID of the
392 * form "documentpid-sectionNumber" */
393 protected Element getMetadata(Document doc, String id)
394 throws RemoteException, UnsupportedEncodingException,
395 SAXException, IOException
396 {
397 // We're going to create the documentNode nested inside the following
398 // documentNodeList:
399 // <documentNodeList>
400 // <documentNode nodeID=""><metadataList>
401 // <metadata name="">value</metadata>
402 // </metadataList></documentNode>
403 // <documentNode>...</documentNode>
404 // </documentNodeList>
405 // <documentNodeList>
406
407 // <documentNode nodeID="docID"> - the docNode on which a structure
408 // retrieve is being performed
409 Element docNode = doc.createElement(GSXML.DOC_NODE_ELEM);
410 Attr attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
411 attribute.setValue(id);
412 docNode.setAttributeNode(attribute);
413
414 // <metadataList>
415 Element metadataList = doc.createElement(
416 GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
417
418 String ex = "";
419 String dc = "";
420 String dls = "";
421 if(id.endsWith(_COLLECTION)) { // docID refers to a collection
422 // Obtain the "EX" datastream (extracted metadata) for the collection
423 ex = this.getEX(id);
424 }
425 else { // docID refers to a document
426 // work out the document's fedora PID and section ID, and then
427 // obtain the EX (extracted metadata) and DC datastreams for the doc
428
429 // Note that EX/DC for pid="greenstone:<colname>-docPID-1"
430 // is the same as for pid="greenstone:<colname>-docPID"
431 // That is, <Section id="1"> refers to the toplevel document docPID
432 // If requested for top-level document, there may also be DLS meta
433 String sectionID = getSectionIDFromDocID(id);
434 String docPID = getDocPIDFromDocID(id);
435 if(sectionID.equals("") || sectionID.equals("1")) {
436 //metadata of toplevel document is requested
437 ex = this.getEX(docPID); // slightly faster than doing
438 //getSectionEXMetadata(docID, "1")
439 dc = this.getDC(docPID);
440 dls = this.getDLS(docPID);
441 }
442 else {
443 ex = getSectionEXMetadata(docPID, sectionID);
444 dc = getSectionDCMetadata(docPID, sectionID);
445 }
446 }
447
448 // Adding in metadata sets in alphabetical order
449 // DC metadata for a top-level document is different from EX, DLS:
450 // only the element's namespace prefix is "dc", the rest of a tagname
451 // is unknown.
452 if(!dc.equals("")) {
453 addMetadataWithNamespacedTagNames(doc, metadataList,
454 dc, DC);
455 }
456
457 // Check if we were supposed to process dls and dc metadata
458 // as well. We only ever do this for top-level documents,
459 // in which case, dls and dc will be non-empty strings
460 if(!dls.equals("")) {
461 addMetadataWithFixedTagName(doc, metadataList, dls, DLS);
462 }
463
464 // we definitely have an EX metadatastream for each
465 // collection object, top-level document object,
466 // and document section item
467 addMetadataWithFixedTagName(doc, metadataList, ex, EX);
468
469 // now the metadataList has been built up
470 docNode.appendChild(metadataList);
471
472 return docNode; // return <documentNode> containing the metadata
473 }
474
475 /** This method retrieves all the metadata elements in the metaDataStream
476 * parameter of the form &lt;"metadataSetNS:metadata"&gt;"value"&lt;/metadata&gt; where
477 * metadataSetNS is the namespace of each tag, and creates a new element of
478 * the form &lt;metadata name="metadataSetNS:metadata"&gt;"value"&lt;/metadata&gt; for
479 * each. Each of these are then appended to the metadataList parameter.
480 * @param doc is the Document object using which the new metadata Elements
481 * are to be constructed
482 * @param metadataList is the &lt;metadataList&gt; Element to which the new
483 * metadata Elements are to be appended as children.
484 * @param metaDatastream the metadata datastream in string form (e.g. the
485 * Dublin Core metadata stored in the Fedora repository).
486 * @param metadataSet is the constant datastream identifier, e.g. "DC".
487 * At present this method only applies to the DC metadata as that's the only
488 * one where each tagname is different except for the constant dc: namespace.
489 */
490 protected void addMetadataWithNamespacedTagNames(Document doc,
491 Element metadataList, String metaDatastream, String metadataSet)
492 throws SAXException, IOException
493 {
494 Document src = builder.parse(
495 new InputSource(new StringReader(metaDatastream)));
496
497 // The following doesn't work for some reason: to retrieve all elements
498 // whose namespace prefix starts with "dc", we pass "*" for localName
499 //NodeList dcMetaTags = src.getElementsByTagNameNS(DC.toLowerCase(), "*");
500
501 // Longer way: get the children of the root document
502 NodeList children = src.getDocumentElement().getChildNodes();
503
504 for(int i = 0; i < children.getLength(); i++) {
505 String nodeName = children.item(i).getNodeName();
506 // check that the nodename starts with the "dc" namespace,
507 // which simultaneously ensures that the node's an element:
508 if(nodeName.startsWith(DC.toLowerCase())) {
509 // need to have a period for Greenstone instead of Fedora's colon
510 nodeName = nodeName.replace(COLON, PERIOD);
511 Element metatag = (Element)children.item(i);
512 String value = FedoraCommons.getValue(metatag);
513 // <dc:tagname>value</dc:tagname>
514 // we're going to put use this in our metadata element as
515 // <metadata name="dc:tagname">value</metadata>
516
517 // create metadata of (name, value) pairs in target DOM (doc)
518 Element metadata = doc.createElement(GSXML.METADATA_ELEM);
519 Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
520 attribute.setValue(nodeName);
521 metadata.setAttributeNode(attribute);
522 Text content = doc.createTextNode(value);
523 metadata.appendChild(content);
524 metadataList.appendChild(metadata);
525 }
526 }
527 }
528
529 /** This method retrieves all the metadata elements in the metaDataStream
530 * of the form &lt;"namespace:"metadata name="metadataName"&gt;value&lt;/metadata&gt;
531 * where "namespace" is the namespace prefix of each tag, and metadataName
532 * is the name of the metadata (like author, title). For each element
533 * it creates a corresponding new element of the form
534 * &lt;metadata name="namespace:metadataName"&gt;value&lt;/metadata&gt;. Each of these
535 * are then appended to the metadataList parameter.
536 * @param doc is the Document object using which the new metadata Elements
537 * are to be constructed
538 * @param metadataList is the &lt;metadataList&gt; Element to which the new
539 * metadata Elements are to be appended as children.
540 * @param metaDatastream the metadata datastream in string form (e.g. the
541 * EX/Greenstone extracted metadata or DLS metadata stored in the Fedora
542 * repository).
543 * @param metadataSet is the constant datastream identifier,
544 * e.g. "DLS" or "EX".
545 * At present this method applies to the DLS and EX metadata as they have
546 * constant tagnames throughout.
547 */
548 protected void addMetadataWithFixedTagName(Document doc,
549 Element metadataList, String metaDatastream, String metadataSet)
550 throws SAXException, IOException
551 {
552 // Namespace prefix can be "ex:" or "dls:"
553 String namespacePrefix = "";
554 if(!metadataSet.equals(EX)) {
555 // need to have a period for Greenstone instead of Fedora's colon
556 namespacePrefix = metadataSet.toLowerCase() + PERIOD;
557 }
558
559 Document src = builder.parse(
560 new InputSource(new StringReader(metaDatastream)));
561 NodeList metaTags = src.getElementsByTagName(
562 metadataSet.toLowerCase()+COLON+METADATA);
563 // Looking for tagnames: <ex:metadata> or <dls:metadata>
564
565 for(int i = 0; i < metaTags.getLength(); i++) {
566 Element metatag = (Element)metaTags.item(i);
567
568 // extract the metadata of (name, value) pairs from src DOM
569 // look for <metadata name="name">value</metadata>
570 String name = metatag.hasAttribute(NAME) ?
571 metatag.getAttribute(NAME) : "";
572 // sometimes, there are several metadata for the same name, in this
573 // case, look for a qualifier and append its value to the name to
574 // distinguish it uniquely:
575 if(metatag.hasAttribute(QUALIFIER)) {
576 name = name + HYPHEN + metatag.getAttribute(QUALIFIER);
577 }
578 String value = FedoraCommons.getValue(metatag);
579
580 // create metadata of (name, value) pairs in target DOM (doc)
581 Element metadata = doc.createElement(GSXML.METADATA_ELEM);
582 Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
583 attribute.setValue(namespacePrefix + name);
584 // prefix with namespace, if any
585 metadata.setAttributeNode(attribute);
586 Text content = doc.createTextNode(value);
587 metadata.appendChild(content);
588
589 metadataList.appendChild(metadata);
590 }
591 }
592
593 /** Given a document identifier, returns a GS3 DocumentMetadataRetrieve
594 * response message containing ONLY the Title metadata for the document.
595 * @param docID is a document identifier (docID can either be a &lt;pid&gt;
596 * of an item (document) in the fedora repository, or it can be
597 * "&lt;pid&gt;-sectionNumber".
598 * @return a GS3 DocumentMetadataRetrieve response message containing the
599 * Title metadata for the requested document */
600 public String getTitleMetadata(String docID) {
601 return getTitleMetadata(new String[] { docID });
602 }
603
604 /** Given a document identifier, returns a GS3 DocumentMetadataRetrieve
605 * response message containing ONLY the Title metadata for the documents.
606 * @param docIDs is a list of document identifiers (where docID can either be
607 * a &lt;pid&gt; of an item (document) in the fedora repository, or it can be
608 * "&lt;pid&gt;-sectionNumber".
609 * @return a GS3 DocumentMetadataRetrieve response message containing the
610 * Title metadata for all the requested documents */
611 public String getTitleMetadata(String[] docIDs) {
612 // Must create message of the following form:
613 // <documentNodeList><documentNode nodeID="docID">
614 // <metadataList><metadata name="Title">sometitle</metadata>
615 // </metadataList></documentNode>
616
617 Document doc = builder.newDocument();
618 FedoraGS3RunException ex = null;
619
620 Element docNodeList = doc.createElement(
621 GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
622 try{
623 for(int i = 0; i < docIDs.length; i++) {
624 Element docNode = getTitleMetadata(doc, docIDs[i]);
625 docNodeList.appendChild(docNode);
626 }
627 }catch(Exception e) {
628 ex = new FedoraGS3RunException(e);
629 ex.setSpecifics("EX metadata datastream");
630 }
631
632 Element responseMsg = createResponseMessage(doc, docNodeList, ex,
633 GSXML.REQUEST_TYPE_PROCESS, "DocumentMetadataRetrieve");
634 try{
635 return FedoraCommons.elementToFormattedString(responseMsg);
636 } catch(TransformerException e) {
637 return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
638 + " " + e;
639 }
640 }
641
642 /** Method that takes a new DOM document, as well as an identifier of either
643 * a document or document section and returns a documentNode element containing
644 * the title metadata for it:
645 * &lt;documentNode nodeID="docID"&gt;&lt;metadataList&gt;
646 * &lt;metadata name="Title"&gt;sometitle&lt;/metadata&gt;
647 * &lt;/metadataList&gt;&lt;/documentNode&gt;
648 * @return documentNode containing the metadata for the collection or
649 * document given by parameter ID
650 * @param docID denotes the id of a document or a document section, so id
651 * is either a document-pid or it's of the form documentpid-sectionNumber */
652 protected Element getTitleMetadata(Document doc, String docID)
653 throws RemoteException, UnsupportedEncodingException,
654 SAXException, IOException
655 {
656 // Returns a docNode element of the following form:
657 // <documentNode nodeID="docID">
658 // <metadataList><metadata name="Title">sometitle</metadata></metadataList>
659 // </documentNode>
660
661 // <documentNode nodeID="docID">
662 Element docNode = doc.createElement(GSXML.DOC_NODE_ELEM);
663 Attr attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
664 attribute.setValue(docID);
665 docNode.setAttributeNode(attribute);
666
667 // <metadataList>
668 Element metaList = doc.createElement(
669 GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
670 // <metadata name="Title">
671 Element metadata = doc.createElement(GSXML.METADATA_ELEM);
672 // if we connect it all up (append children), we can immediately add
673 // the name attribute into the metadata element:
674 metaList.appendChild(metadata);
675 docNode.appendChild(metaList);
676 metadata.setAttribute(GSXML.NAME_ATT, TITLE); // immediately add attribute
677
678 String title = "";
679 String sectionID = getSectionIDFromDocID(docID);
680 String docPID = getDocPIDFromDocID(docID);
681
682 // check if title of toplevel document is requested
683 if(sectionID.equals(""))
684 title = this.getDocTitle(docPID);
685 else { // title of document section
686 title = this.getSectionTitle(docPID, sectionID);
687 }
688
689 metadata.appendChild(doc.createTextNode(title));
690
691 return docNode;
692 }
693
694
695 /** @return the documentStructure of the document or section given by docID.
696 * The structure is returned in the XML format of a Greenstone3
697 * DocumentStructureRetrieve response message. This method returns the entire
698 * subSection of the docID (that is, all descendants included).
699 * @param docID the identifier for the document whose structure is required.
700 * This is of the format "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;"
701 * OR "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-&lt;sectioNumber&gt;"
702 * where "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-1" is the same as
703 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;" and will return the
704 * same response */
705 public String getDocumentStructure(String docID) {
706 return getStructure(new String[]{docID}, DESCENDANTS);
707 }
708
709 /** @return a view of the structure of the document or section given by docID
710 * which contains only the section and its direct children. This structure is
711 * returned in the XML format of a Greenstone3 DocumentStructureRetrieve
712 * response message.
713 * @param docID the identifier for the document whose structure is required.
714 * This is of the format "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;"
715 * OR "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-&lt;sectioNumber&gt;"
716 * where "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-1" is the same as
717 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;" and will return the
718 * same response */
719 public String getChildren(String docID) {
720 return getStructure(new String[]{docID}, CHILDREN);
721 }
722
723 /** @return the documentStructure of the documents or sections given by docIDs.
724 * The structure is returned in the XML format of a Greenstone3
725 * DocumentStructureRetrieve response message. This method returns the entire
726 * subSection of each docID (that is, all descendants included).
727 * @param docIDs is an array of identifiers for the documents whose structures
728 * are required.
729 * This is of the format "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;"
730 * OR "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-&lt;sectioNumber&gt;"
731 * where "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-1" is the same as
732 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;" and will return the
733 * same response */
734 public String getDocumentStructure(String[] docIDs) {
735 return getStructure(docIDs, DESCENDANTS);
736 }
737
738 /** @return the documentStructure of the documents or sections given by docIDs
739 * but only the sections and their children (not any further descendants).
740 * The structure is returned in the XML format of a Greenstone3
741 * DocumentStructureRetrieve response message.
742 * @param docIDs the identifiers for the documents whose structures are
743 * required. The docids are of the format "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;"
744 * OR "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-&lt;sectioNumber&gt;"
745 * where "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-1" is the same as
746 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;" and will return the
747 * same response */
748 public String getChildren(String[] docIDs) {
749 return getStructure(docIDs, CHILDREN);
750 }
751
752 /**
753 * Returns a greenstone3 DocumentStructureRetrieve XML response message
754 * containing the document structures for the given docIDs.
755 * Similar to FedoraConnection.getTOC(), but instead of fedora formatted XML,
756 * greenstone formatted XML is returned. The requested section of the table
757 * of contents (TOC) for a document is converted into the greenstone3 xml
758 * format that is returned upon DocumentStructureRetrieve requests.
759 * @param docIDs the documentIDs for which the section's structure is returned;
760 * where a docID is either a fedora pid &lt;docPID&gt; or &lt;docPID&gt;-&lt;sectionNumber&gt;.
761 * @param levels - either CHILDREN or DESCENDANTS.
762 * CHILDREN returns only the first-level descendants (children) of the
763 * requested document sections indicated by docIDs.
764 * DESCENDANTS returns all descendants of all the document-sections denoted by
765 * docIDs.
766 * @return a greenstone3 DocumentStructureRetrieve XML response message in
767 * String format with the structure of the docIDs requested.
768 */
769 protected String getStructure(String[] docIDs, int levels)
770 {
771 Document doc = builder.newDocument();
772 FedoraGS3RunException ex = null;
773 // <documentNodeList>
774 Element docNodeList = doc.createElement(
775 GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
776
777 try{
778 // append the <documentNodes> for the docIDs
779 // to the docNodeList
780 getStructureElement(docNodeList, docIDs, levels);
781 } catch(Exception e) {
782 ex = new FedoraGS3RunException(e);
783 ex.setSpecifics("(requested portion of) TOC datastream");
784 }
785 // insert our <documentNodeList> into a GS3 response message
786 Element responseMsg = createResponseMessage(doc, docNodeList, ex,
787 GSXML.REQUEST_TYPE_PROCESS, "DocumentStructureRetrieve");
788 try{
789 return FedoraCommons.elementToFormattedString(responseMsg);
790 } catch(TransformerException e) {
791 return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
792 + " " + e;
793 }
794 }
795
796 /** Given a &lt;documentNodeList&gt; portion of a greenstone3
797 * DocumentStructureRetrieve XML response message, this method will populate
798 * it with the &lt;documentNodes&gt; that represent the structure of the given docIDs.
799 * @param docNodeList is a &lt;documentNodeList&gt; to which &lt;documentNodes&gt; of
800 * the doc structures are appended.
801 * @param docIDs the documentIDs for which the section's structure is returned;
802 * where a docID is either a fedora pid &lt;docPID&gt; or &lt;docPID&gt;-&lt;sectionNumber&gt;.
803 * @param levels - either CHILDREN or DESCENDANTS.
804 * CHILDREN returns only the first-level descendants (children) of the
805 * requested document sections indicated by docIDs.
806 * DESCENDANTS returns all descendants of all the document-sections denoted by
807 * docIDs.
808 */
809 protected void getStructureElement(Element docNodeList,
810 String[] docIDs, int levels)
811 throws RemoteException, UnsupportedEncodingException, SAXException,
812 IOException
813 {
814 // process each docID
815 for(int i = 0; i < docIDs.length; i++) {
816 // work out the document's fedora PID and section ID
817 String sectionID = getSectionIDFromDocID(docIDs[i]);
818 String docPID = getDocPIDFromDocID(docIDs[i]);
819
820 // get the required section, along with children or descendants
821 Element srcDocElement = null;
822 if(levels == CHILDREN) // get the requested section with its children
823 srcDocElement = this.getChildrenOfSectionXML(docPID, sectionID);
824 else // levels == DESCENDANTS, get the section with all its descendants
825 srcDocElement = this.getSubsectionXML(docPID, sectionID);
826
827 // copy-and-convert that structure into a structure format for GS3
828 Element docNode = getStructure(docNodeList.getOwnerDocument(),
829 docIDs[i], docPID, srcDocElement);
830
831 // add it to our list of documentNodes
832 docNodeList.appendChild(docNode);
833 }
834 }
835
836 /**
837 * Takes the portion of the XML document outlining the structure of the
838 * document (section)--in the format this is stored in Fedora--and returns
839 * Greenstone 3 DOM XML format for outlining document structure.
840 * @return a &lt;documentNode&gt; element that contains a greenstone3
841 * DocumentStructureRetrieve XML corresponding to the parameter Element section
842 * (which is in fedora XML), for the document indicated by docID.
843 * @param requestingDocID is the identifier of the document for which the
844 * structure was requested. It's this document's children or descendants that
845 * will be returned. Note that this is not always the same as (clear from)
846 * parameter docID.
847 * @param docID is the documentID for which the section's structure is
848 * returned where docID = "docPID-sectionNumber".
849 * @param section - the fedora section XML that is being mirrored in
850 * greenstone3 format.
851 */
852 protected Element getStructure(Document doc, String requestingDocID,
853 String docID, Element section)
854 {
855 // we want to mirror the section's DOM (given in fedora XML) in
856 // greenstone3's XML for a DocumentStructureRetrieve response.
857
858 // <documentNode nodeID="docID"> - the docNode on which a structure retrieve
859 // is being performed
860 Element docNode = doc.createElement(GSXML.DOC_NODE_ELEM);
861 Attr attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
862 attribute.setValue(requestingDocID); //requestingDocID.replace(HYPHEN+SECTION, "")
863 docNode.setAttributeNode(attribute);
864
865 // <nodeStructure>
866 Element nodeStructure = doc.createElement(GSXML.NODE_STRUCTURE_ELEM);
867
868 // <documentNode nodeID="docID" docType="hierarchy" nodeType="root">
869 Element rootNode = createDocNodeFromSubsection(doc, section, docID);
870
871 // fills in the subtree of the rootNode in our nodeStructure element
872 createDocStructure(doc, section, rootNode, docID);
873 //where section represents the root section
874
875 nodeStructure.appendChild(rootNode);
876 docNode.appendChild(nodeStructure);
877 return docNode;
878 }
879
880 /** Recursive method that creates a documentStructure mirroring parameter
881 * section, starting from parameter parent down to all descendants
882 * @param section is the XML &lt;Section&gt; in the fedora repository's TOC
883 * for the docPID whose substructure is to be mirrored
884 * @param parent is the XML documentNode in the greenstone repository whose
885 * descendants created by this method will correspond to the descendants of
886 * parameter section.
887 * @param doc is the document containing the parent;
888 * @param docPID is the prefix of all nodeIDs in the parent's structure
889 */
890 protected void createDocStructure(
891 Document doc, Element section, Element parent, String docPID)
892 {
893 // get the section's children (if any)
894 NodeList children = section.getChildNodes();
895 for(int i = 0; i < children.getLength(); i++) {
896 Node n = children.item(i);
897
898 if(n.getNodeName().equals(SECTION_ELEMENT)) {
899 //then we know it's an element AND that its tagname is "Section"
900 Element subsection = (Element)n;
901 Element child = createDocNodeFromSubsection(doc, subsection, docPID);
902 parent.appendChild(child);
903
904 // recursion call on newly found child-element and subsection
905 createDocStructure(doc, subsection, child, docPID);
906 }
907 }
908 }
909
910 /** Given a particular subsection element, this method creates a
911 * Greenstone3 DocumentNode element that mirrors it.
912 * @param doc is the document that will contain the created DocumentNode
913 * @param docID is the prefix of all nodeIDs in the parent's structure
914 * @param subSection is the XML &lt;Section&gt; in the fedora repository's
915 * TOC for the docPID which will be mirrored in the greenstone XML
916 * documentNode that will be returned.
917 * @return a greenstone &lt;documentNode&gt; that represents the fedora TOC's
918 * &lt;Section&gt; element passed as parameter subSection. */
919 protected Element createDocNodeFromSubsection(
920 Document doc, Element subSection, String docID)
921 {
922 Element docNode = doc.createElement(GSXML.DOC_NODE_ELEM);
923 Attr docType = doc.createAttribute(GSXML.DOC_TYPE_ATT);
924 docType.setValue(GSXML.DOC_TYPE_HIERARCHY);
925 docNode.setAttributeNode(docType);
926
927 Attr nodeID = doc.createAttribute(GSXML.NODE_ID_ATT);
928 String sectionID = subSection.hasAttribute(ID) ?
929 subSection.getAttribute(ID) : "";
930 nodeID.setValue(docID + HYPHEN + sectionID);
931 docNode.setAttributeNode(nodeID);
932
933 Attr nodeType = doc.createAttribute(GSXML.NODE_TYPE_ATT);
934 if(sectionID.equals("1")) { // root case
935 nodeType.setValue(GSXML.NODE_TYPE_ROOT);
936 // reset the attribute without the section number
937 docNode.setAttribute(GSXML.NODE_ID_ATT, docID);
938 }
939 else if(subSection.getElementsByTagName(SECTION_ELEMENT).getLength() > 0)
940 // this section has further <Section> children, so it's an internal node
941 nodeType.setValue(GSXML.NODE_TYPE_INTERNAL);
942 else if(subSection.hasAttribute(TYPE))
943 nodeType.setValue(GSXML.NODE_TYPE_INTERNAL);
944 else // leaf
945 nodeType.setValue(GSXML.NODE_TYPE_LEAF);
946 docNode.setAttributeNode(nodeType);
947 return docNode;
948 }
949
950
951 /** Given an identifier that is either a docPID or a concatenation of
952 * docPID+sectionID, this method works out the fedora assigned docPID and
953 * sectionID and then calls getContentBody(docPID, sectionID) with those.
954 * @param docID is expected to be of the form
955 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-&lt;sectionNumber&gt;" or
956 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;"
957 * If it is "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;", then the content for
958 * "greenstone:&lt;collectionName&gt;-1" ("greenstone:&lt;collectionName&gt;-Section1")
959 * is returned! */
960 public String getContent(String docID) {
961 return this.getContent(new String[]{docID});
962 }
963
964 /** Given an identifier that is a concatenation of docID+sectionID, this
965 * method works out the fedora assigned docPID and sectionID and then calls
966 * getContentBody(docPID, sectionID) with those.
967 * @param docIDs is an array of document identifiers of the form
968 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-&lt;sectionNumber&gt;"
969 * If it is "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;", then the content for
970 * "greenstone:&lt;collectionName&gt;-Section1" is returned! */
971 public String getContent(String[] docIDs) {
972 Document doc = builder.newDocument();
973 FedoraGS3RunException ex = null;
974
975 //<documentNodeList>
976 Element docNodeList = doc.createElement(
977 GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
978
979 try{
980 for(int i = 0; i < docIDs.length; i++) {
981 // get the sectionID and docPID from the docID
982 String sectionID = this.removePrefix(
983 getSectionIDFromDocID(docIDs[i]), SECTION);
984 String docPID = getDocPIDFromDocID(docIDs[i]);
985 if(sectionID.equals("")) // if no section is specified, get
986 sectionID = "1"; // get the content for Section id="1"
987
988 // Get the contents for the requested section of document docPID
989 String sectionContent = this.getContentBody(docPID, sectionID);
990
991 // set the nodeID attribute
992 Element docNode = doc.createElement(GSXML.DOC_NODE_ELEM);
993 Attr nodeId = doc.createAttribute(GSXML.NODE_ID_ATT);
994
995 nodeId.setValue(docIDs[i]); // just set the docID which will contain
996 // the docPID (and sectionID if already present)
997
998 docNode.setAttributeNode(nodeId);
999 // set the text content to what was retrieved
1000 Element nodeContent = doc.createElement(GSXML.NODE_CONTENT_ELEM);
1001 Text textNode = doc.createTextNode(sectionContent);
1002
1003 nodeContent.appendChild(textNode);
1004 docNode.appendChild(nodeContent);
1005 //add the documentNode to the docNodeList
1006 docNodeList.appendChild(docNode);
1007 }
1008 } catch(Exception e) {
1009 ex = new FedoraGS3RunException(e);
1010 ex.setSpecifics("requested doc Section datastream");
1011 }
1012 Element responseMsg = createResponseMessage(doc, docNodeList, ex,
1013 GSXML.REQUEST_TYPE_PROCESS, "DocumentContentRetrieve");
1014 try{
1015 return FedoraCommons.elementToFormattedString(responseMsg);
1016 } catch(TransformerException e) {
1017 return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
1018 + " " + e;
1019 }
1020 }
1021
1022 /** Gets the contents of a textNode from a section.
1023 * @return the text content of a section.
1024 * @param docPID the pid of the document from which a section's text is to
1025 * be retrieved.
1026 * @param sectionID is the section identifier of the document denoted by
1027 * docPID whose text is to be returned.
1028 */
1029 protected String getContentBody(String docPID, String sectionID)
1030 throws RemoteException, UnsupportedEncodingException,
1031 SAXException, IOException
1032 {
1033 String section = this.getSection(docPID, sectionID);
1034
1035 // the content is nested inside a <Section> element,
1036 // we extract it from there:
1037 InputSource source = new InputSource(new StringReader(section));
1038 Document doc = builder.parse(source);
1039
1040 // The document Element is the <Section> we want.
1041 // Get its text contents:
1042 section = FedoraCommons.getValue(doc.getDocumentElement());
1043
1044 // we are going to remove all occurrences of "_httpdocimg_/"
1045 // that precede associated filenames, because that's a GS3
1046 // defined macro for resolving relative urls. It won't help
1047 // with documents stored in fedora.
1048 section = section.replaceAll(GS3FilePathMacro+"/", "");
1049 return section;
1050 }
1051
1052 /** Here we create the greenstone's response message element:
1053 * &lt;message&lg;&lt;response&gt;&lt;content&gt;&lt;/response&gt;&lt;/message&gt;
1054 * @return a greenstone response-message element.
1055 * @param doc - the Document object which should me used to create the
1056 * &lt;message&gt; and &lt;response&gt; elements
1057 * @param content - the element that is to be nested inside &lt;response&gt;
1058 * @param ex - any exception that occurred when trying to create
1059 * the content parameter
1060 * @param responseType - the value for the type attribute of &lt;response&gt;,
1061 * such as "describe", "retrieve", "browse", "query"...
1062 * @param originator - indiates the collectionName or service (like
1063 * DocumentContentRetrieve) from where this response message originates
1064 */
1065 protected Element createResponseMessage(Document doc, Element content,
1066 Exception ex, String responseType, String originator)
1067 {
1068 Element response = doc.createElement(GSXML.RESPONSE_ELEM);
1069 // from = "FedoraGS3"
1070 Attr attribute = doc.createAttribute(GSXML.FROM_ATT);
1071 String from = originator.equals("") ? FEDORA_GS3
1072 : FEDORA_GS3+"/"+originator;
1073
1074 attribute.setValue(from);
1075 response.setAttributeNode(attribute);
1076
1077 // type = "describe" or "process" - whatever's given in requestType:
1078 attribute = doc.createAttribute(GSXML.TYPE_ATT);
1079 attribute.setValue(responseType);
1080 response.setAttributeNode(attribute);
1081
1082 if(content != null)
1083 response.appendChild(content);
1084
1085 // we'll create an error element for RemoteExceptions (web service problems)
1086 // and UnsupportedEncodingExceptions and
1087 if(ex != null) {
1088 Element error = doc.createElement(GSXML.ERROR_ELEM);
1089 error.appendChild(doc.createTextNode(ex.getMessage()));
1090 // now append the error to the <response> element (after
1091 // the content element whatever that was)
1092 response.appendChild(error);
1093 }
1094
1095 Element message = doc.createElement(GSXML.MESSAGE_ELEM);
1096 message.appendChild(response);
1097 doc.appendChild(message);
1098 return message;
1099 }
1100
1101 /** @return a &lt;serviceList&gt; Element as defined by GS3: containing all the
1102 * services (denoted by &lt;service&gt; elements) that are supported by FedoraGS3.
1103 * At present these are: DocumentContentRetrieve, DocumentMetadataRetrieve,
1104 * DocumentStructureRetrieve, TextQuery, FieldQuery, ClassifierBrowse,
1105 * ClassifierBrowseMetadataRetrieve (as indicated by member var serviceNames).
1106 * @param doc - the Document object which should me used to create the
1107 * &lt;serviceList&gt; element */
1108 protected Element createServiceList(Document doc)
1109 {
1110 Element serviceList = doc.createElement(
1111 GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
1112
1113 for(int i = 0; i < serviceNames.length; i++) {
1114 // create the <service name="serviceName[i]" type="servicetype" />
1115 Element service = doc.createElement(GSXML.SERVICE_ELEM);
1116
1117 Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
1118 attribute.setValue(serviceNames[i]);
1119 service.setAttributeNode(attribute);
1120
1121 attribute = doc.createAttribute(GSXML.TYPE_ATT);
1122 if(serviceNames[i].equals("ClassifierBrowse")) //browseTitlesByLetter
1123 attribute.setValue(GSXML.SERVICE_TYPE_BROWSE);
1124 else if(serviceNames[i].contains("Query")) // search services
1125 attribute.setValue(GSXML.SERVICE_TYPE_QUERY);
1126 else
1127 attribute.setValue(GSXML.SERVICE_TYPE_RETRIEVE);
1128 service.setAttributeNode(attribute);
1129
1130 // add the service element to the serviceList element
1131 // <serviceList><service /></serviceList>
1132 serviceList.appendChild(service);
1133 }
1134 return serviceList;
1135 }
1136
1137 /** @return a GS3 response message for a describe services request:
1138 * indicating the list of services supported by the Fedora-Greenstone
1139 * interface. These are DocumentContentRetrieve, DocumentMetadataRetrieve,
1140 * DocumentStructureRetrieve, ClassifierBrowse, TextQuery, FieldQuery,
1141 * ClassifierBrowseMetadataRetrieve - as indicated by member variable
1142 * serviceNames. */
1143 public String getServiceList()
1144 {
1145 Document doc = builder.newDocument();
1146 Element serviceList = createServiceList(doc);
1147 // make <serviceList> the body of the responseMessage:
1148 // <message><response><serviceList></response></message>
1149 Element responseMsg = createResponseMessage(doc, serviceList, null,
1150 GSXML.REQUEST_TYPE_DESCRIBE, "");
1151 try {
1152 return FedoraCommons.elementToFormattedString(responseMsg);
1153 }catch(TransformerException e) {
1154 return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
1155 + " " + e;
1156 }
1157 }
1158
1159 /** @return a GS3 describe response message listing the collections and
1160 * collection-specific metadata stored in the Fedora-Greenstone repository. */
1161 public String getCollectionList()
1162 {
1163 Document doc = builder.newDocument();
1164 FedoraGS3RunException ex = null; // any RemoteException
1165
1166 // create the <collectionList /> element
1167 Element collectionList = doc.createElement(
1168 GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
1169 try{
1170 String[] collectionNames = this.getCollectionNames(
1171 this.getCollections()); // this line could throw RemoteException
1172 for(int i = 0; i < collectionNames.length; i++) {
1173 // create the <collection name="somename" /> element
1174 Element collection = doc.createElement(GSXML.COLLECTION_ELEM);
1175 Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
1176 attribute.setValue(collectionNames[i]);
1177 collection.setAttributeNode(attribute);
1178
1179 // append the <collection> element as child of <collectionList>
1180 collectionList.appendChild(collection);
1181
1182 //if(collection.hasAttribute(GSXML.NAME_ATT))
1183 //LOG.debug(collection.getAttribute(GSXML.NAME_ATT));
1184 }
1185 } catch(RemoteException e) { // if this happens, perhaps it's because it
1186 // can't find Greenstone collections in fedora repository?
1187 ex = new FedoraGS3RunException(e);
1188 ex.setSpecifics(
1189 "greenstone collections in fedora repository");
1190 }
1191
1192 // make <collectionList> the body of the responseMessage:
1193 // <message><response><collectionList></response></message>
1194 Element responseMsg = createResponseMessage(doc, collectionList, ex,
1195 GSXML.REQUEST_TYPE_DESCRIBE, "");
1196 try{
1197 return FedoraCommons.elementToFormattedString(responseMsg);
1198 }catch(TransformerException e) {
1199 return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
1200 + " " + e;
1201 }
1202 }
1203
1204 /** @return a GS3 describe response message for a collection in the
1205 * Fedora-Greenstone repository.
1206 * @param collectionName - the name of the collection that is to be described.
1207 * It will be converted to a fedora collection pid, which is of the form
1208 * "greenstone:&lt;collectionName&gt;-collection". */
1209 public String describeCollection(String collectionName)
1210 {
1211 Document doc = builder.newDocument();
1212 FedoraGS3RunException ex = null;
1213
1214 Element collection = doc.createElement(GSXML.COLLECTION_ELEM);
1215 Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
1216 attribute.setValue(collectionName);
1217 collection.setAttributeNode(attribute);
1218
1219 //<displayItem assigned="true" lang="en" name="name">
1220 //"some display name"</displayItem>
1221 Element displayItem = doc.createElement(GSXML.DISPLAY_TEXT_ELEM);
1222
1223 attribute = doc.createAttribute(GSXML.LANG_ATT);
1224 attribute.setValue(this.lang);
1225 displayItem.setAttributeNode(attribute);
1226
1227 attribute = doc.createAttribute(GSXML.NAME_ATT);
1228 attribute.setValue(GSXML.DISPLAY_TEXT_NAME);
1229 displayItem.setAttributeNode(attribute);
1230
1231 try{
1232 Text textNode = doc.createTextNode(
1233 this.getCollectionTitle(getCollectionPID(collectionName)));
1234 displayItem.appendChild(textNode);
1235 } catch(Exception e) {
1236 // can't find Greenstone collections in fedora repository or problem
1237 // getting their titles from their metadata datastream?
1238 ex = new FedoraGS3RunException(e);
1239 ex.setSpecifics("greenstone collections or their metadata"
1240 + "in the fedora repository");
1241 }
1242 // now append the displayItem element as child of the collection element
1243 collection.appendChild(displayItem);
1244 // get the <serviceList> and add it into the collection description.
1245 // Services for all collections in the FedoraGS3 repository are the
1246 // same, offering a ClassifierBrowse to browse titles by starting letter
1247 // and DocRetrieve services: Content, Metadata and Structure.
1248
1249 Element serviceList = createServiceList(doc);
1250 collection.appendChild(serviceList);
1251
1252 Element responseMsg = createResponseMessage(doc, collection, ex,
1253 GSXML.REQUEST_TYPE_DESCRIBE, collectionName);
1254 try{
1255 return FedoraCommons.elementToFormattedString(responseMsg);
1256 }catch(TransformerException e) {
1257 return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
1258 + " " + e;
1259 }
1260 }
1261
1262 /** @return a GS3 describe response message for the services of a collection
1263 * in the Fedora-Greenstone repository. So far, these services are the same for
1264 * all fedora collections: they are the services given in member variable
1265 * serviceNames: DocumentContent/Metadata/StructureRetrieve, ClassifierBrowse,
1266 * ClassifierBrowseMetadataRetrieve.
1267 * @param collectionName - the name of the collection whose services are to
1268 * be described. It will be converted to a fedora collection pid, which is of
1269 * the form "greenstone:&lt;collectionName&gt;-collection". */
1270 public String describeCollectionServices(String collectionName)
1271 {
1272 Document doc = builder.newDocument();
1273
1274 Element collection = doc.createElement(GSXML.COLLECTION_ELEM);
1275 Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
1276 attribute.setValue(collectionName);
1277 collection.setAttributeNode(attribute);
1278
1279 Element serviceList = createServiceList(doc);
1280 collection.appendChild(serviceList);
1281
1282 Element responseMsg = createResponseMessage(doc, collection, null,
1283 GSXML.REQUEST_TYPE_DESCRIBE, collectionName);
1284 try{
1285 return FedoraCommons.elementToFormattedString(responseMsg);
1286 }catch(TransformerException e) {
1287 return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
1288 + " " + e;
1289 }
1290 }
1291
1292 /** All collections in this Digital Library (Fedora Repository) share
1293 * the same services, so this method returns the same as
1294 * describeCollectionService(collName, serviceName).
1295 * @return a GS3 describe response message for the requested service
1296 * of the given collection. DocumentContent/Metadata/StructureRetrieve
1297 * return nothing special except their names; browse (and any query)
1298 * return more complex XML responses.
1299 * All collections in this Digital Library (Fedora Repository) share
1300 * the same services, so this method returns the same as
1301 * describeService(serviceName).
1302 * @param serviceName - the name of the service in the collection which is to
1303 * be described.*/
1304 public String describeService(String serviceName)
1305 {
1306 // For all the *retrieve* services (incl ClassifierBrowseMetadataRetrieve)
1307 // we return:
1308 // <message><response from="<name>Retrieve" type="describe">
1309 // <service name="<name>Retrieve" type="retrieve" /></response></message>
1310 // But for browse (and any query) service, we return the data necessary
1311 // for displaying it
1312
1313 Document doc = this.builder.newDocument();
1314 Element service = doc.createElement(GSXML.SERVICE_ELEM);
1315 Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
1316 attribute.setValue(serviceName);
1317 service.setAttributeNode(attribute);
1318
1319 attribute = doc.createAttribute(GSXML.TYPE_ATT);
1320
1321 if(serviceName.toLowerCase().endsWith("retrieve"))
1322 attribute.setValue(GSXML.SERVICE_TYPE_RETRIEVE);
1323
1324 else if(serviceName.toLowerCase().contains("browse")) {
1325 attribute.setValue(GSXML.SERVICE_TYPE_BROWSE);
1326
1327 // we need name and description <displayItem> elements
1328 Element displayItem
1329 = createNameValuePairElement(doc,
1330 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_NAME, "Browse");
1331 service.appendChild(displayItem);
1332
1333 displayItem = createNameValuePairElement(doc,
1334 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_DESCRIPTION,
1335 "Browse pre-defined classification hierarchies");
1336 service.appendChild(displayItem);
1337
1338 // now need a classifierList
1339 Element classifierList = doc.createElement(
1340 GSXML.CLASSIFIER_ELEM+GSXML.LIST_MODIFIER);
1341
1342 int classifierNum = 1;
1343 // append a <classifier content="some letter" name="CL#">
1344 // for each letter of the alphabet:
1345 Element classifier = createClassifierElement(doc, "TitleByLetter",
1346 classifierNum++, "titles (by letter)", "Browse titles by letter");
1347 // now add this <classifier> to the <classifierList>
1348 classifierList.appendChild(classifier);
1349
1350 // ANY MORE CLASSIFIERS? ADD THEM HERE
1351
1352 service.appendChild(classifierList);
1353 } // ELSE check for whether it is a query service
1354 else if(serviceName.toLowerCase().contains("query")) {
1355 attribute.setValue(GSXML.SERVICE_TYPE_QUERY);
1356 if(serviceName.equals("TextQuery"))
1357 describeTextQueryService(service);
1358 else if(serviceName.equals("FieldQuery"))
1359 describeFieldQueryService(service);
1360 }
1361
1362 // don't forget to add the type attribute to the service!
1363 service.setAttributeNode(attribute);
1364
1365 String from = serviceName;
1366
1367 Element responseMsg = createResponseMessage(doc, service, null,
1368 GSXML.REQUEST_TYPE_DESCRIBE, from);
1369 try{
1370 return FedoraCommons.elementToFormattedString(responseMsg);
1371 }catch(TransformerException e) {
1372 return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
1373 + " " + e;
1374 }
1375 }
1376
1377 /** Appends children to the parameter service Element that make the
1378 * final service Element into a describe response XML for FedoraGS3's
1379 * TextQuery service.
1380 * @param service is the service Element that is being filled out. */
1381 protected void describeTextQueryService(Element service) {
1382 Document doc = service.getOwnerDocument();
1383 // we need name, submit (button) and description <displayItem> elements
1384 Element displayItem = createNameValuePairElement(doc,
1385 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_NAME,
1386 "Text Search");
1387 service.appendChild(displayItem);
1388
1389 displayItem = createNameValuePairElement(doc,
1390 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_SUBMIT, "Search");
1391 service.appendChild(displayItem);
1392
1393 displayItem = createNameValuePairElement(doc,
1394 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_DESCRIPTION,
1395 "Title and full-text search service");
1396 service.appendChild(displayItem);
1397
1398 //create the <paramList>
1399 Element paramList = doc.createElement(
1400 GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
1401
1402 // we ignore granularity to search at: it will always be
1403 // document and section level
1404 // we ignore casefolding: always on (that is, case is irrelevant)
1405 // we ignore document display order: always ranked
1406
1407 // Constructing the following:
1408 // <param default="100" name="maxDocs" type="integer">
1409 // <displayItem name="name">Maximum hits to return</displayItem>
1410 // </param>
1411 Element param = doc.createElement(GSXML.PARAM_ELEM);
1412
1413 Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
1414 attribute.setValue(MAXDOCS);
1415 param.setAttributeNode(attribute);
1416
1417 attribute = doc.createAttribute(GSXML.DEFAULT_ATT);
1418 attribute.setValue("100");
1419 param.setAttributeNode(attribute);
1420
1421 attribute = doc.createAttribute(GSXML.TYPE_ATT);
1422 attribute.setValue(GSXML.PARAM_TYPE_INTEGER);
1423 param.setAttributeNode(attribute);
1424
1425 displayItem = createNameValuePairElement(doc,
1426 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_NAME,
1427 "Maximum hits to return");
1428 param.appendChild(displayItem);
1429
1430 paramList.appendChild(param);
1431
1432 // Constructing the following:
1433 // <param name="query" type="string">
1434 // <displayItem name="name">Query string</displayItem>
1435 // </param>
1436 param = doc.createElement(GSXML.PARAM_ELEM);
1437
1438 attribute = doc.createAttribute(GSXML.NAME_ATT);
1439 attribute.setValue(QUERY);
1440 param.setAttributeNode(attribute);
1441
1442 attribute = doc.createAttribute(GSXML.TYPE_ATT);
1443 attribute.setValue(GSXML.PARAM_TYPE_STRING);
1444 param.setAttributeNode(attribute);
1445
1446 displayItem = createNameValuePairElement(doc,
1447 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_NAME,
1448 "Query string");
1449 param.appendChild(displayItem);
1450
1451 paramList.appendChild(param);
1452
1453 service.appendChild(paramList);
1454 }
1455
1456 /** Appends children to the parameter service Element that make the
1457 * final service Element into a describe response XML for FedoraGS3's
1458 * FieldQuery service.
1459 * @param service is the service Element that is being filled out. */
1460 protected void describeFieldQueryService(Element service) {
1461 Document doc = service.getOwnerDocument();
1462 // we need name, submit (button) and description <displayItem> elements
1463 Element displayItem = createNameValuePairElement(doc,
1464 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_NAME,
1465 "Form Search");
1466 service.appendChild(displayItem);
1467
1468 displayItem = createNameValuePairElement(doc,
1469 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_SUBMIT, "Search");
1470 service.appendChild(displayItem);
1471
1472 displayItem = createNameValuePairElement(doc,
1473 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_DESCRIPTION,
1474 "Simple fielded search");
1475 service.appendChild(displayItem);
1476
1477 //create the <paramList>
1478 Element paramList = doc.createElement(
1479 GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
1480
1481 // we ignore granularity to search at: it will always be
1482 // document and section level
1483 // we ignore casefolding: always on (that is, case is irrelevant)
1484 // we ignore document display order: always ranked
1485
1486 // Constructing the following:
1487 // <param default="100" name="maxDocs" type="integer">
1488 // <displayItem name="name">Maximum hits to return</displayItem>
1489 // </param>
1490 Element param = doc.createElement(GSXML.PARAM_ELEM);
1491
1492 Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
1493 attribute.setValue(MAXDOCS);
1494 param.setAttributeNode(attribute);
1495
1496 attribute = doc.createAttribute(GSXML.DEFAULT_ATT);
1497 attribute.setValue("100");
1498 param.setAttributeNode(attribute);
1499
1500 attribute = doc.createAttribute(GSXML.TYPE_ATT);
1501 attribute.setValue(GSXML.PARAM_TYPE_INTEGER);
1502 param.setAttributeNode(attribute);
1503
1504 displayItem = createNameValuePairElement(doc,
1505 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_NAME,
1506 "Maximum hits to return");
1507 param.appendChild(displayItem);
1508
1509 paramList.appendChild(param);
1510
1511 // Constructing the following:
1512 // <param name="simpleField" occurs="4" type="multi">
1513 // <displayItem name="name"></displayItem>
1514 //
1515 // <param name="query" type="string">
1516 // <displayItem name="name">Word or phrase </displayItem>
1517 // </param>
1518 //
1519 // <param default="allFields" name="fieldname" type="enum_single">
1520 // <displayItem name="name">in field</displayItem>
1521 //
1522 // <option name="docTitles">
1523 // <displayItem name="name">document titles</displayItem>
1524 // </option>
1525 // <option name="allTitles">
1526 // <displayItem name="name">document and section titles</displayItem>
1527 // </option>
1528 // <option name="fullText">
1529 // <displayItem name="name">full text</displayItem>
1530 // </option>
1531 // <option name="all">
1532 // <displayItem name="name">titles and full text</displayItem>
1533 // </option>
1534 // <option name="">
1535 // <displayItem name="name"></displayItem>
1536 // </option>
1537 // </param>
1538 // </param>
1539 Element rowOfParams = doc.createElement(GSXML.PARAM_ELEM);
1540 attribute = doc.createAttribute(GSXML.NAME_ATT);
1541 attribute.setValue(SIMPLEFIELD_ATT);
1542 rowOfParams.setAttributeNode(attribute);
1543
1544 // we want the row of controls to occur multiple times
1545 attribute = doc.createAttribute(GSXML.TYPE_ATT);
1546 attribute.setValue(GSXML.PARAM_TYPE_MULTI);
1547 rowOfParams.setAttributeNode(attribute);
1548
1549 attribute = doc.createAttribute(OCCURS_ATT);
1550 attribute.setValue("4"); // we want this row to occur 4 times
1551 rowOfParams.setAttributeNode(attribute);
1552
1553 // <param name="query" type="string">
1554 // <displayItem name="name">Word or phrase </displayItem>
1555 // </param>
1556 param = doc.createElement(GSXML.PARAM_ELEM);
1557
1558 attribute = doc.createAttribute(GSXML.NAME_ATT);
1559 attribute.setValue(QUERY);
1560 param.setAttributeNode(attribute);
1561
1562 attribute = doc.createAttribute(GSXML.TYPE_ATT);
1563 attribute.setValue(GSXML.PARAM_TYPE_STRING);
1564 param.setAttributeNode(attribute);
1565
1566 displayItem = createNameValuePairElement(doc,
1567 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_NAME,
1568 "Word or phrase");
1569 param.appendChild(displayItem);
1570 rowOfParams.appendChild(param);
1571
1572 // <param default="allFields" name="fieldName" type="enum_single">
1573 // <displayItem name="name">in field</displayItem>
1574 param = doc.createElement(GSXML.PARAM_ELEM);
1575 attribute = doc.createAttribute(GSXML.NAME_ATT);
1576 attribute.setValue(FIELDNAME_ATT);
1577 param.setAttributeNode(attribute);
1578
1579 attribute = doc.createAttribute(GSXML.TYPE_ATT);
1580 attribute.setValue(GSXML.PARAM_TYPE_ENUM_SINGLE);
1581 param.setAttributeNode(attribute);
1582
1583 attribute = doc.createAttribute(GSXML.DEFAULT_ATT);
1584 attribute.setValue(ALL_FIELDS);
1585 param.setAttributeNode(attribute);
1586
1587 displayItem = createNameValuePairElement(doc,
1588 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_NAME,
1589 "in field");
1590 param.appendChild(displayItem);
1591
1592 String[] searchFieldNames
1593 = {ALL_FIELDS, DOC_TITLES, ALL_TITLES, FULLTEXT};
1594 String[] searchFieldDisplay = {"all titles and full-text",
1595 "document titles only", "document and section titles",
1596 "full-text only"};
1597
1598 // for each fieldName create an option element and insert
1599 // the option into the enum_multi drop-down param:
1600 // <option name="fieldName">
1601 // <displayItem name="name">fieldName</displayItem>
1602 // </option>
1603 for(int i = 0; i < searchFieldNames.length; i++) {
1604 Element option = doc.createElement(GSXML.PARAM_OPTION_ELEM);
1605 attribute = doc.createAttribute(GSXML.NAME_ATT);
1606 attribute.setValue(searchFieldNames[i]);
1607 option.setAttributeNode(attribute);
1608
1609 displayItem = createNameValuePairElement(doc,
1610 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_NAME,
1611 searchFieldDisplay[i]);
1612 option.appendChild(displayItem);
1613 param.appendChild(option); // add option to the drop-down box
1614 }
1615
1616 rowOfParams.appendChild(param);
1617 paramList.appendChild(rowOfParams);
1618 service.appendChild(paramList);
1619 }
1620
1621 /**
1622 * @return a GS3 describe response message for the requested service
1623 * of the given collection. DocumentContent/Metadata/StructureRetrieve
1624 * return nothing special except their names; browse (and any query)
1625 * return more complex XML responses.
1626 * All collections in this Digital Library (Fedora Repository) share
1627 * the same services, so this method returns the same as
1628 * describeService(serviceName).
1629 * @param collectionName - the name of the collection whose service is to
1630 * be described. It will be converted to a fedora collection pid, which is of
1631 * the form "greenstone:&lt;collectionName&gt;-collection".
1632 * @param serviceName - the name of the service in the collection which is to
1633 * be described. */
1634 public String describeCollectionService(String collectionName,
1635 String serviceName) {
1636 // collectionName can be ignored, because all services are FedoraGS3
1637 // services and are not unique to any particular (greenstone) collection.
1638 return describeService(serviceName);
1639 }
1640
1641 /** This method performs the implemented browse operation: allowing the
1642 * user to browse the titles of documents in the given collection by letter
1643 * and returning the results.
1644 * @param classifierID is the id of the classifier on which to browse. In
1645 * this case, the classifier indicates whether we browse titles by letter, or
1646 * browse (documents) by collection; and it is of the form &lt;CL(letter)&gt;.
1647 * @param collectionName is the name of the collection whose documents
1648 * starting with the given letter will be returned.
1649 * @return a GS3 DocumentStructureRetrieve response message which lists all
1650 * the documents that start with the letter indicated by parameter classifier.
1651 */
1652 public String browse(String collectionName, String classifierID)
1653 {
1654 Document doc = builder.newDocument();
1655 FedoraGS3RunException ex = null; //any RemoteException or UnsupportedEncodingException
1656
1657 // <classifierNodeList>
1658 Element classifierNodeList = doc.createElement(
1659 GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
1660
1661 // <classifierNode nodeID="classifierNum">
1662 Element requestedClassifierNode = doc.createElement(
1663 GSXML.CLASS_NODE_ELEM);
1664 Attr attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
1665 attribute.setValue(classifierID);
1666 requestedClassifierNode.setAttributeNode(attribute);
1667 classifierNodeList.appendChild(requestedClassifierNode);
1668
1669 // <nodeStructure>
1670 Element nodeStructure = doc.createElement(GSXML.NODE_STRUCTURE_ELEM);
1671 requestedClassifierNode.appendChild(nodeStructure);
1672
1673 // And one more time, the top level classifierNode:
1674 Element classifierNode = doc.createElement(GSXML.CLASS_NODE_ELEM);
1675 attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
1676 attribute.setValue(classifierID);
1677 classifierNode.setAttributeNode(attribute);
1678 nodeStructure.appendChild(classifierNode);
1679
1680 // Work out what we're browsing base on the classifierID's number
1681 // classifier CL1 = browse titles by letter;
1682 // classifier CL2 = browse by collection;
1683 //remove the CL prefix and obtain the number from the id:
1684 int classifierNum = Integer.parseInt(classifierID.replace("CL", ""));
1685 switch(classifierNum) {
1686 case 1:
1687 // we're going to loop to the end of the alphabet
1688 int num = 1;
1689 for(char ch = 'A'; ch <= 'Z'; ch++, num++) {
1690 // <classifierNode nodeID="CL3.1">
1691 Element subClassifier = doc.createElement(
1692 GSXML.CLASS_NODE_ELEM);
1693 attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
1694 attribute.setValue(classifierID+"."+num);
1695 subClassifier.setAttributeNode(attribute);
1696 classifierNode.appendChild(subClassifier);
1697 // now we are going to retrieve the document structure for
1698 // this subClassifierID: all the documents that begin with
1699 // its letter.
1700 // remove the starting CL
1701 String letter = String.valueOf(ch);
1702 try{
1703 String[] docPIDs = this.browseTitlesByLetter(
1704 collectionName, letter);
1705 // append the <docNodes> for the docPIDs found as children
1706 // of subclassifier
1707 getStructureElement(subClassifier, docPIDs, DESCENDANTS);
1708 //CHILDREN); // for testing
1709 } catch(Exception e) {
1710 ex = new FedoraGS3RunException(e);
1711 ex.setSpecifics("requested portion of TOC file or "
1712 + "trouble with fielded search ");
1713 }
1714 }
1715 break;
1716 case 2:
1717 break;
1718 default:
1719 ex = new FedoraGS3RunException( // cause is regular exception
1720 new Exception("Unknown classifier ID: " + classifierID));
1721 }
1722 Element responseMsg = createResponseMessage(doc, classifierNodeList, ex,
1723 GSXML.REQUEST_TYPE_DESCRIBE, collectionName+"/ClassifierBrowse");
1724 try{
1725 return FedoraCommons.elementToFormattedString(responseMsg);
1726 }catch(TransformerException e) {
1727 return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
1728 + " " + e;
1729 }
1730 }
1731
1732 /** This method performs something equivalent to a greenstone3
1733 * ClassifierBrowseMetadataRetrieve on the classifierNodeIDs
1734 * @param classNodeIDs array of classifierNode IDs of for which the metadata
1735 * needs to be returned.
1736 * @return a GS3 ClassifierBrowseMetadataRetrieve response message which
1737 * lists the metadata for all the classifierNodes passed as parameter.*/
1738 public String browseMetadataRetrieve(String[] classNodeIDs)
1739 {
1740 Document doc = this.builder.newDocument();
1741 // <classifierNodeList>
1742 Element classifierNodeList = doc.createElement(
1743 GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
1744
1745 // create <classifierNode><metadataList><metadata>s
1746 // </metadataList></classifierNode> for all letters of alphabet
1747 for(int i = 0; i < classNodeIDs.length; i++) {
1748 // strip ID of everything before the first '.' (i.e. remove "CL#.")
1749 int index = classNodeIDs[i].indexOf('.');
1750 String subClassifierNumber = classNodeIDs[i].substring(index+1);
1751 int subClassifierNum = Integer.parseInt(subClassifierNumber);
1752 char letter = (char)('A' + subClassifierNum - 1); // A = 1
1753
1754 // <classifierNode nodeID="CL#.subNum">
1755 Element classifierNode = doc.createElement(GSXML.CLASS_NODE_ELEM);
1756 Attr attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
1757 attribute.setValue(classNodeIDs[i]);
1758 classifierNode.setAttributeNode(attribute);
1759
1760 // <metadataList>
1761 Element metadataList = doc.createElement(
1762 GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
1763
1764 // at least one metadata element: that of the title of this
1765 // classifierNode:
1766 // <metadata name="Title">letter</metadata>
1767 Element metadata = this.createNameValuePairElement(doc,
1768 GSXML.METADATA_ELEM, "Title", String.valueOf(letter));
1769
1770 // now connect up everything
1771 metadataList.appendChild(metadata);
1772 classifierNode.appendChild(metadataList);
1773 classifierNodeList.appendChild(classifierNode);
1774 }
1775
1776 Element responseMsg = createResponseMessage(doc, classifierNodeList, null,
1777 GSXML.REQUEST_TYPE_PROCESS, //collName +
1778 "ClassifierBrowseMetadataRetrieve");
1779 try{
1780 return FedoraCommons.elementToFormattedString(responseMsg);
1781 }catch(TransformerException e) {
1782 return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
1783 + " " + e;
1784 }
1785 }
1786
1787 /** @return a newly created element of the following format:
1788 * &lt;classifier content="somecontent" name="CL+num"&gt;
1789 * &lt;displayItem name="name"&gt;someClassifierName&lt;/displayItem&gt;
1790 * &lt;displayItem name="description"&gt;Browse by classifier name&lt;/displayItem&gt;
1791 * &lt;/classifier&gt;
1792 * @param doc - the document used to create the element
1793 * @param content - value of the content attribute
1794 * @param classifierNum - the number suffixed to the CL, together forming
1795 * the classifier Node's ID
1796 * @param displayNameVal is the bodytext of a named displayItem element
1797 * @param displayDescrVal is the bodytext of a displayItem element with
1798 * description */
1799 protected Element createClassifierElement(Document doc, String content,
1800 int classifierNum, String displayNameVal, String displayDescrVal)
1801 {
1802 final String CL = "CL";
1803 Element classifier = doc.createElement(GSXML.CLASSIFIER_ELEM);
1804 // content attribute
1805 Attr att = doc.createAttribute(GSXML.CLASSIFIER_CONTENT_ATT);
1806 att.setValue(content);
1807 classifier.setAttributeNode(att);
1808 // name attribute
1809 att = doc.createAttribute(GSXML.NAME_ATT);
1810 att.setValue(CL + classifierNum);
1811 classifier.setAttributeNode(att);
1812
1813 // now create the displayItem children for classifier:
1814 // <displayItem name="name">#letter</displayItem>
1815 // <displayItem name="description">
1816 //Browse titles starting with #letter</displayItem>
1817 Element displayItem = createNameValuePairElement(doc,
1818 GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_NAME, displayNameVal);
1819 classifier.appendChild(displayItem);
1820 displayItem = createNameValuePairElement(doc, GSXML.DISPLAY_TEXT_ELEM,
1821 GSXML.DISPLAY_TEXT_DESCRIPTION, displayDescrVal);
1822 classifier.appendChild(displayItem);
1823
1824 return classifier;
1825 }
1826
1827
1828 /** @return a newly created element of the following format:
1829 * &lt;elementName name="somename"&gt;"some display value"&lt;/elementName&gt;
1830 * @param doc - the document used to create the element
1831 * @param elementName - the tag name
1832 * @param name - value of attribute name
1833 * @param value - the body text of the element */
1834 protected Element createNameValuePairElement(Document doc, String elementName,
1835 String name, String value) {
1836 // <elementName name="somename">"some display value"</elementName>
1837 Element element = doc.createElement(elementName);
1838 Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
1839 attribute.setValue(name);
1840 element.setAttributeNode(attribute);
1841
1842 element.appendChild(doc.createTextNode(value));
1843 return element;
1844 }
1845
1846 /**
1847 * @param collection is the collection to search in
1848 * @param query is the query term to search for. It won't specify the
1849 * indexed field to search in, which will mean that GSearch will
1850 * search all default indexed fields.
1851 * @param maxDocs is the maximum number of results to return (which
1852 * at present we consider equivalent to FedoraGSearch's hitpageSize).
1853 */
1854 public String[] textQuery(String collection, String query,
1855 int maxDocs)
1856 throws Exception
1857 {
1858 // no need to search there is no query or query is empty spaces
1859 if(query.trim().equals(""))
1860 return new String[]{};
1861
1862 // QUERY value won't specify indexed field to search, Fedora
1863 // Gsearch will take that as meaning all default indexed fields.
1864 // Params to search() method below: string of fielded query terms;
1865 // hitpageStart, hitpageEnd, snippetsMax (leave that 0)
1866 query = query + " " + "PID" + COLON + GREENSTONE;
1867
1868 String searchResult = this.fedoraGSearch.search(query, 1, maxDocs, 0);
1869 // now we have the XML returned by FedoraGSearch, get the pids
1870 // of the documents returned (if any)
1871 String[] pids = this.fedoraGSearch.getPIDsFromSearchResult(
1872 collection, searchResult);
1873 return pids;
1874 }
1875
1876 /**
1877 * This method performs a fieldquery, searching for x number of phrases
1878 * in each of the 4 indexed fields.
1879 * @param collection is the collection to search in
1880 * @param nameValParamsMap is a Map of several(key, value) entries,
1881 * 4 of which we're concerned with here:
1882 * - the keys are ALL_FIELDS, DOC_TITLES, ALL_TITLES, FULLTEXT
1883 * - the values are a comma separated list of terms (phrases or single
1884 * words) to search that field in. There may be more than 1 or
1885 * there may be none (in which case there may be N empty values or
1886 * spaces separated by commas).
1887 * @param maxDocs is the maximum number of results to return (which
1888 * at present we consider equivalent to FedoraGSearch's hitpageSize).
1889 * */
1890 public String[] fieldQuery(String collection, Map nameValParamsMap,
1891 int maxDocs)
1892 throws Exception
1893 {
1894 // we're going to maintain a list of UNIQUE pids that were returned
1895 // in search results. Hence we use Set:
1896 java.util.Set set = new java.util.HashSet();
1897
1898 // (1) Use Fedora's search to search document titles, if they were
1899 // specified:
1900 String[] docTitlepids = {};
1901
1902 String docTitleTerms = (String)nameValParamsMap.get(DOC_TITLES);
1903 if(docTitleTerms != null) { // no doc titles may have been specified
1904 String[] phrases = docTitleTerms.split(COMMA);
1905
1906 // search the individual phrases first:
1907 for(int i = 0; i < phrases.length; i++) {
1908 if(phrases.equals("") || phrases.equals(" "))
1909 continue; //skip when there are no terms
1910 docTitlepids = this.searchDocumentTitles(
1911 collection, phrases[i], false);
1912 for(int j = 0; j < docTitlepids.length; j++)
1913 set.add(docTitlepids[j]);
1914 }
1915 }
1916 // (2) use FedoraGSearch to search doc AND section titles, and
1917 // fulltext (in case these were specified in nameValParamsMap):
1918 String searchResult = this.fedoraGSearch.search(
1919 nameValParamsMap, 1, maxDocs);
1920
1921 String[] pids = this.fedoraGSearch.getPIDsFromSearchResult(
1922 collection, searchResult);
1923
1924 for(int i = 0; i < pids.length; i++)
1925 set.add(pids[i]);
1926
1927 pids = null;
1928 pids = new String[set.size()];
1929 set.toArray(pids); // unique pids
1930 return pids;
1931 }
1932
1933 /** @return a String representing Greenstone3 XML for a query process
1934 * response returning the results for the query denoted by parameter
1935 * nameValParamsMap.
1936 * @param nameValParamsMap is a Hashmap of name and value pairs for all the
1937 * query field data values. The names match the field names that
1938 * describeCollectionService() would have returned for the query service.
1939 * @param collection is the name of the collection
1940 * @param service is the name of the query service
1941 * This method is only ever called when any of the services in the digital
1942 * library described themselves as type=query. Therefore any digital
1943 * libraries that have no query services, can just return emtpy message
1944 * strings (or even "") since this method will never be called on them
1945 * anyway. */
1946 public String query(String collection, String service,
1947 Map nameValParamsMap)
1948 {
1949 FedoraGS3RunException ex = null;
1950 // (1) obtain the requested number of maximum result documents
1951 int maxDocs = 100;
1952 try{
1953 maxDocs = Integer.parseInt((String)nameValParamsMap.get(MAXDOCS));
1954 } catch(NumberFormatException e) {
1955 maxDocs = 100;
1956 }
1957
1958 String pids[] = {};
1959 // (2) for Textquery, we simply search ALL_FIELDS using FedoraGSearch
1960 if(service.equals("TextQuery")) {
1961 try {
1962 // get the Query field:
1963 String query = (String)nameValParamsMap.get(QUERY);
1964 pids = textQuery(collection, query, maxDocs);
1965 }
1966 catch(Exception e) {
1967 LOG.error("Error in TextQuery processing: " + e);
1968 ex = new FedoraGS3RunException(
1969 "When trying to use FedoraGenericSearch for a TextQuery", e);
1970
1971 }
1972 } else { // (3) FieldQuery
1973 // first get the comma-separated lists
1974 String listOfFieldNames = (String)nameValParamsMap.get(FIELDNAME_ATT);
1975 String listOfSearchTerms = (String)nameValParamsMap.get(QUERY);
1976 // both are comma separated lists, so split both on 'comma'
1977 String[] fieldNames = listOfFieldNames.split(COMMA);
1978 String[] searchTerms = listOfSearchTerms.split(COMMA);
1979
1980 // In the fieldNames and searchTerms lists of nameValParamsMap,
1981 // each searchTerm element was matched with its correspondingly
1982 // indexed fieldName.
1983 // A new map is going to reorganise this, by putting all terms
1984 // for a particular fieldName together in a comma separated list
1985 // and associating that with the fieldName. I.e. (key, value) ->
1986 // (fieldName, comma-separated list of all terms in that field)
1987 Map map = new HashMap();
1988 for(int i = 0; i < searchTerms.length; i++) {
1989 // there may be fewer searchTerms than fieldNames (since some
1990 // fieldNames may have been left empty), so loop on searchTerms
1991 if(map.containsKey(fieldNames[i])) { //fieldName is already
1992 // in the list, so append comma with new value
1993 String termsList = (String)map.get(fieldNames[i]);
1994 termsList = termsList + COMMA + searchTerms[i];
1995 map.put(fieldNames[i], termsList);
1996 } else { // this is the first time this fieldName occurred
1997 // just put the fieldName with searchTerm as-is
1998 map.put(fieldNames[i], searchTerms[i]);
1999 }
2000 }
2001
2002 try {
2003 // For fieldquery, we search on all the fieldNames specified
2004 // - if DOC_TITLES is specified then we use Fedora's search
2005 // - for all other fieldNames specified, we use FedoraGSearch
2006 pids = fieldQuery(collection, map, maxDocs);
2007 }
2008 catch(Exception e) {
2009 LOG.error("Error in FieldQuery processing: " + e);
2010 ex = new FedoraGS3RunException(
2011 "When trying to use FedoraGenericSearch for a FieldQuery", e);
2012 }
2013 }
2014
2015 // Build Greenstone XML Query response message for from
2016 // the pids (which should be document identifiers)
2017 Document doc = builder.newDocument();
2018 // <metadataList><metadata name="numDocsMatched" value="n" />
2019 // </metadataList>
2020 Element metadataList = doc.createElement(
2021 GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
2022 Element metadata = doc.createElement(GSXML.METADATA_ELEM);
2023
2024 Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
2025 attribute.setValue(NUM_DOCS_MATCHED);
2026 metadata.setAttributeNode(attribute);
2027
2028 attribute = doc.createAttribute(GSXML.VALUE_ATT);
2029 attribute.setValue(Integer.toString(pids.length));
2030 metadata.setAttributeNode(attribute);
2031
2032 metadataList.appendChild(metadata);
2033
2034 // <documentNodeList>
2035 // <documentNode nodeID="HASHac0a04dd14571c60d7fbfd.4.2"
2036 // docType='hierarchy' nodeType="leaf" />
2037 // ...
2038 // ...
2039 // </documentNodeList>
2040 Element docNodeList = doc.createElement(
2041 GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
2042 // for each
2043 for(int i = 0; i < pids.length; i++) {
2044 Element docNode = doc.createElement(GSXML.DOC_NODE_ELEM);
2045 attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
2046 attribute.setValue(pids[i]);
2047 docNode.setAttributeNode(attribute);
2048
2049 attribute = doc.createAttribute(GSXML.DOC_TYPE_ATT);
2050 attribute.setValue("hierarchy");
2051 docNode.setAttributeNode(attribute);
2052
2053 attribute = doc.createAttribute(GSXML.NODE_TYPE_ATT);
2054 attribute.setValue("root");
2055 docNode.setAttributeNode(attribute);
2056 docNodeList.appendChild(docNode);
2057 }
2058
2059 Element responseMsg = createResponseMessage(doc, docNodeList, ex,
2060 GSXML.REQUEST_TYPE_PROCESS, service);
2061 try{
2062 return FedoraCommons.elementToFormattedString(responseMsg);
2063 }catch(TransformerException e) {
2064 return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
2065 + " " + e;
2066 }
2067 }
2068
2069 public static void main(String args[]) {
2070 try{
2071 // testing default constructor
2072 //FedoraGS3Connection con = new FedoraGS3Connection();
2073
2074 // testing constructor that takes properties file to show initial
2075 // fedora server values
2076 java.io.File propertyFilename
2077 = new java.io.File("fedoraGS3.properties");
2078 FedoraGS3Connection con = new FedoraGS3Connection(propertyFilename);
2079
2080 // DESCRIBE: serviceList, collectionList
2081 System.out.println("serviceList:\n" + con.getServiceList());
2082
2083 System.out.println("collectionList:\n" + con.getCollectionList());
2084
2085 String[] colPIDs = con.getCollections();
2086 String[] collectionNames = con.getCollectionNames(con.getCollections());
2087
2088
2089 for(int i = 0; i < collectionNames.length; i++) {
2090 System.out.println("Describing collections:\n");
2091 System.out.println(con.describeCollection(collectionNames[i]));
2092 System.out.println("Describing collection services:\n"
2093 + con.describeCollectionServices(collectionNames[i]));
2094 }
2095
2096 String[] serviceNames = con.getServiceNames();
2097 for(int i = 0; i < serviceNames.length; i++) {
2098 System.out.println("Describing " + serviceNames[i] + ":\n"
2099 + con.describeCollectionService("demo", serviceNames[i]));
2100 }
2101
2102
2103 // TRYING OUT SPECIAL top-level document metadata retrieval (DLS, DC)
2104 // along with EX of the top-level document:
2105 System.out.println("\nGET META for greenstone:gs2mgdemo-HASH01d667303fe98545f03c14ae:");
2106 System.out.println(con.getDocumentMetadata(new String[]{"greenstone:gs2mgdemo-HASH01d667303fe98545f03c14ae"}));
2107
2108
2109 String[] docIDs = con.getCollectionDocs(colPIDs[0]);
2110 System.out.println("\nGET CONTENT:");
2111 for(int i = 0; i < docIDs.length; i++) {
2112 System.out.println(con.getContent(docIDs[i]));
2113 }
2114
2115 System.out.println("\nGET META:");
2116 for(int i = 0; i < docIDs.length; i++) {
2117 System.out.println(con.getDocumentMetadata(docIDs[i]));
2118 }
2119
2120 String[] getTitlesFor = {
2121 "greenstone:gs2mgdemo-HASH01d667303fe98545f03c14ae",
2122 "greenstone:gs2mgdemo-HASHa568bac1d8d7bd12a0938b",
2123 "greenstone:gs2mgdemo-HASHa568bac1d8d7bd12a0938b-1",
2124 "greenstone:gs2mgdemo-HASH01d667303fe98545f03c14ae-1.7",
2125 "greenstone:gs2mgdemo-HASHa568bac1d8d7bd12a0938b-1.5.1"
2126 };
2127
2128 // first let's display the regular meta for top-level docs and
2129 // their sections
2130 for(int i = 0; i < getTitlesFor.length; i++) {
2131 System.out.println(con.getDocumentMetadata(getTitlesFor[i]));
2132 }
2133
2134 System.out.println("\nTitles are:");
2135 System.out.println(con.getTitleMetadata(getTitlesFor));
2136
2137 System.out.println("\nGET STRUCTURE:");
2138 for(int i = 0; i < docIDs.length; i++) {
2139 System.out.println(con.getChildren(docIDs[i]));
2140 System.out.println(con.getDocumentStructure(docIDs[i]));
2141 }
2142
2143 // TEST ERROR CASES:
2144 System.out.println("\nTESTING ERROR CASES");
2145 System.out.println(con.getContent("greenstone:demo-pinky"));
2146 String[] errorCases = { "greenstone:demo-HASH23d1019b589e2ef6a680e3-1.5.1.5",
2147 "greenstone:demo-pinky" };
2148 System.out.println(con.getContent(errorCases));
2149 System.out.println(con.getDocumentMetadata(errorCases));
2150 System.out.println(con.getDocumentStructure(errorCases));
2151
2152 System.out.println("\nCLASSIFIER BROWSE");
2153 System.out.println(con.browse("gs2mgdemo", //"ClassifierBrowse",
2154 "CL1"));
2155
2156 System.out.println("\nCLASSIFIER BROWSE METADATA RETRIEVE");
2157 String[] classNodeIDs = new String[26];
2158 for(int i = 0; i < classNodeIDs.length; i++) {
2159 int subClassifierNum = i + 1;
2160 classNodeIDs[i] = "CL1." + subClassifierNum;
2161 }
2162 System.out.println(con.browseMetadataRetrieve(//"gs2mgdemo",
2163 classNodeIDs));
2164
2165 System.out.println("Testing query services");
2166 System.out.println("TEXT QUERY:");
2167 Map formControlValsMap = new HashMap();
2168 formControlValsMap.put(MAXDOCS, "100");
2169 formControlValsMap.put(QUERY, "snails");
2170 String searchResponse
2171 = con.query("gs2mgdemo", "TextQuery", formControlValsMap);
2172 System.out.println(searchResponse);
2173
2174 System.out.println("FIELD QUERY:");
2175 formControlValsMap.clear();
2176 formControlValsMap.put(MAXDOCS, "100");
2177 formControlValsMap.put(QUERY, "interview,Gender equality,cyclone");
2178 formControlValsMap.put(FIELDNAME_ATT,
2179 "allFields,docTitles,allFields,allFields");
2180 searchResponse
2181 = con.query("gs2mgdemo", "FieldQuery", formControlValsMap);
2182 System.out.println(searchResponse);
2183
2184 System.exit(0);
2185 }catch(Exception e) {
2186 JOptionPane.showMessageDialog(
2187 null, e, "Error", JOptionPane.ERROR_MESSAGE);
2188 //System.err.println("ERROR: " + e);
2189 e.printStackTrace();
2190 }
2191 }
2192}
Note: See TracBrowser for help on using the repository browser.