001 //$HeadURL$
002 /*----------------------------------------------------------------------------
003 This file is part of deegree, http://deegree.org/
004 Copyright (C) 2001-2009 by:
005 Department of Geography, University of Bonn
006 and
007 lat/lon GmbH
008
009 This library is free software; you can redistribute it and/or modify it under
010 the terms of the GNU Lesser General Public License as published by the Free
011 Software Foundation; either version 2.1 of the License, or (at your option)
012 any later version.
013 This library is distributed in the hope that it will be useful, but WITHOUT
014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016 details.
017 You should have received a copy of the GNU Lesser General Public License
018 along with this library; if not, write to the Free Software Foundation, Inc.,
019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020
021 Contact information:
022
023 lat/lon GmbH
024 Aennchenstr. 19, 53177 Bonn
025 Germany
026 http://lat-lon.de/
027
028 Department of Geography, University of Bonn
029 Prof. Dr. Klaus Greve
030 Postfach 1147, 53001 Bonn
031 Germany
032 http://www.geographie.uni-bonn.de/deegree/
033
034 e-mail: info@deegree.org
035 ----------------------------------------------------------------------------*/
036
037 package org.deegree.ogcwebservices.csw.discovery;
038
039 import java.io.IOException;
040 import java.net.URI;
041 import java.net.URISyntaxException;
042 import java.net.URL;
043 import java.util.ArrayList;
044 import java.util.HashMap;
045 import java.util.List;
046 import java.util.Map;
047
048 import org.deegree.datatypes.QualifiedName;
049 import org.deegree.framework.log.ILogger;
050 import org.deegree.framework.log.LoggerFactory;
051 import org.deegree.framework.xml.XMLParsingException;
052 import org.deegree.framework.xml.XMLTools;
053 import org.deegree.i18n.Messages;
054 import org.deegree.model.filterencoding.AbstractFilter;
055 import org.deegree.model.filterencoding.ComplexFilter;
056 import org.deegree.model.filterencoding.Filter;
057 import org.deegree.model.filterencoding.FilterConstructionException;
058 import org.deegree.ogcbase.CommonNamespaces;
059 import org.deegree.ogcbase.ExceptionCode;
060 import org.deegree.ogcbase.PropertyPath;
061 import org.deegree.ogcbase.PropertyPathFactory;
062 import org.deegree.ogcbase.SortProperty;
063 import org.deegree.ogcwebservices.InvalidParameterValueException;
064 import org.deegree.ogcwebservices.MissingParameterValueException;
065 import org.deegree.ogcwebservices.OGCWebServiceException;
066 import org.deegree.ogcwebservices.OperationNotSupportedException;
067 import org.deegree.ogcwebservices.csw.discovery.GetRecords.RESULT_TYPE;
068 import org.w3c.dom.Element;
069 import org.w3c.dom.Node;
070 import org.xml.sax.SAXException;
071
072 /**
073 *
074 *
075 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
076 * @author last edited by: $Author: poth $
077 *
078 * @version $Revision: 6251 $, $Date: 2007-03-19 16:59:28 +0100 (Mo, 19 Mrz 2007) $
079 */
080 public class GetRecordsDocument_2_0_2 extends GetRecordsDocument {
081
082 private static final long serialVersionUID = -4987866178075594539L;
083
084 private static final ILogger LOG = LoggerFactory.getLogger( GetRecordsDocument_2_0_2.class );
085
086 private static final String XML_TEMPLATE = "GetRecords2.0.2Template.xml";
087
088 /**
089 * Extracts a <code>GetRecords</code> representation of this object.
090 *
091 * @param id
092 * unique ID of the request
093 * @return GetRecords representation of this object
094 * @throws MissingParameterValueException
095 * @throws InvalidParameterValueException
096 * @throws OperationNotSupportedException
097 * if an CqlText constrained is requested
098 * @throws OGCWebServiceException
099 * if something else went wrong
100 */
101 @Override
102 public GetRecords parse( String id )
103 throws OGCWebServiceException {
104
105 // '<csw202:GetRecords>'-element (required)
106 try {
107 Element contextNode = (Element) XMLTools.getRequiredNode( this.getRootElement(), "self::csw202:GetRecords",
108 nsContext );
109 // 'service'-attribute (mandatory for 2.0.2, must be CSW)
110 String service = XMLTools.getRequiredNodeAsString( contextNode, "@service", nsContext );
111 if ( !"CSW".equals( service ) ) {
112 throw new OGCWebServiceException( "GetRecordsDocument_2_0_2",
113 Messages.getMessage( "CSW_INVALID_SERVICE_PARAM" ),
114 ExceptionCode.INVALIDPARAMETERVALUE );
115 }
116
117 boolean isEBRIM = ( contextNode.getOwnerDocument().lookupPrefix(
118 CommonNamespaces.OASIS_EBRIMNS.toASCIIString() ) != null );
119
120 // 'version'-attribute (mandatory for 2.0.2)
121 String version = XMLTools.getRequiredNodeAsString( contextNode, "@version", nsContext );
122 if ( !"2.0.2".equals( version ) ) {
123 throw new OGCWebServiceException( "GetRecordsDocument_2_0_2",
124 Messages.getMessage( "CSW_NOT_SUPPORTED_VERSION",
125 GetRecords.DEFAULT_VERSION, "2.0.2", version ),
126 ExceptionCode.INVALIDPARAMETERVALUE );
127 }
128
129 // 'requestId'-attribute (optional)
130 String requestId = XMLTools.getNodeAsString( contextNode, "@requestId", nsContext, id );
131
132 // 'resultType'-attribute
133 // type="csw202:ResultType" use="optional" default="hits"
134 String resultTypeString = XMLTools.getNodeAsString( contextNode, "@resultType", nsContext,
135 GetRecords.RESULT_TYPE_STRING_HITS );
136 RESULT_TYPE resultType = RESULT_TYPE.RESULTS;
137 if ( GetRecords.RESULT_TYPE_STRING_HITS.equalsIgnoreCase( resultTypeString ) ) {
138 resultType = RESULT_TYPE.HITS;
139 } else if ( GetRecords.RESULT_TYPE_STRING_RESULTS.equalsIgnoreCase( resultTypeString ) ) {
140 resultType = RESULT_TYPE.RESULTS;
141 } else if ( GetRecords.RESULT_TYPE_STRING_VALIDATE.equalsIgnoreCase( resultTypeString ) ) {
142 resultType = RESULT_TYPE.VALIDATE;
143 } else {
144 throw new OGCWebServiceException( Messages.getMessage( "CSW_INVALID_RESULTTYPE", resultTypeString,
145 GetRecords.RESULT_TYPE_STRING_HITS,
146 GetRecords.RESULT_TYPE_STRING_RESULTS,
147 GetRecords.RESULT_TYPE_STRING_VALIDATE ),
148 ExceptionCode.INVALIDPARAMETERVALUE );
149 }
150
151 // 'outputFormat'-attribute
152 // type="xsd:string" use="optional" default="text/xml"
153 String outputFormat = XMLTools.getNodeAsString( contextNode, "@outputFormat", nsContext,
154 GetRecords.DEFAULT_OUTPUTFORMAT );
155
156 String defaultOutputSchema = GetRecords.DEFAULT_OUTPUTSCHEMA_202;
157 if ( isEBRIM ) {
158 defaultOutputSchema = CommonNamespaces.OASIS_EBRIMNS.toASCIIString();
159 }
160 // 'outputSchema'-attribute
161 // type="xsd:anyURI" use="optional" default="OGCCORE"
162 String outputSchema = XMLTools.getNodeAsString( contextNode, "@outputSchema", nsContext,
163 defaultOutputSchema );
164
165 // 'startPosition'-attribute
166 // type="xsd:positiveInteger" use="optional" default="1"
167 int startPosition = XMLTools.getNodeAsInt( contextNode, "@startPosition", nsContext,
168 GetRecords.DEFAULT_STARTPOSITION );
169 if ( startPosition < 1 ) {
170 throw new OGCWebServiceException( Messages.getMessage( "CSW_INVALID_STARTPOSITION",
171 new Integer( startPosition ) ),
172 ExceptionCode.INVALIDPARAMETERVALUE );
173 }
174
175 // 'maxRecords'-attribute
176 // type="xsd:nonNegativeInteger" use="optional" default="10"
177 int maxRecords = XMLTools.getNodeAsInt( contextNode, "@maxRecords", nsContext,
178 GetRecords.DEFAULT_MAX_RECORDS );
179
180 // '<csw202:DistributedSearch>'-element (optional)
181 Node distributedSearchElement = XMLTools.getNode( contextNode, "csw202:DistributedSearch", nsContext );
182 int hopCount = GetRecords.DEFAULT_HOPCOUNT;
183 if ( distributedSearchElement != null ) {
184 hopCount = XMLTools.getNodeAsInt( contextNode, "@hopCount", nsContext, GetRecords.DEFAULT_HOPCOUNT );
185 }
186
187 // '<csw202:ResponseHandler>'-elements (optional)
188 String rHandler = XMLTools.getNodeAsString( contextNode, "csw202:ResponseHandler", nsContext, null );
189 URI responseHandler = null;
190 if ( rHandler != null ) {
191 try {
192 responseHandler = new URI( rHandler );
193 } catch ( URISyntaxException e ) {
194 throw new OGCWebServiceException( Messages.getMessage( "CSW_INVALID_RESPONSE_HANDLER", rHandler ),
195 ExceptionCode.INVALIDPARAMETERVALUE );
196 }
197 LOG.logWarning( Messages.getMessage( "CSW_NO_REPONSE_HANDLER_IMPLEMENTATION" ) );
198
199 }
200
201 // '<csw202:Query>'-elements (required)
202 // List nl = XMLTools.getRequiredNodes( contextNode, "csw202:Query", nsContext );
203 Element queryNode = (Element) XMLTools.getRequiredNode( contextNode, "csw202:Query", nsContext );
204
205 Map<String, QualifiedName> declaredVariables = new HashMap<String, QualifiedName>();
206 List<QualifiedName> queryTypeNames = new ArrayList<QualifiedName>();
207
208 // 'typeName'-attribute use="required"
209 String tNames = XMLTools.getRequiredNodeAsString( queryNode, "@typeNames", nsContext );
210 String[] simpleTypeNames = tNames.split( " " );
211 // only bind the prefixes to namespaces if the version is 2.0.0
212 boolean bindTypeNamesToNS = !GetRecords.DEFAULT_VERSION.equals( version );
213 // Find any variables
214 for ( String typeName : simpleTypeNames ) {
215 findVariablesInTypeName( typeName, queryNode, queryTypeNames, declaredVariables, bindTypeNamesToNS );
216 }
217
218 // '<csw202:ElementSetName>'-element (optional)
219 Element elementSetNameElement = (Element) XMLTools.getNode( queryNode, "csw202:ElementSetName", nsContext );
220 String elementSetName = null;
221 List<QualifiedName> elementSetNameTypeNames = null;
222 Map<String, QualifiedName> elementSetNameVariables = null;
223 List<PropertyPath> elementNames = new ArrayList<PropertyPath>();
224 // choice construct
225 if ( elementSetNameElement != null ) {
226 // must contain one of the values 'brief', 'summary' or
227 // 'full'
228 elementSetName = XMLTools.getRequiredNodeAsString( elementSetNameElement, "text()", nsContext,
229 new String[] { "brief", "summary", "full" } );
230 tNames = elementSetNameElement.getAttribute( "typeNames" );
231 if ( tNames != null ) {
232 String[] esnTypeNames = tNames.split( " " );
233 elementSetNameVariables = new HashMap<String, QualifiedName>();
234 elementSetNameTypeNames = new ArrayList<QualifiedName>();
235 for ( String tn : esnTypeNames ) {
236 if ( tn.trim().startsWith( "$" ) ) {
237 String tmpVar = tn.trim().substring( 1 );
238 if ( !declaredVariables.containsKey( tmpVar ) ) {
239 String msg = Messages.getMessage( "CSW_ELEMENT_SET_NAME_TYPENAME_ALIAS", tmpVar );
240 throw new OGCWebServiceException( msg, ExceptionCode.INVALIDPARAMETERVALUE );
241 }
242 elementSetNameVariables.put( tmpVar, declaredVariables.get( tmpVar ) );
243 } else {
244 QualifiedName qName = parseQNameFromString( tn.trim(), elementSetNameElement,
245 bindTypeNamesToNS );
246 elementSetNameTypeNames.add( qName );
247 }
248 }
249 }
250
251 } else {
252 // '<csw202:ElementName>'-element (required, if no
253 // '<csw202:ElementSetName>' is given)
254 List<Node> elementNameList = XMLTools.getNodes( queryNode, "csw202:ElementName", nsContext );
255 if ( elementNameList.size() == 0 ) {
256 throw new XMLParsingException( Messages.getMessage( "CSW_MISSING_QUERY_ELEMENT(SET)NAME" ) );
257 }
258 for ( Node n : elementNameList ) {
259 QualifiedName elementName = XMLTools.getNodeAsQualifiedName( n, "text()", nsContext, null );
260 if ( elementName != null ) {
261 elementNames.add( PropertyPathFactory.createPropertyPath( elementName ) );
262 }
263 }
264
265 }
266
267 // '<csw202:Constraint>'-element (optional)
268 Element constraintElement = (Element) XMLTools.getNode( queryNode, "csw202:Constraint", nsContext );
269 Filter constraint = null;
270 if ( constraintElement != null ) {
271 String ver = XMLTools.getRequiredNodeAsString( constraintElement, "@version", nsContext );
272 if ( !"1.0.0".equals( ver ) && !"1.1.0".equals( ver ) ) {
273 throw new OGCWebServiceException( Messages.getMessage( "CSW_INVALID_CONSTRAINT_VERSION", ver ),
274 ExceptionCode.INVALIDPARAMETERVALUE );
275 }
276 Node filterElement = XMLTools.getNode( constraintElement, "ogc:Filter", nsContext );
277 if ( filterElement != null ) {
278 try {
279 constraint = AbstractFilter.buildFromDOM( (Element) filterElement, false );
280 } catch ( FilterConstructionException fce ) {
281 throw new OGCWebServiceException( Messages.getMessage( "CSW_INVALID_CONSTRAINT_CONTENT",
282 fce.getMessage() ),
283 ExceptionCode.INVALIDPARAMETERVALUE );
284 }
285 } else {
286 String cqlText = XMLTools.getNodeAsString( constraintElement, "csw202:CqlText", nsContext, null );
287 if ( cqlText == null ) {
288 throw new OGCWebServiceException( Messages.getMessage( "CSW_CQL_NOR_FILTER" ),
289 ExceptionCode.INVALIDPARAMETERVALUE );
290 }
291
292 throw new OGCWebServiceException( Messages.getMessage( "CSW_NO_CQL_IMPLEMENTATION" ),
293 ExceptionCode.OPERATIONNOTSUPPORTED );
294 }
295 }
296 // find undeclared referenced variables used in the filter element.
297 if ( constraint instanceof ComplexFilter ) {
298 checkReferencedVariables( (ComplexFilter) constraint, declaredVariables );
299 }
300
301 // '<ogc:SortBy>'-element (optional)
302 Node sortByElement = XMLTools.getNode( queryNode, "ogc:SortBy", nsContext );
303 SortProperty[] sortProperties = null;
304 if ( sortByElement != null ) {
305 List<Node> sortPropertyList = XMLTools.getNodes( sortByElement, "ogc:SortProperty", nsContext );
306 if ( sortPropertyList.size() == 0 ) {
307 throw new OGCWebServiceException( Messages.getMessage( "CSW_NO_SORTPROPERTY_LIST" ),
308 ExceptionCode.INVALIDPARAMETERVALUE );
309
310 }
311 sortProperties = new SortProperty[sortPropertyList.size()];
312 for ( int j = 0; j < sortPropertyList.size(); j++ ) {
313 sortProperties[j] = SortProperty.create( (Element) sortPropertyList.get( j ) );
314 }
315 }
316
317 Query query = new Query( elementSetName, elementSetNameTypeNames, elementSetNameVariables, elementNames,
318 constraint, sortProperties, queryTypeNames, declaredVariables );
319
320 // in the future the vendorSpecificParameters
321 Map<String, String> vendorSpecificParameters = parseDRMParams( this.getRootElement() );
322 return new GetRecords( requestId, version, vendorSpecificParameters, null, resultType, outputFormat,
323 outputSchema, startPosition, maxRecords, hopCount, responseHandler, query );
324 } catch ( XMLParsingException xmlpe ) {
325 LOG.logError( "CatalogGetRecords", xmlpe );
326 throw new OGCWebServiceException( xmlpe.getMessage(), ExceptionCode.MISSINGPARAMETERVALUE );
327 } catch ( URISyntaxException urise ) {
328 LOG.logError( "CatalogGetRecords", urise );
329 throw new OGCWebServiceException( urise.getMessage(), ExceptionCode.MISSINGPARAMETERVALUE );
330 }
331 }
332
333 @Override
334 /*
335 * (non-Javadoc)
336 *
337 * @see org.deegree.framework.xml.XMLFragment#createEmptyDocument()
338 */
339 void createEmptyDocument()
340 throws IOException, SAXException {
341 URL url = GetRecordsDocument.class.getResource( XML_TEMPLATE );
342 if ( url == null ) {
343 throw new IOException( "The resource '" + XML_TEMPLATE + " could not be found." );
344 }
345 load( url );
346 }
347
348 }