001: // $HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/ogcbase/OGCDocument.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.ogcbase;
045:
046: import java.net.MalformedURLException;
047: import java.net.URI;
048: import java.net.URISyntaxException;
049: import java.net.URL;
050: import java.util.ArrayList;
051: import java.util.List;
052:
053: import org.deegree.datatypes.CodeList;
054: import org.deegree.datatypes.QualifiedName;
055: import org.deegree.datatypes.time.TimeDuration;
056: import org.deegree.datatypes.time.TimePeriod;
057: import org.deegree.datatypes.time.TimePosition;
058: import org.deegree.datatypes.time.TimeSequence;
059: import org.deegree.datatypes.values.Closure;
060: import org.deegree.datatypes.values.Interval;
061: import org.deegree.datatypes.values.TypedLiteral;
062: import org.deegree.datatypes.values.Values;
063: import org.deegree.framework.log.ILogger;
064: import org.deegree.framework.log.LoggerFactory;
065: import org.deegree.framework.util.StringTools;
066: import org.deegree.framework.xml.ElementList;
067: import org.deegree.framework.xml.XMLFragment;
068: import org.deegree.framework.xml.XMLParsingException;
069: import org.deegree.framework.xml.XMLTools;
070: import org.deegree.model.metadata.iso19115.Keywords;
071: import org.deegree.model.metadata.iso19115.Linkage;
072: import org.deegree.model.metadata.iso19115.OnlineResource;
073: import org.deegree.model.spatialschema.Point;
074: import org.deegree.ogcwebservices.LonLatEnvelope;
075: import org.deegree.ogcwebservices.OGCWebServiceException;
076: import org.deegree.ogcwebservices.wcs.describecoverage.InvalidCoverageDescriptionExcpetion;
077: import org.w3c.dom.Element;
078: import org.w3c.dom.Text;
079:
080: /**
081: * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
082: * @author last edited by: $Author: rbezema $
083: *
084: * @version 1.0. $Revision: 10106 $, $Date: 2008-02-18 04:58:04 -0800 (Mon, 18 Feb 2008) $
085: *
086: * @since 1.1
087: */
088: public abstract class OGCDocument extends XMLFragment {
089:
090: protected static final URI GMLNS = CommonNamespaces.GMLNS;
091:
092: private static ILogger LOG = LoggerFactory
093: .getLogger(OGCDocument.class);
094:
095: /**
096: * creates a <tt>LonLatEnvelope</tt> object from the passed element
097: *
098: * @param element
099: * @return created <tt>LonLatEnvelope</tt>
100: * @throws XMLParsingException
101: * @throws OGCWebServiceException
102: * @throws InvalidCoverageDescriptionExcpetion
103: */
104: public static LonLatEnvelope parseLonLatEnvelope(Element element)
105: throws XMLParsingException, OGCWebServiceException {
106:
107: String srs = XMLTools.getRequiredAttrValue("srsName", null,
108: element);
109: if (!"WGS84(DD)".equals(srs)) {
110: throw new OGCWebServiceException(
111: "srsName must be WGS84(DD) for lonLatEnvelope.");
112: }
113:
114: ElementList el = XMLTools.getChildElements("pos", GMLNS,
115: element);
116: if (el == null || el.getLength() != 2) {
117: throw new OGCWebServiceException(
118: "A lonLatEnvelope must contain two gml:pos elements");
119: }
120:
121: Point min = GMLDocument.parsePos(el.item(0));
122: Point max = GMLDocument.parsePos(el.item(1));
123:
124: el = XMLTools.getChildElements("timePosition", GMLNS, element);
125: TimePosition[] timePositions = parseTimePositions(el);
126:
127: return new LonLatEnvelope(min, max, timePositions, "WGS84(DD)");
128: }
129:
130: /**
131: * creates an array of <tt>TimePosition</tt> s from the passed element
132: *
133: * @param el
134: * @return created array of <tt>TimePosition</tt> s
135: * @throws XMLParsingException
136: * @throws InvalidCoverageDescriptionExcpetion
137: */
138: protected static TimePosition[] parseTimePositions(ElementList el)
139: throws XMLParsingException, OGCWebServiceException {
140: TimePosition[] timePos = new TimePosition[el.getLength()];
141: for (int i = 0; i < timePos.length; i++) {
142: timePos[i] = GMLDocument.parseTimePosition(el.item(i));
143: }
144: return timePos;
145: }
146:
147: /**
148: * Creates an array of <code>Keywords</code> from the passed list of <code>keyword</code>
149: * -elements.
150: *
151: * This appears to be pretty superfluous (as one <code>keywords</code>- element may contain
152: * several <code>keyword</code> -elements). However, the schema in the OGC document "Web
153: * Coverage Service (WCS), Version 1.0.0", contains the following line (in the definition of the
154: * CoverageOfferingBriefType):
155: *
156: * <code><xs:element ref="keywords" minOccurs="0" maxOccurs="unbounded"/></code>
157: *
158: * @param el
159: * @return created array of <tt>Keywords</tt>
160: * @throws XMLParsingException
161: */
162: protected Keywords[] parseKeywords(ElementList el, URI namespaceURI) {
163: Keywords[] kws = new Keywords[el.getLength()];
164: for (int i = 0; i < kws.length; i++) {
165: kws[i] = parseKeywords(el.item(i), namespaceURI);
166: }
167: return kws;
168: }
169:
170: /**
171: * Creates a <code>Keywords</code> instance from the given <code>keywords</code> -element.
172: *
173: * @param element
174: * @param namespaceURI
175: * @return created <code>Keywords</code>
176: * @throws XMLParsingException
177: */
178: protected Keywords parseKeywords(Element element, URI namespaceURI) {
179: ElementList el = XMLTools.getChildElements("keyword",
180: namespaceURI, element);
181: String[] kws = new String[el.getLength()];
182: for (int i = 0; i < kws.length; i++) {
183: kws[i] = XMLTools.getStringValue(el.item(i));
184: }
185: return new Keywords(kws);
186: }
187:
188: /**
189: * creates an <tt>TimeSequence</tt> from the passed element
190: *
191: * @param element
192: * @return created <tt>TimeSequence</tt>
193: * @throws XMLParsingException
194: * @throws InvalidCoverageDescriptionExcpetion
195: */
196: protected TimeSequence parseTimeSequence(Element element,
197: URI namespaceURI) throws XMLParsingException,
198: OGCWebServiceException {
199: ElementList el = XMLTools.getChildElements("timePerdiod",
200: namespaceURI, element);
201: TimePeriod[] timePerdiods = parseTimePeriods(el, namespaceURI);
202: el = XMLTools.getChildElements("timePosition", GMLNS, element);
203: TimePosition[] timePositions = parseTimePositions(el);
204:
205: return new TimeSequence(timePerdiods, timePositions);
206: }
207:
208: /**
209: * creates an array of <tt>TimePeriod</tt> s from the passed element
210: *
211: * @param el
212: * @return created array of <tt>TimePeriod</tt> s
213: * @throws XMLParsingException
214: * @throws InvalidCoverageDescriptionExcpetion
215: */
216: protected TimePeriod[] parseTimePeriods(ElementList el,
217: URI namespaceURI) throws XMLParsingException,
218: OGCWebServiceException {
219: TimePeriod[] timePeriods = new TimePeriod[el.getLength()];
220: for (int i = 0; i < timePeriods.length; i++) {
221: timePeriods[i] = parseTimePeriod(el.item(i), namespaceURI);
222: }
223: return timePeriods;
224: }
225:
226: /**
227: * creates a <tt>TimePeriod</tt> from the passed element
228: *
229: * @param element
230: * @return created <tt>TimePeriod</tt>
231: * @throws XMLParsingException
232: * @throws InvalidCoverageDescriptionExcpetion
233: */
234: protected TimePeriod parseTimePeriod(Element element,
235: URI namespaceURI) throws XMLParsingException,
236: OGCWebServiceException {
237: try {
238: Element begin = XMLTools.getRequiredChildElement(
239: "beginPosition", namespaceURI, element);
240: TimePosition beginPosition = GMLDocument
241: .parseTimePosition(begin);
242: Element end = XMLTools.getRequiredChildElement(
243: "endPosition", namespaceURI, element);
244: TimePosition endPosition = GMLDocument
245: .parseTimePosition(end);
246: String dur = XMLTools.getRequiredStringValue(
247: "timeResolution", namespaceURI, element);
248: TimeDuration resolution = TimeDuration
249: .createTimeDuration(dur);
250:
251: return new TimePeriod(beginPosition, endPosition,
252: resolution);
253: } catch (InvalidGMLException e) {
254: LOG.logError(e.getMessage(), e);
255: String s = e.getMessage() + "\n"
256: + StringTools.stackTraceToString(e);
257: throw new OGCWebServiceException(s);
258: }
259:
260: }
261:
262: /**
263: * creates a <tt>Values</tt> object from the passed element
264: *
265: * @param element
266: * @return created <tt>Values</tt>
267: * @throws XMLParsingException
268: */
269: protected Values parseValues(Element element, URI namespaceURI)
270: throws XMLParsingException {
271:
272: String type = XMLTools.getAttrValue(element, namespaceURI,
273: "type", null);
274: String semantic = XMLTools.getAttrValue(element, namespaceURI,
275: "semantic", null);
276:
277: ElementList el = XMLTools.getChildElements("interval",
278: namespaceURI, element);
279: Interval[] intervals = new Interval[el.getLength()];
280: for (int i = 0; i < intervals.length; i++) {
281: intervals[i] = parseInterval(el.item(i), namespaceURI);
282: }
283:
284: el = XMLTools.getChildElements("singleValue", namespaceURI,
285: element);
286: TypedLiteral[] singleValues = new TypedLiteral[el.getLength()];
287: for (int i = 0; i < singleValues.length; i++) {
288: singleValues[i] = parseTypedLiteral(el.item(i));
289: }
290:
291: Element elem = XMLTools.getChildElement("default",
292: namespaceURI, element);
293: TypedLiteral def = null;
294: if (elem != null) {
295: def = parseTypedLiteral(elem);
296: }
297:
298: try {
299: URI sem = null;
300: if (semantic != null)
301: sem = new URI(semantic);
302: URI tp = null;
303: if (type != null)
304: tp = new URI(type);
305: return new Values(intervals, singleValues, tp, sem, def);
306: } catch (URISyntaxException e) {
307: LOG.logError(e.getMessage(), e);
308: throw new XMLParsingException(
309: "couldn't parse URI from valuesl\n"
310: + StringTools.stackTraceToString(e));
311: }
312: }
313:
314: /**
315: * creates an <tt>Interval</tt> object from the passed element
316: *
317: * @param element
318: * @return created <tt>Interval</tt>
319: * @throws XMLParsingException
320: */
321: protected Interval parseInterval(Element element, URI namespaceURI)
322: throws XMLParsingException {
323:
324: try {
325: String tmp = XMLTools.getAttrValue(element, namespaceURI,
326: "type", null);
327: URI type = null;
328: if (tmp != null)
329: type = new URI(tmp);
330: String semantic = XMLTools.getAttrValue(element,
331: namespaceURI, "semantic", null);
332: tmp = XMLTools.getAttrValue(element, null, "atomic", null);
333: boolean atomic = "true".equals(tmp) || "1".equals(tmp);
334: String clos = XMLTools.getAttrValue(element, namespaceURI,
335: "closure", null);
336:
337: Closure closure = new Closure(clos);
338:
339: Element elem = XMLTools.getRequiredChildElement("min",
340: namespaceURI, element);
341: TypedLiteral min = parseTypedLiteral(elem);
342:
343: elem = XMLTools.getRequiredChildElement("min",
344: namespaceURI, element);
345: TypedLiteral max = parseTypedLiteral(elem);
346:
347: elem = XMLTools.getRequiredChildElement("res",
348: namespaceURI, element);
349: TypedLiteral res = parseTypedLiteral(elem);
350:
351: URI sem = null;
352: if (semantic != null)
353: sem = new URI(semantic);
354:
355: return new Interval(min, max, type, sem, atomic, closure,
356: res);
357: } catch (URISyntaxException e) {
358: LOG.logError(e.getMessage(), e);
359: throw new XMLParsingException(
360: "couldn't parse URI from interval\n"
361: + StringTools.stackTraceToString(e));
362: }
363:
364: }
365:
366: /**
367: * creates a <tt>TypedLiteral</tt> from the passed element
368: *
369: * @param element
370: * @return created <tt>TypedLiteral</tt>
371: * @throws XMLParsingException
372: */
373: protected TypedLiteral parseTypedLiteral(Element element)
374: throws XMLParsingException {
375: try {
376: String tmp = XMLTools.getStringValue(element);
377: String mtype = XMLTools.getAttrValue(element, null, "type",
378: null);
379: URI mt = null;
380: if (mtype != null)
381: mt = new URI(mtype);
382: return new TypedLiteral(tmp, mt);
383: } catch (URISyntaxException e) {
384: LOG.logError(e.getMessage(), e);
385: throw new XMLParsingException(
386: "couldn't parse URI from typedLiteral\n"
387: + StringTools.stackTraceToString(e));
388: }
389: }
390:
391: /**
392: * creates an array of <tt>CodeList</tt> objects from the passed element list
393: *
394: * @param el
395: * @return created array of <tt>CodeList</tt>
396: * @throws XMLParsingException
397: */
398: protected CodeList[] parseCodeListArray(ElementList el)
399: throws XMLParsingException {
400: CodeList[] cl = new CodeList[el.getLength()];
401: for (int i = 0; i < cl.length; i++) {
402: cl[i] = parseCodeList(el.item(i));
403: }
404: return cl;
405: }
406:
407: /**
408: * creates a <tt>CodeList</tt> object from the passed element
409: *
410: * @param element
411: * @return created <tt>CodeList</tt>
412: * @throws XMLParsingException
413: */
414: protected CodeList parseCodeList(Element element)
415: throws XMLParsingException {
416: try {
417: String tmp = XMLTools.getAttrValue(element, null,
418: "codeSpace", null);
419: URI codeSpace = null;
420: if (tmp != null) {
421: codeSpace = new URI(tmp);
422: }
423: tmp = XMLTools.getStringValue(element);
424: String[] ar = StringTools.toArray(tmp, " ,;", true);
425: return new CodeList(element.getNodeName(), ar, codeSpace);
426: } catch (URISyntaxException e) {
427: LOG.logError(e.getMessage(), e);
428: throw new XMLParsingException(
429: "couldn't parse URI from CodeList\n"
430: + StringTools.stackTraceToString(e));
431: }
432: }
433:
434: /**
435: * Creates an <tt>OnLineResource</tt> instance from the passed element. The element contains
436: * an OnlineResourse as it is used in the OGC Web XXX CapabilitiesService specifications.
437: *
438: * TODO Compare with XMLFragment#parseSimpleLink
439: *
440: * @param element
441: * @return
442: * @throws XMLParsingException
443: */
444: protected OnlineResource parseOnLineResource(Element element)
445: throws XMLParsingException {
446:
447: OnlineResource olr = null;
448: String attrValue = XMLTools.getRequiredAttrValue("href", XLNNS,
449: element);
450: URL href = null;
451: try {
452: href = resolve(attrValue);
453: } catch (MalformedURLException e) {
454: LOG.logError(e.getMessage(), e);
455: throw new XMLParsingException("Given value '" + attrValue
456: + "' in attribute 'href' " + "(namespace: " + XLNNS
457: + ") of element '" + element.getLocalName()
458: + "' (namespace: " + element.getNamespaceURI()
459: + ") is not a valid URL.");
460: }
461: Linkage linkage = new Linkage(href, Linkage.SIMPLE);
462: String title = XMLTools.getAttrValue(element, XLNNS, "title",
463: null);
464: olr = new OnlineResource(null, null, linkage, null, title, href
465: .getProtocol());
466: return olr;
467: }
468:
469: /**
470: * Creates a new instance of <code>PropertyPath</code> from the given text node.
471: * <p>
472: * NOTE: Namespace prefices used in the property path must be bound using XML namespace
473: * mechanisms (i.e. using xmlns attributes in the document).
474: *
475: * @param textNode
476: * string representation of the property path
477: * @return new PropertyPath instance
478: * @see PropertyPath
479: */
480: public static PropertyPath parsePropertyPath(Text textNode)
481: throws XMLParsingException {
482:
483: String path = XMLTools.getStringValue(textNode);
484: String[] steps = StringTools.toArray(path, "/", false);
485: List<PropertyPathStep> propertyPathSteps = new ArrayList<PropertyPathStep>(
486: steps.length);
487:
488: for (int i = 0; i < steps.length; i++) {
489: PropertyPathStep propertyStep = null;
490: QualifiedName propertyName = null;
491: String step = steps[i];
492: boolean isAttribute = false;
493: boolean isIndexed = false;
494: int selectedIndex = -1;
495:
496: // check if step begins with '@' -> must be the final step then
497: if (step.startsWith("@")) {
498: if (i != steps.length - 1) {
499: String msg = "PropertyName '"
500: + path
501: + "' is illegal: the attribute specifier may only "
502: + "be used for the final step.";
503: throw new XMLParsingException(msg);
504: }
505: step = step.substring(1);
506: isAttribute = true;
507: }
508:
509: // check if the step ends with brackets ([...])
510: if (step.endsWith("]")) {
511: if (isAttribute) {
512: String msg = "PropertyName '"
513: + path
514: + "' is illegal: if the attribute specifier ('@') is used, "
515: + "index selection ('[...']) is not possible.";
516: throw new XMLParsingException(msg);
517: }
518: int bracketPos = step.indexOf('[');
519: if (bracketPos < 0) {
520: String msg = "PropertyName '"
521: + path
522: + "' is illegal. No opening brackets found for step '"
523: + step + "'.";
524: throw new XMLParsingException(msg);
525: }
526: try {
527: selectedIndex = Integer.parseInt(step.substring(
528: bracketPos + 1, step.length() - 1));
529: } catch (NumberFormatException e) {
530: String msg = "PropertyName '"
531: + path
532: + "' is illegal. Specified index '"
533: + step.substring(bracketPos + 1, step
534: .length() - 1)
535: + "' is not a number.";
536: throw new XMLParsingException(msg);
537: }
538: step = step.substring(0, bracketPos);
539: isIndexed = true;
540: }
541:
542: // determine namespace prefix and binding (if any)
543: int colonPos = step.indexOf(':');
544: if (colonPos < 0) {
545: propertyName = new QualifiedName(step);
546: } else {
547: String prefix = step.substring(0, colonPos);
548: step = step.substring(colonPos + 1);
549: URI namespace = null;
550: try {
551: namespace = XMLTools.getNamespaceForPrefix(prefix,
552: textNode);
553: } catch (URISyntaxException e) {
554: throw new XMLParsingException(
555: "Error parsing PropertyName: "
556: + e.getMessage());
557: }
558: if (namespace == null) {
559: throw new XMLParsingException("PropertyName '"
560: + path
561: + "' uses an unbound namespace prefix: "
562: + prefix);
563: }
564: propertyName = new QualifiedName(prefix, step,
565: namespace);
566: }
567:
568: if (isAttribute) {
569: propertyStep = PropertyPathFactory
570: .createAttributePropertyPathStep(propertyName);
571: } else if (isIndexed) {
572: propertyStep = PropertyPathFactory
573: .createPropertyPathStep(propertyName,
574: selectedIndex);
575: } else {
576: propertyStep = PropertyPathFactory
577: .createPropertyPathStep(propertyName);
578: }
579: propertyPathSteps.add(propertyStep);
580: }
581: return PropertyPathFactory
582: .createPropertyPath(propertyPathSteps);
583: }
584: }
|