001    // $HeadURL:
002    // /cvsroot/deegree/src/org/deegree/ogcwebservices/csw/capabilities/CatalogCapabilitiesDocument.java,v
003    // 1.22 2004/08/05 15:40:08 ap Exp $
004    /*----------------    FILE HEADER  ------------------------------------------
005    
006     This file is part of deegree.
007     Copyright (C) 2001-2008 by:
008     EXSE, Department of Geography, University of Bonn
009     http://www.giub.uni-bonn.de/deegree/
010     lat/lon GmbH
011     http://www.lat-lon.de
012    
013     This library is free software; you can redistribute it and/or
014     modify it under the terms of the GNU Lesser General Public
015     License as published by the Free Software Foundation; either
016     version 2.1 of the License, or (at your option) any later version.
017    
018     This library is distributed in the hope that it will be useful,
019     but WITHOUT ANY WARRANTY; without even the implied warranty of
020     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
021     Lesser General Public License for more details.
022    
023     You should have received a copy of the GNU Lesser General Public
024     License along with this library; if not, write to the Free Software
025     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026    
027     Contact:
028    
029     Andreas Poth
030     lat/lon GmbH
031     Aennchenstr. 19
032     53115 Bonn
033     Germany
034     E-Mail: poth@lat-lon.de
035    
036     Prof. Dr. Klaus Greve
037     Department of Geography
038     University of Bonn
039     Meckenheimer Allee 166
040     53115 Bonn
041     Germany
042     E-Mail: greve@giub.uni-bonn.de
043     
044     ---------------------------------------------------------------------------*/
045    package org.deegree.ogcwebservices.csw.capabilities;
046    
047    import java.io.IOException;
048    import java.net.URI;
049    import java.net.URL;
050    import java.util.Arrays;
051    import java.util.HashMap;
052    import java.util.List;
053    import java.util.Map;
054    
055    import org.deegree.datatypes.xlink.SimpleLink;
056    import org.deegree.framework.log.ILogger;
057    import org.deegree.framework.log.LoggerFactory;
058    import org.deegree.framework.xml.ElementList;
059    import org.deegree.framework.xml.InvalidConfigurationException;
060    import org.deegree.framework.xml.XMLParsingException;
061    import org.deegree.framework.xml.XMLTools;
062    import org.deegree.i18n.Messages;
063    import org.deegree.model.filterencoding.capabilities.FilterCapabilities;
064    import org.deegree.model.filterencoding.capabilities.FilterCapabilities100Fragment;
065    import org.deegree.ogcbase.CommonNamespaces;
066    import org.deegree.ogcwebservices.getcapabilities.InvalidCapabilitiesException;
067    import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
068    import org.deegree.ogcwebservices.getcapabilities.Operation;
069    import org.deegree.ogcwebservices.getcapabilities.OperationsMetadata;
070    import org.deegree.owscommon.OWSCommonCapabilitiesDocument;
071    import org.deegree.owscommon.OWSDomainType;
072    import org.w3c.dom.Element;
073    import org.w3c.dom.Node;
074    import org.xml.sax.SAXException;
075    
076    /**
077     * Represents an XML capabilities document for an OGC CSW 2.0 compliant service.
078     * 
079     * @author <a href="mailto:tfr@users.sourceforge.net">Torsten Friebe </a>
080     * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
081     * 
082     * @author last edited by: $Author: apoth $
083     * 
084     * @version 2.0, $Revision: 9501 $, $Date: 2008-01-10 10:41:39 +0100 (Do, 10 Jan 2008) $
085     * 
086     * @since 2.0
087     * 
088     */
089    public class CatalogueCapabilitiesDocument extends OWSCommonCapabilitiesDocument {
090    
091        private static final ILogger LOG = LoggerFactory.getLogger( CatalogueCapabilitiesDocument.class );
092    
093        public final static String FILTER_CAPABILITIES_NAME = "FilterCapabilities";
094    
095        public final static String EBRIM_CAPABILITIES_NAME = "EBRIMCapabilities";
096    
097        protected static final URI OGCNS = CommonNamespaces.OGCNS;
098    
099        private static final String XML_TEMPLATE = "CatalogueCapabilitiesTemplate.xml";
100    
101        /**
102         * Creates a skeleton capabilities document that contains the mandatory elements only.
103         * 
104         * @throws IOException
105         * @throws SAXException
106         */
107        public void createEmptyDocument()
108                                throws IOException, SAXException {
109            URL url = CatalogueCapabilitiesDocument.class.getResource( XML_TEMPLATE );
110            if ( url == null ) {
111                throw new IOException( "The resource '" + XML_TEMPLATE + " could not be found." );
112            }
113            load( url );
114        }
115    
116        /**
117         * Creates a class representation of the document.
118         * 
119         * @return class representation of the configuration document
120         */
121        public OGCCapabilities parseCapabilities()
122                                throws InvalidCapabilitiesException {
123            try {
124                FilterCapabilities filterCapabilities = null;
125                Element filterCapabilitiesElement = (Element) XMLTools.getNode( getRootElement(),
126                                                                                "ogc:Filter_Capabilities", nsContext );
127                if ( filterCapabilitiesElement != null ) {
128                    filterCapabilities = new FilterCapabilities100Fragment( filterCapabilitiesElement, getSystemId() ).parseFilterCapabilities();
129                }
130                return new CatalogueCapabilities( parseVersion(), parseUpdateSequence(), getServiceIdentification(),
131                                                  getServiceProvider(), getOperationsMetadata(), null, filterCapabilities );
132            } catch ( Exception e ) {
133                LOG.logError( e.getMessage(), e );
134                throw new InvalidCapabilitiesException( e.getMessage() );
135            }
136        }
137    
138        /**
139         * Creates a class representation of the <code>OperationsMetadata</code>- section.
140         * 
141         * @return
142         * @throws InvalidConfigurationException
143         */
144        public OperationsMetadata getOperationsMetadata()
145                                throws XMLParsingException {
146    
147            Node root = this.getRootElement();
148    
149            Node omNode = XMLTools.getRequiredChildElement( "OperationsMetadata", OWSNS, root );
150            ElementList elementList = XMLTools.getChildElements( "Operation", OWSNS, omNode );
151    
152            ElementList parameterElements = XMLTools.getChildElements( "Parameter", OWSNS, omNode );
153            OWSDomainType[] parameters = new OWSDomainType[parameterElements.getLength()];
154    
155            for ( int i = 0; i < parameters.length; i++ ) {
156                parameters[i] = getOWSDomainType( null, parameterElements.item( i ) );
157            }
158            
159            OWSDomainType[] constraints = getContraints( (Element)omNode );
160    
161            // build HashMap of 'Operation'-elements for easier access
162            HashMap<String,Node> operations = new HashMap<String,Node>();
163            for ( int i = 0; i < elementList.getLength(); i++ ) {
164                operations.put( XMLTools.getRequiredAttrValue( "name", null, elementList.item( i ) ), elementList.item( i ) );
165            }
166    
167            // 'GetCapabilities'-operation
168            Operation getCapabilites = getOperation( OperationsMetadata.GET_CAPABILITIES_NAME, true, operations );
169            // 'DescribeRecord'-operation
170            Operation describeRecord = getOperation( CatalogueOperationsMetadata.DESCRIBE_RECORD_NAME, true, operations );
171            // 'GetDomain'-operation
172            Operation getDomain = getOperation( CatalogueOperationsMetadata.GET_DOMAIN_NAME, false, operations );
173            // 'GetRecords'-operation
174            Operation getRecords = getOperation( CatalogueOperationsMetadata.GET_RECORDS_NAME, true, operations );
175            // 'GetRecordById'-operation
176            Operation getRecordById = getOperation( CatalogueOperationsMetadata.GET_RECORD_BY_ID_NAME, true, operations );
177            // 'Transaction'-operation
178            Operation transaction = getOperation( CatalogueOperationsMetadata.TRANSACTION_NAME, false, operations );
179            // 'Harvest'-operation
180            Operation harvest = getOperation( CatalogueOperationsMetadata.HARVEST_NAME, false, operations );
181                    
182    
183            return new CatalogueOperationsMetadata( getCapabilites, describeRecord, getDomain, getRecords, getRecordById,
184                                                    transaction, harvest, parameters, constraints );
185        }
186    
187        /**
188         * @return a {@link EBRIMCapabilities} element (specified in the ogc-ebrim extension)
189         * @throws XMLParsingException
190         *             if a required node isn't found
191         */
192        protected EBRIMCapabilities parseEBRIMCapabilities()
193                                throws XMLParsingException {
194            Element rootElement = getRootElement();
195    
196            String prefix = rootElement.getOwnerDocument().lookupPrefix( CommonNamespaces.WRS_EBRIMNS.toString() );
197    
198            if ( prefix == null || "".equals( prefix.trim() ) ) {
199                return null;
200            }
201    
202            // SeviceFeatures
203            Element serviceFeature = (Element) XMLTools.getRequiredNode( rootElement, "wrs:ServiceFeatures", nsContext );
204            List nl = XMLTools.getNodes( serviceFeature, "wrs:feature", nsContext );
205            Map<URI, CSWFeature> features = new HashMap<URI, CSWFeature>();
206            for ( Object n : nl ) {
207                Node featureElement = (Node) n;
208                URI featureName = XMLTools.getRequiredNodeAsURI( featureElement, "@name", nsContext );
209                LOG.logDebug( "found featurename: " + featureName );
210                if ( features.containsKey( featureName ) ) {
211                    throw new XMLParsingException(
212                                                   Messages.getMessage( "WRS_UNAMBIGUOUS_FEAT_PROP", featureName.toString() ) );
213                }
214                CSWFeature feature = new CSWFeature( parsePropties( featureElement ) );
215                features.put( featureName, feature );
216            }
217    
218            Element serviceProps = (Element) XMLTools.getRequiredNode( rootElement, "wrs:ServiceProperties", nsContext );
219            Map<URI, List<String>> serviceProperties = parsePropties( serviceProps );
220            SimpleLink wsdl_SimpleLink = parseSimpleLink( (Element) XMLTools.getRequiredNode( rootElement,
221                                                                                              "wrs:WSDL-services",
222                                                                                              nsContext ) );
223    
224            return new EBRIMCapabilities( features, serviceProperties, wsdl_SimpleLink );
225        }
226    
227        private Map<URI, List<String>> parsePropties( Node xmlNode )
228                                throws XMLParsingException {
229            List pnl = XMLTools.getNodes( xmlNode, "wrs:property", nsContext );
230            Map<URI, List<String>> properties = new HashMap<URI, List<String>>();
231    
232            for ( Object pn : pnl ) {
233                Node property = (Node) pn;
234                URI propName = XMLTools.getRequiredNodeAsURI( property, "@name", nsContext );
235                List<String> propValues = Arrays.asList( XMLTools.getRequiredNodesAsStrings( property, "wrs:value",
236                                                                                             nsContext ) );
237                properties.put( propName, propValues );
238            }
239            return properties;
240        }
241    }