001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/owscommon_1_1_0/CommonsDocument.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    
037    package org.deegree.owscommon_1_1_0;
038    
039    import static org.deegree.framework.xml.XMLTools.getElement;
040    import static org.deegree.framework.xml.XMLTools.getElements;
041    import static org.deegree.framework.xml.XMLTools.getNodeAsString;
042    import static org.deegree.framework.xml.XMLTools.getNodesAsStringList;
043    import static org.deegree.framework.xml.XMLTools.getRequiredElement;
044    import static org.deegree.framework.xml.XMLTools.getRequiredNodeAsString;
045    import static org.deegree.ogcbase.CommonNamespaces.XLINK_PREFIX;
046    
047    import java.util.ArrayList;
048    import java.util.List;
049    
050    import org.deegree.framework.log.ILogger;
051    import org.deegree.framework.log.LoggerFactory;
052    import org.deegree.framework.util.Pair;
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.ogcbase.CommonNamespaces;
057    import org.w3c.dom.Document;
058    import org.w3c.dom.Element;
059    
060    /**
061     * <code>CommonsDocument</code> supplies helper methods for all common ows (version 1.1.0) xml elements.
062     *
063     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
064     *
065     * @author last edited by: $Author: mschneider $
066     *
067     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
068     *
069     */
070    public class CommonsDocument extends XMLFragment {
071    
072        private static ILogger LOG = LoggerFactory.getLogger( CommonsDocument.class );
073    
074        /**
075         *
076         */
077        private static final long serialVersionUID = -7211342372381557201L;
078    
079        /**
080         * The ows 1.1 prefix with a ':' (colon) suffix.
081         */
082        protected static String PRE_OWS = CommonNamespaces.OWS_1_1_0PREFIX + ":";
083    
084        /**
085         * @param operationElements
086         *            to be parsed.
087         * @return a list of operations which may be empty but never <code>null</code>
088         * @throws XMLParsingException
089         */
090        protected List<Operation> parseOperations( List<Element> operationElements )
091                                throws XMLParsingException {
092            if ( operationElements == null || operationElements.size() < 2 ) {
093                throw new XMLParsingException( "At least two " + PRE_OWS + "operations must be defined in the " + PRE_OWS
094                                               + "OperationMetadata element." );
095            }
096            List<Operation> operations = new ArrayList<Operation>( operationElements.size() );
097            for ( Element op : operationElements ) {
098                /**
099                 * from owsOperationsMetadata<br/> Unordered list of Distributed Computing Platforms (DCPs) supported for
100                 * this operation. At present, only the HTTP DCP is defined, so this element will appear only once.
101                 */
102                Element dcp = getRequiredElement( op, PRE_OWS + "DCP", nsContext );
103                Element http = getRequiredElement( dcp, PRE_OWS + "HTTP", nsContext );
104                List<Element> getters = getElements( http, PRE_OWS + "Get", nsContext );
105                List<Pair<String, List<DomainType>>> getURLs = new ArrayList<Pair<String, List<DomainType>>>();
106                if ( getters != null && getters.size() > 0 ) {
107                    for ( Element get : getters ) {
108                        Pair<String, List<DomainType>> t = parseHTTPChild( get );
109                        if ( t != null ) {
110                            getURLs.add( t );
111                        }
112                    }
113                }
114    
115                List<Element> posts = getElements( http, PRE_OWS + "Post", nsContext );
116                List<Pair<String, List<DomainType>>> postURLs = new ArrayList<Pair<String, List<DomainType>>>();
117                if ( posts != null && posts.size() > 0 ) {
118                    for ( Element post : posts ) {
119                        Pair<String, List<DomainType>> t = parseHTTPChild( post );
120                        if ( t != null ) {
121                            postURLs.add( t );
122                        }
123                    }
124                }
125    
126                List<Element> params = getElements( op, PRE_OWS + "Parameter", nsContext );
127                List<DomainType> parameters = new ArrayList<DomainType>();
128                if ( params != null && params.size() > 0 ) {
129                    for ( Element param : params ) {
130                        DomainType t = parseDomainType( param );
131                        if ( t != null ) {
132                            parameters.add( t );
133                        }
134                    }
135                }
136    
137                List<Element> consts = getElements( op, PRE_OWS + "Constraint", nsContext );
138                List<DomainType> constraints = new ArrayList<DomainType>();
139                if ( params != null && params.size() > 0 ) {
140                    for ( Element ce : consts ) {
141                        DomainType t = parseDomainType( ce );
142                        if ( t != null ) {
143                            constraints.add( t );
144                        }
145                    }
146                }
147                List<Metadata> metadataAttribs = parseMetadatas( getElements( op, PRE_OWS + "MetaData", nsContext ) );
148                String name = getRequiredNodeAsString( op, "@name", nsContext );
149                operations.add( new Operation( getURLs, postURLs, parameters, constraints, metadataAttribs, name ) );
150            }
151            return operations;
152        }
153    
154        /**
155         * parses the post or get information beneath a http element.
156         *
157         * @param getOrPost
158         * @return the pair containing the xlink, list&lt;contraint&gt;. or <code>null</code> if attribute and elements
159         *         were not found.
160         * @throws XMLParsingException
161         */
162    
163        protected Pair<String, List<DomainType>> parseHTTPChild( Element getOrPost )
164                                throws XMLParsingException {
165            if ( getOrPost == null ) {
166                return null;
167            }
168            String httpURL = getNodeAsString( getOrPost, "@" + XLINK_PREFIX + ":href", nsContext, null );
169            List<DomainType> getConstraints = null;
170    
171            List<Element> getConstElements = getElements( getOrPost, PRE_OWS + "Constraint", nsContext );
172            if ( getConstElements != null && getConstElements.size() > 0 ) {
173                for ( Element gce : getConstElements ) {
174                    DomainType getConstraint = parseDomainType( gce );
175                    if ( getConstraint != null ) {
176                        // create a list instance.
177                        if ( getConstraints == null ) {
178                            getConstraints = new ArrayList<DomainType>( getConstElements.size() );
179                        }
180                        getConstraints.add( getConstraint );
181                    }
182                }
183            }
184            if ( getConstraints != null || httpURL != null ) {
185                return new Pair<String, List<DomainType>>( httpURL, getConstraints );
186            }
187            return null;
188        }
189    
190        /**
191         * @param domainType
192         *            to parse
193         * @return a bean representation of the domainType or <code>null</code> if given element is <code>null</code>.
194         * @throws XMLParsingException
195         */
196        protected DomainType parseDomainType( Element domainType )
197                                throws XMLParsingException {
198            if ( domainType == null ) {
199                return null;
200            }
201            boolean allowedValues = getElement( domainType, PRE_OWS + "AllowedValues", nsContext ) != null;
202            List<String> values = null;
203            List<Range> ranges = null;
204            if ( allowedValues ) {
205                values = getNodesAsStringList( domainType, PRE_OWS + "AllowedValues/" + PRE_OWS + "Value", nsContext );
206                ranges = parseRanges( getElements( domainType, PRE_OWS + "AllowedValues/" + PRE_OWS + "Range", nsContext ) );
207                if ( ( values == null || values.size() == 0 ) && ( ranges == null || ranges.size() == 0 ) ) {
208                    throw new XMLParsingException( "One of the following values must be defined in an " + PRE_OWS
209                                                   + "AllowedValues: - " + PRE_OWS + "Values or " + PRE_OWS + "Range" );
210                }
211            }
212            boolean anyValue = getElement( domainType, PRE_OWS + "AnyValue", nsContext ) != null;
213            boolean noValues = getElement( domainType, PRE_OWS + "NoValues", nsContext ) != null;
214            Pair<String, String> valuesReference = parseDomainMetadataType( getElement( domainType, PRE_OWS
215                                                                                                    + "ValuesReference",
216                                                                                        nsContext ) );
217            if ( valuesReference != null && valuesReference.second == null ) {
218                throw new XMLParsingException( "The reference attribute of the " + PRE_OWS + "DomatainType/" + PRE_OWS
219                                               + "ValuesReference must be set." );
220            }
221            if ( !( allowedValues || anyValue || noValues || valuesReference != null ) ) {
222                throw new XMLParsingException( "One of the following values must be defined in an " + PRE_OWS
223                                               + "DomainType: - " + PRE_OWS + "AllowedValues, " + PRE_OWS + "AnyValue, "
224                                               + PRE_OWS + "NoValues or " + PRE_OWS + "ValuesReference" );
225            }
226            String defaultValue = getNodeAsString( domainType, PRE_OWS + "DefaultValue", nsContext, null );
227            Pair<String, String> meaning = parseDomainMetadataType( getElement( domainType, PRE_OWS + "Meaning", nsContext ) );
228            Pair<String, String> dataType = parseDomainMetadataType( getElement( domainType, PRE_OWS + "DataType",
229                                                                                 nsContext ) );
230            Element valuesUnit = getElement( domainType, PRE_OWS + "ValuesUnit", nsContext );
231            Pair<String, String> uom = null;
232            Pair<String, String> referenceSystem = null;
233            if ( valuesUnit != null ) {
234                uom = parseDomainMetadataType( getElement( valuesUnit, PRE_OWS + "UOM", nsContext ) );
235                referenceSystem = parseDomainMetadataType( getElement( valuesUnit, PRE_OWS + "ReferenceSystem", nsContext ) );
236                if ( uom == null && referenceSystem == null ) {
237                    throw new XMLParsingException( "Either " + PRE_OWS + "UOM or " + PRE_OWS
238                                                   + "ReferenceSystem are required in a " + PRE_OWS + "ValuesUnit element." );
239                }
240            }
241            List<Metadata> metadataAttribs = parseMetadatas( getElements( domainType, PRE_OWS + "MetaData", nsContext ) );
242    
243            String name = getRequiredNodeAsString( domainType, "@name", nsContext );
244    
245            return new DomainType( values, ranges, anyValue, noValues, valuesReference, defaultValue, meaning, dataType,
246                                   uom, referenceSystem, metadataAttribs, name );
247    
248        }
249    
250        /**
251         * @param metadataElements
252         *            to be parsed.
253         * @return a List of pairs of optional &lt;xlink:href, about&gt; attributes, or an empty list <code>null</code> if
254         *         no elements were found.
255         */
256        protected List<Metadata> parseMetadatas( List<Element> metadataElements ) {
257            if ( metadataElements == null || metadataElements.size() == 0 ) {
258                return null;
259            }
260            List<Metadata> result = new ArrayList<Metadata>( metadataElements.size() );
261            for ( Element mde : metadataElements ) {
262    
263                try {
264                    Metadata md = parseMetadata( mde );
265                    if ( md != null ) {
266                        result.add( md );
267                    }
268                } catch ( XMLParsingException e ) {
269                    LOG.logError( e );
270                }
271    
272            }
273            if ( result.size() == 0 ) {
274                return null;
275            }
276            return result;
277    
278        }
279    
280        /**
281         * @param metadataElement
282         *            to be parsed.
283         * @return the pair of optional &lt;xlink:href, about&gt; attributes.
284         * @throws XMLParsingException
285         *             if the abstract metadatas could not be parsed.
286         */
287        protected Metadata parseMetadata( Element metadataElement )
288                                throws XMLParsingException {
289            if ( metadataElement == null ) {
290                return null;
291            }
292            String metadataHref = metadataElement.getAttributeNS( CommonNamespaces.XLNNS.toASCIIString(), ":href" );
293            metadataHref = "".equals( metadataHref ) ? null : metadataHref;
294            String metadataAbout = metadataElement.getAttribute( "about" );
295            metadataAbout = "".equals( metadataAbout ) ? null : metadataAbout;
296            Element abstractElement = getElement( metadataElement, "*[1]", nsContext );
297            Element result = null;
298            if ( abstractElement != null ) {
299                Document doc = XMLTools.create();
300                Element t = (Element) doc.importNode( abstractElement, true );
301                result = (Element) doc.appendChild( t );
302            }
303            if ( metadataAbout != null || metadataHref != null || result != null ) {
304                return new Metadata( metadataHref, metadataAbout, result );
305            }
306            return null;
307        }
308    
309        /**
310         * Parses the domain metadata type and it's reference attribute and puts them in a pair, like name, reference, which
311         * may be null
312         *
313         * @param domainMDElements
314         * @return a list of pairs containing the values or <code>null</code> if given list is <code>null</code> or it
315         *         does not contain any domain elements value.
316         * @throws XMLParsingException
317         */
318        protected List<Pair<String, String>> parseDomainMetadataTypes( List<Element> domainMDElements )
319                                throws XMLParsingException {
320            if ( domainMDElements == null || domainMDElements.size() == 0 ) {
321                return null;
322            }
323            List<Pair<String, String>> domainMDTypes = new ArrayList<Pair<String, String>>( domainMDElements.size() );
324            for ( Element mdT : domainMDElements ) {
325                Pair<String, String> t = parseDomainMetadataType( mdT );
326                if ( t != null ) {
327                    domainMDTypes.add( t );
328                }
329            }
330            return ( domainMDTypes.size() == 0 ) ? null : domainMDTypes;
331        }
332    
333        /**
334         * Parses the domain metadata type and it's reference attribute and puts them in a pair, like name, reference, the
335         * latter may be null
336         *
337         * @param domainMDElement
338         *            to parse
339         * @return a pair containing the values or <code>null</code> if given element is null or it does not contain a
340         *         value.
341         * @throws XMLParsingException
342         */
343        protected Pair<String, String> parseDomainMetadataType( Element domainMDElement )
344                                throws XMLParsingException {
345            if ( domainMDElement == null ) {
346                return null;
347            }
348            String valuesReference = getNodeAsString( domainMDElement, ".", nsContext, null );
349            String reference = getNodeAsString( domainMDElement, "@reference", nsContext, null );
350            if ( valuesReference != null ) {
351                return new Pair<String, String>( valuesReference, reference );
352            }
353            return null;
354        }
355    
356        /**
357         * @param rangeElements
358         * @return the ranges or <code>null</code> if no elements were given.
359         * @throws XMLParsingException
360         */
361        private List<Range> parseRanges( List<Element> rangeElements )
362                                throws XMLParsingException {
363            if ( rangeElements == null || rangeElements.size() == 0 ) {
364                return null;
365            }
366            List<Range> ranges = new ArrayList<Range>( rangeElements.size() );
367            for ( Element range : rangeElements ) {
368                String minimumValue = getNodeAsString( range, PRE_OWS + "Range/" + PRE_OWS + "MinimumValue", nsContext,
369                                                       null );
370                String maximumValue = getNodeAsString( range, PRE_OWS + "Range/" + PRE_OWS + "MaximumValue", nsContext,
371                                                       null );
372                String spacing = getNodeAsString( range, PRE_OWS + "Range/" + PRE_OWS + "Spacing", nsContext, null );
373                String rangeClosure = getNodeAsString( range, PRE_OWS + "Range/@rangeClosure", nsContext, "closed" );
374                ranges.add( new Range( minimumValue, maximumValue, spacing, rangeClosure ) );
375            }
376            return ranges;
377        }
378    
379        /**
380         * @param serviceContact
381         * @return the service contact bean
382         * @throws XMLParsingException
383         */
384        protected ServiceContact parseServiceContact( Element serviceContact )
385                                throws XMLParsingException {
386            String individualName = getNodeAsString( serviceContact, PRE_OWS + "IndividualName", nsContext, null );
387            String positionName = getNodeAsString( serviceContact, PRE_OWS + "PositionName", nsContext, null );
388            ContactInfo contactInfo = parseContactInfo( getElement( serviceContact, PRE_OWS + "ContactInfo", nsContext ) );
389            Pair<String, String> role = null;
390            String roleS = getNodeAsString( serviceContact, PRE_OWS + "Role", nsContext, null );
391            if ( roleS != null ) {
392                role = new Pair<String, String>( roleS, getNodeAsString( serviceContact, PRE_OWS + "Role/@codeSpace",
393                                                                         nsContext, null ) );
394            }
395            return new ServiceContact( individualName, positionName, contactInfo, role );
396        }
397    
398        /**
399         * @param contactInfo
400         * @return the contactinfo or <code>null</code> if all underlying elements are empty.
401         * @throws XMLParsingException
402         */
403        protected ContactInfo parseContactInfo( Element contactInfo )
404                                throws XMLParsingException {
405            if ( contactInfo == null ) {
406                return null;
407            }
408    
409            Pair<List<String>, List<String>> phone = null;
410            Element phoneElement = getElement( contactInfo, PRE_OWS + "Phone", nsContext );
411            if ( phoneElement != null ) {
412                phone = new Pair<List<String>, List<String>>( getNodesAsStringList( phoneElement, PRE_OWS + "Voice",
413                                                                                    nsContext ),
414                                                              getNodesAsStringList( phoneElement, PRE_OWS + "Facsimile",
415                                                                                    nsContext ) );
416            }
417    
418            List<String> deliveryPoint = null;
419            String city = null;
420            String administrativeArea = null;
421            String postalCode = null;
422            String country = null;
423            List<String> electronicMailAddress = null;
424            Element address = getElement( contactInfo, PRE_OWS + "Address", nsContext );
425            boolean hasAdress = false;
426            if ( address != null ) {
427                deliveryPoint = getNodesAsStringList( address, PRE_OWS + "DeliveryPoint", nsContext );
428                city = getNodeAsString( address, PRE_OWS + "City", nsContext, null );
429                administrativeArea = getNodeAsString( address, PRE_OWS + "AdministrativeArea", nsContext, null );
430                postalCode = getNodeAsString( address, PRE_OWS + "PostalCode", nsContext, null );
431                country = getNodeAsString( address, PRE_OWS + "Country", nsContext, null );
432                electronicMailAddress = getNodesAsStringList( address, PRE_OWS + "ElectronicMailAddress", nsContext );
433                if ( electronicMailAddress.size() == 0 ) {
434                    electronicMailAddress = null;
435                }
436                hasAdress = ( deliveryPoint != null || city != null || administrativeArea != null || postalCode != null
437                              || country != null || electronicMailAddress != null );
438            }
439    
440            String onlineResource = getNodeAsString( contactInfo, PRE_OWS + "OnlineResource/@" + XLINK_PREFIX + ":href",
441                                                     nsContext, null );
442            String hoursOfService = getNodeAsString( contactInfo, PRE_OWS + "HoursOfService", nsContext, null );
443            String contactInstructions = getNodeAsString( contactInfo, PRE_OWS + "ContactInstructions", nsContext, null );
444            if ( ( phone != null ) && !hasAdress && onlineResource == null && hoursOfService == null
445                 && contactInstructions == null ) {
446                return null;
447            }
448            return new ContactInfo( phone, hasAdress, deliveryPoint, city, administrativeArea, postalCode, country,
449                                    electronicMailAddress, onlineResource, hoursOfService, contactInstructions );
450        }
451    
452        /**
453         * @param basicIdentificationType
454         *            to be parsed.
455         * @return the {@link BasicIdentification} bean representation or <code>null</code> if the given element is
456         *         <code>null</code>.
457         * @throws XMLParsingException
458         *             if the given param can not be parsed.
459         */
460        protected BasicIdentification parseBasicIdentificationType( Element basicIdentificationType )
461                                throws XMLParsingException {
462            if ( basicIdentificationType == null ) {
463                return null;
464            }
465            List<String> title = getNodesAsStringList( basicIdentificationType, PRE_OWS + "Title", nsContext );
466            List<String> abstracts = getNodesAsStringList( basicIdentificationType, PRE_OWS + "Abstract", nsContext );
467            List<Element> kws = getElements( basicIdentificationType, PRE_OWS + "Keywords", nsContext );
468            // Pair<List<keywords>, codetype>
469            List<Keywords> keywords = new ArrayList<Keywords>( ( ( kws == null ) ? 0 : kws.size() ) );
470            if ( kws != null ) {
471                for ( Element keyword : kws ) {
472                    keywords.add( parseKeywords( keyword ) );
473                }
474            }
475            Pair<String, String> identifier = parseIdentifier( basicIdentificationType );
476            List<Metadata> metadatas = parseMetadatas( getElements( basicIdentificationType, PRE_OWS + "Metadata",
477                                                                    nsContext ) );
478            return new BasicIdentification( title, abstracts, keywords, identifier, metadatas );
479        }
480    
481        /**
482         * @param root
483         *            element to be parsed for the identifier.
484         * @return a &lt;value, codeSpace&gt; pair or <code>null</code> if the given element is <code>null</code> or if
485         *         the identifier has no value and codeSpace.
486         * @throws XMLParsingException
487         */
488        protected Pair<String, String> parseIdentifier( Element root )
489                                throws XMLParsingException {
490            if ( root == null ) {
491                return null;
492            }
493            Pair<String, String> identifier = null;
494            Element id = getElement( root, PRE_OWS + "Identifier", nsContext );
495            if ( id != null ) {
496                String value = getNodeAsString( id, ".", nsContext, "" );
497                String codeSpace = id.getAttribute( "codeSpace" );
498                if ( !"".equals( value ) || !"".equals( codeSpace.trim() ) ) {
499                    identifier = new Pair<String, String>( value, codeSpace );
500                }
501            }
502            return identifier;
503        }
504    
505        /**
506         * Return the ows_1_1_0 keywords..
507         *
508         * @param keywords
509         *            element to parse from
510         * @return a <List<Keywords>,Type> pair.
511         * @throws XMLParsingException
512         */
513        protected Keywords parseKeywords( Element keywords )
514                                throws XMLParsingException {
515            if ( keywords == null ) {
516                return null;
517            }
518            String codetype = getNodeAsString( keywords, PRE_OWS + "Type", nsContext, null );
519            String typeSpace = null;
520            Pair<String, String> type = null;
521            if ( codetype != null ) {
522                typeSpace = getNodeAsString( keywords, PRE_OWS + "Type/@codeSpace", nsContext, null );
523                type = new Pair<String, String>( codetype, typeSpace );
524            }
525            return new Keywords( getNodesAsStringList( keywords, PRE_OWS + "Keyword", nsContext ), type );
526    
527        }
528    
529    }