001    //$HeadURL$
002    /*----------------    FILE HEADER  ------------------------------------------
003     This file is part of deegree.
004     Copyright (C) 2001-2008 by:
005     Department of Geography, University of Bonn
006     http://www.giub.uni-bonn.de/deegree/
007     lat/lon GmbH
008     http://www.lat-lon.de
009    
010     This library is free software; you can redistribute it and/or
011     modify it under the terms of the GNU Lesser General Public
012     License as published by the Free Software Foundation; either
013     version 2.1 of the License, or (at your option) any later version.
014     This library is distributed in the hope that it will be useful,
015     but WITHOUT ANY WARRANTY; without even the implied warranty of
016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     Lesser General Public License for more details.
018     You should have received a copy of the GNU Lesser General Public
019     License along with this library; if not, write to the Free Software
020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021     Contact:
022    
023     Andreas Poth
024     lat/lon GmbH
025     Aennchenstr. 19
026     53177 Bonn
027     Germany
028     E-Mail: poth@lat-lon.de
029    
030     Prof. Dr. Klaus Greve
031     Department of Geography
032     University of Bonn
033     Meckenheimer Allee 166
034     53115 Bonn
035     Germany
036     E-Mail: greve@giub.uni-bonn.de
037     ---------------------------------------------------------------------------*/
038    
039    package org.deegree.ogcwebservices.csw.manager;
040    
041    import java.io.IOException;
042    import java.io.InputStream;
043    import java.net.MalformedURLException;
044    import java.net.URI;
045    import java.util.ArrayList;
046    import java.util.List;
047    import java.util.Map;
048    
049    import org.deegree.framework.log.ILogger;
050    import org.deegree.framework.log.LoggerFactory;
051    import org.deegree.framework.xml.ElementList;
052    import org.deegree.framework.xml.XMLException;
053    import org.deegree.framework.xml.XMLFragment;
054    import org.deegree.framework.xml.XMLParsingException;
055    import org.deegree.framework.xml.XMLTools;
056    import org.deegree.i18n.Messages;
057    import org.deegree.model.filterencoding.AbstractFilter;
058    import org.deegree.model.filterencoding.Filter;
059    import org.deegree.ogcbase.CommonNamespaces;
060    import org.deegree.ogcbase.ExceptionCode;
061    import org.deegree.ogcwebservices.InvalidParameterValueException;
062    import org.deegree.ogcwebservices.MissingParameterValueException;
063    import org.deegree.ogcwebservices.OGCWebServiceException;
064    import org.w3c.dom.Document;
065    import org.w3c.dom.Element;
066    import org.xml.sax.SAXException;
067    
068    /**
069     * 
070     * 
071     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
072     * @author last edited by: $Author: poth $
073     * 
074     * @version. $Revision: 6251 $, $Date: 2007-03-19 16:59:28 +0100 (Mo, 19 Mrz 2007) $
075     */
076    public class TransactionDocument_2_0_2 extends TransactionDocument {
077    
078        protected static final ILogger LOG = LoggerFactory.getLogger( TransactionDocument_2_0_2.class );
079    
080        /**
081         * initializes an empty TransactionDocument
082         * 
083         */
084        public TransactionDocument_2_0_2() {
085            try {
086                setSystemId( XMLFragment.DEFAULT_URL );
087            } catch ( MalformedURLException e ) {
088                LOG.logError( e.getMessage(), e );
089            }
090        }
091    
092        /**
093         * initializes a TransactionDocument by reading a DOM object from the passed
094         * 
095         * @see InputStream
096         * 
097         * @param transRoot
098         * @throws XMLException
099         * @throws IOException
100         */
101        public TransactionDocument_2_0_2( Element transRoot ) throws XMLException {
102            setRootElement( transRoot );
103        }
104    
105        /**
106         * 
107         * @throws IOException
108         * @throws SAXException
109         */
110        public void createEmptyDocument() {
111            Document doc = XMLTools.create();
112            Element root = doc.createElementNS( CommonNamespaces.CSW202NS.toASCIIString(), "csw202:Transaction" );
113            setRootElement( root );
114    
115        }
116    
117        /**
118         * parses a CS-W 2.0 transaction request
119         * 
120         * @param id
121         *            of the TransactionRequest
122         * 
123         * @return a new transaction parsed from the this xml-encoded request.
124         * @throws XMLParsingException
125         * @throws OGCWebServiceException
126         */
127        public Transaction parse( String id )
128                                throws XMLParsingException, OGCWebServiceException {
129    
130            LOG.logDebug( "parsing CS-W Transaction request" );
131    
132            // 'service'-attribute (required, must be CSW)
133            String service = XMLTools.getRequiredNodeAsString( getRootElement(), "@service", nsContext );
134            if ( !service.equals( "CSW" ) ) {
135                ExceptionCode code = ExceptionCode.INVALIDPARAMETERVALUE;
136                throw new InvalidParameterValueException( "GetRecordById", "'service' must be 'CSW'", code );
137            }
138    
139            String version = XMLTools.getRequiredNodeAsString( getRootElement(), "@version", nsContext );
140            if ( !"2.0.2".equals( version ) ) {
141                throw new OGCWebServiceException( "GetRecordByIdDocument_2_0_2",
142                                                  Messages.getMessage( "CSW_NOT_SUPPORTED_VERSION", "2.0.2", "2.0.2",
143                                                                       version ), ExceptionCode.INVALIDPARAMETERVALUE );
144            }
145            boolean verbose = XMLTools.getNodeAsBoolean( getRootElement(), "./@verboseResponse", nsContext, false );
146    
147            List<Operation> ops = new ArrayList<Operation>();
148    
149            ElementList el = XMLTools.getChildElements( getRootElement() );
150            for ( int i = 0; i < el.getLength(); i++ ) {
151                Element e = el.item( i );
152                // TODO check for qualified name
153                if ( "Insert".equals( e.getLocalName() ) ) {
154                    ops.add( parseInsert( e ) );
155                } else if ( "Update".equals( e.getLocalName() ) ) {
156                    ops.add( parseUpdate( e ) );
157                } else if ( "Delete".equals( e.getLocalName() ) ) {
158                    ops.add( parseDelete( e ) );
159                }
160            }
161    
162            // in the future the vendorSpecificParameters
163            Map<String, String> vendorSpecificParameters = parseDRMParams( this.getRootElement() );
164    
165            return new Transaction( version, id, vendorSpecificParameters, ops, verbose );
166        }
167    
168        /**
169         * parses a Delete element contained in a CS-W Transaction.
170         * 
171         * @param element
172         * @return the Delete class parsed from the given Delete element.
173         * @throws XMLParsingException
174         * @throws MissingParameterValueException
175         * @throws InvalidParameterValueException
176         */
177        private Delete parseDelete( Element element )
178                                throws XMLParsingException, MissingParameterValueException, InvalidParameterValueException {
179    
180            LOG.logDebug( "parsing CS-W Transaction-Delete" );
181    
182            String handle = XMLTools.getNodeAsString( element, "@handle", nsContext, null );
183            String tmp = XMLTools.getNodeAsString( element, "@typeName", nsContext, null );
184            URI typeName = null;
185            if ( tmp != null ) {
186                // part of the corrected CS-W 2.0 spec
187                try {
188                    typeName = new URI( tmp );
189                } catch ( Exception e ) {
190                    throw new XMLParsingException( "if defined attribute 'typeName' must be a valid URI" );
191                }
192            }
193    
194            Element elem = (Element) XMLTools.getRequiredNode( element, "./csw202:Constraint", nsContext );
195            String ver = XMLTools.getNodeAsString( elem, "@version", nsContext, null );
196            if ( ver == null ) {
197                String s = Messages.getMessage( "CSW_MISSING_CONSTRAINT_VERSION" );
198                throw new MissingParameterValueException( s );
199            }
200            if ( !"1.0.0".equals( ver ) && !"1.1.0".equals( ver ) ) {
201                String s = Messages.getMessage( "CSW_INVALID_CONSTRAINT_VERSION", ver );
202                throw new InvalidParameterValueException( s );
203            }
204    
205            elem = (Element) XMLTools.getRequiredNode( elem, "./ogc:Filter", nsContext );
206    
207            Filter constraint = AbstractFilter.buildFromDOM( elem, "1.0.0".equals( ver ) );
208            return new Delete( handle, typeName, constraint );
209        }
210    
211        /**
212         * parses a Update element contained in a CS-W Transaction.
213         * 
214         * @param element
215         * @return the update class containing all parsed values
216         * @throws XMLParsingException
217         * @throws MissingParameterValueException
218         * @throws InvalidParameterValueException
219         */
220        private Update parseUpdate( Element element )
221                                throws XMLParsingException, MissingParameterValueException, InvalidParameterValueException {
222    
223            LOG.logDebug( "parsing CS-W Transaction-Update" );
224    
225            String handle = XMLTools.getNodeAsString( element, "@handle", nsContext, null );
226            String tmp = XMLTools.getNodeAsString( element, "@typeName", nsContext, null );
227            URI typeName = null;
228            if ( tmp != null ) {
229                // part of the corrected CS-W 2.0 spec
230                try {
231                    typeName = new URI( tmp );
232                } catch ( Exception e ) {
233                    throw new XMLParsingException(
234                                                   "if defined attribute 'typeName' must be a valid URI" );
235                }
236            }
237    
238            Element elem = (Element) XMLTools.getRequiredNode( element, "./csw202:Constraint", nsContext );
239            String ver = XMLTools.getNodeAsString( elem, "@version", nsContext, null );
240            if ( ver == null ) {
241                String s = Messages.getMessage( "CSW_MISSING_CONSTRAINT_VERSION" );
242                throw new MissingParameterValueException( s );
243            }
244            if ( !"1.0.0".equals( ver ) && !"1.1.0".equals( ver ) ) {
245                String s = Messages.getMessage( "CSW_INVALID_CONSTRAINT_VERSION", ver );
246                throw new InvalidParameterValueException( s );
247            }
248    
249            elem = (Element) XMLTools.getRequiredNode( elem, "./ogc:Filter", nsContext );
250    
251            Filter constraint = AbstractFilter.buildFromDOM( elem, "1.0.0".equals( ver ) );
252    
253            List children = null;
254            List rp = XMLTools.getNodes( getRootElement(), "./csw202:RecordProperty", nsContext );
255            if ( rp.size() != 0 ) {
256                // at the moment will always be null because it is part of the
257                // CS-W 2.0 corrected version that will not be implemented yet
258            } else {
259                children = XMLTools.getNodes( element, "./child::*", nsContext );
260                if ( children.size() == 0 ) {
261                    throw new XMLParsingException( "one record must be defined within a CS-W update element" );
262                }
263            }
264            return new Update( handle, typeName, constraint, (Element) children.get( 0 ), null );
265        }
266    
267        /**
268         * parses a Insert element contained in a CS-W Transaction.
269         * 
270         * @param element
271         * @return an Insert instance
272         * @throws XMLParsingException
273         */
274        private Insert parseInsert( Element element )
275                                throws XMLParsingException {
276    
277            LOG.logDebug( "parsing CS-W Transaction-Insert" );
278    
279            String handle = XMLTools.getNodeAsString( element, "@handle", nsContext, "" );
280            List<Element> recList = new ArrayList<Element>();
281            List children = XMLTools.getNodes( element, "*", nsContext );
282            if ( children.size() == 0 ) {
283                LOG.logError( "at least one record must be defined within a CS-W insert element" );
284                throw new XMLParsingException( "at least one record must be defined within a CS-W insert element" );
285            }
286    
287            for ( Object n : children ) {
288                LOG.logDebug( "TransactionDocument(insert): adding the element: " + element.getLocalName()
289                              + " to the records list. " );
290                recList.add( (Element) n );
291            }
292          
293            // if no ebrim is done, create the old insert class.
294            return new Insert( handle, recList );
295        }
296    
297    }