001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/portal/standard/csw/control/DisplayMapListener.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    
037    package org.deegree.portal.standard.csw.control;
038    
039    import java.io.File;
040    import java.io.FileOutputStream;
041    import java.io.IOException;
042    import java.io.InputStreamReader;
043    import java.io.Reader;
044    import java.net.MalformedURLException;
045    import java.net.URL;
046    import java.util.ArrayList;
047    import java.util.HashMap;
048    import java.util.Iterator;
049    import java.util.List;
050    
051    import javax.servlet.http.HttpServletRequest;
052    import javax.servlet.http.HttpSession;
053    import javax.xml.transform.TransformerFactoryConfigurationError;
054    
055    import org.deegree.enterprise.control.FormEvent;
056    import org.deegree.enterprise.control.RPCParameter;
057    import org.deegree.enterprise.control.RPCStruct;
058    import org.deegree.enterprise.control.RPCWebEvent;
059    import org.deegree.framework.log.ILogger;
060    import org.deegree.framework.log.LoggerFactory;
061    import org.deegree.framework.util.CharsetUtils;
062    import org.deegree.framework.util.NetWorker;
063    import org.deegree.framework.xml.XMLFragment;
064    import org.deegree.framework.xml.XMLParsingException;
065    import org.deegree.framework.xml.XMLTools;
066    import org.deegree.i18n.Messages;
067    import org.deegree.model.crs.CRSFactory;
068    import org.deegree.model.crs.CoordinateSystem;
069    import org.deegree.model.crs.UnknownCRSException;
070    import org.deegree.model.spatialschema.Envelope;
071    import org.deegree.model.spatialschema.GeometryFactory;
072    import org.deegree.model.spatialschema.Point;
073    import org.deegree.ogcbase.BaseURL;
074    import org.deegree.ogcbase.ImageURL;
075    import org.deegree.ogcwebservices.getcapabilities.InvalidCapabilitiesException;
076    import org.deegree.ogcwebservices.wms.capabilities.Layer;
077    import org.deegree.ogcwebservices.wms.capabilities.LegendURL;
078    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities;
079    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument;
080    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocumentFactory;
081    import org.deegree.portal.PortalException;
082    import org.deegree.portal.context.ContextException;
083    import org.deegree.portal.context.Format;
084    import org.deegree.portal.context.FormatList;
085    import org.deegree.portal.context.General;
086    import org.deegree.portal.context.GeneralExtension;
087    import org.deegree.portal.context.LayerList;
088    import org.deegree.portal.context.Server;
089    import org.deegree.portal.context.Style;
090    import org.deegree.portal.context.StyleList;
091    import org.deegree.portal.context.ViewContext;
092    import org.deegree.portal.context.WebMapContextFactory;
093    import org.deegree.portal.context.XMLFactory;
094    import org.deegree.portal.standard.csw.CatalogClientException;
095    import org.deegree.portal.standard.csw.configuration.CSWClientConfiguration;
096    import org.deegree.portal.standard.csw.model.DataSessionRecord;
097    import org.deegree.portal.standard.csw.model.ServiceSessionRecord;
098    import org.deegree.portal.standard.csw.model.ShoppingCart;
099    import org.w3c.dom.Document;
100    import org.xml.sax.SAXException;
101    
102    /**
103     * A <code>${type_name}</code> class.<br/>
104     *
105     * This listener is called when one or more items of the shopping cart shall be displayed in a map. For all chosen items
106     * of the cart the wms layers are collected and a new mapcontext containing these layers is created/saved in the users
107     * folder (user must be logged in). Then, the contextname is passed to the follow up page to be loaded in the portal.
108     *
109     * @author <a href="mailto:mays@lat-lon.de">Judit Mays</a>
110     * @author last edited by: $Author: mschneider $
111     *
112     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
113     *
114     * @deprecated Shopping cart will not be supported at the moment. update: new changes in deegree1_fork will not be
115     *             carried here, since this class is still not used. Remove when this status changes
116     */
117    @Deprecated
118    public class DisplayMapListener extends AddToShoppingCartListener {
119        // extends AddToShoppingCartListener --> SimpleSearchListener --> AbstractListener.
120    
121        private static final ILogger LOG = LoggerFactory.getLogger( DisplayMapListener.class );
122    
123        private String userDir = "WEB-INF/conf/igeoportal/users/";
124    
125        /*
126         * (non-Javadoc)
127         *
128         * @see org.deegree.enterprise.control.WebListener#actionPerformed(org.deegree.enterprise.control.FormEvent)
129         */
130        @Override
131        public void actionPerformed( FormEvent event ) {
132    
133            RPCWebEvent rpcEvent = (RPCWebEvent) event;
134            HttpSession session = ( (HttpServletRequest) this.getRequest() ).getSession( true );
135            ShoppingCart cart = (ShoppingCart) session.getAttribute( Constants.SESSION_SHOPPINGCART );
136            config = (CSWClientConfiguration) session.getAttribute( Constants.CSW_CLIENT_CONFIGURATION );
137    
138            try {
139                validateRequest( rpcEvent );
140            } catch ( Exception e ) {
141                gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_INVALID_RPC_EVENT", e.getMessage() ) );
142                LOG.logError( e.getMessage(), e );
143                return;
144            }
145    
146            List rpcDataSessionRecords = null;
147    
148            try {
149                rpcDataSessionRecords = getDataSessionRecordsFromList( cart.getContents(), rpcEvent );
150            } catch ( Exception e ) {
151                gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_INVALID_RPC_EVENT", e.getMessage() ) );
152                LOG.logError( e.getMessage(), e );
153                return;
154            }
155    
156            try {
157                validateWMSAbility( rpcDataSessionRecords );
158            } catch ( Exception e ) {
159                gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_ERROR_NOT_WMSABLE", e.getMessage() ) );
160                LOG.logError( e.getMessage(), e );
161                return;
162            }
163    
164            // GetCapabilities block
165    
166            // addressTitlesMap(k=address, v=titleList)
167            HashMap wmsAddressTitlesMap = createWMSAddressToTitlesMapping( rpcDataSessionRecords );
168    
169            // addressRequestMap(k=address, v=request)
170            HashMap wmsAddressRequestMap = createCapabilitiesRequests( wmsAddressTitlesMap );
171    
172            // addressCapabilitiesMap(k=address, v=WMSCapabilities)
173            HashMap wmsAddressCapabilityMap = null;
174            try {
175                wmsAddressCapabilityMap = createAddressToWMSCapabilitiesMapping( wmsAddressRequestMap );
176            } catch ( Exception e ) {
177                gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_ERROR_CREATE_WMSCAPS", e.getMessage() ) );
178                LOG.logError( e.getMessage(), e );
179                return;
180            }
181    
182            // HashMap titleCSWAddressMap = createTitleToCswAddressMap( rpcDataSessionRecords );
183            // HashMap titleIdentifierMap = createTitleToIdentiferMap( rpcDataSessionRecords );
184    
185            ViewContext vc = null;
186            try {
187                vc = setContextLayers( wmsAddressTitlesMap, wmsAddressCapabilityMap, rpcDataSessionRecords );
188            } catch ( Exception e ) {
189                gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_ERROR_CREATE_CNTXT_LAYERS", e.getMessage() ) );
190                LOG.logError( e.getMessage(), e );
191                return;
192            }
193    
194            // identify user block
195    
196            String contextName = "newContext";
197            try {
198                contextName = extractContextName( rpcEvent );
199            } catch ( Exception e ) {
200                gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_MISSING_PARAM", "CONTEXT_NAME" ) );
201                LOG.logError( e.getMessage(), e );
202                return;
203            }
204    
205            String sessionId;
206            try {
207                sessionId = extractSessionId( rpcEvent );
208            } catch ( Exception e ) {
209                gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_MISSING_PARAM", "SESSION_ID" ) );
210                LOG.logError( e.getMessage(), e );
211                return;
212            }
213    
214            String userName = null;
215            try {
216                userName = getUserNameForId( sessionId );
217            } catch ( Exception e ) {
218                gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_ERROR_DETERMIN_USERNAME", e.getMessage() ) );
219                LOG.logError( e.getMessage(), e );
220                return;
221            }
222    
223            // create WebMapContext Document block
224    
225            try {
226                vc.getGeneral().setTitle( contextName );
227            } catch ( Exception e ) {
228                gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_ERROR_SET_CNTXT_TITLE", e.getMessage() ) );
229                LOG.logError( e.getMessage(), e );
230                return;
231            }
232    
233            Envelope bbox = null;
234            String msg = null;
235            try {
236                msg = Messages.getMessage( "IGEO_STD_CSW_ERROR_DETERMIN_BBOX" );
237                bbox = determinCombiningBBox( rpcDataSessionRecords );
238                if ( bbox != null ) {
239                    msg = Messages.getMessage( "IGEO_STD_CSW_ERROR_CHANGE_BBOX" );
240                    changeBBox( vc, bbox );
241                }
242            } catch ( Exception e ) {
243                gotoErrorPage( msg + e.getMessage() );
244                LOG.logError( e.getMessage(), e );
245                return;
246            }
247    
248            try {
249                storeContext( userName, contextName, vc );
250            } catch ( Exception e ) {
251                gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_ERROR_STORE_CNTXT", e.getMessage() ) );
252                LOG.logError( e.getMessage(), e );
253                return;
254            }
255    
256            // write contextname to request
257            StringBuffer path2Dir = new StringBuffer( "users/" );
258            path2Dir.append( userName ).append( "/" ).append( contextName ).append( ".xml" );
259            this.getRequest().setAttribute( "CONTEXTNAME", path2Dir.toString() );
260    
261            return;
262        }
263    
264        /*
265         * (non-Javadoc)
266         *
267         * @see org.deegree.portal.standard.csw.control.SimpleSearchListener#validateRequest(org.deegree.enterprise.control.RPCWebEvent)
268         */
269        @Override
270        protected void validateRequest( RPCWebEvent rpcEvent )
271                                throws CatalogClientException {
272    
273            try {
274                extractSessionId( rpcEvent );
275            } catch ( CatalogClientException e ) {
276                throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_MISSING_PARAM", "SESSION_ID" ) );
277            }
278            String contextName = null;
279            try {
280                contextName = extractContextName( rpcEvent );
281            } catch ( CatalogClientException e ) {
282                throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_MISSING_PARAM", "CONTEXT_NAME" ) );
283            }
284            if ( contextName == null || "null".equals( contextName ) ) {
285                throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_ERROR_CNTXT_NAME_IS_NULL" ) );
286            }
287    
288            RPCParameter[] params = extractRPCParameters( rpcEvent );
289            for ( int i = 1; i < params.length; i++ ) {
290    
291                RPCStruct struct = extractRPCStruct( rpcEvent, 0 );
292                struct = extractRPCStruct( rpcEvent, i );
293                Object o = extractRPCMember( struct, Constants.RPC_IDENTIFIER );
294                if ( o == null ) {
295                    throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_MISSING_PARAM",
296                                                                           Constants.RPC_IDENTIFIER ) );
297                }
298                o = extractRPCMember( struct, RPC_CATALOG );
299                if ( o == null ) {
300                    throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_MISSING_PARAM", RPC_CATALOG ) );
301                }
302                o = extractRPCMember( struct, RPC_TITLE );
303                if ( o == null ) {
304                    throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_MISSING_PARAM", RPC_TITLE ) );
305                }
306    
307                RPCStruct bboxStruct = null;
308                if ( struct.getMember( Constants.RPC_BBOX ) != null ) {
309                    bboxStruct = (RPCStruct) struct.getMember( Constants.RPC_BBOX ).getValue();
310                }
311                if ( bboxStruct != null ) {
312                    Double member = (Double) extractRPCMember( bboxStruct, Constants.RPC_BBOXMINX );
313                    if ( member == null ) {
314                        throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_INVALID_BBOX_VALUE",
315                                                                               Constants.RPC_BBOXMINX ) );
316                    }
317                    member = (Double) extractRPCMember( bboxStruct, Constants.RPC_BBOXMINY );
318                    if ( member == null ) {
319                        throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_INVALID_BBOX_VALUE",
320                                                                               Constants.RPC_BBOXMINY ) );
321                    }
322                    member = (Double) extractRPCMember( bboxStruct, Constants.RPC_BBOXMAXX );
323                    if ( member == null ) {
324                        throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_INVALID_BBOX_VALUE",
325                                                                               Constants.RPC_BBOXMAXX ) );
326                    }
327                    member = (Double) extractRPCMember( bboxStruct, Constants.RPC_BBOXMAXY );
328                    if ( member == null ) {
329                        throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_INVALID_BBOX_VALUE",
330                                                                               Constants.RPC_BBOXMAXY ) );
331                    }
332                }
333            }
334    
335            return;
336        }
337    
338        /**
339         * @param contents
340         *            The List of DataSessionRecords to get DataSessionRecords from.
341         * @param rpcEvent
342         *            The RpcWebEvent contains the parameters defining the DataSessionRecords to get from the passed List.
343         * @return Returns a sublist of the passed contents, where each of the contained DataSessionRecords is defined by
344         *         the parameters of the passed rpcEvent OR null, if no matches were found in the passed List.
345         * @throws CatalogClientException
346         * @throws IllegalArgumentException,
347         *             if if at least one record defined by the passed rpcEvent is not part of the passed List.
348         */
349        private List getDataSessionRecordsFromList( List contents, RPCWebEvent rpcEvent )
350                                throws CatalogClientException {
351    
352            RPCParameter[] params = extractRPCParameters( rpcEvent );
353            List<DataSessionRecord> dsrList = new ArrayList<DataSessionRecord>( params.length );
354            boolean matches = false;
355    
356            for ( int i = 1; i < params.length; i++ ) {
357                RPCStruct struct = extractRPCStruct( rpcEvent, i );
358                String id = (String) struct.getMember( Constants.RPC_IDENTIFIER ).getValue();
359                String catalog = (String) struct.getMember( RPC_CATALOG ).getValue();
360                String title = (String) struct.getMember( RPC_TITLE ).getValue();
361    
362                DataSessionRecord dsr = getDataSessionRecordFromList( contents, id, catalog, title );
363                if ( dsr == null ) {
364                    throw new IllegalArgumentException( Messages.getMessage( "IGEO_STD_CSW_ILLEGAL_ARGS", id ) );
365                }
366                dsrList.add( dsr );
367                matches = true;
368            }
369    
370            if ( matches ) {
371                return dsrList;
372            }
373            return null;
374        }
375    
376        /**
377         * Checks, if each DataSessionRecord in the passed List contains at least one "OGC:WMS" serviceType.
378         *
379         * @param dataSessionRecords
380         *            List of DataSessionRecords in the ShoppingCart.
381         * @throws CatalogClientException,
382         *             if at least one record in the passed List has no WMS ability.
383         */
384        private void validateWMSAbility( List dataSessionRecords )
385                                throws CatalogClientException {
386    
387            for ( int i = 0; i < dataSessionRecords.size(); i++ ) {
388                boolean wmsAble = false;
389                DataSessionRecord dsr = (DataSessionRecord) dataSessionRecords.get( i );
390                for ( int j = 0; j < dsr.getServices().length; j++ ) {
391                    if ( "OGC:WMS".equals( dsr.getServices()[j].getServiceType() ) ) {
392                        wmsAble = true;
393                        break;
394                    }
395                }
396                if ( !wmsAble ) {
397                    throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_ERROR_NO_WMSABLE_ID",
398                                                                           dsr.getIdentifier() ) );
399                }
400            }
401    
402            return;
403        }
404    
405        /**
406         * Creates a HashMap with the WebMapService address as key and a List of titles of the resources as value. Both
407         * titles and addresses are taken from the passed List of DataSessionRecords. For each DataSessionRecord only the
408         * first WMS address is used.
409         *
410         * @param dataSessionRecords
411         * @return Returns a HashMap containing the wmsAddress (as key) and the title (as value).
412         */
413        private HashMap<String, List<String>> createWMSAddressToTitlesMapping( List dataSessionRecords ) {
414    
415            HashMap<String, List<String>> wmsAddressToTitlesMap = new HashMap<String, List<String>>(
416                                                                                                     dataSessionRecords.size() );
417    
418            for ( int i = 0; i < dataSessionRecords.size(); i++ ) {
419                String title = ( (DataSessionRecord) dataSessionRecords.get( i ) ).getTitle();
420                ServiceSessionRecord[] ssrs = ( (DataSessionRecord) dataSessionRecords.get( i ) ).getServices();
421                for ( int j = 0; j < ssrs.length; j++ ) {
422                    if ( "OGC:WMS".equals( ssrs[j].getServiceType() ) ) {
423                        String addr = ssrs[j].getServiceAddress();
424    
425                        // since a WMS address might be used by more than one DataSessionRecord,
426                        // a List of titles for one address is needed.
427                        ArrayList<String> titleList = null;
428                        if ( wmsAddressToTitlesMap.get( addr ) != null ) {
429                            titleList = (ArrayList<String>) wmsAddressToTitlesMap.get( addr );
430                            if ( !titleList.contains( title ) ) {
431                                titleList.add( title );
432                            }
433                        } else {
434                            titleList = new ArrayList<String>( 10 );
435                            titleList.add( title );
436                        }
437                        wmsAddressToTitlesMap.put( addr, titleList );
438                        break; // only use the first WMS address for each DataSessionRecord.
439                    }
440                }
441            }
442    
443            return wmsAddressToTitlesMap;
444        }
445    
446        /**
447         * @param addressTitlesMap
448         *            Map from which the WMS addresses are taken.
449         * @return Returns a HashMap containing the WMS address as key and the GetCapabilities request as value.
450         */
451        private HashMap<String, String> createCapabilitiesRequests( HashMap addressTitlesMap ) {
452    
453            HashMap<String, String> addressRequestMap = new HashMap<String, String>( addressTitlesMap.size() );
454    
455            for ( Iterator it = addressTitlesMap.keySet().iterator(); it.hasNext(); ) {
456                String address = (String) it.next();
457                String request = null;
458                if ( address.endsWith( "?" ) ) {
459                    request = address + "request=GetCapabilities&service=WMS";
460                } else {
461                    request = address + "?request=GetCapabilities&service=WMS";
462                }
463                addressRequestMap.put( address, request );
464            }
465    
466            return addressRequestMap;
467        }
468    
469        /**
470         * Creates a HashMap with the WebMapService address as key and a WMSCapabilities object as value.
471         *
472         * @param addressRequestMap
473         *            The Map containing the address as key for the Map to be returned, and the request as String, with
474         *            which to create the Capability object.
475         * @return Returns a HashMap containing the WMS address as key and a WMSCapabilities object as value.
476         * @throws MalformedURLException
477         * @throws SAXException
478         * @throws IOException
479         * @throws MalformedURLException
480         * @throws InvalidCapabilitiesException
481         * @throws XMLParsingException
482         */
483        private HashMap<String, WMSCapabilities> createAddressToWMSCapabilitiesMapping( HashMap addressRequestMap )
484                                throws MalformedURLException, IOException, SAXException, InvalidCapabilitiesException,
485                                XMLParsingException {
486    
487            HashMap<String, WMSCapabilities> addressCapabilitiesMap = new HashMap<String, WMSCapabilities>(
488                                                                                                            addressRequestMap.size() );
489    
490            for ( Iterator it = addressRequestMap.keySet().iterator(); it.hasNext(); ) {
491                String address = (String) it.next();
492                String request = (String) addressRequestMap.get( address );
493    
494                WMSCapabilitiesDocument capsDoc = WMSCapabilitiesDocumentFactory.getWMSCapabilitiesDocument( new URL(
495                                                                                                                      request ) );
496                WMSCapabilities capabilities = (WMSCapabilities) capsDoc.parseCapabilities();
497    
498                addressCapabilitiesMap.put( address, capabilities );
499    
500            }
501    
502            return addressCapabilitiesMap;
503        }
504    
505        /**
506         * Creates a new ViewContext and sets the context Layers from the passed WMSCapabilities objects that match the
507         * corresponding titles of the passed addressTitlesMap.
508         *
509         * @param wmsAddressTitlesMap
510         *            The Map contains the titles for which to search the matching layers.
511         * @param wmsAddressCapabilitiesMap
512         *            The Map contains the WMSCapabilities for each address.
513         * @param dataSessionRecords
514         *            The List contains the DataSessionRecords.
515         * @return Returns a new ViewContext with the ContextLayers set.
516         * @throws ContextException
517         * @throws SAXException
518         * @throws IOException
519         * @throws XMLParsingException
520         * @throws UnknownCRSException
521         */
522        private ViewContext setContextLayers( HashMap wmsAddressTitlesMap, HashMap wmsAddressCapabilitiesMap,
523                                              List dataSessionRecords )
524                                throws ContextException, IOException, SAXException, XMLParsingException,
525                                UnknownCRSException {
526    
527            List<org.deegree.portal.context.Layer> contextLayerList = new ArrayList<org.deegree.portal.context.Layer>( 10 );
528    
529            File file = new File( getHomePath() + config.getMapContextTemplatePath() );
530            ViewContext vc = WebMapContextFactory.createViewContext( file.toURL(), null, null );
531            Point[] env = vc.getGeneral().getBoundingBox();
532            String[] srs = new String[] { env[0].getCoordinateSystem().getIdentifier() };
533    
534            Format[] formats = new Format[1];
535            formats[0] = new Format( "image/jpeg", true );
536            FormatList formatList = new FormatList( formats );
537    
538            for ( Iterator it = wmsAddressTitlesMap.keySet().iterator(); it.hasNext(); ) {
539                String address = (String) it.next();
540                List titles = (List) wmsAddressTitlesMap.get( address );
541    
542                for ( int i = 0; i < titles.size(); i++ ) {
543                    String title = (String) titles.get( i );
544    
545                    WMSCapabilities capabilities = (WMSCapabilities) wmsAddressCapabilitiesMap.get( address );
546                    Layer layer = getLayer( capabilities, title );
547    
548                    BaseURL metadataURL = createMetadataURL( dataSessionRecords, title );
549    
550                    ImageURL imageURL = getLegendURL( address, capabilities, layer );
551                    Style[] styles = new Style[1];
552                    styles[0] = new Style( "default", "default", "", imageURL, true );
553                    StyleList styleList = new StyleList( styles );
554    
555                    Server server = new Server( capabilities.getServiceIdentification().getTitle(),
556                                                capabilities.getVersion(), "OGC:WMS", new URL( address ), capabilities );
557    
558                    org.deegree.portal.context.Layer contextLayer = new org.deegree.portal.context.Layer(
559                                                                                                          server,
560                                                                                                          layer.getName(),
561                                                                                                          layer.getTitle(),
562                                                                                                          layer.getAbstract(),
563                                                                                                          srs,
564                                                                                                          null,
565                                                                                                          metadataURL,
566                                                                                                          formatList,
567                                                                                                          styleList,
568                                                                                                          layer.isQueryable(),
569                                                                                                          false, null );
570                    contextLayerList.add( contextLayer );
571                }
572            }
573    
574            org.deegree.portal.context.Layer[] contextLayers = new org.deegree.portal.context.Layer[contextLayerList.size()];
575            contextLayers = contextLayerList.toArray( contextLayers );
576    
577            vc.setLayerList( new LayerList( contextLayers ) );
578    
579            return vc;
580        }
581    
582        /**
583         * Creates a MetadataURL for a layer of the passed title.
584         *
585         * @param dataSessionRecords
586         *            The List contains information necessary for creating the URL.
587         * @param title
588         *            The layer's title.
589         * @return Returns the MetadataURL for the passed title.
590         * @throws MalformedURLException
591         */
592        private BaseURL createMetadataURL( List dataSessionRecords, String title )
593                                throws MalformedURLException {
594    
595            String catalogAddress = getCatalogAddressToTitle( dataSessionRecords, title );
596            String identifier = getIdentifierToTitel( dataSessionRecords, title );
597    
598            StringBuffer sb = new StringBuffer( catalogAddress );
599            if ( sb.lastIndexOf( "?" ) != sb.length() - 1 ) {
600                sb.append( "?" );
601            }
602            sb.append( "request=GetRecordById&version=2.0.0&elementsetname=full&id=" );
603            sb.append( identifier );
604    
605            URL onlineResource = new URL( sb.toString() );
606            String format = "text/xml";
607    
608            BaseURL metadataURL = new BaseURL( format, onlineResource );
609    
610            return metadataURL;
611        }
612    
613        /**
614         * Gets the catalog address from the configuration file for the catalog that is part of the same DataSessionRecord
615         * in the passed list as the passed title.
616         *
617         * @param dataSessionRecords
618         *            List of DataSessionRecords
619         * @param title
620         * @return Returns the catalog address for the passed title.
621         */
622        private String getCatalogAddressToTitle( List dataSessionRecords, String title ) {
623            String catalogAddress = null;
624            String catalogName;
625            for ( int i = 0; i < dataSessionRecords.size(); i++ ) {
626                String dsrTitle = ( (DataSessionRecord) dataSessionRecords.get( i ) ).getTitle();
627                if ( title.equals( dsrTitle ) ) {
628                    catalogName = ( (DataSessionRecord) dataSessionRecords.get( i ) ).getCatalogName();
629                    catalogAddress = config.getCatalogServerAddress( catalogName );
630                    break;
631                }
632            }
633            return catalogAddress;
634        }
635    
636        /**
637         * Gets the identifier that is part of the same DataSessionRecord in the passed list as the passed title.
638         *
639         * @param dataSessionRecords
640         *            List of DataSessionRecords
641         * @param title
642         * @return Returns the catalog address for the passed title.
643         */
644        private String getIdentifierToTitel( List dataSessionRecords, String title ) {
645            String identifier = null;
646            for ( int i = 0; i < dataSessionRecords.size(); i++ ) {
647                String dsrTitle = ( (DataSessionRecord) dataSessionRecords.get( i ) ).getTitle();
648                if ( title.equals( dsrTitle ) ) {
649                    identifier = ( (DataSessionRecord) dataSessionRecords.get( i ) ).getIdentifier();
650                    break;
651                }
652            }
653            return identifier;
654        }
655    
656        /**
657         * @param address
658         * @param capabilities
659         * @param layer
660         * @return Returns the getLegendGraphic request url.
661         * @throws MalformedURLException
662         */
663        private ImageURL getLegendURL( String address, WMSCapabilities capabilities, Layer layer )
664                                throws MalformedURLException {
665    
666            org.deegree.ogcwebservices.wms.capabilities.Style style = layer.getStyleResource( "default:" + layer.getName() );
667            if ( style == null ) {
668                style = layer.getStyleResource( "default" );
669            }
670    
671            ImageURL imageURL = null;
672            if ( style != null && style.getLegendURL() != null && style.getLegendURL().length > 0 ) {
673                LegendURL lu = style.getLegendURL()[0];
674                imageURL = new ImageURL( lu.getWidth(), lu.getHeight(), lu.getFormat(), lu.getOnlineResource() );
675            } else {
676                StringBuffer sb = new StringBuffer( 5000 );
677                sb.append( address ).append( "?VERSION=" ).append( capabilities.getVersion() );
678                sb.append( "&STYLE=&REQUEST=GetLegendGraphic&FORMAT=image/jpeg&WIDTH=50&HEIGHT=50" );
679                sb.append( "&EXCEPTIONS=application/vnd.ogc.se_inimage" );
680                sb.append( "&LAYER=" ).append( layer.getName() );
681                imageURL = new ImageURL( 50, 50, "image/jpeg", new URL( sb.toString() ) );
682            }
683    
684            return imageURL;
685        }
686    
687        /**
688         * Returns the Layer identified by the submitted name. If no Layer matches the title <tt>null</tt> will be
689         * returned.
690         *
691         * @param capabilities
692         * @param title
693         *            The title of the requested layer.
694         * @return Returns a layer object or <tt>null</tt>
695         */
696        private Layer getLayer( WMSCapabilities capabilities, String title ) {
697            Layer layer = capabilities.getLayer();
698            Layer lay = null;
699    
700            if ( layer.getTitle() != null && title.equals( layer.getTitle() ) ) {
701                lay = layer;
702            } else {
703                lay = getLayer( title, layer.getLayer() );
704            }
705            return lay;
706        }
707    
708        /**
709         * Recursion over all layers to find the layer that matches the submitted title. If no layer can be found that
710         * fullfills the condition <tt>null</tt> will be returned.
711         *
712         * @param title
713         *            The title of the layer to be found
714         * @param layers
715         *            An array of layers to be searched.
716         * @return Returns a layer object or <tt>null</tt>
717         */
718        private Layer getLayer( String title, Layer[] layers ) {
719            Layer lay = null;
720    
721            if ( layers != null ) {
722                for ( int i = 0; i < layers.length; i++ ) {
723                    // TODO
724                    // remove break statements
725                    if ( layers[i].getTitle() != null && title.equals( layers[i].getTitle() ) ) {
726                        lay = layers[i];
727                        break;
728                    }
729                    lay = getLayer( title, layers[i].getLayer() );
730                    if ( lay != null )
731                        break;
732                }
733            }
734            return lay;
735        }
736    
737        /**
738         * Extracts the context name from the RPCStruct of the first parameter in the passed RPCWebEvent.
739         *
740         * @param rpcEvent
741         * @return Returns the context (file) name from the rpcEvent.
742         * @throws CatalogClientException
743         */
744        private String extractContextName( RPCWebEvent rpcEvent )
745                                throws CatalogClientException {
746            RPCStruct struct = extractRPCStruct( rpcEvent, 0 );
747            return (String) extractRPCMember( struct, "CONTEXT_NAME" );
748        }
749    
750        /**
751         * Extracts the sessionId from the RPCStruct of the first parameter in the passed RPCWebEvent.
752         *
753         * @param rpcEvent
754         * @return Returns the sessionId from the rpcEvent.
755         * @throws CatalogClientException
756         */
757        private String extractSessionId( RPCWebEvent rpcEvent )
758                                throws CatalogClientException {
759            RPCStruct struct = extractRPCStruct( rpcEvent, 0 );
760            return (String) extractRPCMember( struct, "SESSION_ID" );
761        }
762    
763        /**
764         * Gets the user name assigned to the passed session ID from an authentication service.
765         *
766         * If the session ID equals "null", then the default user name is returned. If no user is assigned to the session ID
767         * a CatalogClientException will be returned. If the session is closed or expired an exception will be thrown.
768         *
769         * @param sessionId
770         * @return Returns the user name for the passed session id.
771         * @throws IOException
772         * @throws SAXException
773         * @throws CatalogClientException
774         * @throws XMLParsingException
775         */
776        private String getUserNameForId( String sessionId )
777                                throws IOException, SAXException, CatalogClientException, XMLParsingException {
778    
779            if ( "null".equals( sessionId ) ) {
780                LOG.logDebug( "sessionId is 'null' => user is 'default'\n" );
781                return "default";
782            }
783    
784            HttpSession session = ( (HttpServletRequest) getRequest() ).getSession( true );
785            ViewContext vc = (ViewContext) session.getAttribute( Constants.CURRENTMAPCONTEXT );
786            GeneralExtension ge = vc.getGeneral().getExtension();
787    
788            BaseURL baseUrl = ge.getAuthentificationSettings().getAuthentificationURL();
789            StringBuffer sb = new StringBuffer( NetWorker.url2String( baseUrl.getOnlineResource() ) );
790            sb.append( "?request=GetUser&SESSIONID=" ).append( sessionId );
791    
792            NetWorker nw = new NetWorker( CharsetUtils.getSystemCharset(), new URL( sb.toString() ) );
793            Reader reader = new InputStreamReader( nw.getInputStream() );
794            Document doc = XMLTools.parse( reader );
795            // Node nsNode = XMLTools.getNamespaceNode(new HashMap());
796    
797            String tmp = null;
798            tmp = XMLTools.getNodeAsString( doc.getDocumentElement(), "/User/Name", nsContext, null );
799            if ( tmp == null ) {
800                throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_ERROR_GET_USERNAME", sessionId ) );
801            }
802    
803            return tmp;
804        }
805    
806        /**
807         * Determins the minimum and maximum values for x and y for the bounding box of each DataSessionRecord in the passed
808         * <code>List</code> and uses these values to determin an all combining bounding box. If none of the passed
809         * records has a bounding box, then null is returned.
810         *
811         * @param rpcDataSessionRecords
812         *            List of DataSessionRecords for which to determin a combining bounding box.
813         * @return Returns a new GM_Envelope for a combining bounding box, OR null, if no bounding box was set in any of the
814         *         passed DataSessionRecords.
815         * @throws UnknownCRSException
816         */
817        private Envelope determinCombiningBBox( List rpcDataSessionRecords )
818                                throws UnknownCRSException {
819    
820            Envelope bbox = null;
821    
822            // upper left corner of combining bounding box
823            double minx = Double.MAX_VALUE;
824            double maxy = Double.MIN_VALUE;
825            // lower right corner of combining bounding box
826            double maxx = Double.MIN_VALUE;
827            double miny = Double.MAX_VALUE;
828    
829            int count = 0;
830            for ( int i = 0; i < rpcDataSessionRecords.size(); i++ ) {
831                DataSessionRecord dsr = (DataSessionRecord) rpcDataSessionRecords.get( i );
832                if ( dsr.getBoundingBox() != null ) {
833                    count++;
834                    double tempMinx, tempMiny, tempMaxx, tempMaxy;
835                    tempMinx = dsr.getBoundingBox().getMin().getX();
836                    tempMiny = dsr.getBoundingBox().getMin().getY();
837                    tempMaxx = dsr.getBoundingBox().getMax().getX();
838                    tempMaxy = dsr.getBoundingBox().getMax().getY();
839    
840                    // find min for x and y
841                    minx = Math.min( tempMinx, minx );
842                    miny = Math.min( tempMiny, miny );
843                    // find max for x and y
844                    maxx = Math.max( tempMaxx, maxx );
845                    maxy = Math.max( tempMaxy, maxy );
846                }
847            }
848            if ( count > 0 ) {
849                CoordinateSystem srs = CRSFactory.create( config.getSrs() );
850                bbox = GeometryFactory.createEnvelope( minx, miny, maxx, maxy, srs );
851            }
852    
853            return bbox;
854        }
855    
856        /**
857         * Changes the bounding box of a given view context.
858         *
859         * @param vc
860         *            The view context to be changed
861         * @param bbox
862         *            The new bounding box
863         * @throws ContextException
864         */
865        private void changeBBox( ViewContext vc, Envelope bbox )
866                                throws ContextException {
867            General general = vc.getGeneral();
868            CoordinateSystem cs = general.getBoundingBox()[0].getCoordinateSystem();
869            Point[] p = new Point[] { GeometryFactory.createPoint( bbox.getMin(), cs ),
870                                     GeometryFactory.createPoint( bbox.getMax(), cs ) };
871            general.setBoundingBox( p );
872        }
873    
874        /**
875         * @param userName
876         * @param contextName
877         * @param vc
878         * @throws TransformerFactoryConfigurationError
879         * @throws PortalException
880         */
881        private void storeContext( String userName, String contextName, ViewContext vc )
882                                throws PortalException, TransformerFactoryConfigurationError {
883    
884            // save new context
885            StringBuffer path2Dir = new StringBuffer( getHomePath() );
886            path2Dir.append( userDir );
887            path2Dir.append( userName );
888            File file = new File( path2Dir.toString() );
889            if ( !file.exists() ) {
890                // create directory if not existent
891                file.mkdir();
892            }
893            path2Dir.append( "/" ).append( contextName ).append( ".xml" );
894    
895            // Document doc = XMLFactory.export( vc );
896            // FileOutputStream fos = new FileOutputStream( path2Dir.toString() );
897            // internalSave( new StreamResult(fos), doc );
898            // fos.close();
899            saveDocument( vc, path2Dir.toString() );
900    
901            return;
902        }
903    
904        // /**
905        // * common method to save xml
906        // *
907        // * @param result
908        // * @param doc
909        // * @throws TransformerFactoryConfigurationError
910        // * @throws TransformerException
911        // */
912        // protected static void internalSave(Result result, Document doc)
913        // throws TransformerFactoryConfigurationError, TransformerException {
914        // Source source = new DOMSource(doc);
915        // Transformer transformer =
916        // TransformerFactory.newInstance().newTransformer();
917        // transformer.transform(source, result);
918        // }
919    
920        /**
921         * saves the new context as xml
922         *
923         * @param vc
924         * @param filename
925         * @throws PortalException
926         */
927        public static final void saveDocument( ViewContext vc, String filename )
928                                throws PortalException {
929            try {
930                XMLFragment xml = XMLFactory.export( vc );
931                FileOutputStream fos = new FileOutputStream( filename );
932                xml.write( fos );
933                fos.close();
934            } catch ( Exception e ) {
935                throw new PortalException( Messages.getMessage( "IGEO_STD_CSW_ERROR_SAVE_FILE", filename ) );
936            }
937        }
938    
939    }