001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/csw/manager/TransactionDocument.java $
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 package org.deegree.ogcwebservices.csw.manager;
037
038 import java.io.InputStream;
039 import java.net.MalformedURLException;
040 import java.net.URI;
041 import java.util.ArrayList;
042 import java.util.HashMap;
043 import java.util.List;
044 import java.util.Map;
045
046 import org.deegree.framework.log.ILogger;
047 import org.deegree.framework.log.LoggerFactory;
048 import org.deegree.framework.xml.ElementList;
049 import org.deegree.framework.xml.XMLException;
050 import org.deegree.framework.xml.XMLFragment;
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.Filter;
056 import org.deegree.ogcbase.CommonNamespaces;
057 import org.deegree.ogcwebservices.InvalidParameterValueException;
058 import org.deegree.ogcwebservices.MissingParameterValueException;
059 import org.deegree.ogcwebservices.OGCWebServiceException;
060 import org.deegree.ogcwebservices.csw.AbstractCSWRequestDocument;
061 import org.w3c.dom.Document;
062 import org.w3c.dom.Element;
063 import org.w3c.dom.Node;
064
065 /**
066 * The Transaction operation defines an interface for creating, modifying and deleting catalogue
067 * records. The specific payload being manipulated must be defined in a profile.
068 *
069 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
070 * @author last edited by: $Author: mschneider $
071 *
072 * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
073 *
074 */
075 public class TransactionDocument extends AbstractCSWRequestDocument {
076
077 private static final long serialVersionUID = 7914686453810419662L;
078
079 protected static final ILogger LOG = LoggerFactory.getLogger( TransactionDocument.class );
080
081 /**
082 * initializes an empty TransactionDocument
083 *
084 */
085 public TransactionDocument() {
086 try {
087 setSystemId( XMLFragment.DEFAULT_URL );
088 } catch ( MalformedURLException e ) {
089 LOG.logError( e.getMessage(), e );
090 }
091 }
092
093 /**
094 *
095 */
096 public void createEmptyDocument() {
097 Document doc = XMLTools.create();
098 Element root = doc.createElementNS( CommonNamespaces.CSWNS.toASCIIString(), "csw:Transaction" );
099 setRootElement( root );
100
101 }
102
103 /**
104 * initializes a TransactionDocument by reading a DOM object from the passed
105 *
106 * @see InputStream
107 *
108 * @param transRoot
109 * @throws XMLException
110 */
111 public TransactionDocument( Element transRoot ) throws XMLException {
112 setRootElement( transRoot );
113 // setSystemId( XMLFragment.DEFAULT_URL );
114 }
115
116 /**
117 * parses a CS-W 2.0 transaction request
118 *
119 * @param id
120 * of the TransactionRequest
121 *
122 * @return a new transaction parsed from the this xml-encoded request.
123 * @throws XMLParsingException
124 * @throws OGCWebServiceException
125 * @throws InvalidParameterValueException
126 * @throws MissingParameterValueException
127 */
128 public Transaction parse( String id )
129 throws XMLParsingException, OGCWebServiceException {
130
131 LOG.logDebug( "parsing CS-W Transaction request" );
132 String version = XMLTools.getNodeAsString( getRootElement(), "@version", nsContext, null );
133 boolean verbose = XMLTools.getNodeAsBoolean( getRootElement(), "./@verboseResponse", nsContext, false );
134
135 List<Operation> ops = new ArrayList<Operation>();
136
137 ElementList el = XMLTools.getChildElements( getRootElement() );
138 for ( int i = 0; i < el.getLength(); i++ ) {
139 Element e = el.item( i );
140 // TODO check for qualified name
141 if ( "Insert".equals( e.getLocalName() ) ) {
142 ops.add( parseInsert( e ) );
143 } else if ( "Update".equals( e.getLocalName() ) ) {
144 ops.add( parseUpdate( e ) );
145 } else if ( "Delete".equals( e.getLocalName() ) ) {
146 ops.add( parseDelete( e ) );
147 }
148 }
149
150 // in the future the vendorSpecificParameters
151 Map<String, String> vendorSpecificParameters = parseDRMParams( this.getRootElement() );
152
153 return new Transaction( version, id, vendorSpecificParameters, ops, verbose );
154 }
155
156 /**
157 * parses a Delete element contained in a CS-W Transaction.
158 *
159 * @param element
160 * @return the Delete class parsed from the given Delete element.
161 * @throws XMLParsingException
162 * @throws MissingParameterValueException
163 * @throws InvalidParameterValueException
164 */
165 private Delete parseDelete( Element element )
166 throws XMLParsingException, MissingParameterValueException, InvalidParameterValueException {
167
168 LOG.logDebug( "parsing CS-W Transaction-Delete" );
169
170 String handle = XMLTools.getNodeAsString( element, "@handle", nsContext, null );
171 String tmp = XMLTools.getNodeAsString( element, "@typeName", nsContext, null );
172 URI typeName = null;
173 if ( tmp != null ) {
174 // part of the corrected CS-W 2.0 spec
175 try {
176 typeName = new URI( tmp );
177 } catch ( Exception e ) {
178 throw new XMLParsingException( "if defined attribute 'typeName' must be " + "a valid URI" );
179 }
180 }
181
182 Element elem = (Element) XMLTools.getRequiredNode( element, "./csw:Constraint", nsContext );
183 String ver = XMLTools.getNodeAsString( elem, "@version", nsContext, null );
184 if ( ver == null ) {
185 String s = Messages.getMessage( "CSW_MISSING_CONSTRAINT_VERSION" );
186 throw new MissingParameterValueException( s );
187 }
188 if ( !"1.0.0".equals( ver ) && !"1.1.0".equals( ver ) ) {
189 String s = Messages.getMessage( "CSW_INVALID_CONSTRAINT_VERSION", ver );
190 throw new InvalidParameterValueException( s );
191 }
192
193 elem = (Element) XMLTools.getRequiredNode( elem, "./ogc:Filter", nsContext );
194
195 Filter constraint = AbstractFilter.buildFromDOM( elem, "1.0.0".equals( ver ) );
196 return new Delete( handle, typeName, constraint );
197 }
198
199 /**
200 * parses a Update element contained in a CS-W Transaction.
201 *
202 * @param element
203 * @return the update class containing all parsed values
204 * @throws XMLParsingException
205 * @throws MissingParameterValueException
206 * @throws InvalidParameterValueException
207 */
208 private Update parseUpdate( Element element )
209 throws XMLParsingException, MissingParameterValueException, InvalidParameterValueException {
210
211 LOG.logDebug( "parsing CS-W Transaction-Update" );
212
213 String handle = XMLTools.getNodeAsString( element, "@handle", nsContext, null );
214 String tmp = XMLTools.getNodeAsString( element, "@typeName", nsContext, null );
215 URI typeName = null;
216 if ( tmp != null ) {
217 // part of the corrected CS-W 2.0 spec
218 try {
219 typeName = new URI( tmp );
220 } catch ( Exception e ) {
221 throw new XMLParsingException( "if defined attribute 'typeName' must be a valid URI" );
222 }
223 }
224 Element elem = (Element) XMLTools.getRequiredNode( element, "./csw:Constraint", nsContext );
225 String ver = XMLTools.getNodeAsString( elem, "@version", nsContext, null );
226 if ( ver == null ) {
227 String s = Messages.getMessage( "CSW_MISSING_CONSTRAINT_VERSION" );
228 throw new MissingParameterValueException( s );
229 }
230 if ( !"1.0.0".equals( ver ) && !"1.1.0".equals( ver ) ) {
231 String s = Messages.getMessage( "CSW_INVALID_CONSTRAINT_VERSION", ver );
232 throw new InvalidParameterValueException( s );
233 }
234
235 elem = (Element) XMLTools.getRequiredNode( elem, "./ogc:Filter", nsContext );
236
237 Filter constraint = AbstractFilter.buildFromDOM( elem, "1.0.0".equals( ver ) );
238
239 List<Node> children = null;
240 List<Node> rp = XMLTools.getNodes( getRootElement(), "./csw:RecordProperty", nsContext );
241 if ( rp.size() != 0 ) {
242 // at the moment will always be null because it is part of the
243 // CS-W 2.0 corrected version that will not be implemented yet
244 } else {
245 children = XMLTools.getNodes( element, "./child::*", nsContext );
246 if ( children.size() == 0 ) {
247 throw new XMLParsingException( "one record must be defined within a CS-W update element" );
248 }
249 }
250 return new Update( handle, typeName, constraint, (Element) children.get( 0 ), null );
251 }
252
253 /**
254 * parses a Insert element contained in a CS-W Transaction.
255 *
256 * @param element
257 * @return an Insert instance
258 * @throws XMLParsingException
259 */
260 private Insert parseInsert( Element element )
261 throws XMLParsingException {
262
263 LOG.logDebug( "parsing CS-W Transaction-Insert" );
264
265 String handle = XMLTools.getNodeAsString( element, "@handle", nsContext, "" );
266 List<Element> recList = new ArrayList<Element>();
267 List<Node> children = XMLTools.getNodes( element, "*", nsContext );
268 if ( children.size() == 0 ) {
269 LOG.logError( "at least one record must be defined within a CS-W insert element" );
270 throw new XMLParsingException( "at least one record must be defined " + "within a CS-W insert element" );
271 }
272
273 String prefixForRim = null;
274 for ( Object n : children ) {
275 LOG.logDebug( "TransactionDocument(insert): adding the element: " + element.getLocalName()
276 + " to the records list. " );
277 if ( prefixForRim == null ) {
278 prefixForRim = ( (Element) n ).lookupPrefix( CommonNamespaces.OASIS_EBRIMNS.toASCIIString() );
279 }
280 recList.add( (Element) n );
281 }
282
283 // check if the rim namespace is used
284 // nsForRim = XMLTools.getNamespaceForPrefix( "rim", element );
285
286 LOG.logDebug( "TransactionDocument: for the insert operation found following prefix: " + prefixForRim );
287 if ( prefixForRim != null ) {
288 List<Element> nl = XMLTools.getElements( element, "rim:ExtrinsicObject", nsContext );
289 Map<String, Element> extrinsicObjects = new HashMap<String, Element>( nl.size() );
290 LOG.logDebug( "TransactionDocument: number of ExtrinsicObjects found: " + extrinsicObjects.size() );
291 for ( Element n : nl ) {
292 String id = XMLTools.getRequiredNodeAsString( n, "@id", nsContext );
293 if ( "".equals( id.trim() ) ) {
294 throw new XMLParsingException( "The value of the id attribute in a {"
295 + CommonNamespaces.OASIS_EBRIMNS.toASCIIString()
296 + "}extrinsicObject may not be empty" );
297 }
298 LOG.logDebug( "TransactionDocument: found the id " + id );
299 extrinsicObjects.put( id.trim(), n );
300 }
301 return new Insert( handle, recList, extrinsicObjects );
302 }
303 // if no ebrim is done, create the old insert class.
304 return new Insert( handle, recList );
305 }
306 }