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 }