001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/ogcwebservices/csw/discovery/Discovery.java $
002: /*---------------- FILE HEADER ------------------------------------------
003:
004: This file is part of deegree.
005: Copyright (C) 2001-2008 by:
006: EXSE, Department of Geography, University of Bonn
007: http://www.giub.uni-bonn.de/deegree/
008: lat/lon GmbH
009: http://www.lat-lon.de
010:
011: This library is free software; you can redistribute it and/or
012: modify it under the terms of the GNU Lesser General Public
013: License as published by the Free Software Foundation; either
014: version 2.1 of the License, or (at your option) any later version.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: Contact:
026:
027: Andreas Poth
028: lat/lon GmbH
029: Aennchenstr. 19
030: 53115 Bonn
031: Germany
032: E-Mail: poth@lat-lon.de
033:
034: Prof. Dr. Klaus Greve
035: Department of Geography
036: University of Bonn
037: Meckenheimer Allee 166
038: 53115 Bonn
039: Germany
040: E-Mail: greve@giub.uni-bonn.de
041:
042:
043: ---------------------------------------------------------------------------*/
044: package org.deegree.ogcwebservices.csw.discovery;
045:
046: import java.io.ByteArrayInputStream;
047: import java.io.ByteArrayOutputStream;
048: import java.io.IOException;
049: import java.io.StringWriter;
050: import java.net.MalformedURLException;
051: import java.net.URI;
052: import java.net.URISyntaxException;
053: import java.net.URL;
054: import java.util.HashMap;
055: import java.util.Iterator;
056: import java.util.List;
057: import java.util.Map;
058:
059: import javax.xml.transform.TransformerException;
060:
061: import org.deegree.datatypes.QualifiedName;
062: import org.deegree.enterprise.servlet.OGCServletController;
063: import org.deegree.framework.log.ILogger;
064: import org.deegree.framework.log.LoggerFactory;
065: import org.deegree.framework.util.FileUtils;
066: import org.deegree.framework.util.StringTools;
067: import org.deegree.framework.util.TimeTools;
068: import org.deegree.framework.xml.XMLFragment;
069: import org.deegree.framework.xml.XMLParsingException;
070: import org.deegree.framework.xml.XSLTDocument;
071: import org.deegree.framework.xml.schema.XSDocument;
072: import org.deegree.i18n.Messages;
073: import org.deegree.model.feature.FeatureCollection;
074: import org.deegree.model.feature.FeatureException;
075: import org.deegree.model.feature.GMLFeatureAdapter;
076: import org.deegree.ogcbase.ExceptionCode;
077: import org.deegree.ogcwebservices.InvalidParameterValueException;
078: import org.deegree.ogcwebservices.OGCWebServiceException;
079: import org.deegree.ogcwebservices.csw.capabilities.CatalogueOperationsMetadata;
080: import org.deegree.ogcwebservices.csw.configuration.CatalogueConfiguration;
081: import org.deegree.ogcwebservices.csw.configuration.CatalogueConfigurationDocument;
082: import org.deegree.ogcwebservices.csw.configuration.CatalogueOutputSchemaParameter;
083: import org.deegree.ogcwebservices.csw.configuration.CatalogueOutputSchemaValue;
084: import org.deegree.ogcwebservices.csw.configuration.CatalogueTypeNameSchemaParameter;
085: import org.deegree.ogcwebservices.csw.configuration.CatalogueTypeNameSchemaValue;
086: import org.deegree.ogcwebservices.csw.discovery.GetRecords.RESULT_TYPE;
087: import org.deegree.ogcwebservices.wfs.WFService;
088: import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities;
089: import org.deegree.ogcwebservices.wfs.operation.FeatureResult;
090: import org.deegree.ogcwebservices.wfs.operation.GetFeature;
091: import org.w3c.dom.Document;
092: import org.w3c.dom.NamedNodeMap;
093: import org.w3c.dom.Node;
094: import org.w3c.dom.NodeList;
095:
096: /**
097: * The Discovery class allows clients to discover resources registered in a catalogue, by providing
098: * four operations named <code>query</code>,<code>present</code>,
099: * <code>describeRecordType</code>, and <code>getDomain</code>. This class has a required
100: * association from the Catalogue Service class, and is thus always implemented by all Catalogue
101: * Service implementations. The Session class can be included with the Discovery class, in
102: * associations with the Catalogue Service class. The "e;query"e; and "e;present"e;
103: * operations may be executed in a session or stateful context. If a session context exists, the
104: * dynamic model uses internal states of the session and the allowed transitions between states.
105: * When the "e;query"e; and "e;present"e; state does not include a session between a
106: * server and a client, any memory or shared information between the client and the server may be
107: * based on private understandings or features available in the protocol binding. The
108: * describeRecordType and getDomain operations do not require a session context.
109: *
110: * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
111: * @author <a href="mailto:tfr@users.sourceforge.net">Torsten Friebe </a>
112: *
113: * @author last edited by: $Author: lbuesching $
114: *
115: * @version $Revision: 9592 $, $Date: 2008-01-17 05:20:45 -0800 (Thu, 17 Jan 2008) $
116: *
117: */
118: public class Discovery {
119:
120: private static final ILogger LOG = LoggerFactory
121: .getLogger(Discovery.class);
122:
123: // Keys are Strings, values are XSLDocuments
124: private static final Map<String, XSLTDocument> IN_XSL = new HashMap<String, XSLTDocument>();
125:
126: // Keys are Strings, values are XSLDocuments
127: private static final Map<String, XSLTDocument> OUT_XSL = new HashMap<String, XSLTDocument>();
128:
129: // Keys are Strings, values are URLs
130: private static final Map<String, URL> SCHEMA_URLS = new HashMap<String, URL>();
131:
132: // Keys are Strings, values are XMLFragments
133: private static final Map<String, XSDocument> SCHEMA_DOCS = new HashMap<String, XSDocument>();
134:
135: private static final String DEFAULT_SCHEMA = "DublinCore";
136:
137: private static final String OGC_CORE_SCHEMA = "OGCCORE";
138:
139: private CatalogueConfiguration cswConfiguration = null;
140:
141: /**
142: * The complete data access of a catalog service is managed by one instances of WFService.
143: */
144: private WFService wfsResource; // single instance only for this CSW
145:
146: /**
147: * @param wfsService
148: * to contact
149: * @param cswConfiguration
150: * of this service
151: */
152: public Discovery(WFService wfsService,
153: CatalogueConfiguration cswConfiguration) {
154: this .wfsResource = wfsService;
155: this .cswConfiguration = cswConfiguration;
156: try {
157: CatalogueOperationsMetadata catalogMetadata = (CatalogueOperationsMetadata) cswConfiguration
158: .getOperationsMetadata();
159: CatalogueOutputSchemaParameter outputSchemaParameter = (CatalogueOutputSchemaParameter) catalogMetadata
160: .getGetRecords().getParameter("outputSchema");
161:
162: CatalogueConfigurationDocument document = new CatalogueConfigurationDocument();
163: document.setSystemId(cswConfiguration.getSystemId());
164: CatalogueOutputSchemaValue[] values = outputSchemaParameter
165: .getSpecializedValues();
166: for (int i = 0; i < values.length; i++) {
167: CatalogueOutputSchemaValue value = values[i];
168: String schemaName = value.getValue().toUpperCase();
169:
170: URL fileURL = document.resolve(value.getInXsl());
171: LOG.logInfo(StringTools.concat(300, "Input schema '",
172: schemaName,
173: "' is processed using XSLT-sheet from URL '",
174: fileURL, "'"));
175: XSLTDocument inXSLSheet = new XSLTDocument();
176: inXSLSheet.load(fileURL);
177: IN_XSL.put(schemaName, inXSLSheet);
178:
179: fileURL = document.resolve(value.getOutXsl());
180: LOG.logInfo(StringTools.concat(300, "Output schema '",
181: schemaName,
182: "' is processed using XSLT-sheet from URL '",
183: fileURL, "'"));
184: XSLTDocument outXSLSheet = new XSLTDocument();
185: outXSLSheet.load(fileURL);
186: OUT_XSL.put(schemaName, outXSLSheet);
187:
188: }
189:
190: // read and store schema definitions
191: // each type(Name) provided by a CS-W is assigned to one schema
192: CatalogueTypeNameSchemaParameter outputTypeNameParameter = (CatalogueTypeNameSchemaParameter) catalogMetadata
193: .getGetRecords().getParameter("typeName");
194: CatalogueTypeNameSchemaValue[] tn_values = outputTypeNameParameter
195: .getSpecializedValues();
196: for (int i = 0; i < tn_values.length; i++) {
197: CatalogueTypeNameSchemaValue value = tn_values[i];
198: URL fileURL = document.resolve(value.getSchema());
199: XSDocument schemaDoc = new XSDocument();
200: schemaDoc.load(fileURL);
201: String typeName = value.getValue().toUpperCase();
202: LOG.logInfo(StringTools.concat(300,
203: "Schema for type '", typeName,
204: "' is defined in XSD-file at URL '", fileURL,
205: "'"));
206: SCHEMA_URLS.put(typeName, fileURL);
207: SCHEMA_DOCS.put(typeName, schemaDoc);
208: }
209: } catch (Exception e) {
210: e.printStackTrace();
211: LOG.logError("Error while creating CSW Discovery: "
212: + e.getMessage(), e);
213: }
214: WFSCapabilities capa = wfsResource.getCapabilities();
215: LOG
216: .logInfo("CSW Discovery initialized with WFS resource, wfs version: "
217: + capa.getVersion());
218: }
219:
220: /**
221: * Performs the submitted <code>DescribeRecord</code> -request.
222: *
223: * TODO: Check output schema & Co.
224: *
225: * @param request
226: * @return The DescribeRecordResult created from the given request
227: * @throws OGCWebServiceException
228: */
229: public DescribeRecordResult describeRecordType(
230: DescribeRecord request) throws OGCWebServiceException {
231:
232: // requested output format must be 'text/xml'
233: if (!("text/xml".equals(request.getOutputFormat()) || "application/xml"
234: .equals(request.getOutputFormat()))) {
235: String s = Messages.getMessage(
236: "CSW_DESCRIBERECORD_INVALID_FORMAT", request
237: .getOutputFormat());
238: throw new OGCWebServiceException(getClass().getName(), s,
239: ExceptionCode.INVALID_FORMAT);
240: }
241:
242: // requested schema language must be 'XMLSCHEMA'
243: if (!("XMLSCHEMA"
244: .equals(request.getSchemaLanguage().toString()) || "http://www.w3.org/XML/Schema"
245: .equals(request.getSchemaLanguage().toString()))) {
246: String s = Messages.getMessage(
247: "CSW_DESCRIBERECORD_INVALID_SCHEMA", request
248: .getSchemaLanguage());
249: throw new InvalidParameterValueException(s);
250: }
251:
252: // if no type names are specified, describe all known types
253: String[] typeNames = request.getTypeNames();
254: if (typeNames == null || typeNames.length == 0) {
255: typeNames = SCHEMA_DOCS.keySet().toArray(
256: new String[SCHEMA_DOCS.keySet().size()]);
257: }
258:
259: SchemaComponent[] schemaComponents = new SchemaComponent[typeNames.length];
260:
261: for (int i = 0; i < typeNames.length; i++) {
262: XSDocument doc = SCHEMA_DOCS
263: .get(typeNames[i].toUpperCase());
264: if (doc == null) {
265: LOG
266: .logDebug("Discovery.describeRecord, no key found for: "
267: + typeNames[i].toUpperCase()
268: + " trying again with added 'RIM:' prefix");
269: doc = SCHEMA_DOCS.get("RIM:"
270: + typeNames[i].toUpperCase());
271: }
272: if (doc == null) {
273: String msg = Messages.getMessage(
274: "CSW_DESCRIBERECORD_UNSUPPORTED_TN",
275: typeNames[i]);
276: throw new OGCWebServiceException(getClass().getName(),
277: msg);
278: }
279: try {
280: schemaComponents[i] = new SchemaComponent(doc, doc
281: .getTargetNamespace(), null, new URI(
282: "XMLSCHEMA"));
283: } catch (URISyntaxException e) {
284: throw new OGCWebServiceException(this .getClass()
285: .getName(), e.getMessage());
286: } catch (XMLParsingException e) {
287: throw new OGCWebServiceException(this .getClass()
288: .getName(), e.getMessage());
289: }
290: }
291:
292: return new DescribeRecordResult(request, "2.0.0",
293: schemaComponents);
294: }
295:
296: /**
297: * @param request
298: * which is not handled
299: * @return just a new empty DomainValues instance.
300: * @todo not implemented, yet
301: */
302: public DomainValues getDomain(@SuppressWarnings("unused")
303: GetDomain request) {
304: return new DomainValues();
305: }
306:
307: private String normalizeOutputSchema(String outputSchema)
308: throws InvalidParameterValueException {
309: LOG.logDebug("Normalizing following outputschema: "
310: + outputSchema);
311: if (outputSchema == null) {
312: LOG.logDebug("Setting the outputSchema to: "
313: + DEFAULT_SCHEMA);
314: outputSchema = DEFAULT_SCHEMA;
315: } else if (outputSchema.equalsIgnoreCase(OGC_CORE_SCHEMA)) {
316: LOG.logDebug("Setting the outputSchema to: "
317: + DEFAULT_SCHEMA);
318: outputSchema = DEFAULT_SCHEMA;
319: }
320: outputSchema = outputSchema.toUpperCase();
321: if (IN_XSL.get(outputSchema) == null) {
322: String msg = "Unsupported output schema '" + outputSchema
323: + "' requested. Supported schemas are: ";
324: Iterator<String> it = IN_XSL.keySet().iterator();
325: while (it.hasNext()) {
326: msg += it.next();
327: if (it.hasNext()) {
328: msg += ", ";
329: } else {
330: msg += ".";
331: }
332: }
333: throw new InvalidParameterValueException(msg);
334: }
335: return outputSchema;
336: }
337:
338: private String getAllNamespaceDeclarations(Document doc) {
339: Map<String, String> nsp = new HashMap<String, String>();
340: nsp = collect(nsp, doc);
341:
342: Iterator<String> iter = nsp.keySet().iterator();
343: StringBuffer sb = new StringBuffer(1000);
344: while (iter.hasNext()) {
345: String s = iter.next();
346: String val = nsp.get(s);
347: sb.append(s).append(":").append(val);
348: if (iter.hasNext()) {
349: sb.append(';');
350: }
351: }
352: return sb.toString();
353: }
354:
355: private Map<String, String> collect(Map<String, String> nsp,
356: Node node) {
357: NamedNodeMap nnm = node.getAttributes();
358: if (nnm != null) {
359: for (int i = 0; i < nnm.getLength(); i++) {
360: String s = nnm.item(i).getNodeName();
361: if (s.startsWith("xmlns:")) {
362: nsp.put(s.substring(6, s.length()), nnm.item(i)
363: .getNodeValue());
364: }
365: }
366: }
367: NodeList nl = node.getChildNodes();
368: if (nl != null) {
369: for (int i = 0; i < nl.getLength(); i++) {
370: collect(nsp, nl.item(i));
371: }
372: }
373: return nsp;
374: }
375:
376: /**
377: * Performs a <code>GetRecords</code> request.
378: * <p>
379: * This involves the following steps:
380: * <ul>
381: * <li><code>GetRecords</code>-><code>GetRecordsDocument</code></li>
382: * <li><code>GetRecordsDocument</code>-><code>GetFeatureDocument</code> using XSLT</li>
383: * <li><code>GetFeatureDocument</code>-><code>GetFeature</code></li>
384: * <li><code>GetFeature</code> request is performed against the underlying WFS</li>
385: * <li>WFS answers with a <code>FeatureResult</code> object (which contains a
386: * <code>FeatureCollection</code>)</li>
387: * <li><code>FeatureCollection</code>-> GMLFeatureCollectionDocument (as a String)</li>
388: * <li>GMLFeatureCollectionDocument</code>-><code>GetRecordsResultDocument</code> using
389: * XSLT</li>
390: * <li><code>GetRecordsResultDocument</code>-><code>GetRecordsResult</code></li>
391: * </ul>
392: * </p>
393: *
394: * @param getRecords
395: * @return GetRecordsResult
396: * @throws OGCWebServiceException
397: */
398: public GetRecordsResult query(GetRecords getRecords)
399: throws OGCWebServiceException {
400: GetFeature getFeature = null;
401: XMLFragment getFeatureDocument = null;
402: Object wfsResponse = null;
403: GetRecordsResult cswResponse = null;
404: String outputSchema = normalizeOutputSchema(getRecords
405: .getOutputSchema());
406:
407: // TODO remove this (only necessary because determineRecordsMatched changes the resultType)
408: String resultType = getRecords.getResultTypeAsString();
409:
410: XMLFragment getRecordsDocument = new XMLFragment(XMLFactory
411: .export(getRecords).getRootElement());
412: LOG.logDebug("Input GetRecords request:\n"
413: + getRecordsDocument.getAsPrettyString());
414: try {
415: String nsp = getAllNamespaceDeclarations(getRecordsDocument
416: .getRootElement().getOwnerDocument());
417: // incoming GetRecord request must be transformed to a GetFeature
418: // request because the underlying 'data engine' of the CSW is a WFS
419: XSLTDocument xslSheet = IN_XSL.get(outputSchema);
420: synchronized (xslSheet) {
421: Map<String, String> param = new HashMap<String, String>();
422: param.put("NSP", nsp);
423: try {
424: getFeatureDocument = xslSheet.transform(
425: getRecordsDocument,
426: XMLFragment.DEFAULT_URL, null, param);
427: } catch (MalformedURLException e) {
428: LOG.logError(e.getMessage(), e);
429: }
430: LOG
431: .logDebug("*****First Generated WFS GetFeature request:\n"
432: + getFeatureDocument
433: .getAsPrettyString());
434: xslSheet.notifyAll();
435: }
436:
437: } catch (TransformerException e) {
438: e.printStackTrace();
439: String msg = "Can't transform GetRecord request to WFS GetFeature request: "
440: + e.getMessage();
441: LOG.logError(msg, e);
442: throw new OGCWebServiceException(msg);
443: }
444:
445: // if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
446: // StringWriter sw = new StringWriter( 5000 );
447: // try {
448: // getFeatureDocument.prettyPrint( sw );
449: // } catch ( TransformerException e ) {
450: // getFeatureDocument.write( sw );
451: // }
452: // LOG.logDebug( sw.getBuffer().toString() );
453: // }
454:
455: try {
456: LOG
457: .logDebug("Creating the GetFeature bean from the transformed GetRecordsDocument");
458: getFeature = GetFeature.create(getRecords.getId(),
459: getFeatureDocument.getRootElement());
460: } catch (Exception e) {
461: String msg = "Cannot generate object representation for GetFeature request: "
462: + e.getMessage();
463: LOG.logError(msg, e);
464: throw new OGCWebServiceException(msg);
465: }
466:
467: try {
468: LOG
469: .logDebug("Sending the GetFeature Request to the local wfs");
470: wfsResponse = wfsResource.doService(getFeature);
471: } catch (OGCWebServiceException e) {
472: String msg = "Generated WFS GetFeature request failed: "
473: + e.getMessage();
474: LOG.logError(msg, e);
475: throw new OGCWebServiceException(msg);
476: }
477:
478: // theoretical it is possible the result of a GetFeature request is not
479: // an instance of FeatureResult; but this never should happen
480: if (!(wfsResponse instanceof FeatureResult)) {
481: String msg = "Unexpected result type '"
482: + wfsResponse.getClass().getName()
483: + "' from WFS (must be FeatureResult)."
484: + " Maybe a FeatureType is not correctly registered!?";
485: LOG.logError(msg);
486: throw new OGCWebServiceException(msg);
487: }
488:
489: FeatureResult featureResult = (FeatureResult) wfsResponse;
490:
491: // this never should happen too - but it is possible
492: if (!(featureResult.getResponse() instanceof FeatureCollection)) {
493: String msg = "Unexpected reponse type: '"
494: + featureResult.getResponse().getClass().getName()
495: + " "
496: + featureResult.getResponse().getClass()
497: + "' in FeatureResult of WFS (must be a FeatureCollection).";
498: LOG.logError(msg);
499: throw new OGCWebServiceException(msg);
500: }
501: FeatureCollection featureCollection = (FeatureCollection) featureResult
502: .getResponse();
503:
504: try {
505: int numberOfRecordsReturned = featureCollection.size();
506: int numberOfMatchedRecords = 0;
507: if (getRecords.getResultType().equals(RESULT_TYPE.HITS)) {
508: numberOfMatchedRecords = Integer
509: .parseInt(featureCollection
510: .getAttribute("numberOfFeatures"));
511: } else {
512: // if result type does not equal 'HITS', a separate request must
513: // be created and performed to determine how many records match
514: // the query
515: LOG
516: .logDebug("Going to determine the number of matched records");
517: numberOfMatchedRecords = determineRecordsMatched(getRecords);
518: }
519:
520: int startPosition = getRecords.getStartPosition();
521: if (startPosition < 1)
522: startPosition = 1;
523: int nextRecord = startPosition + featureCollection.size();
524:
525: HashMap<String, String> params = new HashMap<String, String>();
526: params.put("REQUEST_ID", getRecords.getId());
527: if (numberOfRecordsReturned != 0) {
528: params.put("SEARCH_STATUS", "complete");
529: } else {
530: params.put("SEARCH_STATUS", "none");
531: }
532: params.put("TIMESTAMP", TimeTools.getISOFormattedTime());
533: List<QualifiedName> typenames = getRecords.getQuery()
534: .getTypeNamesAsList();
535: // this is a bit critical because
536: // a) not the complete result can be validated but just single records
537: // b) it is possible that several different record types are part
538: // of a response that must be validated against different schemas
539: String s = null;
540: String version = getRecords.getVersion();
541: if (version == null || "".equals(version.trim())) {
542: version = GetRecords.DEFAULT_VERSION;
543: }
544: if ("2.0.0".equals(version)) {
545: s = StringTools.concat(300,
546: OGCServletController.address,
547: "?service=CSW&version=2.0.0&",
548: "request=DescribeRecord&typeName=", typenames
549: .get(0).getPrefix(), ":", typenames
550: .get(0).getLocalName());
551: } else {
552: s = StringTools.concat(300,
553: OGCServletController.address,
554: "?service=CSW&version=" + version + "&",
555: "request=DescribeRecord&typeName=", typenames
556: .get(0).getFormattedString());
557: }
558: params.put("VERSION", version);
559: params.put("RECORD_SCHEMA", s);
560: params.put("RECORDS_MATCHED", "" + numberOfMatchedRecords);
561: params
562: .put("RECORDS_RETURNED", ""
563: + numberOfRecordsReturned);
564: params.put("NEXT_RECORD", "" + nextRecord);
565: String elementSet = getRecords.getQuery()
566: .getElementSetName();
567: if (elementSet == null) {
568: elementSet = "brief";
569: }
570: params.put("ELEMENT_SET", elementSet.toLowerCase());
571: params.put("RESULT_TYPE", resultType);
572: params.put("REQUEST_NAME", "GetRecords");
573:
574: ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
575: GMLFeatureAdapter ada = new GMLFeatureAdapter(true);
576:
577: ada.export(featureCollection, bos);
578: if (LOG.getLevel() == ILogger.LOG_DEBUG) {
579: s = new String(bos.toByteArray());
580: LOG.logDebug(s);
581: FileUtils.writeToFile("CSW_GetRecord_FC.xml", s);
582: }
583:
584: // vice versa to request transforming the feature collection being result
585: // to the GetFeature request must be transformed into a GetRecords result
586: ByteArrayInputStream bis = new ByteArrayInputStream(bos
587: .toByteArray());
588: XSLTDocument xslSheet = OUT_XSL.get(outputSchema);
589: XMLFragment resultDocument = xslSheet.transform(bis, null,
590: null, params);
591: GetRecordsResultDocument cswResponseDocument = new GetRecordsResultDocument();
592: cswResponseDocument.setRootElement(resultDocument
593: .getRootElement());
594: cswResponse = cswResponseDocument
595: .parseGetRecordsResponse(getRecords);
596: } catch (IOException e) {
597: String msg = "Can't transform WFS response (FeatureCollection) to CSW response: "
598: + e.getMessage();
599: LOG.logError(msg, e);
600: throw new OGCWebServiceException(msg);
601:
602: } catch (FeatureException e) {
603: String msg = "Can't transform WFS response (FeatureCollection) to CSW response: "
604: + e.getMessage();
605: LOG.logError(msg, e);
606: throw new OGCWebServiceException(msg);
607:
608: } catch (TransformerException e) {
609: String msg = "Can't transform WFS response (FeatureCollection) to CSW response: "
610: + e.getMessage();
611: LOG.logError(msg, e);
612: throw new OGCWebServiceException(msg);
613:
614: }
615:
616: return cswResponse;
617: }
618:
619: /**
620: * Returns the number of records matching a GetRecords request.
621: *
622: * @param getRecords
623: * @return the number of records matching a GetRecords request
624: * @throws OGCWebServiceException
625: */
626: private int determineRecordsMatched(GetRecords getRecords)
627: throws OGCWebServiceException {
628: getRecords.setResultType(GetRecords.RESULT_TYPE.HITS);
629: GetFeature getFeature = null;
630: XMLFragment getFeatureDocument = null;
631: Object wfsResponse = null;
632: String outputSchema = normalizeOutputSchema(getRecords
633: .getOutputSchema());
634:
635: XMLFragment getRecordsDocument = new XMLFragment(XMLFactory
636: .export(getRecords).getRootElement());
637: try {
638: LOG
639: .logDebug("Getting the xslt sheet for the determination of the number of matched records");
640: String nsp = getAllNamespaceDeclarations(getRecordsDocument
641: .getRootElement().getOwnerDocument());
642: XSLTDocument xslSheet = IN_XSL.get(outputSchema);
643:
644: synchronized (xslSheet) {
645: Map<String, String> param = new HashMap<String, String>();
646: param.put("NSP", nsp);
647: try {
648: getFeatureDocument = xslSheet.transform(
649: getRecordsDocument,
650: XMLFragment.DEFAULT_URL, null, param);
651: } catch (MalformedURLException e) {
652: LOG.logError(e.getMessage(), e);
653: }
654: LOG
655: .logDebug("*****Second Generated WFS GetFeature request (to determine records matched):\n"
656: + getFeatureDocument
657: .getAsPrettyString());
658: xslSheet.notifyAll();
659: }
660: // getFeatureDocument = xslSheet.transform( getRecordsDocument );
661: // LOG.logDebug( "Generated WFS GetFeature request (HITS):\n" + getFeatureDocument );
662: } catch (TransformerException e) {
663: e.printStackTrace();
664: String msg = "Can't transform GetRecord request to WFS GetFeature request: "
665: + e.getMessage();
666: LOG.logError(msg, e);
667: throw new OGCWebServiceException(msg);
668: }
669:
670: try {
671: getFeature = GetFeature.create(getRecords.getId(),
672: getFeatureDocument.getRootElement());
673: } catch (Exception e) {
674: String msg = "Cannot generate object representation for GetFeature request: "
675: + e.getMessage();
676: LOG.logError(msg, e);
677: throw new OGCWebServiceException(msg);
678: }
679:
680: try {
681: wfsResponse = wfsResource.doService(getFeature);
682: } catch (OGCWebServiceException e) {
683: String msg = "Generated WFS GetFeature request failed: "
684: + e.getMessage();
685: LOG.logError(msg, e);
686: throw new OGCWebServiceException(msg);
687: }
688:
689: if (!(wfsResponse instanceof FeatureResult)) {
690: String msg = "Unexpected result type '"
691: + wfsResponse.getClass().getName()
692: + "' from WFS (must be FeatureResult)."
693: + " Maybe a FeatureType is not correctly registered!?";
694: LOG.logError(msg);
695: throw new OGCWebServiceException(msg);
696: }
697:
698: FeatureResult featureResult = (FeatureResult) wfsResponse;
699:
700: if (!(featureResult.getResponse() instanceof FeatureCollection)) {
701: String msg = "Unexpected reponse type: '"
702: + featureResult.getResponse().getClass().getName()
703: + " "
704: + featureResult.getResponse().getClass()
705: + "' in FeatureResult of WFS (must be a FeatureCollection).";
706: LOG.logError(msg);
707: throw new OGCWebServiceException(msg);
708: }
709: FeatureCollection featureCollection = (FeatureCollection) featureResult
710: .getResponse();
711:
712: return Integer.parseInt(featureCollection
713: .getAttribute("numberOfFeatures"));
714: }
715:
716: /**
717: * Performs a <code>GetRecordById</code> request.
718: * <p>
719: * This involves the following steps:
720: * <ul>
721: * <li><code>GetRecordById</code>-><code>GetRecordByIdDocument</code></li>
722: * <li><code>GetRecordByIdDocument</code>-><code>GetFeatureDocument</code> using XSLT</li>
723: * <li><code>GetFeatureDocument</code>-><code>GetFeature</code></li>
724: * <li><code>GetFeature</code> request is performed against the underlying WFS</li>
725: * <li>WFS answers with a <code>FeatureResult</code> object (which contains a
726: * <code>FeatureCollection</code>)</li>
727: * <li><code>FeatureCollection</code>-> GMLFeatureCollectionDocument (as a String)</li>
728: * <li>GMLFeatureCollectionDocument</code>-><code>GetRecordsResultDocument</code> using
729: * XSLT</li>
730: * <li><code>GetRecordsResultDocument</code>-><code>GetRecordsResult</code></li>
731: * </ul>
732: * </p>
733: *
734: * @param getRecordById
735: * @return The GetRecordByIdResult created from teh given GetRecordById
736: * @throws OGCWebServiceException
737: */
738: public GetRecordByIdResult query(GetRecordById getRecordById)
739: throws OGCWebServiceException {
740:
741: GetFeature getFeature = null;
742: XMLFragment getFeatureDocument = null;
743: Object wfsResponse = null;
744: GetRecordByIdResult cswResponse = null;
745: String outputSchema = cswConfiguration.getDeegreeParams()
746: .getDefaultOutputSchema();
747:
748: XMLFragment getRecordsDocument = new XMLFragment(XMLFactory
749: .export(getRecordById).getRootElement());
750: try {
751: XSLTDocument xslSheet = IN_XSL.get(outputSchema
752: .toUpperCase());
753: getFeatureDocument = xslSheet.transform(getRecordsDocument);
754: LOG.logDebug("Generated WFS GetFeature request:\n"
755: + getFeatureDocument);
756: } catch (TransformerException e) {
757: String msg = "Can't transform GetRecordById request to WFS GetFeature request: "
758: + e.getMessage();
759: LOG.logError(msg, e);
760: throw new OGCWebServiceException(msg);
761: }
762:
763: if (LOG.getLevel() == ILogger.LOG_DEBUG) {
764: StringWriter sw = new StringWriter(5000);
765: getFeatureDocument.write(sw);
766: LOG.logDebug(sw.getBuffer().toString());
767: }
768:
769: try {
770: getFeature = GetFeature.create(getRecordById.getId(),
771: getFeatureDocument.getRootElement());
772: } catch (Exception e) {
773: String msg = "Cannot generate object representation for GetFeature request: "
774: + e.getMessage();
775: LOG.logError(msg, e);
776: throw new OGCWebServiceException(msg);
777: }
778:
779: try {
780: wfsResponse = wfsResource.doService(getFeature);
781: } catch (OGCWebServiceException e) {
782: String msg = "Generated WFS GetFeature request failed: "
783: + e.getMessage();
784: LOG.logError(msg, e);
785: throw new OGCWebServiceException(msg);
786: }
787:
788: if (!(wfsResponse instanceof FeatureResult)) {
789: String msg = "Unexpected result type '"
790: + wfsResponse.getClass().getName()
791: + "' from WFS (must be FeatureResult)."
792: + " Maybe a FeatureType is not correctly registered!?";
793: LOG.logError(msg);
794: throw new OGCWebServiceException(msg);
795: }
796:
797: FeatureResult featureResult = (FeatureResult) wfsResponse;
798:
799: if (!(featureResult.getResponse() instanceof FeatureCollection)) {
800: String msg = "Unexpected reponse type: '"
801: + featureResult.getResponse().getClass().getName()
802: + " "
803: + featureResult.getResponse().getClass()
804: + "' in FeatureResult of WFS (must be a FeatureCollection).";
805: LOG.logError(msg);
806: throw new OGCWebServiceException(msg);
807: }
808: FeatureCollection featureCollection = (FeatureCollection) featureResult
809: .getResponse();
810:
811: try {
812: int numberOfMatchedRecords = featureCollection == null ? 0
813: : featureCollection.size();
814: int startPosition = 1;
815: long maxRecords = Integer.MAX_VALUE;
816: long numberOfRecordsReturned = startPosition + maxRecords < numberOfMatchedRecords ? maxRecords
817: : numberOfMatchedRecords - startPosition + 1;
818: long nextRecord = numberOfRecordsReturned + startPosition > numberOfMatchedRecords ? 0
819: : numberOfRecordsReturned + startPosition;
820:
821: HashMap<String, String> params = new HashMap<String, String>();
822: params.put("REQUEST_ID", getRecordById.getId());
823: if (numberOfRecordsReturned != 0) {
824: params.put("SEARCH_STATUS", "complete");
825: } else {
826: params.put("SEARCH_STATUS", "none");
827: }
828: params.put("TIMESTAMP", TimeTools.getISOFormattedTime());
829: String s = OGCServletController.address
830: + "?service=CSW&version=2.0.0&request=DescribeRecord";
831: params.put("RECORD_SCHEMA", s);
832: params.put("RECORDS_MATCHED", "" + numberOfMatchedRecords);
833: params
834: .put("RECORDS_RETURNED", ""
835: + numberOfRecordsReturned);
836: params.put("NEXT_RECORD", "" + nextRecord);
837: params.put("ELEMENT_SET", "full");
838: params.put("REQUEST_NAME", "GetRecordById");
839:
840: featureCollection.setAttribute("byID", "true");
841: ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
842: GMLFeatureAdapter ada = new GMLFeatureAdapter(true);
843: ada.export(featureCollection, bos);
844:
845: if (LOG.getLevel() == ILogger.LOG_DEBUG) {
846: LOG.logDebug(new String(bos.toByteArray()));
847: }
848:
849: ByteArrayInputStream bis = new ByteArrayInputStream(bos
850: .toByteArray());
851: XSLTDocument xslSheet = OUT_XSL.get(outputSchema
852: .toUpperCase());
853: XMLFragment resultDocument = xslSheet.transform(bis, null,
854: null, params);
855: GetRecordByIdResultDocument cswResponseDocument = new GetRecordByIdResultDocument();
856: cswResponseDocument.setRootElement(resultDocument
857: .getRootElement());
858: cswResponse = cswResponseDocument
859: .parseGetRecordByIdResponse(getRecordById);
860: } catch (Exception e) {
861: e.printStackTrace();
862: String msg = "Can't transform WFS response (FeatureCollection) "
863: + "to CSW response: " + e.getMessage();
864: LOG.logError(msg, e);
865: throw new OGCWebServiceException(msg);
866: }
867:
868: return cswResponse;
869: }
870: }
|