001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/portal/context/WebMapContextFactory.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     53177 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.portal.context;
045    
046    import java.awt.Rectangle;
047    import java.io.IOException;
048    import java.io.InputStreamReader;
049    import java.io.Reader;
050    import java.net.MalformedURLException;
051    import java.net.URL;
052    import java.util.HashMap;
053    import java.util.Map;
054    
055    import org.apache.commons.httpclient.HttpClient;
056    import org.apache.commons.httpclient.methods.GetMethod;
057    import org.deegree.datatypes.QualifiedName;
058    import org.deegree.enterprise.WebUtils;
059    import org.deegree.framework.log.ILogger;
060    import org.deegree.framework.log.LoggerFactory;
061    import org.deegree.framework.util.Parameter;
062    import org.deegree.framework.util.ParameterList;
063    import org.deegree.framework.util.StringTools;
064    import org.deegree.framework.xml.ElementList;
065    import org.deegree.framework.xml.XMLFragment;
066    import org.deegree.framework.xml.XMLParsingException;
067    import org.deegree.framework.xml.XMLTools;
068    import org.deegree.graphics.sld.FeatureTypeStyle;
069    import org.deegree.graphics.sld.SLDFactory;
070    import org.deegree.graphics.sld.StyledLayerDescriptor;
071    import org.deegree.model.crs.CRSFactory;
072    import org.deegree.model.crs.CoordinateSystem;
073    import org.deegree.model.crs.UnknownCRSException;
074    import org.deegree.model.metadata.iso19115.Address;
075    import org.deegree.model.metadata.iso19115.CitedResponsibleParty;
076    import org.deegree.model.metadata.iso19115.ContactInfo;
077    import org.deegree.model.metadata.iso19115.Phone;
078    import org.deegree.model.metadata.iso19115.RoleCode;
079    import org.deegree.model.spatialschema.GeometryFactory;
080    import org.deegree.model.spatialschema.Point;
081    import org.deegree.ogcbase.BaseURL;
082    import org.deegree.ogcbase.CommonNamespaces;
083    import org.deegree.ogcbase.ImageURL;
084    import org.deegree.ogcwebservices.OWSUtils;
085    import org.deegree.ogcwebservices.getcapabilities.OGCCapabilities;
086    import org.deegree.ogcwebservices.getcapabilities.OGCCapabilitiesDocument;
087    import org.deegree.ogcwebservices.wcs.getcapabilities.WCSCapabilities;
088    import org.deegree.ogcwebservices.wcs.getcapabilities.WCSCapabilitiesDocument;
089    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities;
090    import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilitiesDocument;
091    import org.deegree.ogcwebservices.wms.capabilities.LegendURL;
092    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities;
093    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument;
094    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocumentFactory;
095    import org.deegree.ogcwebservices.wms.operation.GetLegendGraphic;
096    import org.deegree.owscommon_new.HTTP;
097    import org.deegree.owscommon_new.Operation;
098    import org.deegree.owscommon_new.OperationsMetadata;
099    import org.deegree.security.drm.model.User;
100    import org.w3c.dom.Element;
101    import org.w3c.dom.Text;
102    import org.xml.sax.SAXException;
103    
104    /**
105     * Factory class for creating an instance of a web map Context (<tt>ViewContext</tt>). The
106     * factory is able to parse deegree specific extensions (General and Layer) as well as standard web
107     * map context documents.
108     * 
109     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
110     * @author last edited by: $Author: apoth $
111     * 
112     * @version $Revision: 9346 $, $Date: 2007-12-27 17:39:07 +0100 (Do, 27 Dez 2007) $
113     */
114    public class WebMapContextFactory {
115    
116        private static final ILogger LOG = LoggerFactory.getLogger( WebMapContextFactory.class );
117    
118        private static Map<URL, WMSCapabilities> wmsCache = new HashMap<URL, WMSCapabilities>();
119    
120        private static Map<URL, WFSCapabilities> wfsCache = new HashMap<URL, WFSCapabilities>();
121    
122        private static Map<URL, WCSCapabilities> wcsCache = new HashMap<URL, WCSCapabilities>();
123    
124        /**
125         * creates an instance of a ViewContext from the web map context document read from the passed
126         * URL
127         * 
128         * @param url
129         * @param user
130         * @param sessionID
131         * @return
132         * @throws IOException
133         * @throws XMLParsingException
134         * @throws ContextException
135         * @throws SAXException
136         * @throws UnknownCRSException
137         */
138        public synchronized static ViewContext createViewContext( URL url, User user, String sessionID )
139                                throws IOException, XMLParsingException, ContextException, SAXException,
140                                UnknownCRSException {
141            // cache have to be cleared because contained capabilities may has been
142            // requested with other user identification
143            wmsCache.clear();
144    
145            XMLFragment xml = new XMLFragment( url );
146    
147            return createViewContext( xml, user, sessionID );
148        }
149    
150        /**
151         * @param xml
152         * @param user
153         * @param sessionID
154         * @return
155         * @throws IOException
156         * @throws XMLParsingException
157         * @throws ContextException
158         * @throws SAXException
159         * @throws UnknownCRSException
160         */
161        public synchronized static ViewContext createViewContext( XMLFragment xml, User user, String sessionID )
162                                throws IOException, XMLParsingException, ContextException, UnknownCRSException {
163            // general section
164            Element element = XMLTools.getRequiredChildElement( "General", CommonNamespaces.CNTXTNS, xml.getRootElement() );
165            General general = createGeneral( element, xml );
166    
167            // Layer (List) section
168            element = XMLTools.getRequiredChildElement( "LayerList", CommonNamespaces.CNTXTNS, xml.getRootElement() );
169    
170            LayerList layerList = createLayerList( element, user, sessionID );
171    
172            ViewContext vc = new ViewContext( general, layerList );
173    
174            return vc;
175        }
176    
177        /**
178         * creates an instance of a class encapsulating the general context informations
179         * 
180         * @param element
181         *            <General>
182         * @param xml
183         * 
184         * @return instance of <tt>General</tt>
185         * 
186         * @throws XMLParsingException
187         * @throws UnknownCRSException
188         */
189        private static General createGeneral( Element element, XMLFragment xml )
190                                throws XMLParsingException, MalformedURLException, UnknownCRSException {
191    
192            // <Window>
193            Element elem = XMLTools.getChildElement( "Window", CommonNamespaces.CNTXTNS, element );
194            Rectangle rect = createWindow( elem );
195    
196            // <BoundingBox>
197            elem = XMLTools.getRequiredChildElement( "BoundingBox", CommonNamespaces.CNTXTNS, element );
198            Point[] bbox = createBoundingBox( elem );
199    
200            // <Title>
201            String title = XMLTools.getRequiredStringValue( "Title", CommonNamespaces.CNTXTNS, element );
202    
203            // <KeywordList>
204            elem = XMLTools.getChildElement( "KeywordList", CommonNamespaces.CNTXTNS, element );
205            String[] keywords = createKeywords( elem );
206    
207            // <Abstract>
208            String abstract_ = XMLTools.getStringValue( "Abstract", CommonNamespaces.CNTXTNS, element, null );
209    
210            // <LogoURL>
211            elem = XMLTools.getChildElement( "LogoURL", CommonNamespaces.CNTXTNS, element );
212            ImageURL logoURL = createImageURL( elem );
213    
214            // <DescriptionURL>
215    
216            // elem = XMLTools.getChildElement( "DescriptionURL", CommonNamespaces.CNTXTNS, element );
217            elem = XMLTools.getRequiredElement( element, CommonNamespaces.CNTXT_PREFIX + ":DescriptionURL",
218                                                CommonNamespaces.getNamespaceContext() );
219    
220            BaseURL descriptionURL = createBaseURL( elem );
221    
222            // <ContactInformation>
223            elem = XMLTools.getChildElement( "ContactInformation", CommonNamespaces.CNTXTNS, element );
224            CitedResponsibleParty contact = createContactInformation( elem );
225    
226            // <Extension>
227            elem = XMLTools.getChildElement( "Extension", CommonNamespaces.CNTXTNS, element );
228            GeneralExtension extension = createGeneralExtension( elem, xml );
229    
230            General general = null;
231            try {
232                general = new General( title, abstract_, rect, contact, bbox, descriptionURL, logoURL, keywords, extension );
233            } catch ( Exception e ) {
234                throw new XMLParsingException( e.getMessage(), e );
235            }
236    
237            return general;
238        }
239    
240        /**
241         * creates a <tt>Rectangle<tt> (Window) instance from the passed Element.
242         *
243         * @param element <Window>
244         *
245         * @return instance of <tt>Rectangle</tt>
246         *
247         * @throws XMLParsingException
248         */
249        private static Rectangle createWindow( Element element )
250                                throws XMLParsingException {
251    
252            Rectangle rect = null;
253    
254            if ( element != null ) {
255                String tmp = XMLTools.getRequiredAttrValue( "width", null, element );
256                int width = Integer.parseInt( tmp );
257                tmp = XMLTools.getRequiredAttrValue( "height", null, element );
258    
259                int height = Integer.parseInt( tmp );
260                rect = new Rectangle( width, height );
261            }
262    
263            return rect;
264        }
265    
266        /**
267         * creates a <tt>Envelope </tt> from the passed Element
268         * 
269         * @param element
270         *            <BoundingBox>
271         * 
272         * @return instance of <tt>Envelope</tt>
273         * 
274         * @throws XMLParsingException
275         * @throws UnknownCRSException
276         */
277        private static Point[] createBoundingBox( Element element )
278                                throws XMLParsingException, UnknownCRSException {
279    
280            String srs = XMLTools.getRequiredAttrValue( "SRS", null, element );
281            CoordinateSystem crs = CRSFactory.create( srs );
282            String tmp = XMLTools.getRequiredAttrValue( "minx", null, element );
283            double minx = Double.parseDouble( tmp );
284            tmp = XMLTools.getRequiredAttrValue( "miny", null, element );
285    
286            double miny = Double.parseDouble( tmp );
287            tmp = XMLTools.getRequiredAttrValue( "maxx", null, element );
288    
289            double maxx = Double.parseDouble( tmp );
290            tmp = XMLTools.getRequiredAttrValue( "maxy", null, element );
291    
292            double maxy = Double.parseDouble( tmp );
293    
294            Point[] points = new Point[2];
295            points[0] = GeometryFactory.createPoint( minx, miny, crs );
296            points[1] = GeometryFactory.createPoint( maxx, maxy, crs );
297    
298            return points;
299        }
300    
301        /**
302         * creates an array of keywords (String) from the passed Keyword list
303         * 
304         * @param element
305         *            <KeywordList>
306         * 
307         * @return array of Strings
308         * 
309         * @throws XMLParsingException
310         */
311        private static String[] createKeywords( Element element ) {
312    
313            ElementList el = XMLTools.getChildElements( "Keyword", CommonNamespaces.CNTXTNS, element );
314            String[] keywords = new String[el.getLength()];
315    
316            for ( int i = 0; i < keywords.length; i++ ) {
317                keywords[i] = XMLTools.getStringValue( el.item( i ) );
318            }
319    
320            return keywords;
321        }
322    
323        /**
324         * creates an instance of an ImageURL that is used for <LogoURL> and LegendURL
325         * 
326         * @param element
327         *            <LogoURL> or <LegendURL>
328         * 
329         * @return instance of <tt>ImageURL</tt>
330         * 
331         * @throws XMLParsingException
332         */
333        private static ImageURL createImageURL( Element element )
334                                throws XMLParsingException {
335    
336            ImageURL imageURL = null;
337    
338            if ( element != null ) {
339                String tmp = XMLTools.getAttrValue( element, null, "width", null );
340                int width = -1;
341                if ( tmp != null ) {
342                    width = Integer.parseInt( tmp );
343                }
344                tmp = XMLTools.getAttrValue( element, null, "height", null );
345                int height = -1;
346                if ( tmp != null ) {
347                    height = Integer.parseInt( tmp );
348                }
349                String format = XMLTools.getAttrValue( element, null, "format", null );
350    
351                Element elem = XMLTools.getRequiredChildElement( "OnlineResource", CommonNamespaces.CNTXTNS, element );
352                URL onlineResource = createOnlineResource( elem );
353    
354                imageURL = new ImageURL( width, height, format, onlineResource );
355            }
356    
357            return imageURL;
358        }
359    
360        /**
361         * creates an instance of an URL described by a <OnlineResource> element
362         * 
363         * @param element
364         *            <OnlineResource>
365         * 
366         * @return instance of <tt>URL</tt>
367         * 
368         * @throws XMLParsingException
369         */
370        private static URL createOnlineResource( Element element )
371                                throws XMLParsingException {
372    
373            URL onlineResource = null;
374    
375            if ( element != null ) {
376                // String type = XMLTools.getAttrValue( element, null, "type", null );
377                String type = element.getAttributeNS( CommonNamespaces.XLNNS.toASCIIString(), "type" );
378    
379                // if ( type == null || "".equals( type.trim() ) ) {
380                // type = XMLTools.getAttrValue( element, CommonNamespaces.XLNNS, "type", null );
381                // }
382                // System.out.println( "document: " + new XMLFragment( element ).getAsPrettyString() );
383                // System.out.println("Type is: " + type);
384                if ( ( type != null ) && !"".equals( type ) && !type.equals( "simple" ) ) {
385                    throw new XMLParsingException( "unknown type of online resource: " + type );
386                }
387    
388                // String tmp = XMLTools.getAttrValue( element, null, "href", null );
389                String tmp = element.getAttributeNS( CommonNamespaces.XLNNS.toASCIIString(), "href" );
390    
391                // if ( tmp == null ) {
392                // tmp = XMLTools.getAttrValue( element, CommonNamespaces.XLNNS, "href", null );
393                // }
394    
395                // System.out.println("href is: " + tmp);
396                try {
397                    onlineResource = new URL( tmp );
398                } catch ( Exception e ) {
399                    throw new XMLParsingException( "couldn't create online resource", e );
400                }
401            }
402    
403            return onlineResource;
404        }
405    
406        /**
407         * creates an instance of BaseURL that is used for <DescriptionURL>
408         * 
409         * @param element
410         *            <DescriptionURL>
411         * 
412         * @return instance of <tt>BaseURL</tt>
413         * 
414         * @throws XMLParsingException
415         */
416        private static BaseURL createBaseURL( Element element )
417                                throws XMLParsingException {
418    
419            BaseURL baseURL = null;
420    
421            if ( element != null ) {
422                String format = XMLTools.getAttrValue( element, null, "format", null );
423    
424                Element elem = XMLTools.getElement( element, CommonNamespaces.CNTXT_PREFIX + ":OnlineResource",
425                                                    CommonNamespaces.getNamespaceContext() );
426                URL onlineResource = createOnlineResource( elem );
427    
428                baseURL = new BaseURL( format, onlineResource );
429            }
430    
431            return baseURL;
432        }
433    
434        /**
435         * Creates a <tt>ContactInformation</tt>-instance according to the contents of the
436         * DOM-subtree starting at the given 'ContactInformation'-<tt>Element</tt>.
437         * <p>
438         * 
439         * @param element
440         *            the 'ContactInformation'-<tt>Element</tt>
441         * @throws XMLParsingException
442         *             if a syntactic or semantic error in the DOM-subtree is encountered
443         * @return the constructed <tt>ContactInformation</tt>-instance
444         */
445        private static CitedResponsibleParty createContactInformation( Element element )
446                                throws XMLParsingException {
447    
448            CitedResponsibleParty contact = null;
449    
450            if ( element != null ) {
451                // optional: <ContactPersonPrimary>
452                Element contactPersonPrimaryElement = XMLTools.getChildElement( "ContactPersonPrimary",
453                                                                                CommonNamespaces.CNTXTNS, element );
454    
455                String contactPerson = null;
456                String contactOrganization = null;
457                if ( contactPersonPrimaryElement != null ) {
458                    // required: <ContactPerson>
459                    contactPerson = XMLTools.getRequiredStringValue( "ContactPerson", CommonNamespaces.CNTXTNS,
460                                                                     contactPersonPrimaryElement );
461    
462                    // required: <ContactOrganization>
463                    contactOrganization = XMLTools.getRequiredStringValue( "ContactOrganization", CommonNamespaces.CNTXTNS,
464                                                                           contactPersonPrimaryElement );
465                }
466    
467                // optional: <ContactPosition>
468                String contactPosition = XMLTools.getStringValue( "ContactPosition", CommonNamespaces.CNTXTNS, element,
469                                                                  null );
470    
471                // optional: <ContactAddress>
472                Address contactAddress = null;
473                Element contactAddressElement = XMLTools.getChildElement( "ContactAddress", CommonNamespaces.CNTXTNS,
474                                                                          element );
475    
476                if ( contactAddressElement != null ) {
477                    // optional: <ContactElectronicMailAddress>
478                    String eMailAddress = XMLTools.getStringValue( "ContactElectronicMailAddress",
479                                                                   CommonNamespaces.CNTXTNS, element, null );
480                    contactAddress = createContactAddress( eMailAddress, contactAddressElement );
481                }
482    
483                // optional: <ContactVoiceTelephone>
484                String voice = XMLTools.getStringValue( "ContactVoiceTelephone", CommonNamespaces.CNTXTNS, element, null );
485    
486                // optional: <ContactFacsimileTelephone>
487                String fax = XMLTools.getStringValue( "ContactFacsimileTelephone", CommonNamespaces.CNTXTNS, element, null );
488    
489                Phone phone = new Phone( new String[] { fax }, new String[] { voice } );
490                ContactInfo ci = new ContactInfo( contactAddress, null, null, null, phone );
491                contact = new CitedResponsibleParty( new ContactInfo[] { ci }, new String[] { contactPerson },
492                                                     new String[] { contactOrganization },
493                                                     new String[] { contactPosition }, new RoleCode[0] );
494            }
495    
496            return contact;
497        }
498    
499        /**
500         * Creates a <tt>ContactAddress</tt>-instance according to the contents of the DOM-subtree
501         * starting at the given 'ContactAddress'-<tt>Element</tt>.
502         * <p>
503         * 
504         * @param element
505         *            the 'ContactAddress'-<tt>Element</tt>
506         * @throws XMLParsingException
507         *             if a syntactic or semantic error in the DOM-subtree is encountered
508         * @return the constructed <tt>ContactAddress</tt>-instance
509         */
510        private static Address createContactAddress( String eMail, Element element )
511                                throws XMLParsingException {
512    
513            // required: <AddressType>
514            /*
515             * String addressType = XMLTools.getRequiredStringValue( "AddressType",
516             * CommonNamespaces.CNTXTNS, element );
517             */
518            // required: <Address>
519            String address = XMLTools.getRequiredStringValue( "Address", CommonNamespaces.CNTXTNS, element );
520    
521            // required: <City>
522            String city = XMLTools.getRequiredStringValue( "City", CommonNamespaces.CNTXTNS, element );
523    
524            // required: <StateOrProvince>
525            String stateOrProvince = XMLTools.getRequiredStringValue( "StateOrProvince", CommonNamespaces.CNTXTNS, element );
526    
527            // required: <PostCode>
528            String postCode = XMLTools.getRequiredStringValue( "PostCode", CommonNamespaces.CNTXTNS, element );
529    
530            // required: <Country>
531            String country = XMLTools.getRequiredStringValue( "Country", CommonNamespaces.CNTXTNS, element );
532    
533            return new Address( stateOrProvince, city, country, new String[] { address }, new String[] { eMail }, postCode );
534        }
535    
536        /**
537         * creates an instance of a class encapsulating the deegree specific extensions of the general
538         * section of a web map context document
539         * 
540         * @param element
541         *            <Extension>
542         * @param xml
543         * 
544         * @return instance of <tt>GeneralExtension</tt>
545         * 
546         * @throws XMLParsingException
547         */
548        private static GeneralExtension createGeneralExtension( Element element, XMLFragment xml )
549                                throws XMLParsingException, MalformedURLException {
550    
551            GeneralExtension ge = null;
552    
553            if ( element != null ) {
554    
555                // retunrs the current mode of a client using a WMC
556                String mode = XMLTools.getStringValue( "Mode", CommonNamespaces.DGCNTXTNS, element, "ZOOMIN" );
557    
558                // <AuthentificationSettings>
559                Element elem = XMLTools.getChildElement( "AuthentificationSettings", CommonNamespaces.DGCNTXTNS, element );
560                AuthentificationSettings authSettings = null;
561                if ( elem != null ) {
562                    authSettings = createAuthentificationSettings( elem );
563                }
564                // <IOSetiings>
565                elem = XMLTools.getChildElement( "IOSettings", CommonNamespaces.DGCNTXTNS, element );
566                IOSettings ioSettings = null;
567                if ( elem != null ) {
568                    ioSettings = createIOSettings( elem, xml );
569                }
570                // <Frontend>
571                elem = XMLTools.getChildElement( "Frontend", CommonNamespaces.DGCNTXTNS, element );
572                Frontend frontend = null;
573                if ( elem != null ) {
574                    frontend = createFrontend( elem );
575                }
576                // <MapParameter>
577                elem = XMLTools.getRequiredChildElement( "MapParameter", CommonNamespaces.DGCNTXTNS, element );
578                MapParameter mapParameter = createMapParameter( elem );
579    
580                // <LayerTree>
581                elem = XMLTools.getChildElement( "LayerTree", CommonNamespaces.DGCNTXTNS, element );
582    
583                Node layerTreeRoot = null;
584                if ( elem != null ) {
585                    Element nodeElem = XMLTools.getRequiredChildElement( "Node", CommonNamespaces.DGCNTXTNS, elem );
586                    layerTreeRoot = createNode( nodeElem, null );
587                } else {
588                    try {
589                        layerTreeRoot = new Node( 0, null, "root", false, false );
590                        Node[] nodes = new Node[] { new Node( 1, layerTreeRoot, "subroot", false, false ) };
591                        layerTreeRoot.setNodes( nodes );
592                    } catch ( ContextException e ) {
593                        throw new XMLParsingException( "couldn't create layertree node", e );
594                    }
595                }
596                ge = new GeneralExtension( ioSettings, frontend, mapParameter, authSettings, mode, layerTreeRoot );
597            }
598    
599            return ge;
600        }
601    
602        /**
603         * creates a node in the layerTree
604         */
605        private static Node createNode( Element nodeElem, Node parent )
606                                throws XMLParsingException {
607    
608            int id = Integer.parseInt( XMLTools.getRequiredAttrValue( "id", null, nodeElem ) );
609            String title = XMLTools.getRequiredAttrValue( "title", null, nodeElem );
610            String s = XMLTools.getAttrValue( nodeElem, null, "selectable", null );
611            boolean selectable = "true".equals( s ) || "1".equals( s );
612            s = XMLTools.getAttrValue( nodeElem, null, "collapsed", null );
613            boolean collapsed = "true".equals( s ) || "1".equals( s );
614            Node node = null;
615            try {
616                node = new Node( id, parent, title, selectable, collapsed );
617            } catch ( Exception e ) {
618                throw new XMLParsingException( "couldn't create layertree node", e );
619            }
620    
621            // get Child nodes
622            ElementList nl = XMLTools.getChildElements( "Node", CommonNamespaces.DGCNTXTNS, nodeElem );
623            Node[] nodes = new Node[nl.getLength()];
624            for ( int i = 0; i < nodes.length; i++ ) {
625                nodes[i] = createNode( nl.item( i ), node );
626            }
627            // set child nodes
628            node.setNodes( nodes );
629    
630            return node;
631        }
632    
633        /**
634         * creates an instance of a class encapsulating access descrition to an authentification service
635         * for a deegree map client
636         * 
637         * @param element
638         *            <AuthentificationSettings>
639         * @return instance of <tt>AuthentificationSettings</tt>
640         * @throws XMLParsingException
641         */
642        private static AuthentificationSettings createAuthentificationSettings( Element element )
643                                throws XMLParsingException {
644    
645            Element elem = XMLTools.getRequiredChildElement( "AuthentificationService", CommonNamespaces.DGCNTXTNS, element );
646            elem = XMLTools.getRequiredChildElement( "OnlineResource", CommonNamespaces.CNTXTNS, elem );
647    
648            URL url = createOnlineResource( elem );
649            BaseURL bu = new BaseURL( "text/xml", url );
650    
651            return new AuthentificationSettings( bu );
652        }
653    
654        /**
655         * creates an instance of a class encapsulating the frontend (GUI) description of a deegree map
656         * client
657         * 
658         * @param element
659         *            <Frontend>
660         * 
661         * @return instance of <tt>Frontend</tt>
662         * 
663         * @throws XMLParsingException
664         */
665        private static Frontend createFrontend( Element element )
666                                throws XMLParsingException {
667    
668            // <Controller>
669            String controller = XMLTools.getRequiredStringValue( "Controller", CommonNamespaces.DGCNTXTNS, element );
670            // <Style>
671            String style = XMLTools.getStringValue( "Style", CommonNamespaces.DGCNTXTNS, element, null );
672            // <Buttons>
673            String buttons = XMLTools.getStringValue( "Buttons", CommonNamespaces.DGCNTXTNS, element, null );
674            // <CommonJS>
675            Element elem = XMLTools.getChildElement( "CommonJS", CommonNamespaces.DGCNTXTNS, element );
676            String[] commonJS = createCommonJS( elem );
677            // <West>
678            elem = XMLTools.getChildElement( "West", CommonNamespaces.DGCNTXTNS, element );
679            GUIArea west = createGUIArea( elem );
680            // <East>
681            elem = XMLTools.getChildElement( "East", CommonNamespaces.DGCNTXTNS, element );
682            GUIArea east = createGUIArea( elem );
683            // <North>
684            elem = XMLTools.getChildElement( "North", CommonNamespaces.DGCNTXTNS, element );
685            GUIArea north = createGUIArea( elem );
686            // <South>
687            elem = XMLTools.getChildElement( "South", CommonNamespaces.DGCNTXTNS, element );
688            GUIArea south = createGUIArea( elem );
689            // <Center>
690            elem = XMLTools.getChildElement( "Center", CommonNamespaces.DGCNTXTNS, element );
691            GUIArea center = createGUIArea( elem );
692            // <Header>
693            String header = XMLTools.getStringValue( "Header", CommonNamespaces.DGCNTXTNS, element, null );
694            // <Footer>
695            String footer = XMLTools.getStringValue( "Footer", CommonNamespaces.DGCNTXTNS, element, null );
696    
697            Frontend frontend = new JSPFrontend( controller, west, east, south, north, center, style, buttons, commonJS,
698                                                 header, footer );
699    
700            return frontend;
701        }
702    
703        /**
704         * creates a list of javascript pages (names) that contains javascript objects and methods that
705         * are used by more than one module
706         * 
707         * @param element
708         *            <CommonJS>
709         * 
710         * @return instance of <tt>String[]</tt>
711         * 
712         * @throws XMLParsingException
713         */
714        private static String[] createCommonJS( Element element ) {
715    
716            String[] commonJS = null;
717            if ( element != null ) {
718                ElementList el = XMLTools.getChildElements( "Name", CommonNamespaces.DGCNTXTNS, element );
719                commonJS = new String[el.getLength()];
720                for ( int i = 0; i < commonJS.length; i++ ) {
721                    commonJS[i] = XMLTools.getStringValue( el.item( i ) );
722                }
723            }
724    
725            return commonJS;
726        }
727    
728        /**
729         * creates an instance of a class encapsulating the GUI description of one region of the GUI
730         * 
731         * @param element
732         *            <West>; <East>; <South>; <North> or <Center>
733         * 
734         * @return instance of <tt>GUIArea</tt>
735         * 
736         * @throws XMLParsingException
737         */
738        private static GUIArea createGUIArea( Element element )
739                                throws XMLParsingException {
740    
741            GUIArea gui = null;
742            if ( element != null ) {
743                String tmp = element.getLocalName();
744                int area = 0;
745                if ( tmp.equals( "West" ) ) {
746                    area = GUIArea.WEST;
747                } else if ( tmp.equals( "East" ) ) {
748                    area = GUIArea.EAST;
749                } else if ( tmp.equals( "South" ) ) {
750                    area = GUIArea.SOUTH;
751                } else if ( tmp.equals( "North" ) ) {
752                    area = GUIArea.NORTH;
753                } else if ( tmp.equals( "Center" ) ) {
754                    area = GUIArea.CENTER;
755                }
756    
757                // hidden
758                tmp = XMLTools.getAttrValue( element, null, "hidden", null );
759                boolean hidden = "1".equals( tmp ) || "true".equals( tmp );
760                // <Module>
761                ElementList el = XMLTools.getChildElements( "Module", CommonNamespaces.DGCNTXTNS, element );
762                Module[] modules = new Module[el.getLength()];
763                for ( int i = 0; i < modules.length; i++ ) {
764                    modules[i] = createModule( el.item( i ) );
765                }
766                gui = new GUIArea( area, hidden, modules );
767            }
768    
769            return gui;
770        }
771    
772        /**
773         * creates an instance of a class encapsulating module informations
774         * 
775         * @param element
776         *            <Module>
777         * 
778         * @return instance of <tt>Module</tt>
779         * 
780         * @throws XMLParsingException
781         */
782        private static Module createModule( Element element )
783                                throws XMLParsingException {
784    
785            // hidden
786            String tmp = XMLTools.getAttrValue( element, null, "hidden", null );
787            boolean hidden = tmp.equals( "1" ) || tmp.equals( "true" );
788            // <Name>
789            String name = XMLTools.getRequiredStringValue( "Name", CommonNamespaces.DGCNTXTNS, element );
790            // <Content>
791            String content = XMLTools.getRequiredStringValue( "Content", CommonNamespaces.DGCNTXTNS, element );
792            // <ModuleConfiguration>
793            Element elem = XMLTools.getChildElement( "ModuleConfiguration", CommonNamespaces.DGCNTXTNS, element );
794            ModuleConfiguration mc = createModuleConfiguration( elem );
795            // <ParameterList>
796            elem = XMLTools.getChildElement( "ParameterList", CommonNamespaces.DGCNTXTNS, element );
797            ParameterList paramList = createParameterList( elem );
798    
799            String type = XMLTools.getAttrValue( element, null, "type", null );
800    
801            // width and height of a Module are optional
802            // if not set '0' will be used instead
803            tmp = XMLTools.getAttrValue( element, null, "width", null );
804            int w = 0;
805            try {
806                w = Integer.parseInt( tmp );
807            } catch ( Exception e ) {
808            }
809            tmp = XMLTools.getAttrValue( element, null, "height", null );
810            int h = 0;
811            try {
812                h = Integer.parseInt( tmp );
813            } catch ( Exception e ) {
814            }
815    
816            String scrollable = XMLTools.getAttrValue( element, null, "scrolling", null );
817    
818            String[] moduleJS = createModuleJSList( element );
819            Module module = new Module( name, content, hidden, type, w, h, scrollable, moduleJS, mc, paramList );
820    
821            return module;
822        }
823    
824        /**
825         * creates an instance of a class encapsulating the access the configuration of Module
826         * 
827         * @param element
828         *            <ModuleConfiguration>
829         * 
830         * @return instance of <tt>ModuleConfiguration</tt>
831         * 
832         * @throws XMLParsingException
833         */
834        private static ModuleConfiguration createModuleConfiguration( Element element )
835                                throws XMLParsingException {
836    
837            ModuleConfiguration mc = null;
838            if ( element != null ) {
839                Element elem = XMLTools.getRequiredChildElement( "OnlineResource", CommonNamespaces.DGCNTXTNS, element );
840                URL onlineResource = createOnlineResource( elem );
841                mc = new ModuleConfiguration( onlineResource );
842            }
843    
844            return mc;
845        }
846    
847        /**
848         * creates an instance of a class encapsulating the layer list informations
849         * 
850         * @param element
851         *            <LayerList>
852         * 
853         * @return instance of <tt>LayerList</tt>
854         * 
855         * @throws XMLParsingException
856         */
857        private static ParameterList createParameterList( Element element )
858                                throws XMLParsingException {
859    
860            ParameterList parameterList = new ParameterList();
861            if ( element != null ) {
862                ElementList el = XMLTools.getChildElements( "Parameter", CommonNamespaces.DGCNTXTNS, element );
863                for ( int i = 0; i < el.getLength(); i++ ) {
864                    Parameter parameter = createParameter( el.item( i ) );
865                    parameterList.addParameter( parameter );
866                }
867            }
868    
869            return parameterList;
870        }
871    
872        /**
873         * creates an instance of a class encapsulating a parameter that shall be passed to a module
874         * 
875         * @param element
876         *            <Parameter>
877         * 
878         * @return instance of <tt>Parameter</tt>
879         * 
880         * @throws XMLParsingException
881         */
882        private static Parameter createParameter( Element element )
883                                throws XMLParsingException {
884    
885            String name = XMLTools.getRequiredStringValue( "Name", CommonNamespaces.DGCNTXTNS, element );
886            String value = XMLTools.getRequiredStringValue( "Value", CommonNamespaces.DGCNTXTNS, element );
887            // Parameter param = new Parameter_Impl( name+":"+value, value );
888            Parameter param = new Parameter( name, value );
889    
890            return param;
891        }
892    
893        /**
894         * creates an instance of a class encapsulating informations about controlling options for a map
895         * presented to the user
896         * 
897         * @param element
898         *            <MapParameter>
899         * 
900         * @return instance of <tt>MapParameter</tt>
901         * 
902         * @throws XMLParsingException
903         */
904        private static MapParameter createMapParameter( Element element )
905                                throws XMLParsingException {
906    
907            // <OfferedInfoFormats>
908            Element elem = XMLTools.getChildElement( "OfferedInfoFormats", CommonNamespaces.DGCNTXTNS, element );
909            Format[] infoFormats = null;
910            if ( elem != null ) {
911                infoFormats = createOfferedInfoFormats( elem );
912            }
913            // <OfferedZoomFactor>
914            elem = XMLTools.getChildElement( "OfferedZoomFactor", CommonNamespaces.DGCNTXTNS, element );
915            MapOperationFactor[] zoomFactors = null;
916            if ( elem != null ) {
917                zoomFactors = createOfferedMapOperationFactors( elem );
918            }
919            // <OfferedPanFactor>
920            elem = XMLTools.getChildElement( "OfferedPanFactor", CommonNamespaces.DGCNTXTNS, element );
921            MapOperationFactor[] panFactors = null;
922            if ( elem != null ) {
923                panFactors = createOfferedMapOperationFactors( elem );
924            }
925            // <MinScale>
926            String tmp = XMLTools.getStringValue( "MinScale", CommonNamespaces.DGCNTXTNS, element, "0" );
927            double minScale = Double.parseDouble( tmp );
928            // <MaxScale>
929            tmp = XMLTools.getStringValue( "MaxScale", CommonNamespaces.DGCNTXTNS, element, "9999999999" );
930            double maxScale = Double.parseDouble( tmp );
931    
932            MapParameter mp = new MapParameter( infoFormats, panFactors, zoomFactors, minScale, maxScale );
933    
934            return mp;
935        }
936    
937        /**
938         * Creates a list of the feature info formats offered by the client.
939         * 
940         * @param element
941         *            <OfferedInfoFormats> element of the configuration
942         * 
943         * @return list of offered feature info formats
944         * 
945         * @throws XMLParsingException
946         */
947        private static Format[] createOfferedInfoFormats( Element element )
948                                throws XMLParsingException {
949    
950            Format[] format = null;
951    
952            // get list of offered feature info formats
953            ElementList el = XMLTools.getChildElements( "Format", CommonNamespaces.DGCNTXTNS, element );
954    
955            format = new Format[el.getLength()];
956    
957            for ( int i = 0; i < el.getLength(); i++ ) {
958                String name = XMLTools.getStringValue( el.item( i ) );
959                String sel = XMLTools.getAttrValue( el.item( i ), null, "selected", null );
960    
961                boolean selected = "1".equals( sel ) || "true".equals( sel );
962                try {
963                    format[i] = new Format( name, selected );
964                } catch ( ContextException e ) {
965                    throw new XMLParsingException( "", e );
966                }
967            }
968    
969            return format;
970        }
971    
972        /**
973         * returns a list of offered numerical map operation factors that can be used to determine zoom
974         * or pan levels
975         * 
976         * @param element
977         *            a <tt>Element</tt> that contains <Factor> elements as children
978         * 
979         * @return list of <tt>MapOperationFactor</tt>s
980         * 
981         * @throws XMLParsingException
982         */
983        private static MapOperationFactor[] createOfferedMapOperationFactors( Element element ) {
984    
985            // get list of offered factors
986            ElementList el = XMLTools.getChildElements( "Factor", CommonNamespaces.DGCNTXTNS, element );
987    
988            MapOperationFactor[] mof = new MapOperationFactor[el.getLength()];
989    
990            for ( int i = 0; i < el.getLength(); i++ ) {
991                boolean free = true;
992                String tmp = XMLTools.getStringValue( el.item( i ) );
993                double fac = -99;
994    
995                if ( !tmp.equals( "*" ) ) {
996                    free = false;
997                    fac = Double.parseDouble( tmp );
998                }
999    
1000                String sel = XMLTools.getAttrValue( el.item( i ), null, "selected", null );
1001                boolean selected = "1".equals( sel ) || "true".equals( sel );
1002                mof[i] = new MapOperationFactor( fac, selected, free );
1003            }
1004    
1005            return mof;
1006        }
1007    
1008        /**
1009         * creates an instance of a class encapsulating the IO setting informations
1010         * 
1011         * @param element
1012         * @param xml
1013         * @return
1014         * @throws XMLParsingException
1015         */
1016        private static IOSettings createIOSettings( Element element, XMLFragment xml )
1017                                throws XMLParsingException, MalformedURLException {
1018    
1019            // temp directory
1020            Element elem = XMLTools.getChildElement( "TempDirectory", CommonNamespaces.DGCNTXTNS, element );
1021            DirectoryAccess temp = null;
1022            if ( elem != null ) {
1023                temp = createDirectoryAccess( elem, null, xml );
1024            }
1025            // download directory
1026            elem = XMLTools.getChildElement( "DownloadDirectory", CommonNamespaces.DGCNTXTNS, element );
1027            DirectoryAccess download = null;
1028            if ( elem != null ) {
1029                download = createDirectoryAccess( elem, temp, xml );
1030            }
1031            if ( temp == null && elem == null ) {
1032                throw new XMLParsingException( "If <TempDirectory> isn't set, " + "downloaddirectory must be set!" );
1033            }
1034            // SLD directory
1035            elem = XMLTools.getChildElement( "SLDDirectory", CommonNamespaces.DGCNTXTNS, element );
1036            DirectoryAccess sld = null;
1037            if ( elem != null ) {
1038                sld = createDirectoryAccess( elem, temp, xml );
1039            }
1040            if ( temp == null && elem == null ) {
1041                throw new XMLParsingException( "If <TempDirectory> isn't set, " + "slddirectory must be set!" );
1042            }
1043            // Print directory
1044            elem = XMLTools.getChildElement( "PrintDirectory", CommonNamespaces.DGCNTXTNS, element );
1045            DirectoryAccess print = null;
1046            if ( elem != null ) {
1047                print = createDirectoryAccess( elem, temp, xml );
1048            }
1049            if ( temp == null && elem == null ) {
1050                throw new XMLParsingException( "If <TempDirectory> isn't set, " + "printdirectory must be set!" );
1051            }
1052    
1053            IOSettings ioSettings = new IOSettings( download, sld, print, temp );
1054    
1055            return ioSettings;
1056        }
1057    
1058        /**
1059         * @param element
1060         * @param tempDir
1061         * @return
1062         * @throws XMLParsingException
1063         */
1064        private static DirectoryAccess createDirectoryAccess( Element element, DirectoryAccess tempDir, XMLFragment xml )
1065                                throws XMLParsingException, MalformedURLException {
1066    
1067            // directory name
1068            String name = XMLTools.getStringValue( "Name", CommonNamespaces.DGCNTXTNS, element, null );
1069            name = xml.resolve( name ).toExternalForm();
1070    
1071            URL url = null;
1072            Element elem = XMLTools.getChildElement( "Access", CommonNamespaces.DGCNTXTNS, element );
1073            if ( elem != null ) {
1074                elem = XMLTools.getRequiredChildElement( "OnlineResource", CommonNamespaces.CNTXTNS, elem );
1075                url = createOnlineResource( elem );
1076            }
1077    
1078            DirectoryAccess da = null;
1079            if ( name == null || url == null ) {
1080                da = tempDir;
1081            } else {
1082                da = new DirectoryAccess( xml.resolve( name ).toExternalForm(), url );
1083            }
1084    
1085            return da;
1086    
1087        }
1088    
1089        /**
1090         * creates an instance of a class encapsulating the layer list informations
1091         * 
1092         * @param element
1093         *            <LayerList>
1094         * @param user
1095         * @param sessionID
1096         * 
1097         * @return instance of <tt>LayerList</tt>
1098         * 
1099         * @throws XMLParsingException
1100         */
1101        private static LayerList createLayerList( Element element, User user, String sessionID )
1102                                throws XMLParsingException {
1103    
1104            ElementList el = XMLTools.getChildElements( "Layer", CommonNamespaces.CNTXTNS, element );
1105            Layer[] layers = new Layer[el.getLength()];
1106            for ( int i = 0; i < layers.length; i++ ) {
1107                layers[i] = createLayer( el.item( i ), user, sessionID );
1108            }
1109            LayerList list = new LayerList( layers );
1110    
1111            return list;
1112        }
1113    
1114        /**
1115         * creates an instance of a class encapsulating a web map context layer's attributes
1116         * 
1117         * @param element
1118         *            <Layer>
1119         * @param user
1120         * @param sessionID
1121         * 
1122         * @return instance of <tt>Layer</tt>
1123         * 
1124         * @throws XMLParsingException
1125         */
1126        private static Layer createLayer( Element element, User user, String sessionID )
1127                                throws XMLParsingException {
1128    
1129            String tmp = XMLTools.getRequiredAttrValue( "queryable", null, element );
1130            boolean queryable = "1".equals( tmp ) || "true".equals( tmp );
1131            tmp = XMLTools.getRequiredAttrValue( "hidden", null, element );
1132            boolean hidden = "1".equals( tmp ) || "true".equals( tmp );
1133    
1134            // <Name>
1135            String name = XMLTools.getRequiredStringValue( "Name", CommonNamespaces.CNTXTNS, element );
1136            // <Title>
1137            String title = XMLTools.getRequiredStringValue( "Title", CommonNamespaces.CNTXTNS, element );
1138            // <Abstract>
1139            String abstract_ = XMLTools.getStringValue( "Abstract", CommonNamespaces.CNTXTNS, element, null );
1140            // <DataURL>
1141            Element elem = XMLTools.getChildElement( "DataURL", CommonNamespaces.CNTXTNS, element );
1142            BaseURL dataURL = createBaseURL( elem );
1143            // <MetaDataURL>
1144            elem = XMLTools.getChildElement( "MetaDataURL", CommonNamespaces.CNTXTNS, element );
1145            BaseURL metadataURL = createBaseURL( elem );
1146            // <SRS>
1147            tmp = XMLTools.getStringValue( "SRS", CommonNamespaces.CNTXTNS, element, null );
1148            String[] srs = StringTools.toArray( tmp, ",; ", true );
1149            // <FormatList>
1150            elem = XMLTools.getChildElement( "FormatList", CommonNamespaces.CNTXTNS, element );
1151            FormatList formatList = createFormatList( elem );
1152            // <Extension>
1153            elem = XMLTools.getChildElement( "Extension", CommonNamespaces.CNTXTNS, element );
1154            LayerExtension extension = createLayerExtension( elem, user, sessionID );
1155            // <Server>
1156            elem = XMLTools.getRequiredChildElement( "Server", CommonNamespaces.CNTXTNS, element );
1157            Server server = createServer( elem, user, sessionID, extension.getAuthentication() );
1158            // <StyleList>
1159            elem = XMLTools.getChildElement( "StyleList", CommonNamespaces.CNTXTNS, element );
1160            StyleList styleList = createStyleList( elem, name, server );
1161    
1162            Layer layer = null;
1163            try {
1164                layer = new Layer( server, name, title, abstract_, srs, dataURL, metadataURL, formatList, styleList,
1165                                   queryable, hidden, extension );
1166            } catch ( Exception e ) {
1167                throw new XMLParsingException( "couldn't create map context layer", e );
1168            }
1169    
1170            return layer;
1171        }
1172    
1173        /**
1174         * creates an instance of a class encapsulating informations about the server (service) a layer
1175         * based on
1176         * 
1177         * @param element
1178         *            <Server>
1179         * @param user
1180         * @param sessionID
1181         * @param useAuthentication
1182         * 
1183         * @return instance of <tt>Server</tt>
1184         * 
1185         * @throws XMLParsingException
1186         */
1187        private static Server createServer( Element element, User user, String sessionID, int useAuthentication )
1188                                throws XMLParsingException {
1189    
1190            String service = XMLTools.getRequiredAttrValue( "service", null, element );
1191            String version = XMLTools.getRequiredAttrValue( "version", null, element );
1192            String title = XMLTools.getRequiredAttrValue( "title", null, element );
1193            // <OnlineResource>
1194            Element elem = XMLTools.getRequiredChildElement( "OnlineResource", CommonNamespaces.CNTXTNS, element );
1195            URL onlineResource = createOnlineResource( elem );
1196    
1197            OGCCapabilities capabilities = getCapabilities( onlineResource, service, version, user, sessionID,
1198                                                            useAuthentication );
1199    
1200            Server server = null;
1201            try {
1202                server = new Server( title, version, service, onlineResource, capabilities );
1203            } catch ( Exception e ) {
1204                LOG.logError( e.getMessage(), e );
1205                throw new XMLParsingException( "could not create context server", e );
1206            }
1207    
1208            return server;
1209        }
1210    
1211        /**
1212         * creates an instance of a class encapsulating a list of image formats a layer offers
1213         * 
1214         * @param element
1215         *            <FormatList>
1216         * 
1217         * @return instance of <tt>FormatList</tt>
1218         * 
1219         * @throws XMLParsingException
1220         */
1221        private static FormatList createFormatList( Element element )
1222                                throws XMLParsingException {
1223    
1224            ElementList el = XMLTools.getChildElements( "Format", CommonNamespaces.CNTXTNS, element );
1225            Format[] formats = new Format[el.getLength()];
1226            for ( int i = 0; i < formats.length; i++ ) {
1227                String name = XMLTools.getStringValue( el.item( i ) );
1228                String tmp = XMLTools.getAttrValue( el.item( i ), null, "current", null );
1229                boolean current = "1".equals( tmp ) || "true".equals( tmp ) || formats.length == 1;
1230                try {
1231                    formats[i] = new Format( name, current );
1232                } catch ( Exception e ) {
1233                    throw new XMLParsingException( "could not create context format", e );
1234                }
1235            }
1236    
1237            FormatList formatList = null;
1238            try {
1239                formatList = new FormatList( formats );
1240            } catch ( Exception e ) {
1241                LOG.logDebug( e.getMessage(), e );
1242                throw new XMLParsingException( "could not create context formatList", e );
1243            }
1244    
1245            return formatList;
1246        }
1247    
1248        /**
1249         * creates an instance of a class encapsulating a list of styles available for a layer
1250         * 
1251         * @param element
1252         *            <StyleList>
1253         * @param layerName
1254         * @param server
1255         * 
1256         * @return instance of <tt>StyleList</tt>
1257         * 
1258         * @throws XMLParsingException
1259         */
1260        private static StyleList createStyleList( Element element, String layerName, Server server )
1261                                throws XMLParsingException {
1262    
1263            ElementList el = XMLTools.getChildElements( "Style", CommonNamespaces.CNTXTNS, element );
1264            Style[] styles = new Style[el.getLength()];
1265            for ( int i = 0; i < styles.length; i++ ) {
1266                styles[i] = createStyle( el.item( i ), layerName, server );
1267            }
1268            StyleList styleList = null;
1269            try {
1270                styleList = new StyleList( styles );
1271            } catch ( Exception e ) {
1272                LOG.logDebug( e.getMessage(), e );
1273                throw new XMLParsingException( "could not create context stylelist", e );
1274            }
1275    
1276            return styleList;
1277        }
1278    
1279        /**
1280         * creates an instance of a class encapsulating a description of a Style
1281         * 
1282         * @param element
1283         *            <Style>
1284         * 
1285         * @return instance of <tt>Style</tt>
1286         * 
1287         * @throws XMLParsingException
1288         */
1289        private static Style createStyle( Element element, String layerName, Server server )
1290                                throws XMLParsingException {
1291    
1292            Style style = null;
1293    
1294            String tmp = XMLTools.getAttrValue( element, null, "current", null );
1295            boolean current = "1".equals( tmp ) || "true".equals( tmp );
1296    
1297            Element elem = XMLTools.getChildElement( "SLD", CommonNamespaces.CNTXTNS, element );
1298            if ( elem != null ) {
1299                SLD sld = createSLD( elem );
1300                try {
1301                    style = new Style( sld, current );
1302                } catch ( Exception e ) {
1303                    throw new XMLParsingException( "could not create context style", e );
1304                }
1305            } else {
1306                String name = XMLTools.getRequiredStringValue( "Name", CommonNamespaces.CNTXTNS, element );
1307                String title = XMLTools.getRequiredStringValue( "Title", CommonNamespaces.CNTXTNS, element );
1308                String abstract_ = XMLTools.getStringValue( "Abstract", CommonNamespaces.CNTXTNS, element, null );
1309                // <LegendURL>
1310                elem = XMLTools.getChildElement( "LegendURL", CommonNamespaces.CNTXTNS, element );
1311                ImageURL legendURL = null;
1312                if ( elem != null ) {
1313                    legendURL = createImageURL( elem );
1314                } else {
1315                    try {
1316                        legendURL = createLegendURL( name, layerName, server );
1317                    } catch ( Exception e ) {
1318                        throw new XMLParsingException( "could not create context style", e );
1319                    }
1320                }
1321                try {
1322                    style = new Style( name, title, abstract_, legendURL, current );
1323                } catch ( Exception e ) {
1324                    LOG.logDebug( e.getMessage(), e );
1325                    throw new XMLParsingException( "could not create context style", e );
1326                }
1327            }
1328    
1329            return style;
1330        }
1331    
1332        /**
1333         * creates a legendURL for a style/layer by evaluating the servers capabilities the layer is
1334         * servered by.
1335         * 
1336         * @param layer
1337         * @return
1338         * @throws XMLParsingException
1339         */
1340        private static ImageURL createLegendURL( String styleName, String layerName, Server server )
1341                                throws XMLParsingException {
1342    
1343            WMSCapabilities capa = (WMSCapabilities) server.getCapabilities();
1344            ImageURL legendURL = null;
1345            if ( capa != null ) {
1346                org.deegree.ogcwebservices.wms.capabilities.Layer layer = capa.getLayer( layerName );
1347                // FIXME null layer will produce NullPointerException@layer.getStyles()
1348                // is this exception correct ?
1349                if ( layer == null ) {
1350                    throw new XMLParsingException( "LayerName: " + layerName + " does not exist in the WMSCapabilities" );
1351                }
1352    
1353                org.deegree.ogcwebservices.wms.capabilities.Style[] styles = layer.getStyles();
1354                org.deegree.ogcwebservices.wms.capabilities.Style style = null;
1355                for ( int i = 0; i < styles.length; i++ ) {
1356                    // find responsible style definition
1357                    style = styles[i];
1358                    if ( style.getName().equals( styleName ) ) {
1359                        break;
1360                    }
1361                }
1362    
1363                LegendURL[] urls = null;
1364    
1365                if ( style != null ) {
1366                    urls = style.getLegendURL();
1367                }
1368    
1369                if ( urls != null && urls.length > 0 && urls[0] != null ) {
1370                    // if style has defined LegendURL(s) take the first
1371                    legendURL = new ImageURL( urls[0].getWidth(), urls[0].getHeight(), urls[0].getFormat(),
1372                                              urls[0].getOnlineResource() );
1373                } else {
1374                    // create a GetLegendGraphic request as style URL if the server
1375                    // supports GetLegendGraphic operation
1376                    OperationsMetadata om = capa.getOperationMetadata();
1377                    Operation operation = om.getOperation( new QualifiedName( "GetLegendGraphics" ) );
1378                    if ( operation != null ) {
1379                        HTTP http = (HTTP) operation.getDCP().get( 0 );
1380                        URL url = http.getGetOnlineResources().get( 0 );
1381                        StringBuffer sb = new StringBuffer( 500 );
1382                        sb.append( OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() ) );
1383                        GetLegendGraphic glg = GetLegendGraphic.create( "12", capa.getVersion(), layerName, styleName,
1384                                                                        null, null, 1, null, null, "image/jpeg", 20, 20,
1385                                                                        null, null );
1386                        try {
1387                            sb.append( glg.getRequestParameter() );
1388                            url = new URL( sb.toString() );
1389                            legendURL = new ImageURL( 20, 20, "image/jpeg", url );
1390                        } catch ( Exception shouldNeverHappen ) {
1391                            shouldNeverHappen.printStackTrace();
1392                        }
1393                    }
1394                }
1395            }
1396    
1397            return legendURL;
1398        }
1399    
1400        /**
1401         * creates an instance of a class encapsulating a description of a Style based on a SLD
1402         * 
1403         * @param element
1404         *            <SLD>
1405         * 
1406         * @return instance of <tt>SLD</tt>
1407         * 
1408         * @throws XMLParsingException
1409         */
1410        private static SLD createSLD( Element element )
1411                                throws XMLParsingException {
1412    
1413            SLD sld = null;
1414    
1415            String name = XMLTools.getRequiredStringValue( "Name", CommonNamespaces.CNTXTNS, element );
1416            String title = XMLTools.getStringValue( "Title", CommonNamespaces.CNTXTNS, element, null );
1417    
1418            Element elem = XMLTools.getChildElement( "OnlineResource", CommonNamespaces.CNTXTNS, element );
1419            try {
1420                if ( elem != null ) {
1421                    URL onlineResource = createOnlineResource( elem );
1422                    sld = new SLD( name, title, onlineResource );
1423                } else {
1424                    elem = XMLTools.getChildElement( "StyledLayerDescriptor", CommonNamespaces.SLDNS, element );
1425                    if ( elem != null ) {
1426                        XMLFragment xml = new XMLFragment();
1427                        xml.setRootElement( elem );
1428                        StyledLayerDescriptor styledLayerDescriptor = SLDFactory.createSLD( xml );
1429                        sld = new SLD( name, title, styledLayerDescriptor );
1430                    } else {
1431                        FeatureTypeStyle fts = SLDFactory.createFeatureTypeStyle( elem );
1432                        sld = new SLD( name, title, fts );
1433                    }
1434                }
1435            } catch ( Exception e ) {
1436                LOG.logDebug( e.getMessage(), e );
1437                throw new XMLParsingException( "couldn't create map context SLD", e );
1438            }
1439    
1440            return sld;
1441        }
1442    
1443        /**
1444         * creates an instance of a class encapsulating the deegree specific extensions of a Layer
1445         * 
1446         * @param element
1447         *            Extension
1448         * @param user
1449         * @param sessionID
1450         * 
1451         * @return instance of <tt>LayerExtension</tt>
1452         * 
1453         * @throws XMLParsingException
1454         */
1455        private static LayerExtension createLayerExtension( Element element, User user, String sessionID )
1456                                throws XMLParsingException {
1457    
1458            LayerExtension le = null;
1459            if ( element != null ) {
1460    
1461                String tmp = XMLTools.getNodeAsString( element, "./dgcntxt:UseAuthentication/text()",
1462                                                       CommonNamespaces.getNamespaceContext(), "NONE" );
1463                int ua = LayerExtension.NONE;
1464                if ( "sessionID".equalsIgnoreCase( tmp ) ) {
1465                    ua = LayerExtension.SESSIONID;
1466                } else if ( "user/password".equalsIgnoreCase( tmp ) ) {
1467                    ua = LayerExtension.USERPASSWORD;
1468                }
1469    
1470                DataService dataService = null;
1471                Element elem = XMLTools.getChildElement( "DataService", CommonNamespaces.DGCNTXTNS, element );
1472                if ( elem != null ) {
1473                    Element el = XMLTools.getRequiredChildElement( "Server", CommonNamespaces.CNTXTNS, elem );
1474                    Server server = createServer( el, user, sessionID, ua );
1475                    String geoType = XMLTools.getStringValue( "GeometryType", CommonNamespaces.DGCNTXTNS, elem, null );
1476                    String featureType = XMLTools.getStringValue( "FeatureType", CommonNamespaces.DGCNTXTNS, elem, null );
1477                    dataService = new DataService( server, featureType, geoType );
1478                }
1479                boolean masterLayer = false;
1480                elem = XMLTools.getChildElement( "MasterLayer", CommonNamespaces.DGCNTXTNS, element );
1481                if ( elem != null ) {
1482                    String s = XMLTools.getStringValue( elem );
1483                    masterLayer = "true".equals( s ) || "1".equals( s );
1484                }
1485                elem = XMLTools.getChildElement( "ScaleHint", CommonNamespaces.DGCNTXTNS, element );
1486                double min = 0;
1487                double max = 9E99;
1488                if ( elem != null ) {
1489                    String s = XMLTools.getRequiredAttrValue( "min", null, elem );
1490                    min = Double.parseDouble( s );
1491                    s = XMLTools.getRequiredAttrValue( "max", null, elem );
1492                    max = Double.parseDouble( s );
1493                } else {
1494                    /*
1495                     * double[] sc = getScaleHintFromCapabilities(mapServer, name); min = sc[0]; max =
1496                     * sc[1];
1497                     */
1498                }
1499                boolean selectedForFI = false;
1500                elem = XMLTools.getChildElement( "SelectedForQuery", CommonNamespaces.DGCNTXTNS, element );
1501                if ( elem != null ) {
1502                    String s = XMLTools.getStringValue( elem );
1503                    selectedForFI = "true".equals( s ) || "1".equals( s );
1504                }
1505    
1506                int parentNodeId = 1;
1507                elem = XMLTools.getChildElement( "parentNodeId", CommonNamespaces.DGCNTXTNS, element );
1508                if ( elem != null ) {
1509                    parentNodeId = Integer.parseInt( XMLTools.getStringValue( elem ) );
1510                }
1511                boolean showLegendGraphic = false;
1512                elem = XMLTools.getChildElement( "showLegendGraphic", CommonNamespaces.DGCNTXTNS, element );
1513                if ( elem != null ) {
1514                    String s = XMLTools.getStringValue( elem );
1515                    showLegendGraphic = "true".equals( s ) || "1".equals( s );
1516                }
1517                le = new LayerExtension( dataService, masterLayer, min, max, selectedForFI, ua, parentNodeId,
1518                                         showLegendGraphic );
1519    
1520            } else {
1521                le = new LayerExtension();
1522            }
1523    
1524            return le;
1525        }
1526    
1527        /**
1528         * returns the capabilities for the passed server. The capabilities are read directly from the
1529         * server or from the loacal cache.
1530         * 
1531         * @param url
1532         * @param service
1533         * @param version
1534         * @param user
1535         * @param sessionID
1536         * @param useAuthentication
1537         * @return he capabilities for the passed server. The capabilities are read directly from the
1538         *         server or from the loacal cache.
1539         */
1540        private static OGCCapabilities getCapabilities( URL url, String service, String version, User user,
1541                                                        String sessionID, int useAuthentication ) {
1542    
1543            OGCCapabilities capa = null;
1544    
1545            String href = OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() );
1546            if ( href.toLowerCase().startsWith( "http://" ) || href.toLowerCase().startsWith( "https://" ) ) {
1547                if ( "OGC:WMS".equals( service ) ) {
1548                    // is a HTTP URL so GetCapabilities request must be constructed
1549                    if ( "1.0.0".equals( version ) ) {
1550                        href = StringTools.concat( 1000, href, "request=capabilities&service=WMS", "&WMTVER=", version );
1551                    } else {
1552                        href = StringTools.concat( 1000, href, "request=GetCapabilities&service=WMS", "&version=", version );
1553                    }
1554    
1555                } else if ( "OGC:WFS".equals( service ) ) {
1556                    // is a HTTP URL so GetCapabilities request must be constructed
1557                    href = StringTools.concat( 1000, href, "request=GetCapabilities&service=WFS", "&version=", version );
1558    
1559                } else if ( "OGC:WCS".equals( service ) ) {
1560                    // is a HTTP URL so GetCapabilities request must be constructed
1561                    href = StringTools.concat( 1000, href, "request=GetCapabilities&service=WCS", "&version=", version );
1562    
1563                }
1564    
1565                if ( useAuthentication == LayerExtension.SESSIONID ) {
1566                    href = StringTools.concat( 1000, href, "&sessionID=", sessionID );
1567                } else if ( useAuthentication == LayerExtension.USERPASSWORD ) {
1568                    href = StringTools.concat( 1000, href, "&user=", user.getName(), "&password=", user.getPassword() );
1569                }
1570            }
1571    
1572            if ( wmsCache.get( url ) == null && "OGC:WMS".equals( service ) ) {
1573                LOG.logDebug( "get " + service + " capabilities from GetCapabilities request" );
1574                capa = parseCapabilities( href, service );
1575                if ( capa != null ) {
1576                    // write capabilities into local cache
1577                    wmsCache.put( url, (WMSCapabilities) capa );
1578                }
1579            } else if ( "OGC:WMS".equals( service ) ) {
1580                LOG.logDebug( "get WMS capabilities from cache" );
1581                capa = wmsCache.get( url );
1582            } else if ( wfsCache.get( url ) == null && "OGC:WFS".equals( service ) ) {
1583                LOG.logDebug( "get " + service + " capabilities from GetCapabilities request" );
1584                capa = parseCapabilities( href, service );
1585                if ( capa != null ) {
1586                    // write capabilities into local cache
1587                    wfsCache.put( url, (WFSCapabilities) capa );
1588                }
1589            } else if ( "OGC:WFS".equals( service ) ) {
1590                LOG.logDebug( "get WFS capabilities from cache" );
1591                capa = wfsCache.get( url );
1592            } else if ( wcsCache.get( url ) == null && "OGC:WCS".equals( service ) ) {
1593                LOG.logDebug( "get " + service + " capabilities from GetCapabilities request" );
1594                capa = parseCapabilities( href, service );
1595                if ( capa != null ) {
1596                    // write capabilities into local cache
1597                    wcsCache.put( url, (WCSCapabilities) capa );
1598                }
1599            } else if ( "OGC:WFS".equals( service ) ) {
1600                LOG.logDebug( "get WCS capabilities from cache" );
1601                capa = wcsCache.get( url );
1602            }
1603    
1604            return capa;
1605        }
1606    
1607        /**
1608         * 
1609         * @param href
1610         * @param service
1611         * @return
1612         */
1613        private static OGCCapabilities parseCapabilities( String href, String service ) {
1614    
1615            OGCCapabilities capa = null;
1616            try {
1617                URL url = null;
1618                Reader reader = null;
1619    
1620                // consider that the reference to the capabilities may has been
1621                // made by a file URL to a local copy
1622                if ( href.toLowerCase().startsWith( "http://" ) || href.toLowerCase().startsWith( "https://" ) ) {
1623                    HttpClient httpclient = new HttpClient();
1624                    httpclient = WebUtils.enableProxyUsage( httpclient, new URL( href ) );
1625                    int timeout = Integer.parseInt( Messages.getString( "WebMapContextFactory.timeout" ) );
1626                    httpclient.getHttpConnectionManager().getParams().setSoTimeout( timeout );
1627    
1628                    GetMethod httpget = new GetMethod( href );
1629                    LOG.logDebug( "GetCapabilities: ", href );
1630    
1631                    httpclient.executeMethod( httpget );
1632                    reader = new InputStreamReader( httpget.getResponseBodyAsStream() );
1633                } else {
1634                    if ( href.endsWith( "?" ) ) {
1635                        url = new URL( href.substring( 0, href.length() - 1 ) );
1636                    }
1637                    reader = new InputStreamReader( url.openStream() );
1638                }
1639    
1640                OGCCapabilitiesDocument doc = null;
1641                if ( "OGC:WMS".equals( service ) ) {
1642                    doc = new WMSCapabilitiesDocument();
1643                    doc.load( reader, XMLFragment.DEFAULT_URL );
1644                    doc = WMSCapabilitiesDocumentFactory.getWMSCapabilitiesDocument( doc.getRootElement() );
1645                } else if ( "OGC:WFS".equals( service ) ) {
1646                    doc = new WFSCapabilitiesDocument();
1647                    doc.load( reader, XMLFragment.DEFAULT_URL );
1648                } else if ( "OGC:WCS".equals( service ) ) {
1649                    doc = new WCSCapabilitiesDocument();
1650                    doc.load( reader, XMLFragment.DEFAULT_URL );
1651                } else {
1652                    throw new XMLParsingException( "not supported service type: " + service );
1653                }
1654                
1655                capa = doc.parseCapabilities();
1656            } catch ( Exception e ) {
1657                System.out.println( "could not read capabilities: " );
1658                System.out.println( href );
1659                LOG.logError( e.getMessage(), e );
1660                return null;
1661            }
1662            return capa;
1663        }
1664    
1665        /**
1666         * @param mapServer
1667         * @param layer
1668         * @return ScaleHint
1669         */
1670        private static double[] getScaleHintFromCapabilities( Server mapServer, String layer ) {
1671    
1672            double[] sc = new double[] { 0, 9999999 };
1673            WMSCapabilities capa = (WMSCapabilities) mapServer.getCapabilities();
1674            if ( capa != null ) {
1675                org.deegree.ogcwebservices.wms.capabilities.Layer lay = capa.getLayer( layer );
1676                if ( lay != null ) {
1677                    sc[0] = lay.getScaleHint().getMin();
1678                    sc[1] = lay.getScaleHint().getMax();
1679                }
1680            }
1681            return sc;
1682        }
1683    
1684        /**
1685         * creates a list (String[]) containing the name of the JavaScript files used by the moudle
1686         * 
1687         * @param element
1688         *            <Module>
1689         * 
1690         * @return instance of <tt>String[]</tt>
1691         * 
1692         * @throws XMLParsingException
1693         */
1694        private static String[] createModuleJSList( Element element ) {
1695    
1696            String[] moduleJS = null;
1697            if ( element != null ) {
1698                ElementList el = XMLTools.getChildElements( "ModuleJS", CommonNamespaces.DGCNTXTNS, element );
1699                moduleJS = new String[el.getLength()];
1700                for ( int i = 0; i < el.getLength(); i++ ) {
1701                    moduleJS[i] = ( (Text) el.item( i ).getFirstChild() ).getData();
1702                }
1703            }
1704    
1705            return moduleJS;
1706        }
1707    }