001: //$HeadURL: $
002: /*---------------- FILE HEADER ------------------------------------------
003: This file is part of deegree.
004: Copyright (C) 2001-2008 by:
005: Department of Geography, University of Bonn
006: http://www.giub.uni-bonn.de/deegree/
007: lat/lon GmbH
008: http://www.lat-lon.de
009:
010: This library is free software; you can redistribute it and/or
011: modify it under the terms of the GNU Lesser General Public
012: License as published by the Free Software Foundation; either
013: version 2.1 of the License, or (at your option) any later version.
014: This library is distributed in the hope that it will be useful,
015: but WITHOUT ANY WARRANTY; without even the implied warranty of
016: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: Lesser General Public License for more details.
018: You should have received a copy of the GNU Lesser General Public
019: License along with this library; if not, write to the Free Software
020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021: Contact:
022:
023: Andreas Poth
024: lat/lon GmbH
025: Aennchenstr. 19
026: 53177 Bonn
027: Germany
028: E-Mail: poth@lat-lon.de
029:
030: Prof. Dr. Klaus Greve
031: Department of Geography
032: University of Bonn
033: Meckenheimer Allee 166
034: 53115 Bonn
035: Germany
036: E-Mail: greve@giub.uni-bonn.de
037: ---------------------------------------------------------------------------*/
038:
039: package org.deegree.ogcwebservices.wcts;
040:
041: import static org.deegree.framework.xml.XMLTools.appendElement;
042: import static org.deegree.ogcbase.CommonNamespaces.DEEGREEWCTS;
043: import static org.deegree.ogcbase.CommonNamespaces.DEEGREEWCTS_PREFIX;
044: import static org.deegree.ogcbase.CommonNamespaces.OWSNS_1_1_0;
045: import static org.deegree.ogcbase.CommonNamespaces.OWS_1_1_0PREFIX;
046: import static org.deegree.ogcbase.CommonNamespaces.WCTSNS;
047: import static org.deegree.ogcbase.CommonNamespaces.WCTS_PREFIX;
048: import static org.deegree.ogcbase.CommonNamespaces.XLINK_PREFIX;
049: import static org.deegree.ogcbase.CommonNamespaces.XLNNS;
050:
051: import java.io.IOException;
052: import java.util.List;
053:
054: import javax.vecmath.Point3d;
055:
056: import org.deegree.framework.log.ILogger;
057: import org.deegree.framework.log.LoggerFactory;
058: import org.deegree.framework.util.Pair;
059: import org.deegree.framework.xml.XMLFragment;
060: import org.deegree.framework.xml.XMLTools;
061: import org.deegree.model.crs.CoordinateSystem;
062: import org.deegree.model.feature.FeatureCollection;
063: import org.deegree.model.feature.FeatureException;
064: import org.deegree.model.feature.GMLFeatureAdapter;
065: import org.deegree.model.spatialschema.GMLGeometryAdapter;
066: import org.deegree.model.spatialschema.Geometry;
067: import org.deegree.model.spatialschema.GeometryException;
068: import org.deegree.ogcwebservices.wcts.capabilities.Content;
069: import org.deegree.ogcwebservices.wcts.capabilities.CoverageAbilities;
070: import org.deegree.ogcwebservices.wcts.capabilities.FeatureAbilities;
071: import org.deegree.ogcwebservices.wcts.capabilities.InputOutputFormat;
072: import org.deegree.ogcwebservices.wcts.capabilities.WCTSCapabilities;
073: import org.deegree.ogcwebservices.wcts.data.FeatureCollectionData;
074: import org.deegree.ogcwebservices.wcts.data.GeometryData;
075: import org.deegree.ogcwebservices.wcts.data.SimpleData;
076: import org.deegree.ogcwebservices.wcts.data.TransformableData;
077: import org.deegree.ogcwebservices.wcts.operation.GetResourceByID;
078: import org.deegree.ogcwebservices.wcts.operation.Transform;
079: import org.deegree.ogcwebservices.wcts.operation.TransformResponse;
080: import org.deegree.owscommon_1_1_0.Manifest;
081: import org.w3c.dom.Document;
082: import org.w3c.dom.Element;
083: import org.xml.sax.SAXException;
084:
085: /**
086: * The <code>XMLFactory</code> provides helper methods to create xml-doc representations of bean encapsulations.
087: *
088: * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
089: *
090: * @author last edited by: $Author:$
091: *
092: * @version $Revision:$, $Date:$
093: *
094: */
095: public class XMLFactory {
096:
097: private static ILogger LOG = LoggerFactory
098: .getLogger(XMLFactory.class);
099:
100: private static final String PRE = WCTS_PREFIX + ":";
101:
102: /**
103: * Exports an GetResourceById bean to xml.
104: *
105: * @param resourceByID
106: * @return a dom-representation.
107: */
108: public static XMLFragment create(GetResourceByID resourceByID) {
109: return null;
110: }
111:
112: /**
113: * Exports an WCTSCapabilies bean to xml.
114: *
115: * @param capabilities
116: * to be exported.
117: * @return an xml-dom-representation of the given bean or <code>null</code> if the given parameter is
118: * <code>null</code>.
119: *
120: */
121: public static XMLFragment create(WCTSCapabilities capabilities) {
122: if (capabilities == null) {
123: return null;
124: }
125: org.deegree.owscommon_1_1_0.XMLFactory fac = new org.deegree.owscommon_1_1_0.XMLFactory();
126: Document doc = XMLTools.create();
127: Element root = doc.createElementNS(WCTSNS.toASCIIString(), PRE
128: + "Capabilities");
129: XMLFragment result = new XMLFragment(root);
130: fac.exportCapabilities(root, capabilities);
131: Content content = capabilities.getContents();
132: if (content != null) {
133: appendCapabilitiesContent(root, content);
134: }
135: return result;
136: }
137:
138: /**
139: * Creates a response to a Transform request. The wcts spec defines it to be a ows_1_1_0:OperationResponse, this
140: * method appends the deegreewcts:MultiParts or the deegreewcts:InlineData element(s) to the root node.
141: *
142: * @param transformResponse
143: * to create.
144: * @return the ows_1_1_0:OperationResponse with deegreewcts:MultiPart element added or <code>null</code> if the
145: * given param is <code>null</code>.
146: */
147: public static XMLFragment createResponse(
148: TransformResponse transformResponse) {
149: if (transformResponse == null) {
150: return null;
151: }
152: org.deegree.owscommon_1_1_0.XMLFactory owsFac = new org.deegree.owscommon_1_1_0.XMLFactory();
153: XMLFragment result = null;
154: Element dataElement = null;
155: switch (transformResponse.getDataPresentation()) {
156: case Transform.INLINE:
157: result = createOperationResponse(owsFac, transformResponse
158: .getInputData());
159: if (result != null) {
160: dataElement = appendElement(result.getRootElement(),
161: DEEGREEWCTS, DEEGREEWCTS_PREFIX + ":InlineData");
162: }
163: break;
164: case Transform.MULTIPART: // fall through
165: default:
166: result = owsFac.createOperationResponse(transformResponse
167: .getInputData());
168: if (result != null) {
169: dataElement = appendElement(result.getRootElement(),
170: DEEGREEWCTS, DEEGREEWCTS_PREFIX + ":MultiParts");
171: }
172: break;
173: }
174: appendTransformableData(dataElement, transformResponse
175: .getTransformableData());
176: return result;
177: }
178:
179: /**
180: * Will create an XMLFragment which holds the d_wcts:OperationResponse as the root element, values from the given
181: * manifest will be appended by the given ows_1_1 XMLFactory.
182: *
183: * @param owsFactory
184: * an instance of the ows_1-1 XMLFactory
185: *
186: * @param operationResponse
187: * to create the dom-xml representation from.
188: * @return the xmlFragment as defined in ows 1.1.0 or <code>null</code> if the given parameter is
189: * <code>null</code>.
190: */
191: public static XMLFragment createOperationResponse(
192: org.deegree.owscommon_1_1_0.XMLFactory owsFactory,
193: Manifest operationResponse) {
194: if (operationResponse == null) {
195: return null;
196: }
197: Document doc = XMLTools.create();
198: Element root = doc.createElementNS(DEEGREEWCTS.toASCIIString(),
199: PRE + "OperationResponse");
200: owsFactory.appendManifest(root, operationResponse);
201: return new XMLFragment(root);
202: }
203:
204: /**
205: * Appends the TransformableData bean, as an xml-dom element to the given root. If either one of the parameters is
206: * <code>null</code>, this method just returns.
207: *
208: * @param root
209: * to append to.
210: * @param transformableData
211: * to append.
212: */
213: protected static void appendTransformableData(Element root,
214: TransformableData<?> transformableData) {
215: if (root == null || transformableData == null) {
216: return;
217: }
218: if (transformableData instanceof SimpleData) {
219: appendSimpleData(root, (SimpleData) transformableData);
220: } else if (transformableData instanceof GeometryData) {
221: appendGeometryData(root, (GeometryData) transformableData);
222: } else if (transformableData instanceof FeatureCollectionData) {
223: appendFeatureCollectionData(root,
224: (FeatureCollectionData) transformableData);
225: }
226: }
227:
228: /**
229: * Appends a dom-xml document element with the name {http://www.deegree.org/wcts}:FeatureCollectionData. It will
230: * contain all transformed FeaturCollection as it's children. Or if no FeatureCollections were transformed this
231: * element will have no children at all.
232: * <p>
233: * If either one of the parameters is <code>null</code>, this method just returns.
234: * </p>
235: *
236: * @param root
237: * to append to.
238: * @param transformableData
239: * to append.
240: */
241: protected static void appendFeatureCollectionData(Element root,
242: FeatureCollectionData transformableData) {
243: if (root == null || transformableData == null) {
244: return;
245: }
246: GMLFeatureAdapter ad = new GMLFeatureAdapter();
247: Element featureCollectionElement = appendElement(root,
248: DEEGREEWCTS, DEEGREEWCTS_PREFIX
249: + ":FeatureCollectionData");
250: List<FeatureCollection> transformedData = transformableData
251: .getTransformedData();
252: if (transformedData != null && transformedData.size() >= 0) {
253: for (FeatureCollection featureCollection : transformedData) {
254: if (featureCollection != null) {
255: try {
256: ad.append(featureCollectionElement,
257: featureCollection);
258: } catch (FeatureException e) {
259: LOG.logError(e.getMessage(), e);
260: } catch (IOException e) {
261: LOG.logError(e.getMessage(), e);
262: } catch (SAXException e) {
263: LOG.logError(e.getMessage(), e);
264: }
265: }
266: }
267: }
268: }
269:
270: /**
271: * Appends a dom-xml document element with the name {http://www.deegree.org/wcts}:GeometryData. It it will contain
272: * all transformed Geometries as it's children. Or if no Geometries were transformed this element will have no
273: * children at all.
274: * <p>
275: * If either one of the parameters is <code>null</code>, this method just returns.
276: * </p>
277: *
278: * @param root
279: * to append to.
280: * @param transformableData
281: * to append.
282: */
283: protected static void appendGeometryData(Element root,
284: GeometryData transformableData) {
285: if (root == null || transformableData == null) {
286: return;
287: }
288: Element geometryElement = appendElement(root, DEEGREEWCTS,
289: DEEGREEWCTS_PREFIX + ":GeometryData");
290: Document doc = geometryElement.getOwnerDocument();
291: List<Geometry> transformedGeometries = transformableData
292: .getTransformedData();
293: if (transformedGeometries.size() >= 0) {
294: for (Geometry geom : transformedGeometries) {
295: if (geom != null) {
296: try {
297: StringBuffer sb = GMLGeometryAdapter
298: .export(geom);
299: Element tmp = XMLTools
300: .getStringFragmentAsElement(sb
301: .toString());
302: if (tmp != null) {
303: tmp = (Element) doc.importNode(tmp, true);
304: geometryElement.appendChild(tmp);
305: }
306: } catch (GeometryException e) {
307: LOG.logError(e.getMessage(), e);
308: } catch (SAXException e) {
309: LOG.logError(e.getMessage(), e);
310: } catch (IOException e) {
311: LOG.logError(e.getMessage(), e);
312: }
313: }
314: }
315: }
316: }
317:
318: /**
319: * Appends a dom-xml document element with the name is {http://www.deegree.org/wcts}:SimpleData. It will contain the
320: * points as a separated list as defined by the 'cs' separator. The element has the attribute 'srsDimension'. The
321: * list elements can therefore be interpreted as a tuple of the value of 'srsDimension'. If no points were
322: * transformed the list will be empty.
323: * <p>
324: * If either one of the parameters is <code>null</code>, this method just returns.
325: * </p>
326: *
327: * @param root
328: * to append to.
329: * @param transformableData
330: * to append.
331: */
332: protected static void appendSimpleData(Element root,
333: SimpleData transformableData) {
334: if (root == null || transformableData == null) {
335: return;
336: }
337: Element simpleDataElement = appendElement(root, DEEGREEWCTS,
338: DEEGREEWCTS_PREFIX + ":SimpleData");
339: int dim = transformableData.getTargetCRS().getDimension();
340: final String ts = transformableData.getTupleSeparator();
341: simpleDataElement.setAttribute("ts", ts);
342: final String cs = transformableData.getCoordinateSeparator();
343: simpleDataElement.setAttribute("cs", cs);
344: List<Point3d> transformedPoints = transformableData
345: .getTransformedData();
346: StringBuilder sb = new StringBuilder(transformedPoints.size()
347: * dim);
348: for (int i = 0; i < transformedPoints.size(); ++i) {
349: Point3d point = transformedPoints.get(i);
350: if (point != null) {
351: sb.append(point.x);
352: sb.append(cs);
353: sb.append(point.y);
354: if (dim == 3) {
355: sb.append(cs);
356: sb.append(point.z);
357: }
358: if ((i + 1) < transformedPoints.size()) {
359: sb.append(ts);
360: }
361: }
362: }
363: XMLTools.setNodeValue(simpleDataElement, sb.toString());
364: }
365:
366: /**
367: * Appends the WCTSContent bean, as an xml-dom element to the given root. If either one of the parameters is
368: * <code>null</code>, this method just returns.
369: *
370: * @param root
371: * to append the values to.
372: * @param content
373: * to be appended.
374: */
375: protected static void appendCapabilitiesContent(Element root,
376: Content content) {
377: if (content == null || root == null) {
378: return;
379: }
380: Element contentElement = appendElement(root, WCTSNS, PRE
381: + "Contents");
382: List<String> transformations = content.getTransformations();
383: if (transformations != null && transformations.size() > 0) {
384: for (String transform : transformations) {
385: if (transform != null) {
386: appendElement(contentElement, WCTSNS, PRE
387: + "Transformation", transform);
388: }
389: }
390: }
391:
392: List<String> methods = content.getMethods();
393: if (methods != null && methods.size() > 0) {
394: for (String s : methods) {
395: if (s != null) {
396: appendElement(contentElement, WCTSNS, PRE
397: + "Method", s);
398: }
399: }
400: }
401:
402: List<CoordinateSystem> sourceCRSs = content.getSourceCRSs();
403: if (sourceCRSs != null && sourceCRSs.size() > 0) {
404: for (CoordinateSystem s : sourceCRSs) {
405: if (s != null) {
406: appendElement(contentElement, WCTSNS, PRE
407: + "SourceCRS", s.getIdentifier());
408: }
409: }
410: }
411:
412: List<CoordinateSystem> targetCRSs = content.getTargetCRSs();
413: if (targetCRSs != null && targetCRSs.size() > 0) {
414: for (CoordinateSystem s : targetCRSs) {
415: if (s != null) {
416: appendElement(contentElement, WCTSNS, PRE
417: + "TargetCRS", s.getIdentifier());
418: }
419: }
420: }
421:
422: CoverageAbilities cAbilities = content.getCoverageAbilities();
423: if (cAbilities != null) {
424: Element caElement = appendElement(contentElement, WCTSNS,
425: PRE + "CoverageAbilities");
426: List<Pair<String, String>> coverageTypes = cAbilities
427: .getCoverageTypes();
428: if (coverageTypes != null && coverageTypes.size() > 0) {
429: for (Pair<String, String> values : coverageTypes) {
430: if (values != null) {
431: Element ctElement = appendElement(caElement,
432: WCTSNS, PRE + "CoverageType",
433: values.first);
434: ctElement.setAttribute("codeSpace",
435: values.second);
436: }
437: }
438: }
439: List<InputOutputFormat> cFormats = cAbilities
440: .getCoverageFormats();
441: if (cFormats != null && cFormats.size() > 0) {
442: for (InputOutputFormat iof : cFormats) {
443: appendInputOutput(caElement, iof, "CoverageFormat");
444: }
445: }
446: List<Element> interpolationMethods = cAbilities
447: .getInterPolationMethods();
448: if (interpolationMethods != null
449: && interpolationMethods.size() > 0) {
450: for (Element element : interpolationMethods) {
451: if (element != null) {
452: Element copyOf = (Element) caElement
453: .getOwnerDocument().importNode(element,
454: true);
455: caElement.appendChild(copyOf);
456: }
457: }
458: }
459:
460: }
461: FeatureAbilities fAbilities = content.getFeatureAbilities();
462: if (fAbilities != null) {
463: Element faElement = appendElement(contentElement, WCTSNS,
464: PRE + "FeatureAbilities");
465: List<Pair<String, String>> geometryTypes = fAbilities
466: .getGeometryTypes();
467: if (geometryTypes != null && geometryTypes.size() > 0) {
468: for (Pair<String, String> values : geometryTypes) {
469: if (values != null) {
470: Element ctElement = appendElement(faElement,
471: WCTSNS, PRE + "GeometryType",
472: values.first);
473: ctElement.setAttribute("codeSpace",
474: values.second);
475: }
476: }
477: }
478: List<InputOutputFormat> fFormats = fAbilities
479: .getFeatureFormats();
480: if (fFormats != null && fFormats.size() > 0) {
481: for (InputOutputFormat iof : fFormats) {
482: appendInputOutput(faElement, iof, "FeatureFormat");
483: }
484: }
485: faElement.setAttribute("remoteProperties", fAbilities
486: .getRemoteProperties() ? "true" : "false");
487: }
488:
489: List<Pair<String, String>> metadataList = content.getMetadata();
490: if (metadataList != null && metadataList.size() > 0) {
491: for (Pair<String, String> values : metadataList) {
492: if (values != null) {
493: Element mdElement = appendElement(contentElement,
494: OWSNS_1_1_0, OWS_1_1_0PREFIX + ":Metadata");
495: mdElement.setAttributeNS(XLNNS.toASCIIString(),
496: XLINK_PREFIX + ":href", values.first);
497: mdElement.setAttribute("about", values.second);
498: }
499: }
500: }
501: contentElement.setAttribute("userDefinedCRSs", content
502: .supportsUserDefinedCRS() ? "true" : "false");
503: }
504:
505: /**
506: * Appends the input output element
507: *
508: * @param root
509: * to append to
510: * @param inputOutput
511: * to append
512: * @param nodeName
513: * the element name, i.e. CoverageFormat or FeatureFormat
514: */
515: private static void appendInputOutput(Element root,
516: InputOutputFormat inputOutput, String nodeName) {
517: if (inputOutput != null && root != null) {
518: Element cfElement = appendElement(root, WCTSNS, PRE
519: + nodeName, inputOutput.getValue());
520: cfElement.setAttribute("input",
521: inputOutput.canInput() ? "true" : "false");
522: cfElement.setAttribute("output",
523: inputOutput.canOutput() ? "true" : "false");
524:
525: }
526: }
527: }
|