001    // $HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcbase/XMLFactory.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     ---------------------------------------------------------------------------*/
044    package org.deegree.ogcbase;
045    
046    import java.io.ByteArrayInputStream;
047    import java.net.URI;
048    
049    import org.deegree.datatypes.CodeList;
050    import org.deegree.datatypes.time.TimeDuration;
051    import org.deegree.datatypes.time.TimePeriod;
052    import org.deegree.datatypes.time.TimePosition;
053    import org.deegree.datatypes.time.TimeSequence;
054    import org.deegree.datatypes.values.Interval;
055    import org.deegree.datatypes.values.TypedLiteral;
056    import org.deegree.datatypes.values.Values;
057    import org.deegree.datatypes.xlink.SimpleLink;
058    import org.deegree.framework.log.ILogger;
059    import org.deegree.framework.log.LoggerFactory;
060    import org.deegree.framework.util.StringTools;
061    import org.deegree.framework.util.TimeTools;
062    import org.deegree.framework.xml.XMLFragment;
063    import org.deegree.framework.xml.XMLTools;
064    import org.deegree.model.crs.CoordinateSystem;
065    import org.deegree.model.metadata.iso19115.Keywords;
066    import org.deegree.model.metadata.iso19115.OnlineResource;
067    import org.deegree.model.spatialschema.Envelope;
068    import org.deegree.model.spatialschema.GMLGeometryAdapter;
069    import org.deegree.model.spatialschema.Geometry;
070    import org.deegree.model.spatialschema.GeometryException;
071    import org.deegree.ogcwebservices.LonLatEnvelope;
072    import org.w3c.dom.Element;
073    import org.w3c.dom.Node;
074    import org.w3c.dom.Text;
075    
076    /**
077     * Factory for creating <code>DOM</code> representations from java objects used to represent OGC
078     * related schema types.
079     * 
080     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
081     * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
082     * @author last edited by: $Author: apoth $
083     * 
084     * @version $Revision: 9344 $, $Date: 2007-12-27 17:21:56 +0100 (Do, 27 Dez 2007) $
085     */
086    public class XMLFactory {
087    
088        protected static final ILogger LOG = LoggerFactory.getLogger( XMLFactory.class );
089    
090        protected static final URI OGCNS = CommonNamespaces.OGCNS;
091    
092        protected static final URI GMLNS = CommonNamespaces.GMLNS;
093    
094        protected static final URI XLNNS = CommonNamespaces.XLNNS;
095    
096        /**
097         * Appends the <code>DOM</code> representation of a <code>LonLatEnvelope</code> to the
098         * passed <code>Element</code>.
099         * 
100         * @param root
101         * @param lonLatEnvelope
102         * @param namespaceURI
103         */
104        protected static void appendLonLatEnvelope( Element root, LonLatEnvelope lonLatEnvelope,
105                                                    URI namespaceURI ) {
106            Element lonLatEnvelopeElement = XMLTools.appendElement( root, namespaceURI,
107                                                                    "lonLatEnvelope" );
108            lonLatEnvelopeElement.setAttribute( "srsName", "WGS84(DD)" );
109            String min = lonLatEnvelope.getMin().getX() + " " + lonLatEnvelope.getMin().getY();
110            Element elem = XMLTools.appendElement( lonLatEnvelopeElement, GMLNS, "gml:pos", min );
111            elem.setAttribute( "dimension", "2" );
112            String max = lonLatEnvelope.getMax().getX() + " " + lonLatEnvelope.getMax().getY();
113            elem = XMLTools.appendElement( lonLatEnvelopeElement, GMLNS, "gml:pos", max );
114            elem.setAttribute( "dimension", "2" );
115            TimePosition[] tpos = lonLatEnvelope.getTimePositions();
116            if ( tpos != null ) {
117                for ( int i = 0; i < tpos.length; i++ ) {
118                    appendTimePosition( lonLatEnvelopeElement, tpos[i] );
119                }
120            }
121        }
122    
123        /**
124         * Appends an <code>XML/GML Envelope</code> -element to the passed <code>Element</code>.
125         * 
126         * @param xmlNode
127         * @param envelope
128         */
129        protected static void appendEnvelope( Element xmlNode, Envelope envelope ) {
130            Element node = XMLTools.appendElement( xmlNode, GMLNS, "gml:Envelope" );
131            CoordinateSystem crs = envelope.getCoordinateSystem();
132            if ( crs != null ) {
133                try {
134                    node.setAttribute( "srsName", crs.getName() );
135                } catch ( Exception e ) {
136                    e.printStackTrace();
137                }
138            }
139            Element env = node;
140    
141            String min = envelope.getMin().getX() + " " + envelope.getMin().getY();
142            node = XMLTools.appendElement( env, GMLNS, "gml:pos", min );
143            node.setAttribute( "dimension", "2" );
144    
145            String max = envelope.getMax().getX() + " " + envelope.getMax().getY();
146            node = XMLTools.appendElement( env, GMLNS, "gml:pos", max );
147            node.setAttribute( "dimension", "2" );
148        }
149    
150        /**
151         * Appends the <code>XML/GML</code> representation of a <code>TimePosition</code> to the
152         * passed <code>Element</code>.
153         * 
154         * @param xmlNode
155         * @param tpos
156         */
157        protected static void appendTimePosition( Element xmlNode, TimePosition tpos ) {
158            if ( tpos != null ) {
159                String s = TimeTools.getISOFormattedTime( tpos.getTime() );
160                Element element = XMLTools.appendElement( xmlNode, GMLNS, "gml:timePosition", s );
161                element.setAttribute( "calendarEraName", tpos.getCalendarEraName() );
162                element.setAttribute( "frame", tpos.getFrame().toString() );
163                element.setAttribute( "indeterminatePosition", tpos.getIndeterminatePosition().value );
164            }
165        }
166    
167        /**
168         * Appends a <code>keywords</code> -element for each <code>Keywords</code> object of the
169         * passed array to the passed <code>Element</code>.
170         * 
171         * @param xmlNode
172         * @param keywords
173         * @param namespaceURI
174         */
175        protected static void appendKeywords( Element xmlNode, Keywords[] keywords, URI namespaceURI ) {
176            if ( keywords != null ) {
177                for ( int i = 0; i < keywords.length; i++ ) {
178                    Element node = XMLTools.appendElement( xmlNode, namespaceURI, "keywords" );
179                    appendKeywords( node, keywords[i], namespaceURI );
180                }
181            }
182        }
183    
184        /**
185         * Appends a <code>keywords</code> -element to the passed <code>Element</code> and fills it
186         * with the available keywords.
187         * 
188         * @param xmlNode
189         * @param keywords
190         * @param namespaceURI
191         */
192        protected static void appendKeywords( Element xmlNode, Keywords keywords, URI namespaceURI ) {
193            if ( keywords != null ) {
194                String[] kw = keywords.getKeywords();
195                for ( int i = 0; i < kw.length; i++ ) {
196                    XMLTools.appendElement( xmlNode, namespaceURI, "keyword", kw[i] );
197                }
198                if ( keywords.getThesaurusName() != null ) {
199                    XMLTools.appendElement( xmlNode, namespaceURI, "type", keywords.getThesaurusName() );
200                }
201            }
202        }
203    
204        /**
205         * Appends an <code>XML</code> representation of the passed <code>TimeSequence</code> to the
206         * passed <code>Element</code>.
207         * 
208         * @param xmlNode
209         * @param timeSeq
210         * @param namespaceURI
211         */
212        protected static void appendTemporalDomain( Element xmlNode, TimeSequence timeSeq,
213                                                    URI namespaceURI ) {
214            if ( timeSeq != null ) {
215                Element node = XMLTools.appendElement( xmlNode, namespaceURI, "temporalDomain", null );
216                TimePeriod[] tPer = timeSeq.getTimePeriod();
217                if ( tPer != null ) {
218                    for ( int i = 0; i < tPer.length; i++ ) {
219                        appendTimePeriod( node, tPer[i], namespaceURI );
220                    }
221                }
222    
223                TimePosition[] tPos = timeSeq.getTimePosition();
224                if ( tPos != null ) {
225                    for ( int i = 0; i < tPos.length; i++ ) {
226                        appendTimePosition( node, tPos[i] );
227                    }
228                }
229            }
230        }
231    
232        /**
233         * Appends an <code>XML</code> representation of the passed <code>TimePeriod</code> to the
234         * passed <code>Element</code>.
235         * 
236         * @param xmlNode
237         * @param tPeriod
238         * @param namespaceURI
239         */
240        protected static void appendTimePeriod( Element xmlNode, TimePeriod tPeriod, URI namespaceURI ) {
241            Element node = XMLTools.appendElement( xmlNode, namespaceURI, "timePeriod" );
242            appendTimePosition( node, tPeriod.getBeginPosition() );
243            appendTimePosition( node, tPeriod.getEndPosition() );
244            appendTimeResolution( node, tPeriod.getTimeResolution() );
245        }
246    
247        /**
248         * Appends an <code>XML/GML</code> representation of the passed <code>TimeDuration</code> to
249         * the passed <code>Element</code>.
250         * 
251         * @param xmlNode
252         * @param duration
253         */
254        protected static void appendTimeResolution( Element xmlNode, TimeDuration duration ) {
255            XMLTools.appendElement( xmlNode, GMLNS, "gml:timeResolution",
256                                    duration.getAsGMLTimeDuration() );
257        }
258    
259        /**
260         * Appends an <code>XML</code> representation of the passed <code>Values</code> to the
261         * passed <code>Element</code>.
262         * 
263         * @param xmlNode
264         * @param values
265         * @param namespaceURI
266         */
267        protected static void appendValues( Element xmlNode, Values values, URI namespaceURI ) {
268            Element node = XMLTools.appendElement( xmlNode, namespaceURI, "values" );
269            if ( values.getType() != null ) {
270                node.setAttribute( "type", values.getType().toString() );
271            }
272            if ( values.getSemantic() != null ) {
273                node.setAttribute( "xmlns:dgr", namespaceURI.toString() );
274                node.setAttributeNS( namespaceURI.toString(), "dgr:semantic",
275                                     values.getSemantic().toString() );
276            }
277            Interval[] intervals = values.getInterval();
278            if ( intervals != null ) {
279                for ( int i = 0; i < intervals.length; i++ ) {
280                    appendInterval( node, intervals[i], namespaceURI );
281                }
282            }
283            TypedLiteral[] sVal = values.getSingleValue();
284            if ( sVal != null ) {
285                for ( int i = 0; i < sVal.length; i++ ) {
286                    appendTypedLiteral( node, sVal[i], "singleValue", namespaceURI );
287                }
288            }
289        }
290    
291        /**
292         * Appends an <code>XML</code> representation of the passed <code>Interval</code> to the
293         * passed <code>Element</code>.
294         * 
295         * @param xmlNode
296         * @param interval
297         * @param namespaceURI
298         */
299        protected static void appendInterval( Element xmlNode, Interval interval, URI namespaceURI ) {
300            Element node = XMLTools.appendElement( xmlNode, namespaceURI, "interval" );
301            Element inter = node;
302            if ( interval.getType() != null ) {
303                node.setAttribute( "type", interval.getType().toString() );
304            }
305    
306            if ( interval.getSemantic() != null ) {
307                node.setAttribute( "xmlns:dgr", namespaceURI.toString() );
308                node.setAttributeNS( namespaceURI.toString(), "dgr:semantic",
309                                     interval.getSemantic().toString() );
310            }
311            node.setAttribute( "atomic", "" + interval.isAtomic() );
312            if ( interval.getClosure() != null && interval.getClosure().value != ""
313                 && interval.getClosure().value != null ) {
314                node.setAttribute( "xmlns:dgr", namespaceURI.toString() );
315                node.setAttributeNS( namespaceURI.toString(), "dgr:closure",
316                                     interval.getClosure().value );
317            }
318            node = XMLTools.appendElement( inter, namespaceURI, "min", interval.getMin().getValue() );
319            if ( interval.getMin().getType() != null ) {
320                node.setAttribute( "type", interval.getMin().getType().toString() );
321            }
322            node = XMLTools.appendElement( inter, namespaceURI, "max", interval.getMin().getValue() );
323            if ( interval.getMax().getType() != null ) {
324                node.setAttribute( "type", interval.getMax().getType().toString() );
325            }
326            node = XMLTools.appendElement( inter, namespaceURI, "res", interval.getRes().getValue() );
327            if ( interval.getRes().getType() != null ) {
328                node.setAttribute( "type", interval.getRes().getType().toString() );
329            }
330        }
331    
332        /**
333         * Appends an <code>XML</code> representation of the passed <code>TypedLiteral</code> to the
334         * passed <code>Element</code>.
335         * 
336         * @param xmlNode
337         * @param singleValue
338         * @param name
339         * @param namespaceURI
340         */
341        protected static void appendTypedLiteral( Element xmlNode, TypedLiteral singleValue,
342                                                  String name, URI namespaceURI ) {
343            Node node = XMLTools.appendElement( xmlNode, namespaceURI, name, singleValue.getValue() );
344            if ( singleValue.getType() != null ) {
345                ( (Element) node ).setAttribute( "type", singleValue.getType().toString() );
346            }
347        }
348    
349        /**
350         * Appends an <code>XML</code> representation of the passed <code>CodeList</code> to the
351         * passed <code>Element</code>.
352         * 
353         * @param xmlNode
354         * @param codeList
355         * @param namespaceURI
356         */
357        protected static void appendCodeList( Element xmlNode, CodeList codeList, URI namespaceURI ) {
358            String[] codes = codeList.getCodes();
359            String s = StringTools.arrayToString( codes, ' ' );
360            Node node = XMLTools.appendElement( xmlNode, namespaceURI, codeList.getName(), s );
361            if ( codeList.getCodeSpace() != null ) {
362                ( (Element) node ).setAttribute( "codeSpace", codeList.getCodeSpace().toString() );
363            }
364        }
365    
366        /**
367         * Appends the XML attributes of the given <code>SimpleLink</code> to the also passed
368         * <code>Element</code>.
369         * 
370         * @param linkElement
371         * @param simpleLink
372         */
373        protected static void appendSimpleLinkAttributes( Element linkElement, SimpleLink simpleLink ) {
374    
375            linkElement.setAttributeNS( XLNNS.toString(), "xlink:type", "simple" );
376            if ( simpleLink.getHref() != null ) {
377                linkElement.setAttributeNS( XLNNS.toString(), "xlink:href",
378                                            simpleLink.getHref().toString() );
379            }
380            if ( simpleLink.getRole() != null ) {
381                linkElement.setAttributeNS( XLNNS.toString(), "xlink:role",
382                                            simpleLink.getRole().toString() );
383            }
384            if ( simpleLink.getArcrole() != null ) {
385                linkElement.setAttributeNS( XLNNS.toString(), "xlink:arcrole",
386                                            simpleLink.getArcrole().toString() );
387            }
388            if ( simpleLink.getTitle() != null ) {
389                linkElement.setAttributeNS( XLNNS.toString(), "xlink:title", simpleLink.getTitle() );
390            }
391            if ( simpleLink.getShow() != null ) {
392                linkElement.setAttributeNS( XLNNS.toString(), "xlink:show", simpleLink.getShow() );
393            }
394            if ( simpleLink.getActuate() != null ) {
395                linkElement.setAttributeNS( XLNNS.toString(), "xlink:actuate", simpleLink.getActuate() );
396            }
397        }
398    
399        /**
400         * Appends the <code>DOM</code> representation of a simple <code>XLink</code> -element to
401         * the passed <code>Element</code>.
402         * 
403         * @param xmlNode
404         * @param elementName
405         * @param onlineResource
406         * @param namespaceURI
407         */
408        protected static void appendOnlineResource( Element xmlNode, String elementName,
409                                                    OnlineResource onlineResource, URI namespaceURI ) {
410            Element linkElement = XMLTools.appendElement( xmlNode, namespaceURI, elementName );
411            linkElement.setAttributeNS( XLNNS.toString(), "xlink:type", "simple" );
412            linkElement.setAttributeNS( XLNNS.toString(), "xlink:href",
413                                        onlineResource.getLinkage().getHref().toString() );
414        }
415    
416        /**
417         * Appends the <code>DOM</code> representation of the given <code>PropertyPath</code> as a
418         * new text node to the given element (including necessary namespace bindings).
419         * 
420         * @param element
421         *            Element node where the PropertyPath is appended to
422         * @param propertyPath
423         */
424        protected static void appendPropertyPath( Element element, PropertyPath propertyPath ) {
425            StringBuffer sb = new StringBuffer();
426            sb.append( propertyPath );
427    
428            Text textNode = element.getOwnerDocument().createTextNode( sb.toString() );
429            element.appendChild( textNode );
430            XMLTools.appendNSBindings( element, propertyPath.getNamespaceContext() );
431        }
432    
433        /**
434         * Appends the <code>DOM</code> representation of the given feature id to the given element.
435         * 
436         * @param root
437         *            Element node where the "ogc:FeatureId" element is appended to
438         * @param fid
439         *            feature identifier
440         */
441        protected static void appendFeatureId( Element root, String fid ) {
442            Element gmlObjectIdElement = XMLTools.appendElement( root, OGCNS, "ogc:FeatureId" );
443            gmlObjectIdElement.setAttribute( "fid", fid );
444        }
445    
446        /**
447         * Appends the <code>DOM</code> representation of the given {@link Geometry} to the given element.
448         * 
449         * TODO Do this a better way...
450         * 
451         * @param el
452         *            element node where the geometry is appended to
453         * @param geom
454         *            geometry to be appended
455         * @throws GeometryException 
456         */    
457        protected static void appendGeometry (Element el, Geometry geom) throws GeometryException {
458    
459            StringBuffer sb = new StringBuffer ();
460            sb.append ("<dummy xmlns:gml=\"");
461            sb.append (CommonNamespaces.GMLNS.toString());
462            sb.append ("\">");
463            sb.append (GMLGeometryAdapter.export( geom ));
464            sb.append ("</dummy>");
465    
466            ByteArrayInputStream bis = new ByteArrayInputStream( sb.toString().getBytes() );
467            try {
468                GMLDocument doc = new GMLDocument();
469                doc.load( bis, XMLFragment.DEFAULT_URL );
470                XMLTools.insertNodeInto( XMLTools.getFirstChildElement( doc.getRootElement()), el );
471            } catch ( Exception e ) {
472                throw new GeometryException (e.getMessage());
473            }
474        }
475    }