001    // $HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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: lbuesching $
077     *
078     * @version $Revision: 27246 $, $Date: 2010-10-18 09:45:30 +0200 (Mo, 18 Okt 2010) $
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" );
137                XMLTools.appendElement( e, OWSNS, "ows:ExceptionText", exc.getMessage() );
138                
139                if ( exc.getCode() != null ) {
140                    e.setAttribute( "exceptionCode", exc.getCode().value );
141                }
142    
143                String locator = exc.getLocator();
144                try {
145                    if ( locator != null ) {
146                        locator = URLEncoder.encode( locator, CharsetUtils.getSystemCharset() );
147                    } else {
148                        locator = "unknown";
149                    }
150                } catch ( UnsupportedEncodingException _ ) {
151                    // if catched why not do something -> setting locator to "unknown"
152                    locator = "unknown";
153                }
154                e.setAttribute( "locator", locator );
155            }
156    
157            return doc;
158    
159        }
160    
161        /**
162         * appends a xml representation of an <tt>OGCWebServiceException</tt> to the passed <tt>Element</tt>
163         *
164         * @param node
165         * @param ex
166         * @param namespace
167         *            if true, the ogc prefix (bound to the ogc namespace) will be appended
168         */
169        protected static void appendException( Element node, OGCWebServiceException ex, boolean namespace ) {
170    
171            if ( namespace ) {
172                node = XMLTools.appendElement( node, OGCNS, POGC + "ServiceException", ex.getMessage() );
173            } else {
174                node = XMLTools.appendElement( node, null, "ServiceException", ex.getMessage() );
175            }
176    
177            if ( ex.getCode() != null ) {
178                node.setAttribute( "code", ex.getCode().value );
179            }
180            String locator = ex.getLocator();
181            try {
182                if ( locator != null ) {
183                    locator = URLEncoder.encode( locator, CharsetUtils.getSystemCharset() );
184                } else {
185                    locator = "unknown";
186                }
187            } catch ( UnsupportedEncodingException e ) {
188                // if catched why not do something -> setting locator to "unknown"
189                locator = "unknown";
190            }
191            node.setAttribute( "locator", locator );
192        }
193    
194        /**
195         * Appends the DOM representation of the <code>ServiceIdentification</code>- section to the passed
196         * <code>Element</code>.
197         *
198         * @param root
199         * @param serviceIdentification
200         */
201        protected static void appendServiceIdentification( Element root, ServiceIdentification serviceIdentification ) {
202    
203            // 'ServiceIdentification'-element
204            Element serviceIdentificationNode = XMLTools.appendElement( root, OWSNS, "ows:ServiceIdentification" );
205    
206            // 'ServiceType'-element
207            XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:ServiceType",
208                                    serviceIdentification.getServiceType().getCode() );
209    
210            // 'ServiceTypeVersion'-elements
211            String[] versions = serviceIdentification.getServiceTypeVersions();
212            for ( int i = 0; i < versions.length; i++ ) {
213                XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:ServiceTypeVersion", versions[i] );
214            }
215    
216            // 'Title'-element
217            XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:Title", serviceIdentification.getTitle() );
218    
219            // 'Abstract'-element
220            if ( serviceIdentification.getAbstract() != null ) {
221                XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:Abstract",
222                                        serviceIdentification.getAbstract() );
223            }
224    
225            // 'Keywords'-element
226            appendOWSKeywords( serviceIdentificationNode, serviceIdentification.getKeywords() );
227    
228            // 'Fees'-element
229            XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:Fees", serviceIdentification.getFees() );
230    
231            // 'AccessConstraints'-element
232            String[] constraints = serviceIdentification.getAccessConstraints();
233            if ( constraints != null ) {
234                for ( int i = 0; i < constraints.length; i++ ) {
235                    XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:AccessConstraints", constraints[i] );
236                }
237            }
238        }
239    
240        /**
241         * Appends a <code>ows:Keywords</code> -element for each <code>Keywords</code> object of the passed array to the
242         * passed <code>Element</code>.
243         *
244         * @param xmlNode
245         * @param keywords
246         */
247        protected static void appendOWSKeywords( Element xmlNode, Keywords[] keywords ) {
248            if ( keywords != null ) {
249                for ( int i = 0; i < keywords.length; i++ ) {
250                    Element node = XMLTools.appendElement( xmlNode, OWSNS, "ows:Keywords" );
251                    appendOWSKeywords( node, keywords[i] );
252                }
253            }
254        }
255    
256        /**
257         * Appends a <code>ows:Keywords</code> -element to the passed <code>Element</code> and fills it with the available
258         * keywords.
259         *
260         * @param xmlNode
261         * @param keywords
262         */
263        protected static void appendOWSKeywords( Element xmlNode, Keywords keywords ) {
264            if ( keywords != null ) {
265                String[] kw = keywords.getKeywords();
266                for ( int i = 0; i < kw.length; i++ ) {
267                    XMLTools.appendElement( xmlNode, OWSNS, "ows:Keyword", kw[i] );
268                }
269                TypeCode typeCode = keywords.getTypeCode();
270                if ( typeCode != null ) {
271                    Element node = XMLTools.appendElement( xmlNode, OWSNS, "ows:Type", typeCode.getCode() );
272                    if ( typeCode.getCodeSpace() != null ) {
273                        node.setAttribute( "codeSpace", typeCode.getCodeSpace().toString() );
274                    }
275                }
276            }
277        }
278    
279        /**
280         * Appends the DOM representation of the <code>ServiceProvider</code>- section to the passed <code>Element</code>.
281         *
282         * @param root
283         * @param serviceProvider
284         */
285        protected static void appendServiceProvider( Element root, ServiceProvider serviceProvider ) {
286    
287            // 'ServiceProvider'-element
288            Element serviceProviderNode = XMLTools.appendElement( root, OWSNS, "ows:ServiceProvider" );
289    
290            // 'ProviderName'-element
291            XMLTools.appendElement( serviceProviderNode, OWSNS, "ows:ProviderName", serviceProvider.getProviderName() );
292    
293            // 'ProviderSite'-element
294            if ( serviceProvider.getProviderSite() != null ) {
295                Element providerSiteNode = XMLTools.appendElement( serviceProviderNode, OWSNS, "ows:ProviderSite" );
296                appendSimpleLinkAttributes( providerSiteNode, serviceProvider.getProviderSite() );
297            }
298    
299            // 'ServiceContact'-element
300            Element serviceContactNode = XMLTools.appendElement( serviceProviderNode, OWSNS, "ows:ServiceContact" );
301    
302            // 'IndividualName'-element
303            XMLTools.appendElement( serviceContactNode, OWSNS, "ows:IndividualName", serviceProvider.getIndividualName() );
304    
305            // 'PositionName'-element
306            if ( serviceProvider.getPositionName() != null ) {
307                XMLTools.appendElement( serviceContactNode, OWSNS, "ows:PositionName", serviceProvider.getPositionName() );
308            }
309    
310            // 'ContactInfo'-element
311            ContactInfo contactInfo = serviceProvider.getContactInfo();
312            if ( contactInfo != null ) {
313                Element contactInfoNode = XMLTools.appendElement( serviceContactNode, OWSNS, "ows:ContactInfo" );
314                Phone phone = contactInfo.getPhone();
315                if ( phone != null ) {
316                    appendPhone( contactInfoNode, phone );
317                }
318                Address address = contactInfo.getAddress();
319                if ( address != null ) {
320                    appendAddress( contactInfoNode, address );
321                }
322                OnlineResource onlineResource = contactInfo.getOnLineResource();
323                if ( onlineResource != null ) {
324                    appendOnlineResource( contactInfoNode, "ows:OnlineResource", onlineResource, OWSNS );
325                }
326                String hoursOfService = contactInfo.getHoursOfService();
327                if ( hoursOfService != null ) {
328                    XMLTools.appendElement( contactInfoNode, OWSNS, "ows:HoursOfService", hoursOfService );
329                }
330                String contactInstructions = contactInfo.getContactInstructions();
331                if ( contactInstructions != null ) {
332                    XMLTools.appendElement( contactInfoNode, OWSNS, "ows:ContactInstructions", contactInstructions );
333                }
334            }
335            TypeCode role = serviceProvider.getRole();
336            if ( role != null ) {
337                Element roleElement = XMLTools.appendElement( serviceContactNode, OWSNS, "ows:Role", role.getCode() );
338                if ( role.getCodeSpace() != null ) {
339                    roleElement.setAttribute( "codeSpace", role.getCodeSpace().toString() );
340                }
341            }
342        }
343    
344        /**
345         * Appends the DOM representation of the <code>Phone</code> -section to the passed <code>Element</code>.
346         *
347         * @param root
348         * @param phone
349         */
350        protected static void appendPhone( Element root, Phone phone ) {
351    
352            // 'Phone'-element
353            Element phoneNode = XMLTools.appendElement( root, OWSNS, "ows:Phone" );
354    
355            // 'Voice'-elements
356            String[] voiceNumbers = phone.getVoice();
357            for ( int i = 0; i < voiceNumbers.length; i++ ) {
358                XMLTools.appendElement( phoneNode, OWSNS, "ows:Voice", voiceNumbers[i] );
359            }
360    
361            // 'Facsimile'-elements
362            String[] facsimileNumbers = phone.getFacsimile();
363            for ( int i = 0; i < facsimileNumbers.length; i++ ) {
364                XMLTools.appendElement( phoneNode, OWSNS, "ows:Facsimile", facsimileNumbers[i] );
365            }
366        }
367    
368        /**
369         * Appends the DOM representation of the <code>Address</code> -section to the passed <code>Element</code>.
370         *
371         * @param root
372         * @param address
373         */
374        protected static void appendAddress( Element root, Address address ) {
375    
376            // 'Address'-element
377            Element addressNode = XMLTools.appendElement( root, OWSNS, "ows:Address" );
378    
379            // 'DeliveryPoint'-elements
380            String[] deliveryPoints = address.getDeliveryPoint();
381            for ( int i = 0; i < deliveryPoints.length; i++ ) {
382                XMLTools.appendElement( addressNode, OWSNS, "ows:DeliveryPoint", deliveryPoints[i] );
383            }
384    
385            // 'City'-element
386            if ( address.getCity() != null ) {
387                XMLTools.appendElement( addressNode, OWSNS, "ows:City", address.getCity() );
388            }
389    
390            // 'AdministrativeArea'-element
391            if ( address.getAdministrativeArea() != null ) {
392                XMLTools.appendElement( addressNode, OWSNS, "ows:AdministrativeArea", address.getAdministrativeArea() );
393            }
394    
395            // 'PostalCode'-element
396            if ( address.getPostalCode() != null ) {
397                XMLTools.appendElement( addressNode, OWSNS, "ows:PostalCode", address.getPostalCode() );
398            }
399    
400            // 'Country'-element
401            if ( address.getCountry() != null ) {
402                XMLTools.appendElement( addressNode, OWSNS, "ows:Country", address.getCountry() );
403            }
404    
405            // 'ElectronicMailAddress'-elements
406            String[] electronicMailAddresses = address.getElectronicMailAddress();
407            if ( address.getElectronicMailAddress() != null ) {
408                for ( int i = 0; i < electronicMailAddresses.length; i++ ) {
409                    XMLTools.appendElement( addressNode, OWSNS, "ows:ElectronicMailAddress", electronicMailAddresses[i] );
410                }
411            }
412        }
413    
414        /**
415         * Appends the DOM representation of the <code>OperationsMetadata</code>- section to the passed <code>Element</code>
416         * .
417         *
418         * @param root
419         */
420        protected static void appendOperationsMetadata( Element root, OperationsMetadata operationsMetadata ) {
421    
422            // 'ows:OperationsMetadata'-element
423            Element operationsMetadataNode = XMLTools.appendElement( root, OWSNS, "ows:OperationsMetadata" );
424    
425            // append all Operations
426            Operation[] operations = operationsMetadata.getOperations();
427            for ( int i = 0; i < operations.length; i++ ) {
428                Operation operation = operations[i];
429    
430                // 'ows:Operation'-element
431                Element operationElement = XMLTools.appendElement( operationsMetadataNode, OWSNS, "ows:Operation" );
432                operationElement.setAttribute( "name", operation.getName() );
433    
434                // 'ows:DCP'-elements
435                DCPType[] dcps = operation.getDCPs();
436                for ( int j = 0; j < dcps.length; j++ ) {
437                    appendDCP( operationElement, dcps[j] );
438                }
439    
440                // 'ows:Parameter'-elements
441                OWSDomainType[] parameters = operation.getParameters();
442                for ( int j = 0; j < parameters.length; j++ ) {
443                    appendParameter( operationElement, parameters[j], "ows:Parameter" );
444                }
445    
446                // 'ows:Metadata'-elements
447                Object[] metadata = operation.getMetadata();
448                if ( metadata != null ) {
449                    for ( int j = 0; j < metadata.length; j++ ) {
450                        appendMetadata( operationElement, metadata[j] );
451                    }
452                }
453            }
454    
455            // append general parameters
456            OWSDomainType[] parameters = operationsMetadata.getParameter();
457            for ( int i = 0; i < parameters.length; i++ ) {
458                appendParameter( operationsMetadataNode, parameters[i], "ows:Parameter" );
459            }
460    
461            // append constraints
462            OWSDomainType[] constraints = operationsMetadata.getConstraints();
463            for ( int i = 0; i < constraints.length; i++ ) {
464                appendParameter( operationsMetadataNode, constraints[i], "ows:Constraint" );
465            }
466        }
467    
468        /**
469         * Appends the DOM representation of a <code>DCPType</code> instance to the passed <code>Element</code>.
470         *
471         * @param root
472         * @param dcp
473         */
474        protected static void appendDCP( Element root, DCPType dcp ) {
475    
476            // 'ows:DCP'-element
477            Element dcpNode = XMLTools.appendElement( root, OWSNS, "ows:DCP" );
478    
479            // currently, the only supported DCP is HTTP!
480            if ( dcp.getProtocol() instanceof HTTP ) {
481                HTTP http = (HTTP) dcp.getProtocol();
482    
483                // 'ows:HTTP'-element
484                Element httpNode = XMLTools.appendElement( dcpNode, OWSNS, "ows:HTTP" );
485    
486                // 'ows:Get'-elements
487                URL[] getURLs = http.getGetOnlineResources();
488                for ( int i = 0; i < getURLs.length; i++ ) {
489                    appendOnlineResource( httpNode, "ows:Get", new OnlineResource( new Linkage( getURLs[i] ) ), OWSNS );
490                }
491    
492                // 'ows:Post'-elements
493                URL[] postURLs = http.getPostOnlineResources();
494                for ( int i = 0; i < postURLs.length; i++ ) {
495                    appendOnlineResource( httpNode, "ows:Post", new OnlineResource( new Linkage( postURLs[i] ) ), OWSNS );
496                }
497            }
498        }
499    
500        /**
501         * Appends the DOM representation of a <code>OWSDomainType</code> instance to the passed <code>Element</code>.
502         *
503         * @param root
504         * @param parameter
505         */
506        protected static void appendParameter( Element root, OWSDomainType parameter, String elementName ) {
507    
508            // 'ows:Parameter'-element
509            Element parameterNode = XMLTools.appendElement( root, OWSNS, elementName );
510            parameterNode.setAttribute( "name", parameter.getName() );
511    
512            // 'ows:Value'-elements
513            String[] values = parameter.getValues();
514            for ( int i = 0; i < values.length; i++ ) {
515                XMLTools.appendElement( parameterNode, OWSNS, "ows:Value", values[i] );
516            }
517        }
518    
519        /**
520         * Appends the DOM representation of a <code>Metadata</code> instance to the passed <code>Element</code>.
521         *
522         * @param root
523         * @param metadata
524         */
525        protected static void appendMetadata( Element root, Object metadata ) {
526    
527            // TODO
528    
529        }
530    
531        /**
532         * @param exc
533         * @return the exported new document
534         */
535        public static XMLFragment exportExceptionReportWFS( OGCWebServiceException exc ) {
536            XMLFragment doc = new XMLFragment( new QualifiedName( "ows", "ExceptionReport", OWSNS ) );
537            Element root = doc.getRootElement();
538            root.setAttribute( "version", "1.1.0" );
539    
540            Element e = appendElement( root, OWSNS, "ows:Exception" );
541            if ( exc.getCode() != null ) {
542                e.setAttribute( "exceptionCode", exc.getCode().value );
543            } else {
544                e.setAttribute( "exceptionCode", NOAPPLICABLECODE.value );
545            }
546    
547            String locator = exc.getLocator();
548            try {
549                if ( locator != null ) {
550                    locator = encode( locator, getSystemCharset() );
551                } else {
552                    locator = "unknown";
553                }
554            } catch ( UnsupportedEncodingException _ ) {
555                // if caught why not do something -> setting locator to "unknown"
556                locator = "unknown";
557            }
558            e.setAttribute( "locator", locator );
559    
560            appendElement( e, OWSNS, "ows:ExceptionText", exc.getMessage() );
561    
562            return doc;
563        }
564    
565        /**
566         * @param exc
567         * @return the exported exception
568         */
569        public static XMLFragment exportExceptionReportWFS100( OGCWebServiceException exc ) {
570            XMLFragment doc = new XMLFragment( new QualifiedName( "ogc", "ServiceExceptionReport", OGCNS ) );
571            Element root = doc.getRootElement();
572            root.setAttribute( "version", "1.2.0" );
573    
574            Element e = appendElement( root, OGCNS, "ogc:ServiceException", exc.getMessage() );
575            e.setAttribute( "code", exc.getCode() == null ? NOAPPLICABLECODE.value : exc.getCode().value );
576    
577            String locator = exc.getLocator();
578            try {
579                if ( locator != null ) {
580                    locator = encode( locator, getSystemCharset() );
581                } else {
582                    locator = "unknown";
583                }
584            } catch ( UnsupportedEncodingException _ ) {
585                // if caught why not do something -> setting locator to "unknown"
586                locator = "unknown";
587            }
588            e.setAttribute( "locator", locator );
589    
590            return doc;
591        }
592    
593        /**
594         * @param elem
595         * @param name
596         * @param value
597         */
598        public static void maybeSetAttribute( Element elem, String name, String value ) {
599            if ( value != null ) {
600                elem.setAttribute( name, value );
601            }
602        }
603    
604    }