// $Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/owscommon/OWSCommonCapabilitiesDocument.java,v 1.27 2006/10/11 13:53:31 mschneider 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.owscommon; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.List; import java.util.Map; import org.deegree.datatypes.Code; import org.deegree.datatypes.xlink.SimpleLink; import org.deegree.framework.log.ILogger; import org.deegree.framework.log.LoggerFactory; import org.deegree.framework.util.StringTools; import org.deegree.framework.xml.ElementList; import org.deegree.framework.xml.InvalidConfigurationException; import org.deegree.framework.xml.XMLParsingException; import org.deegree.framework.xml.XMLTools; import org.deegree.model.metadata.iso19115.Address; import org.deegree.model.metadata.iso19115.ContactInfo; import org.deegree.model.metadata.iso19115.Keywords; import org.deegree.model.metadata.iso19115.OnlineResource; import org.deegree.model.metadata.iso19115.Phone; import org.deegree.model.metadata.iso19115.TypeCode; import org.deegree.model.spatialschema.Envelope; import org.deegree.model.spatialschema.GeometryFactory; import org.deegree.ogcbase.CommonNamespaces; import org.deegree.ogcwebservices.getcapabilities.DCPType; import org.deegree.ogcwebservices.getcapabilities.HTTP; import org.deegree.ogcwebservices.getcapabilities.OGCCapabilitiesDocument; import org.deegree.ogcwebservices.getcapabilities.Operation; import org.deegree.ogcwebservices.getcapabilities.Protocol; import org.deegree.ogcwebservices.getcapabilities.ServiceIdentification; import org.deegree.ogcwebservices.getcapabilities.ServiceProvider; import org.w3c.dom.Element; import org.w3c.dom.Node; /** * Represents a configuration document for an OGC-Webservice according to the * <code>OWS Common Implementation Specification 0.2</code>. * <p> * It consists of the following elements: <table border="1"> * <tr> * <th>Name</th> * <th>Function</th> * </tr> * <tr> * <td>ServiceIdentification</td> * <td>corresponds to and expands the SV_ServiceIdentification class in ISO 19119</td> * </tr> * <tr> * <td>ServiceProvider</td> * <td>corresponds to and expands the SV_ServiceProvider class in ISO 19119 </td> * </tr> * <tr> * <td>OperationsMetadata</td> * <td>contains set of Operation elements that each corresponds to and expand the * SV_OperationsMetadata class in ISO 19119</td> * </tr> * <tr> * <td>Contents</td> * <td>whenever relevant, contains set of elements that each corresponds to the * MD_DataIdentification class in ISO 19119 and 19115</td> * </tr> * </table> * * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a> * @author last edited by: $Author: mschneider $ * * @version 2.0, $Revision: 1.27 $, $Date: 2006/10/11 13:53:31 $ * * @since 2.0 * */ public abstract class OWSCommonCapabilitiesDocument extends OGCCapabilitiesDocument { private static final ILogger LOG = LoggerFactory .getLogger( OWSCommonCapabilitiesDocument.class ); public final static String ALL_NAME = "All"; public final static String SERVICE_IDENTIFICATION_NAME = "ServiceIdentification"; public final static String SERVICE_PROVIDER_NAME = "ServiceProvider"; public final static String OPERATIONS_METADATA_NAME = "OperationsMetadata"; public final static String CONTENTS_NAME = "Contents"; protected static final URI OWSNS = CommonNamespaces.OWSNS; protected static final URI OGCNS = CommonNamespaces.OGCNS; /** * Returns the class representation for the <code>ServiceProvider</code> section of the * document. * * @return class representation for the <code>ServiceProvider</code> section * @throws XMLParsingException */ public ServiceProvider getServiceProvider() throws XMLParsingException { LOG.entering(); Element element = XMLTools.getRequiredChildElement( "ServiceProvider", OWSNS, getRootElement() ); // 'ProviderName' element (optional, default value: 'deegree') String providerName = XMLTools.getStringValue( "ProviderName", OWSNS, element, "deegree" ); // 'ProviderSite' element (optional) Element providerSiteElement = XMLTools.getChildElement( "ProviderSite", OWSNS, element ); SimpleLink providerSite = null; if ( providerSiteElement != null ) { providerSite = parseSimpleLink( providerSiteElement ); } // 'ServiceContact' element (mandatory) Element serviceContactElement = XMLTools.getRequiredChildElement( "ServiceContact", OWSNS, element ); // 'IndividualName' element (optional) String individualName = XMLTools.getStringValue( "IndividualName", OWSNS, serviceContactElement, null ); // 'PositionName' element (optional) String positionName = XMLTools.getStringValue( "PositionName", OWSNS, serviceContactElement, null ); // 'ContactInfo' element (optional) ContactInfo contactInfo = null; Element contactInfoElement = XMLTools.getChildElement( "ContactInfo", OWSNS, serviceContactElement ); if ( contactInfoElement != null ) { contactInfo = getContactInfo( contactInfoElement ); } TypeCode role = null; Element roleElement = (Element) XMLTools .getNode( serviceContactElement, "ows:Role", nsContext ); if ( roleElement != null ) { role = getCodeType( roleElement ); } ServiceProvider serviceProvider = new ServiceProvider( providerName, providerSite, individualName, positionName, contactInfo, role ); LOG.exiting(); return serviceProvider; } /** * Returns the class representation for the <code>ServiceIdentification</code> section of the * document. * * @return class representation for the <code>ServiceIdentification</code> section * @throws XMLParsingException */ public ServiceIdentification getServiceIdentification() throws XMLParsingException { LOG.entering(); Element element = XMLTools.getRequiredChildElement( "ServiceIdentification", OWSNS, getRootElement() ); // 'ServiceType' element (mandatory) Element serviceTypeElement = XMLTools.getRequiredChildElement( "ServiceType", OWSNS, element ); Code serviceType = null; try { String codeSpace = XMLTools.getAttrValue( serviceTypeElement, OWSNS, "codeSpace" ); URI uri = codeSpace != null ? new URI( codeSpace ) : null; serviceType = new Code( XMLTools.getStringValue( serviceTypeElement ), uri ); } catch (URISyntaxException e) { throw new XMLParsingException( "Given value '" + XMLTools.getAttrValue( serviceTypeElement, OWSNS, "codeSpace" ) + "' in attribute 'codeSpace' of element 'ServiceType' " + "(namespace: '" + OWSNS + "') is not a valid URI." ); } // 'ServiceTypeVersion' elements (mandatory) String[] serviceTypeVersions = XMLTools.getRequiredNodeAsStrings( element, "ows:ServiceTypeVersion", nsContext, ",;" ); // 'Title' element (mandatory) String title = XMLTools.getRequiredStringValue( "Title", OWSNS, element ); // 'Abstract' element (optional) String serviceAbstract = XMLTools.getRequiredStringValue( "Abstract", OWSNS, element ); // 'Keywords' elements (optional) List keywordsList = XMLTools.getNodes( element, "ows:Keywords", nsContext ); Keywords[] keywords = getKeywords( keywordsList ); // 'Fees' element (optional) String fees = XMLTools.getStringValue( "Fees", OWSNS, element, null ); // 'AccessConstraints' elements (optional) String accessConstraints[] = XMLTools.getNodesAsStrings( element, "ows:AccessConstraints", nsContext ); ServiceIdentification serviceIdentification = new ServiceIdentification( serviceType, serviceTypeVersions, title, serviceAbstract, keywords, fees, accessConstraints ); LOG.exiting(); return serviceIdentification; } /** * Creates a <code>Keywords</code> instance from the given element of type * <code>ows:KeywordsType</code>. * * NOTE: This method is redefined here (it is already defined in <code>OGCDocument</code>), * because the spelling of the first letter ('K') changed in the OWS Common Implementation * Specification 0.2 from lowercase to uppercase. * * @param element * @return created <code>Keywords</code> * @throws XMLParsingException */ protected Keywords getKeywords( Element element ) throws XMLParsingException { LOG.entering(); TypeCode codeType = null; Element codeTypeElement = (Element) XMLTools.getNode( element, "ows:Type", nsContext ); if ( codeTypeElement != null ) { codeType = getCodeType( codeTypeElement ); } Keywords keywords = new Keywords( XMLTools.getNodesAsStrings( element, "ows:Keyword/text()", nsContext ), null, codeType ); LOG.exiting(); return keywords; } /** * Creates an array of <code> Keywords </code> instances from the passed list of elements of * type <code> ows:KeywordsType </code>. * * This may appear to be pretty superfluous (as one <code> ows:KeywordsType * </code> can hold * several elements of type <code> ows:Keyword * </code>. * * @param nl * may be null * @return created array of <code> Keywords </code>, null if <code>NodeList</code> constains * zero elements * @throws XMLParsingException */ protected Keywords[] getKeywords( List nl ) throws XMLParsingException { LOG.entering(); Keywords[] kws = null; if ( nl.size() > 0 ) { kws = new Keywords[nl.size()]; for (int i = 0; i < kws.length; i++) { kws[i] = getKeywords( (Element) nl.get( i ) ); } } LOG.exiting(); return kws; } /** * Creates a <code>DCPType</code> object from the passed <code>DCP</code> element. * <p> * NOTE: Currently the <code>OnlineResources</code> included in the <code>DCPType</code> are * just stored as simple <code>URLs</code> (not as <code>OnLineResource</code> instances)! * <p> * NOTE: In an <code>OGCStandardCapabilitiesDocument</code> the <code>XLinks</code> (the * <code>URLs</code>) are stored in separate elements (<code>OnlineResource</code>), in * an <code>OGCCommonCapabilitiesDocument</code> they are the * <code>Get<code>/<code>Post</code> elements themselves. * * @param element * @param namespaceURI * @return created <code>DCPType</code> * @throws XMLParsingException * @see org.deegree.ogcwebservices.getcapabilities.OGCStandardCapabilities */ protected DCPType getDCP( Element element ) throws XMLParsingException { LOG.entering(); DCPType dcpType = null; try { Element elem = (Element) XMLTools.getRequiredNode( element, "ows:HTTP", nsContext ); List nl = XMLTools.getNodes( elem, "ows:Get", nsContext ); URL[] get = new URL[nl.size()]; for (int i = 0; i < get.length; i++) { String s = XMLTools.getNodeAsString( (Node)nl.get( i ), "./@xlink:href", nsContext, null ); if ( s == null ) { s = XMLTools.getRequiredNodeAsString( (Node)nl.get( i ), "./ows:OnlineResource/@xlink:href", nsContext ); } get[i] = new URL( s ); } nl = XMLTools.getNodes( elem, "ows:Post", nsContext ); URL[] post = new URL[nl.size()]; for (int i = 0; i < post.length; i++) { String s = XMLTools.getNodeAsString( (Node)nl.get( i ), "./@xlink:href", nsContext, null ); if ( s == null ) { s = XMLTools.getRequiredNodeAsString( (Node)nl.get( i ), "./ows:OnlineResource/@xlink:href", nsContext ); } post[i] = new URL( s ); } Protocol protocol = new HTTP( get, post ); dcpType = new DCPType( protocol ); } catch (MalformedURLException e) { throw new XMLParsingException( "Couldn't parse DCPType onlineresource URL about: " + StringTools.stackTraceToString( e ) ); } LOG.exiting(); return dcpType; } /** * Creates an array of <code>DCPType</code> objects from the passed element list. * <p> * NOTE: Currently the <code>OnlineResources</code> included in the <code>DCPType</code> are * just stored as simple <code>URLs</code> (not as <code>OnLineResource</code> instances)! * * @param el * @return * @throws XMLParsingException */ protected DCPType[] getDCPs( List el ) throws XMLParsingException { LOG.entering(); DCPType[] dcpTypes = new DCPType[el.size()]; for (int i = 0; i < dcpTypes.length; i++) { dcpTypes[i] = getDCP( (Element) el.get( i ) ); } LOG.exiting(); return dcpTypes; } /** * Creates a class representation of an <code>ows:Operation</code>- element. * * @param name * @param isMandatory * @param operations * @return * @throws InvalidConfigurationException */ protected Operation getOperation( String name, boolean isMandatory, Map operations ) throws XMLParsingException { LOG.entering(); Operation operation = null; Element operationElement = (Element) operations.get( name ); if ( operationElement == null ) { if ( isMandatory ) { throw new XMLParsingException( "Mandatory operation '" + name + "' not defined in " + "'OperationsMetadata'-section." ); } } else { // "ows:Parameter"-elements ElementList parameterElements = XMLTools.getChildElements( "Parameter", OWSNS, operationElement ); OWSDomainType[] parameters = new OWSDomainType[parameterElements.getLength()]; for (int i = 0; i < parameters.length; i++) { parameters[i] = getOWSDomainType( name, parameterElements.item( i ) ); } DCPType[] dcps = getDCPs( XMLTools.getRequiredNodes( operationElement, "ows:DCP", nsContext ) ); operation = new Operation( name, dcps, parameters ); } LOG.exiting(); return operation; } /** * Creates a class representation of an element of type <code>ows:DomainType</code>. * * @param element * @return * @throws XMLParsingException */ protected OWSDomainType getOWSDomainType( String operation, Element element ) throws XMLParsingException { LOG.entering(); // "name"-attribute String name = XMLTools.getRequiredNodeAsString( element, "@name", nsContext ); // "ows:Value"-elements String[] values = XMLTools.getNodesAsStrings( element, "ows:Value/text()", nsContext ); if ( values.length < 1 ) { throw new XMLParsingException( "At least one 'ows:Value'-element must be defined in each " + "element of type 'ows:DomainType'." ); } // TODO: "ows:Metadata"-elements OWSDomainType domainType = new OWSDomainType( name, values, null ); LOG.exiting(); return domainType; } /** * Creates a class representation of an element of type <code>ows:CodeType</code>. * * @param element * @return * @throws XMLParsingException */ protected TypeCode getCodeType( Element element ) throws XMLParsingException { String code = XMLTools.getRequiredNodeAsString( element, "text()", nsContext ); URI codeSpace = null; String codeSpaceString = XMLTools.getNodeAsString( element, "ows:Type/@codespace", nsContext, null ); if ( codeSpaceString != null ) { try { codeSpace = new URI( codeSpaceString ); } catch (URISyntaxException e) { throw new XMLParsingException( "'" + codeSpaceString + "' does not denote a valid URI in: " + e.getMessage() ); } } return new TypeCode( code, codeSpace ); } /** * Creates a <code>ContactInfo</code> object from the given element of type * <code>ows:ContactInfoType</code>. * * @param element * @return * @throws XMLParsingException */ private ContactInfo getContactInfo( Element element ) throws XMLParsingException { // 'Phone' element (optional) Phone phone = null; Element phoneElement = XMLTools.getChildElement( "Phone", OWSNS, element ); if ( phoneElement != null ) { phone = parsePhone( phoneElement, OWSNS ); } // 'Address' element (optional) Address address = null; Element addressElement = XMLTools.getChildElement( "Address", OWSNS, element ); if ( addressElement != null ) { address = parseAddress( addressElement, OWSNS ); } // 'OnlineResource' element (optional) OnlineResource onlineResource = null; Element onlineResourceElement = XMLTools.getChildElement( "OnlineResource", OWSNS, element ); if ( onlineResourceElement != null ) { onlineResource = parseOnLineResource( onlineResourceElement ); } String hoursOfService = XMLTools.getNodeAsString( element, "ows:HoursOfService/text()", nsContext, null ); String contactInstructions = XMLTools.getNodeAsString( element, "ows:ContactInstructions/text()", nsContext, null ); return new ContactInfo( address, contactInstructions, hoursOfService, onlineResource, phone ); } /** * Creates an <code>Envelope</code> object from the given element of type * <code>ows:WGS84BoundingBoxType</code>. * * @param element * @return * @throws XMLParsingException */ protected Envelope getWGS84BoundingBoxType( Element element ) throws XMLParsingException { double[] lowerCorner = XMLTools.getRequiredNodeAsDoubles( element, "ows:LowerCorner/text()", nsContext, " " ); if ( lowerCorner.length != 2 ) { throw new XMLParsingException( "Element 'ows:LowerCorner' must contain exactly two double values." ); } double[] upperCorner = XMLTools.getRequiredNodeAsDoubles( element, "ows:UpperCorner/text()", nsContext, " " ); if ( upperCorner.length != 2 ) { throw new XMLParsingException( "Element 'ows:UpperCorner' must contain exactly two double values." ); } return GeometryFactory.createEnvelope( lowerCorner[0], lowerCorner[1], upperCorner[0], upperCorner[1], null ); } } /*************************************************************************************************** * Changes to this class. What the people have been up to: $Log: OWSCommonCapabilitiesDocument.java,v $ * Changes to this class. What the people have been up to: Revision 1.27 2006/10/11 13:53:31 mschneider * Changes to this class. What the people have been up to: Javadoc improvement. * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.26 2006/07/12 17:00:02 poth * Changes to this class. What the people have been up to: required adaptions according to renaming of OnLineResource to OnlineResource * Changes to this class. What the people have been up to: * Changes to this class. What the people have been up to: Revision 1.25 2006/04/06 20:25:31 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.24 2006/04/04 20:39:44 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.23 2006/03/30 21:20:28 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.22 2006/03/28 09:06:41 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.21 2006/01/04 08:59:11 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 2005/11/17 08:13:58 deshmukh * Changes to this class. What the people have been up to: Renamed nsNode to nsContext * 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 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.18.2.3 2005/11/07 16:25:57 deshmukh * Changes to this class. What the people have been up to: NodeList to List * 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.2.2 2005/11/07 15:38:04 mschneider * Changes to this class. What the people have been up to: Refactoring: use NamespaceContext instead of Node for namespace bindings. * Changes to this class. What the people have been up to: * Revision 1.7 2004/06/22 13:25:14 ap no message * * Revision 1.6 2004/06/21 06:44:57 ap no message * * Revision 1.5 2004/06/09 15:30:37 ap no message * * Revision 1.4 2004/06/08 07:01:27 ap no message * * Revision 1.3 2004/06/03 09:02:20 ap no message * * Revision 1.2 2004/06/02 14:10:44 ap no message * * Revision 1.1 2004/06/02 09:34:07 ap no message * **************************************************************************************************/