001    // $HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/owscommon/XMLFactory.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.owscommon;
037    
038    import static java.net.URLEncoder.encode;
039    import static org.deegree.framework.util.CharsetUtils.getSystemCharset;
040    import static org.deegree.framework.xml.XMLTools.appendElement;
041    import static org.deegree.ogcbase.ExceptionCode.NOAPPLICABLECODE;
042    
043    import java.io.UnsupportedEncodingException;
044    import java.net.URI;
045    import java.net.URL;
046    import java.net.URLEncoder;
047    
048    import org.deegree.datatypes.QualifiedName;
049    import org.deegree.framework.util.CharsetUtils;
050    import org.deegree.framework.xml.XMLFragment;
051    import org.deegree.framework.xml.XMLTools;
052    import org.deegree.model.metadata.iso19115.Address;
053    import org.deegree.model.metadata.iso19115.ContactInfo;
054    import org.deegree.model.metadata.iso19115.Keywords;
055    import org.deegree.model.metadata.iso19115.Linkage;
056    import org.deegree.model.metadata.iso19115.OnlineResource;
057    import org.deegree.model.metadata.iso19115.Phone;
058    import org.deegree.model.metadata.iso19115.TypeCode;
059    import org.deegree.ogcbase.CommonNamespaces;
060    import org.deegree.ogcwebservices.ExceptionDocument;
061    import org.deegree.ogcwebservices.ExceptionReport;
062    import org.deegree.ogcwebservices.OGCWebServiceException;
063    import org.deegree.ogcwebservices.getcapabilities.DCPType;
064    import org.deegree.ogcwebservices.getcapabilities.HTTP;
065    import org.deegree.ogcwebservices.getcapabilities.Operation;
066    import org.deegree.ogcwebservices.getcapabilities.OperationsMetadata;
067    import org.deegree.ogcwebservices.getcapabilities.ServiceIdentification;
068    import org.deegree.ogcwebservices.getcapabilities.ServiceProvider;
069    import org.w3c.dom.Element;
070    
071    /**
072     * Factory to create XML representations of components that are defined in the
073     * <code>OWS Common Implementation Capabilities Specification 0.3</code>.
074     *
075     * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
076     * @author last edited by: $Author: mschneider $
077     *
078     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
079     */
080    public class XMLFactory extends org.deegree.ogcbase.XMLFactory {
081    
082        protected static final URI OWSNS = CommonNamespaces.OWSNS;
083    
084        private static final String POGC = CommonNamespaces.OGC_PREFIX + ':';
085    
086        protected static final URI DEEGREECSWNS = CommonNamespaces.DEEGREECSW;
087    
088        /**
089         * Exports an <tt>ExceptionReport</tt> to an XML Document as defined in the
090         * <code>OGC common implementation specification 0.2.0</code>.
091         *
092         * @param exr
093         * @return a new ServiceException document
094         */
095        public static XMLFragment export( ExceptionReport exr ) {
096    
097            ExceptionDocument eDoc = new ExceptionDocument();
098            eDoc.createEmptyDocument();
099            Element node = eDoc.getRootElement();
100    
101            for ( int i = 0; i < exr.getExceptions().length; i++ ) {
102                appendException( node, exr.getExceptions()[i], false );
103            }
104    
105            return eDoc;
106        }
107    
108        /**
109         * @param exr
110         * @return a new ServiceException document
111         */
112        public static XMLFragment exportNS( ExceptionReport exr ) {
113    
114            ExceptionDocument eDoc = new ExceptionDocument();
115            eDoc.createEmptyDocumentNS();
116            Element node = eDoc.getRootElement();
117    
118            for ( int i = 0; i < exr.getExceptions().length; i++ ) {
119                appendException( node, exr.getExceptions()[i], true );
120            }
121    
122            return eDoc;
123    
124        }
125    
126        /**
127         * @param exr
128         * @return a new ExceptionReport document according to OWS 1.0.0
129         */
130        public static XMLFragment exportExceptionReport( ExceptionReport exr ) {
131            XMLFragment doc = new XMLFragment( new QualifiedName( "ows", "ExceptionReport", OWSNS ) );
132            Element root = doc.getRootElement();
133    
134            for ( int i = 0; i < exr.getExceptions().length; i++ ) {
135                OGCWebServiceException exc = exr.getExceptions()[i];
136                Element e = XMLTools.appendElement( root, OWSNS, "ows:Exception", exc.getMessage() );
137                if ( exc.getCode() != null ) {
138                    e.setAttribute( "exceptionCode", exc.getCode().value );
139                }
140    
141                String locator = exc.getLocator();
142                try {
143                    if ( locator != null ) {
144                        locator = URLEncoder.encode( locator, CharsetUtils.getSystemCharset() );
145                    } else {
146                        locator = "unknown";
147                    }
148                } catch ( UnsupportedEncodingException _ ) {
149                    // if catched why not do something -> setting locator to "unknown"
150                    locator = "unknown";
151                }
152                e.setAttribute( "locator", locator );
153            }
154    
155            return doc;
156    
157        }
158    
159        /**
160         * appends a xml representation of an <tt>OGCWebServiceException</tt> to the passed <tt>Element</tt>
161         *
162         * @param node
163         * @param ex
164         * @param namespace
165         *            if true, the ogc prefix (bound to the ogc namespace) will be appended
166         */
167        protected static void appendException( Element node, OGCWebServiceException ex, boolean namespace ) {
168    
169            if ( namespace ) {
170                node = XMLTools.appendElement( node, OGCNS, POGC + "ServiceException", ex.getMessage() );
171            } else {
172                node = XMLTools.appendElement( node, null, "ServiceException", ex.getMessage() );
173            }
174    
175            if ( ex.getCode() != null ) {
176                node.setAttribute( "code", ex.getCode().value );
177            }
178            String locator = ex.getLocator();
179            try {
180                if ( locator != null ) {
181                    locator = URLEncoder.encode( locator, CharsetUtils.getSystemCharset() );
182                } else {
183                    locator = "unknown";
184                }
185            } catch ( UnsupportedEncodingException e ) {
186                // if catched why not do something -> setting locator to "unknown"
187                locator = "unknown";
188            }
189            node.setAttribute( "locator", locator );
190        }
191    
192        /**
193         * Appends the DOM representation of the <code>ServiceIdentification</code>- section to the passed
194         * <code>Element</code>.
195         *
196         * @param root
197         * @param serviceIdentification
198         */
199        protected static void appendServiceIdentification( Element root, ServiceIdentification serviceIdentification ) {
200    
201            // 'ServiceIdentification'-element
202            Element serviceIdentificationNode = XMLTools.appendElement( root, OWSNS, "ows:ServiceIdentification" );
203    
204            // 'ServiceType'-element
205            XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:ServiceType",
206                                    serviceIdentification.getServiceType().getCode() );
207    
208            // 'ServiceTypeVersion'-elements
209            String[] versions = serviceIdentification.getServiceTypeVersions();
210            for ( int i = 0; i < versions.length; i++ ) {
211                XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:ServiceTypeVersion", versions[i] );
212            }
213    
214            // 'Title'-element
215            XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:Title", serviceIdentification.getTitle() );
216    
217            // 'Abstract'-element
218            if ( serviceIdentification.getAbstract() != null ) {
219                XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:Abstract",
220                                        serviceIdentification.getAbstract() );
221            }
222    
223            // 'Keywords'-element
224            appendOWSKeywords( serviceIdentificationNode, serviceIdentification.getKeywords() );
225    
226            // 'Fees'-element
227            XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:Fees", serviceIdentification.getFees() );
228    
229            // 'AccessConstraints'-element
230            String[] constraints = serviceIdentification.getAccessConstraints();
231            if ( constraints != null ) {
232                for ( int i = 0; i < constraints.length; i++ ) {
233                    XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:AccessConstraints", constraints[i] );
234                }
235            }
236        }
237    
238        /**
239         * Appends a <code>ows:Keywords</code> -element for each <code>Keywords</code> object of the passed array to the
240         * passed <code>Element</code>.
241         *
242         * @param xmlNode
243         * @param keywords
244         */
245        protected static void appendOWSKeywords( Element xmlNode, Keywords[] keywords ) {
246            if ( keywords != null ) {
247                for ( int i = 0; i < keywords.length; i++ ) {
248                    Element node = XMLTools.appendElement( xmlNode, OWSNS, "ows:Keywords" );
249                    appendOWSKeywords( node, keywords[i] );
250                }
251            }
252        }
253    
254        /**
255         * Appends a <code>ows:Keywords</code> -element to the passed <code>Element</code> and fills it with the available
256         * keywords.
257         *
258         * @param xmlNode
259         * @param keywords
260         */
261        protected static void appendOWSKeywords( Element xmlNode, Keywords keywords ) {
262            if ( keywords != null ) {
263                String[] kw = keywords.getKeywords();
264                for ( int i = 0; i < kw.length; i++ ) {
265                    XMLTools.appendElement( xmlNode, OWSNS, "ows:Keyword", kw[i] );
266                }
267                TypeCode typeCode = keywords.getTypeCode();
268                if ( typeCode != null ) {
269                    Element node = XMLTools.appendElement( xmlNode, OWSNS, "ows:Type", typeCode.getCode() );
270                    if ( typeCode.getCodeSpace() != null ) {
271                        node.setAttribute( "codeSpace", typeCode.getCodeSpace().toString() );
272                    }
273                }
274            }
275        }
276    
277        /**
278         * Appends the DOM representation of the <code>ServiceProvider</code>- section to the passed <code>Element</code>.
279         *
280         * @param root
281         * @param serviceProvider
282         */
283        protected static void appendServiceProvider( Element root, ServiceProvider serviceProvider ) {
284    
285            // 'ServiceProvider'-element
286            Element serviceProviderNode = XMLTools.appendElement( root, OWSNS, "ows:ServiceProvider" );
287    
288            // 'ProviderName'-element
289            XMLTools.appendElement( serviceProviderNode, OWSNS, "ows:ProviderName", serviceProvider.getProviderName() );
290    
291            // 'ProviderSite'-element
292            if ( serviceProvider.getProviderSite() != null ) {
293                Element providerSiteNode = XMLTools.appendElement( serviceProviderNode, OWSNS, "ows:ProviderSite" );
294                appendSimpleLinkAttributes( providerSiteNode, serviceProvider.getProviderSite() );
295            }
296    
297            // 'ServiceContact'-element
298            Element serviceContactNode = XMLTools.appendElement( serviceProviderNode, OWSNS, "ows:ServiceContact" );
299    
300            // 'IndividualName'-element
301            XMLTools.appendElement( serviceContactNode, OWSNS, "ows:IndividualName", serviceProvider.getIndividualName() );
302    
303            // 'PositionName'-element
304            if ( serviceProvider.getPositionName() != null ) {
305                XMLTools.appendElement( serviceContactNode, OWSNS, "ows:PositionName", serviceProvider.getPositionName() );
306            }
307    
308            // 'ContactInfo'-element
309            ContactInfo contactInfo = serviceProvider.getContactInfo();
310            if ( contactInfo != null ) {
311                Element contactInfoNode = XMLTools.appendElement( serviceContactNode, OWSNS, "ows:ContactInfo" );
312                Phone phone = contactInfo.getPhone();
313                if ( phone != null ) {
314                    appendPhone( contactInfoNode, phone );
315                }
316                Address address = contactInfo.getAddress();
317                if ( address != null ) {
318                    appendAddress( contactInfoNode, address );
319                }
320                OnlineResource onlineResource = contactInfo.getOnLineResource();
321                if ( onlineResource != null ) {
322                    appendOnlineResource( contactInfoNode, "ows:OnlineResource", onlineResource, OWSNS );
323                }
324                String hoursOfService = contactInfo.getHoursOfService();
325                if ( hoursOfService != null ) {
326                    XMLTools.appendElement( contactInfoNode, OWSNS, "ows:HoursOfService", hoursOfService );
327                }
328                String contactInstructions = contactInfo.getContactInstructions();
329                if ( contactInstructions != null ) {
330                    XMLTools.appendElement( contactInfoNode, OWSNS, "ows:ContactInstructions", contactInstructions );
331                }
332            }
333            TypeCode role = serviceProvider.getRole();
334            if ( role != null ) {
335                Element roleElement = XMLTools.appendElement( serviceContactNode, OWSNS, "ows:Role", role.getCode() );
336                if ( role.getCodeSpace() != null ) {
337                    roleElement.setAttribute( "codeSpace", role.getCodeSpace().toString() );
338                }
339            }
340        }
341    
342        /**
343         * Appends the DOM representation of the <code>Phone</code> -section to the passed <code>Element</code>.
344         *
345         * @param root
346         * @param phone
347         */
348        protected static void appendPhone( Element root, Phone phone ) {
349    
350            // 'Phone'-element
351            Element phoneNode = XMLTools.appendElement( root, OWSNS, "ows:Phone" );
352    
353            // 'Voice'-elements
354            String[] voiceNumbers = phone.getVoice();
355            for ( int i = 0; i < voiceNumbers.length; i++ ) {
356                XMLTools.appendElement( phoneNode, OWSNS, "ows:Voice", voiceNumbers[i] );
357            }
358    
359            // 'Facsimile'-elements
360            String[] facsimileNumbers = phone.getFacsimile();
361            for ( int i = 0; i < facsimileNumbers.length; i++ ) {
362                XMLTools.appendElement( phoneNode, OWSNS, "ows:Facsimile", facsimileNumbers[i] );
363            }
364        }
365    
366        /**
367         * Appends the DOM representation of the <code>Address</code> -section to the passed <code>Element</code>.
368         *
369         * @param root
370         * @param address
371         */
372        protected static void appendAddress( Element root, Address address ) {
373    
374            // 'Address'-element
375            Element addressNode = XMLTools.appendElement( root, OWSNS, "ows:Address" );
376    
377            // 'DeliveryPoint'-elements
378            String[] deliveryPoints = address.getDeliveryPoint();
379            for ( int i = 0; i < deliveryPoints.length; i++ ) {
380                XMLTools.appendElement( addressNode, OWSNS, "ows:DeliveryPoint", deliveryPoints[i] );
381            }
382    
383            // 'City'-element
384            if ( address.getCity() != null ) {
385                XMLTools.appendElement( addressNode, OWSNS, "ows:City", address.getCity() );
386            }
387    
388            // 'AdministrativeArea'-element
389            if ( address.getAdministrativeArea() != null ) {
390                XMLTools.appendElement( addressNode, OWSNS, "ows:AdministrativeArea", address.getAdministrativeArea() );
391            }
392    
393            // 'PostalCode'-element
394            if ( address.getPostalCode() != null ) {
395                XMLTools.appendElement( addressNode, OWSNS, "ows:PostalCode", address.getPostalCode() );
396            }
397    
398            // 'Country'-element
399            if ( address.getCountry() != null ) {
400                XMLTools.appendElement( addressNode, OWSNS, "ows:Country", address.getCountry() );
401            }
402    
403            // 'ElectronicMailAddress'-elements
404            String[] electronicMailAddresses = address.getElectronicMailAddress();
405            if ( address.getElectronicMailAddress() != null ) {
406                for ( int i = 0; i < electronicMailAddresses.length; i++ ) {
407                    XMLTools.appendElement( addressNode, OWSNS, "ows:ElectronicMailAddress", electronicMailAddresses[i] );
408                }
409            }
410        }
411    
412        /**
413         * Appends the DOM representation of the <code>OperationsMetadata</code>- section to the passed <code>Element</code>
414         * .
415         *
416         * @param root
417         */
418        protected static void appendOperationsMetadata( Element root, OperationsMetadata operationsMetadata ) {
419    
420            // 'ows:OperationsMetadata'-element
421            Element operationsMetadataNode = XMLTools.appendElement( root, OWSNS, "ows:OperationsMetadata" );
422    
423            // append all Operations
424            Operation[] operations = operationsMetadata.getOperations();
425            for ( int i = 0; i < operations.length; i++ ) {
426                Operation operation = operations[i];
427    
428                // 'ows:Operation'-element
429                Element operationElement = XMLTools.appendElement( operationsMetadataNode, OWSNS, "ows:Operation" );
430                operationElement.setAttribute( "name", operation.getName() );
431    
432                // 'ows:DCP'-elements
433                DCPType[] dcps = operation.getDCPs();
434                for ( int j = 0; j < dcps.length; j++ ) {
435                    appendDCP( operationElement, dcps[j] );
436                }
437    
438                // 'ows:Parameter'-elements
439                OWSDomainType[] parameters = operation.getParameters();
440                for ( int j = 0; j < parameters.length; j++ ) {
441                    appendParameter( operationElement, parameters[j], "ows:Parameter" );
442                }
443    
444                // 'ows:Metadata'-elements
445                Object[] metadata = operation.getMetadata();
446                if ( metadata != null ) {
447                    for ( int j = 0; j < metadata.length; j++ ) {
448                        appendMetadata( operationElement, metadata[j] );
449                    }
450                }
451            }
452    
453            // append general parameters
454            OWSDomainType[] parameters = operationsMetadata.getParameter();
455            for ( int i = 0; i < parameters.length; i++ ) {
456                appendParameter( operationsMetadataNode, parameters[i], "ows:Parameter" );
457            }
458    
459            // append constraints
460            OWSDomainType[] constraints = operationsMetadata.getConstraints();
461            for ( int i = 0; i < constraints.length; i++ ) {
462                appendParameter( operationsMetadataNode, constraints[i], "ows:Constraint" );
463            }
464        }
465    
466        /**
467         * Appends the DOM representation of a <code>DCPType</code> instance to the passed <code>Element</code>.
468         *
469         * @param root
470         * @param dcp
471         */
472        protected static void appendDCP( Element root, DCPType dcp ) {
473    
474            // 'ows:DCP'-element
475            Element dcpNode = XMLTools.appendElement( root, OWSNS, "ows:DCP" );
476    
477            // currently, the only supported DCP is HTTP!
478            if ( dcp.getProtocol() instanceof HTTP ) {
479                HTTP http = (HTTP) dcp.getProtocol();
480    
481                // 'ows:HTTP'-element
482                Element httpNode = XMLTools.appendElement( dcpNode, OWSNS, "ows:HTTP" );
483    
484                // 'ows:Get'-elements
485                URL[] getURLs = http.getGetOnlineResources();
486                for ( int i = 0; i < getURLs.length; i++ ) {
487                    appendOnlineResource( httpNode, "ows:Get", new OnlineResource( new Linkage( getURLs[i] ) ), OWSNS );
488                }
489    
490                // 'ows:Post'-elements
491                URL[] postURLs = http.getPostOnlineResources();
492                for ( int i = 0; i < postURLs.length; i++ ) {
493                    appendOnlineResource( httpNode, "ows:Post", new OnlineResource( new Linkage( postURLs[i] ) ), OWSNS );
494                }
495            }
496        }
497    
498        /**
499         * Appends the DOM representation of a <code>OWSDomainType</code> instance to the passed <code>Element</code>.
500         *
501         * @param root
502         * @param parameter
503         */
504        protected static void appendParameter( Element root, OWSDomainType parameter, String elementName ) {
505    
506            // 'ows:Parameter'-element
507            Element parameterNode = XMLTools.appendElement( root, OWSNS, elementName );
508            parameterNode.setAttribute( "name", parameter.getName() );
509    
510            // 'ows:Value'-elements
511            String[] values = parameter.getValues();
512            for ( int i = 0; i < values.length; i++ ) {
513                XMLTools.appendElement( parameterNode, OWSNS, "ows:Value", values[i] );
514            }
515        }
516    
517        /**
518         * Appends the DOM representation of a <code>Metadata</code> instance to the passed <code>Element</code>.
519         *
520         * @param root
521         * @param metadata
522         */
523        protected static void appendMetadata( Element root, Object metadata ) {
524    
525            // TODO
526    
527        }
528    
529        /**
530         * @param exc
531         * @return the exported new document
532         */
533        public static XMLFragment exportExceptionReportWFS( OGCWebServiceException exc ) {
534            XMLFragment doc = new XMLFragment( new QualifiedName( "ows", "ExceptionReport", OWSNS ) );
535            Element root = doc.getRootElement();
536            root.setAttribute( "version", "1.1.0" );
537    
538            Element e = appendElement( root, OWSNS, "ows:Exception" );
539            if ( exc.getCode() != null ) {
540                e.setAttribute( "exceptionCode", exc.getCode().value );
541            } else {
542                e.setAttribute( "exceptionCode", NOAPPLICABLECODE.value );
543            }
544    
545            String locator = exc.getLocator();
546            try {
547                if ( locator != null ) {
548                    locator = encode( locator, getSystemCharset() );
549                } else {
550                    locator = "unknown";
551                }
552            } catch ( UnsupportedEncodingException _ ) {
553                // if caught why not do something -> setting locator to "unknown"
554                locator = "unknown";
555            }
556            e.setAttribute( "locator", locator );
557    
558            appendElement( e, OWSNS, "ows:ExceptionText", exc.getMessage() );
559    
560            return doc;
561        }
562    
563        /**
564         * @param exc
565         * @return the exported exception
566         */
567        public static XMLFragment exportExceptionReportWFS100( OGCWebServiceException exc ) {
568            XMLFragment doc = new XMLFragment( new QualifiedName( "ogc", "ServiceExceptionReport", OGCNS ) );
569            Element root = doc.getRootElement();
570            root.setAttribute( "version", "1.2.0" );
571    
572            Element e = appendElement( root, OGCNS, "ogc:ServiceException", exc.getMessage() );
573            e.setAttribute( "code", exc.getCode() == null ? NOAPPLICABLECODE.value : exc.getCode().value );
574    
575            String locator = exc.getLocator();
576            try {
577                if ( locator != null ) {
578                    locator = encode( locator, getSystemCharset() );
579                } else {
580                    locator = "unknown";
581                }
582            } catch ( UnsupportedEncodingException _ ) {
583                // if caught why not do something -> setting locator to "unknown"
584                locator = "unknown";
585            }
586            e.setAttribute( "locator", locator );
587    
588            return doc;
589        }
590    
591        /**
592         * @param elem
593         * @param name
594         * @param value
595         */
596        public static void maybeSetAttribute( Element elem, String name, String value ) {
597            if ( value != null ) {
598                elem.setAttribute( name, value );
599            }
600        }
601    
602    }