// $Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/ogcbase/OGCDocument.java,v 1.21 2006/07/12 16:57:57 poth Exp $
/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2006 by:
EXSE, Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53115 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.ogcbase;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.deegree.datatypes.CodeList;
import org.deegree.datatypes.QualifiedName;
import org.deegree.datatypes.time.TimeDuration;
import org.deegree.datatypes.time.TimePeriod;
import org.deegree.datatypes.time.TimePosition;
import org.deegree.datatypes.time.TimeSequence;
import org.deegree.datatypes.values.Closure;
import org.deegree.datatypes.values.Interval;
import org.deegree.datatypes.values.TypedLiteral;
import org.deegree.datatypes.values.Values;
import org.deegree.framework.util.StringTools;
import org.deegree.framework.xml.ElementList;
import org.deegree.framework.xml.XMLFragment;
import org.deegree.framework.xml.XMLParsingException;
import org.deegree.framework.xml.XMLTools;
import org.deegree.model.metadata.iso19115.Keywords;
import org.deegree.model.metadata.iso19115.Linkage;
import org.deegree.model.metadata.iso19115.OnlineResource;
import org.deegree.model.spatialschema.Point;
import org.deegree.ogcwebservices.LonLatEnvelope;
import org.deegree.ogcwebservices.OGCWebServiceException;
import org.deegree.ogcwebservices.wcs.describecoverage.InvalidCoverageDescriptionExcpetion;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
/**
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
* @author last edited by: $Author: poth $
*
* @version 1.0. $Revision: 1.21 $, $Date: 2006/07/12 16:57:57 $
*
* @since 1.1
*/
public abstract class OGCDocument extends XMLFragment {
protected static final URI GMLNS = CommonNamespaces.GMLNS;
/**
* creates a <tt>LonLatEnvelope</tt> object from the passed element
*
* @param element
* @return created <tt>LonLatEnvelope</tt>
* @throws XMLParsingException
* @throws InvalidCoverageDescriptionExcpetion
*/
protected LonLatEnvelope parseLonLatEnvelope( Element element )
throws XMLParsingException, OGCWebServiceException {
String srs = XMLTools.getRequiredAttrValue( "srsName", null, element );
if ( !"WGS84(DD)".equals( srs ) ) {
throw new OGCWebServiceException( "srsName must be WGS84(DD) for lonLatEnvelope." );
}
ElementList el = XMLTools.getChildElements( "pos", GMLNS, element );
if ( el == null || el.getLength() != 2 ) {
throw new OGCWebServiceException( "A lonLatEnvelope must contain two gml:pos elements" );
}
Point min = GMLDocument.parsePos( el.item( 0 ) );
Point max = GMLDocument.parsePos( el.item( 1 ) );
el = XMLTools.getChildElements( "timePosition", GMLNS, element );
TimePosition[] timePositions = parseTimePositions( el );
return new LonLatEnvelope( min, max, timePositions, "WGS84(DD)" );
}
/**
* creates an array of <tt>TimePosition</tt> s from the passed element
*
* @param el
* @return created array of <tt>TimePosition</tt> s
* @throws XMLParsingException
* @throws InvalidCoverageDescriptionExcpetion
*/
protected TimePosition[] parseTimePositions( ElementList el )
throws XMLParsingException, OGCWebServiceException {
TimePosition[] timePos = new TimePosition[el.getLength()];
for ( int i = 0; i < timePos.length; i++ ) {
timePos[i] = GMLDocument.parseTimePosition( el.item( i ) );
}
return timePos;
}
/**
* Creates an array of <code>Keywords</code> from the passed list of <code>keyword</code>
* -elements.
*
* This appears to be pretty superfluous (as one <code>keywords</code>- element may contain
* several <code>keyword</code> -elements). However, the schema in the OGC document "Web
* Coverage Service (WCS), Version 1.0.0", contains the following line (in the definition of the
* CoverageOfferingBriefType):
*
* <code><xs:element ref="keywords" minOccurs="0" maxOccurs="unbounded"/></code>
*
* @param el
* @return created array of <tt>Keywords</tt>
* @throws XMLParsingException
*/
protected Keywords[] parseKeywords( ElementList el, URI namespaceURI ) {
Keywords[] kws = new Keywords[el.getLength()];
for ( int i = 0; i < kws.length; i++ ) {
kws[i] = parseKeywords( el.item( i ), namespaceURI );
}
return kws;
}
/**
* Creates a <code>Keywords</code> instance from the given <code>keywords</code> -element.
*
* @param element
* @param namespaceURI
* @return created <code>Keywords</code>
* @throws XMLParsingException
*/
protected Keywords parseKeywords( Element element, URI namespaceURI ) {
ElementList el = XMLTools.getChildElements( "keyword", namespaceURI, element );
String[] kws = new String[el.getLength()];
for ( int i = 0; i < kws.length; i++ ) {
kws[i] = XMLTools.getStringValue( el.item( i ) );
}
return new Keywords( kws );
}
/**
* creates an <tt>TimeSequence</tt> from the passed element
*
* @param element
* @return created <tt>TimeSequence</tt>
* @throws XMLParsingException
* @throws InvalidCoverageDescriptionExcpetion
*/
protected TimeSequence parseTimeSequence( Element element, URI namespaceURI )
throws XMLParsingException, OGCWebServiceException {
ElementList el = XMLTools.getChildElements( "timePerdiod", namespaceURI, element );
TimePeriod[] timePerdiods = parseTimePeriods( el, namespaceURI );
el = XMLTools.getChildElements( "timePosition", GMLNS, element );
TimePosition[] timePositions = parseTimePositions( el );
return new TimeSequence( timePerdiods, timePositions );
}
/**
* creates an array of <tt>TimePeriod</tt> s from the passed element
*
* @param el
* @return created array of <tt>TimePeriod</tt> s
* @throws XMLParsingException
* @throws InvalidCoverageDescriptionExcpetion
*/
protected TimePeriod[] parseTimePeriods( ElementList el, URI namespaceURI )
throws XMLParsingException, OGCWebServiceException {
TimePeriod[] timePeriods = new TimePeriod[el.getLength()];
for ( int i = 0; i < timePeriods.length; i++ ) {
timePeriods[i] = parseTimePeriod( el.item( i ), namespaceURI );
}
return timePeriods;
}
/**
* creates a <tt>TimePeriod</tt> from the passed element
*
* @param element
* @return created <tt>TimePeriod</tt>
* @throws XMLParsingException
* @throws InvalidCoverageDescriptionExcpetion
*/
protected TimePeriod parseTimePeriod( Element element, URI namespaceURI )
throws XMLParsingException, OGCWebServiceException {
try {
Element begin = XMLTools.getRequiredChildElement( "beginPosition", namespaceURI,
element );
TimePosition beginPosition = GMLDocument.parseTimePosition( begin );
Element end = XMLTools.getRequiredChildElement( "endPosition", namespaceURI, element );
TimePosition endPosition = GMLDocument.parseTimePosition( end );
String dur = XMLTools.getRequiredStringValue( "timeResolution", namespaceURI, element );
TimeDuration resolution = TimeDuration.createTimeDuration( dur );
return new TimePeriod( beginPosition, endPosition, resolution );
} catch ( InvalidGMLException e ) {
String s = e.getMessage() + "\n" + StringTools.stackTraceToString( e );
throw new OGCWebServiceException( s );
}
}
/**
* creates a <tt>Values</tt> object from the passed element
*
* @param element
* @return created <tt>Values</tt>
* @throws XMLParsingException
*/
protected Values parseValues( Element element, URI namespaceURI )
throws XMLParsingException {
String type = XMLTools.getAttrValue( element, namespaceURI, "type" );
String semantic = XMLTools.getAttrValue( element, namespaceURI, "semantic" );
ElementList el = XMLTools.getChildElements( "interval", namespaceURI, element );
Interval[] intervals = new Interval[el.getLength()];
for ( int i = 0; i < intervals.length; i++ ) {
intervals[i] = parseInterval( el.item( i ), namespaceURI );
}
el = XMLTools.getChildElements( "singleValue", namespaceURI, element );
TypedLiteral[] singleValues = new TypedLiteral[el.getLength()];
for ( int i = 0; i < singleValues.length; i++ ) {
singleValues[i] = parseTypedLiteral( el.item( i ) );
}
Element elem = XMLTools.getChildElement( "default", namespaceURI, element );
TypedLiteral def = null;
if ( elem != null ) {
def = parseTypedLiteral( elem );
}
try {
URI sem = null;
if ( semantic != null )
sem = new URI( semantic );
URI tp = null;
if ( type != null )
tp = new URI( type );
return new Values( intervals, singleValues, tp, sem, def );
} catch ( URISyntaxException e ) {
throw new XMLParsingException( "couldn't parse URI from valuesl\n"
+ StringTools.stackTraceToString( e ) );
}
}
/**
* creates an <tt>Interval</tt> object from the passed element
*
* @param element
* @return created <tt>Interval</tt>
* @throws XMLParsingException
*/
protected Interval parseInterval( Element element, URI namespaceURI )
throws XMLParsingException {
try {
String tmp = XMLTools.getAttrValue( element, namespaceURI, "type" );
URI type = null;
if ( tmp != null )
type = new URI( tmp );
String semantic = XMLTools.getAttrValue( element, namespaceURI, "semantic" );
tmp = XMLTools.getAttrValue( element, "atomic" );
boolean atomic = "true".equals( tmp ) || "1".equals( tmp );
String clos = XMLTools.getAttrValue( element, namespaceURI, "closure" );
Closure closure = new Closure( clos );
Element elem = XMLTools.getRequiredChildElement( "min", namespaceURI, element );
TypedLiteral min = parseTypedLiteral( elem );
elem = XMLTools.getRequiredChildElement( "min", namespaceURI, element );
TypedLiteral max = parseTypedLiteral( elem );
elem = XMLTools.getRequiredChildElement( "res", namespaceURI, element );
TypedLiteral res = parseTypedLiteral( elem );
URI sem = null;
if ( semantic != null )
sem = new URI( semantic );
return new Interval( min, max, type, sem, atomic, closure, res );
} catch ( URISyntaxException e ) {
throw new XMLParsingException( "couldn't parse URI from interval\n"
+ StringTools.stackTraceToString( e ) );
}
}
/**
* creates a <tt>TypedLiteral</tt> from the passed element
*
* @param element
* @return created <tt>TypedLiteral</tt>
* @throws XMLParsingException
*/
protected TypedLiteral parseTypedLiteral( Element element )
throws XMLParsingException {
try {
String tmp = XMLTools.getStringValue( element );
String mtype = XMLTools.getAttrValue( element, "type" );
URI mt = null;
if ( mtype != null )
mt = new URI( mtype );
return new TypedLiteral( tmp, mt );
} catch ( URISyntaxException e ) {
throw new XMLParsingException( "couldn't parse URI from typedLiteral\n"
+ StringTools.stackTraceToString( e ) );
}
}
/**
* creates an array of <tt>CodeList</tt> objects from the passed element list
*
* @param el
* @return created array of <tt>CodeList</tt>
* @throws XMLParsingException
*/
protected CodeList[] parseCodeListArray( ElementList el )
throws XMLParsingException {
CodeList[] cl = new CodeList[el.getLength()];
for ( int i = 0; i < cl.length; i++ ) {
cl[i] = parseCodeList( el.item( i ) );
}
return cl;
}
/**
* creates a <tt>CodeList</tt> object from the passed element
*
* @param element
* @return created <tt>CodeList</tt>
* @throws XMLParsingException
*/
protected CodeList parseCodeList( Element element )
throws XMLParsingException {
try {
String tmp = XMLTools.getAttrValue( element, "codeSpace" );
URI codeSpace = null;
if ( tmp != null ) {
codeSpace = new URI( tmp );
}
tmp = XMLTools.getStringValue( element );
String[] ar = StringTools.toArray( tmp, " ,;", true );
return new CodeList( element.getNodeName(), ar, codeSpace );
} catch ( URISyntaxException e ) {
throw new XMLParsingException( "couldn't parse URI from CodeList\n"
+ StringTools.stackTraceToString( e ) );
}
}
/**
* Creates an <tt>OnLineResource</tt> instance from the passed element. The element contains
* an OnlineResourse as it is used in the OGC Web XXX CapabilitiesService specifications.
*
* TODO Compare with XMLFragment#parseSimpleLink
*
* @param element
* @return
* @throws XMLParsingException
*/
protected OnlineResource parseOnLineResource( Element element )
throws XMLParsingException {
OnlineResource olr = null;
String attrValue = XMLTools.getRequiredAttrValue( "href", XLNNS, element );
URL href = null;
try {
href = resolve( attrValue );
} catch ( MalformedURLException e ) {
throw new XMLParsingException( "Given value '" + attrValue + "' in attribute 'href' "
+ "(namespace: " + XLNNS + ") of element '"
+ element.getLocalName() + "' (namespace: "
+ element.getNamespaceURI() + ") is not a valid URL." );
}
Linkage linkage = new Linkage( href, Linkage.SIMPLE );
String title = XMLTools.getAttrValue( element, XLNNS, "title" );
olr = new OnlineResource( null, null, linkage, null, title, href.getProtocol() );
return olr;
}
/**
* Creates a new instance of <code>PropertyPath</code> from the given text node.
* <p>
* NOTE: Namespace prefices used in the property path must be bound using XML namespace
* mechanisms (i.e. using xmlns attributes in the document).
*
* @param textNode
* string representation of the property path
* @return new PropertyPath instance
* @see PropertyPath
*/
public static PropertyPath parsePropertyPath( Text textNode )
throws XMLParsingException {
String path = XMLTools.getStringValue( textNode );
String[] steps = StringTools.toArray( path, "/", false );
List<PropertyPathStep> propertyPathSteps = new ArrayList<PropertyPathStep>( steps.length );
for ( int i = 0; i < steps.length; i++ ) {
PropertyPathStep propertyStep = null;
QualifiedName propertyName = null;
String step = steps[i];
boolean isAttribute = false;
boolean isIndexed = false;
int selectedIndex = -1;
// check if step begins with '@' -> must be the final step then
if ( step.startsWith( "@" ) ) {
if ( i != steps.length - 1 ) {
String msg = "PropertyName '" + path
+ "' is illegal: the attribute specifier may only "
+ "be used for the final step.";
throw new XMLParsingException( msg );
}
step = step.substring( 1 );
isAttribute = true;
}
// check if the step ends with brackets ([...])
if ( step.endsWith( "]" ) ) {
if ( isAttribute ) {
String msg = "PropertyName '" + path
+ "' is illegal: if the attribute specifier ('@') is used, "
+ "index selection ('[...']) is not possible.";
throw new XMLParsingException( msg );
}
int bracketPos = step.indexOf( '[' );
if ( bracketPos < 0 ) {
String msg = "PropertyName '" + path
+ "' is illegal. No opening brackets found for step '" + step
+ "'.";
throw new XMLParsingException( msg );
}
try {
selectedIndex = Integer.parseInt( step.substring( bracketPos + 1,
step.length() - 1 ) );
} catch ( NumberFormatException e ) {
String msg = "PropertyName '" + path + "' is illegal. Specified index '"
+ step.substring( bracketPos + 1, step.length() - 1 )
+ "' is not a number.";
throw new XMLParsingException( msg );
}
step = step.substring( 0, bracketPos );
isIndexed = true;
}
// determine namespace prefix and binding (if any)
int colonPos = step.indexOf( ':' );
if ( colonPos < 0 ) {
propertyName = new QualifiedName( step );
} else {
String prefix = step.substring( 0, colonPos );
step = step.substring( colonPos + 1 );
URI namespace = null;
try {
namespace = XMLTools.getNamespaceForPrefix( prefix, textNode );
} catch ( URISyntaxException e ) {
throw new XMLParsingException( "Error parsing PropertyName: " + e.getMessage() );
}
if ( namespace == null ) {
throw new XMLParsingException( "PropertyName '" + path
+ "' uses an unbound namespace prefix: "
+ prefix );
}
propertyName = new QualifiedName( prefix, step, namespace );
}
if ( isAttribute ) {
propertyStep = PropertyPathFactory.createAttributePropertyPathStep( propertyName );
} else if ( isIndexed ) {
propertyStep = PropertyPathFactory.createPropertyPathStep( propertyName,
selectedIndex );
} else {
propertyStep = PropertyPathFactory.createPropertyPathStep( propertyName );
}
propertyPathSteps.add( propertyStep );
}
return PropertyPathFactory.createPropertyPath( propertyPathSteps );
}
}
/***************************************************************************************************
* Changes to this class. What the people have been up to: $Log: OGCDocument.java,v $
* Changes to this class. What the people have been up to: Revision 1.21 2006/07/12 16:57:57 poth
* Changes to this class. What the people have been up to: *** empty log message ***
* Changes to this class. What the people have been up to:
* Changes to this class. What the people have been up to: Revision 1.20 2006/07/06 17:34:55 mschneider
* Changes to this class. What the people have been up to: Fixed handling of unbound namespace prefices in parsePropertyPath().
* Changes to this class. What the people have been up to:
* Changes to this class. What the people have been up to: Revision 1.19 2006/04/06 20:25:22 poth
* Changes to this class. What the people have been up to: *** empty log message ***
* Changes to this class. What the people have been up to:
* Changes to this class. What the people have been up to: Revision 1.18 2006/04/04 20:39:40 poth
* Changes to this class. What the people have been up to: *** empty log message ***
* Changes to this class. What the people have been up to:
* Changes to this class. What the people have been up to: Revision 1.17 2006/04/04 10:33:06 mschneider
* Changes to this class. What the people have been up to: Adapted to updated PropertyPath classes.
* Changes to this class. What the people have been up to: Changes to
* this class. What the people have been up to: Revision 1.16 2006/03/30 21:20:24 poth Changes to
* this class. What the people have been up to: *** empty log message *** Changes to this class.
* What the people have been up to: Changes to this class. What the people have been up to: Revision
* 1.15 2006/03/21 21:38:40 poth Changes to this class. What the people have been up to: *** empty
* log message *** Changes to this class. What the people have been up to: Changes to this class.
* What the people have been up to: Revision 1.14 2006/01/11 16:57:15 poth Changes to this class.
* What the people have been up to: *** empty log message *** Changes to this class. What the people
* have been up to: Changes to this class. What the people have been up to: Revision 1.13 2005/11/22
* 18:05:17 deshmukh Changes to this class. What the people have been up to: java split method
* replaced with StringTools.toArray() Changes to this class. What the people have been up to:
* Changes to this class. What the people have been up to: Revision 1.12 2005/11/16 13:45:00
* mschneider Changes to this class. What the people have been up to: Merge of wfs development
* branch. Changes to this class. What the people have been up to: Changes to this class. What the
* people have been up to: Revision 1.11.2.3 2005/11/15 17:01:04 mschneider Changes to this class.
* What the people have been up to: Fixed off-by one error in parsePropertyPath(). Changes to this
* class. What the people have been up to: Changes to this class. What the people have been up to:
* Revision 1.11.2.2 2005/11/10 15:24:44 mschneider Changes to this class. What the people have been
* up to: Refactoring: use "PropertyPath" in "org.deegree.model.filterencoding.PropertyName".
* Changes to this class. What the people have been up to: Revision 1.2 2005/03/09 11:55:46
* mschneider *** empty log message ***
*
* Revision 1.1.1.1 2005/01/05 10:33:22 poth no message
*
* Revision 1.21 2004/08/26 15:43:31 tf no message
*
*
* Revision 1.9 2004/06/30 15:16:05 mschneider Refactoring of XMLTools.
*
* Revision 1.8 2004/06/28 06:40:04 ap no message
*
* Revision 1.7 2004/06/23 14:55:14 ap no message
*
* Revision 1.6 2004/06/23 14:01:04 tf add getCapabilities() method
*
* Revision 1.5 2004/06/23 11:48:38 tf javadoc updated
*
* Revision 1.4 2004/06/21 08:05:49 ap no message
*
* Revision 1.3 2004/06/02 14:10:34 ap no message
*
* Revision 1.2 2004/06/02 07:01:41 ap no message
*
* Revision 1.1 2004/05/31 07:37:45 ap no message
*
**************************************************************************************************/