001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/csw/manager/TransactionDocument.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53115 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     ---------------------------------------------------------------------------*/
043    package org.deegree.ogcwebservices.csw.manager;
044    
045    import java.io.IOException;
046    import java.io.InputStream;
047    import java.net.MalformedURLException;
048    import java.net.URI;
049    import java.util.ArrayList;
050    import java.util.HashMap;
051    import java.util.List;
052    import java.util.Map;
053    
054    import org.deegree.framework.log.ILogger;
055    import org.deegree.framework.log.LoggerFactory;
056    import org.deegree.framework.xml.ElementList;
057    import org.deegree.framework.xml.XMLException;
058    import org.deegree.framework.xml.XMLFragment;
059    import org.deegree.framework.xml.XMLParsingException;
060    import org.deegree.framework.xml.XMLTools;
061    import org.deegree.i18n.Messages;
062    import org.deegree.model.filterencoding.AbstractFilter;
063    import org.deegree.model.filterencoding.Filter;
064    import org.deegree.ogcbase.CommonNamespaces;
065    import org.deegree.ogcwebservices.InvalidParameterValueException;
066    import org.deegree.ogcwebservices.MissingParameterValueException;
067    import org.deegree.ogcwebservices.OGCWebServiceException;
068    import org.deegree.ogcwebservices.csw.AbstractCSWRequestDocument;
069    import org.w3c.dom.Document;
070    import org.w3c.dom.Element;
071    import org.xml.sax.SAXException;
072    
073    /**
074     * The Transaction operation defines an interface for creating, modifying and deleting catalogue
075     * records. The specific payload being manipulated must be defined in a profile.
076     * 
077     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
078     * @author last edited by: $Author: apoth $
079     * 
080     * @version $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $
081     * 
082     */
083    public class TransactionDocument extends AbstractCSWRequestDocument {
084    
085        private static final long serialVersionUID = 7914686453810419662L;
086    
087        protected static final ILogger LOG = LoggerFactory.getLogger( TransactionDocument.class );
088    
089        /**
090         * initializes an empty TransactionDocument
091         * 
092         */
093        public TransactionDocument() {
094            try {
095                setSystemId( XMLFragment.DEFAULT_URL );
096            } catch ( MalformedURLException e ) {
097                LOG.logError( e.getMessage(), e );
098            }
099        }
100    
101        /**
102         * 
103         * @throws IOException
104         * @throws SAXException
105         */
106        public void createEmptyDocument() {
107            Document doc = XMLTools.create();
108            Element root = doc.createElementNS( CommonNamespaces.CSWNS.toASCIIString(),
109                                                "csw:Transaction" );
110            setRootElement( root );
111    
112        }
113    
114        /**
115         * initializes a TransactionDocument by reading a DOM object from the passed
116         * 
117         * @see InputStream
118         * 
119         * @param transRoot
120         * @throws XMLException
121         * @throws IOException
122         */
123        public TransactionDocument( Element transRoot ) throws XMLException {
124            setRootElement( transRoot );
125            //setSystemId( XMLFragment.DEFAULT_URL );
126        }
127    
128        /**
129         * parses a CS-W 2.0 transaction request
130         * @param id of the TransactionRequest
131         * 
132         * @return a new transaction parsed from the this xml-encoded request.
133         * @throws XMLParsingException
134         * @throws InvalidParameterValueException
135         * @throws MissingParameterValueException
136         */
137        public Transaction parse( String id )
138                                throws XMLParsingException, OGCWebServiceException {
139    
140            LOG.logDebug( "parsing CS-W Transaction request" );
141            String version = XMLTools.getNodeAsString( getRootElement(), "@version", nsContext, null );
142            boolean verbose = XMLTools.getNodeAsBoolean( getRootElement(), "./@verboseResponse", nsContext,
143                                                         false );
144    
145            List<Operation> ops = new ArrayList<Operation>();
146    
147            ElementList el = XMLTools.getChildElements( getRootElement() );
148            for ( int i = 0; i < el.getLength(); i++ ) {
149                Element e = el.item( i );
150                // TODO check for qualified name
151                if ( "Insert".equals( e.getLocalName() ) ) {
152                    ops.add( parseInsert( e ) );
153                } else if ( "Update".equals( e.getLocalName() ) ) {
154                    ops.add( parseUpdate( e ) );
155                } else if ( "Delete".equals( e.getLocalName() ) ) {
156                    ops.add( parseDelete( e ) );
157                }
158            }
159            
160            //in the future the vendorSpecificParameters 
161            Map<String,String> vendorSpecificParameters = parseDRMParams( this.getRootElement() );
162    
163            return new Transaction( version, id, vendorSpecificParameters, ops, verbose );
164        }
165    
166        /**
167         * parses a Delete element contained in a CS-W Transaction.
168         * 
169         * @param element
170         * @return the Delete class parsed from the given Delete element.
171         * @throws XMLParsingException
172         * @throws MissingParameterValueException
173         * @throws InvalidParameterValueException
174         */
175        private Delete parseDelete( Element element )
176                                throws XMLParsingException, MissingParameterValueException,
177                                InvalidParameterValueException {
178    
179            LOG.logDebug( "parsing CS-W Transaction-Delete" );
180    
181            String handle = XMLTools.getNodeAsString( element, "@handle", nsContext, null );
182            String tmp = XMLTools.getNodeAsString( element, "@typeName", nsContext, null );
183            URI typeName = null;
184            if ( tmp != null ) {
185                // part of the corrected CS-W 2.0 spec
186                try {
187                    typeName = new URI( tmp );
188                } catch ( Exception e ) {
189                    throw new XMLParsingException( "if defined attribute 'typeName' must be "
190                                                   + "a valid URI" );
191                }
192            }
193    
194            Element elem = (Element) XMLTools.getRequiredNode( element, "./csw: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,
222                                InvalidParameterValueException {
223    
224            LOG.logDebug( "parsing CS-W Transaction-Update" );
225    
226            String handle = XMLTools.getNodeAsString( element, "@handle", nsContext, null );
227            String tmp = XMLTools.getNodeAsString( element, "@typeName", nsContext, null );
228            URI typeName = null;
229            if ( tmp != null ) {
230                // part of the corrected CS-W 2.0 spec
231                try {
232                    typeName = new URI( tmp );
233                } catch ( Exception e ) {
234                    throw new XMLParsingException(
235                                                   "if defined attribute 'typeName' must be a valid URI" );
236                }
237            }
238            Element elem = (Element) XMLTools.getRequiredNode( element, "./csw: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(), "./csw: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(
262                                                   "one record must be defined within a CS-W update element" );
263                }
264            }
265            return new Update( handle, typeName, constraint, (Element) children.get( 0 ), null );
266        }
267    
268        /**
269         * parses a Insert element contained in a CS-W Transaction.
270         * 
271         * @param element
272         * @return an Insert instance
273         * @throws XMLParsingException
274         */
275        private Insert parseInsert( Element element )
276                                throws XMLParsingException {
277    
278            LOG.logDebug( "parsing CS-W Transaction-Insert" );
279    
280            String handle = XMLTools.getNodeAsString( element, "@handle", nsContext, "" );
281            List<Element> recList = new ArrayList<Element>( );
282            List children = XMLTools.getNodes( element, "*", nsContext );
283            if ( children.size() == 0 ) {
284                LOG.logError( "at least one record must be defined within a CS-W insert element" );
285                throw new XMLParsingException( "at least one record must be defined "
286                                               + "within a CS-W insert element" );
287            }
288    
289            String prefixForRim = null;
290            for ( Object n : children ) {
291                LOG.logDebug( "TransactionDocument(insert): adding the element: " + element.getLocalName() + " to the records list. " );
292                if( prefixForRim == null ){
293                    prefixForRim = ((Element)n).lookupPrefix( CommonNamespaces.OASIS_EBRIMNS.toASCIIString() );       
294                }
295                recList.add( (Element) n );
296            }
297            
298            //check if the rim namespace is used        
299            //nsForRim = XMLTools.getNamespaceForPrefix( "rim", element );
300             
301            LOG.logDebug( "TransactionDocument: for the insert operation found following prefix: " + prefixForRim );
302            if ( prefixForRim != null ) {
303                List<Element> nl = XMLTools.getElements( element, "rim:ExtrinsicObject", nsContext );
304                Map<String, Element> extrinsicObjects = new HashMap<String, Element>( nl.size() );
305                LOG.logDebug( "TransactionDocument: number of ExtrinsicObjects found: " + extrinsicObjects.size() );
306                for ( Element n : nl ) {
307                    String id = XMLTools.getRequiredNodeAsString( n, "@id", nsContext );
308                    if( "".equals( id.trim() ) ){
309                        throw new XMLParsingException( "The value of the id attribute in a {" + CommonNamespaces.OASIS_EBRIMNS.toASCIIString() + "}extrinsicObject may not be empty" );
310                    }
311                    LOG.logDebug( "TransactionDocument: found the id " + id );
312                    extrinsicObjects.put( id.trim(), n );
313                }
314                return new Insert( handle, recList, extrinsicObjects );
315            }
316            // if no ebrim is done, create the old insert class.
317            return new Insert( handle, recList );
318        }
319    }