    001    //$HeadURL: svn+ssh://melmasry@svn.wald.intevation.org/deegree/base/trunk/src/org/deegree/portal/standard/context/control/FullScreenListener.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.context.control;
    038
    039    import java.awt.Rectangle;
    040    import java.io.IOException;
    041    import java.net.MalformedURLException;
    042    import java.util.HashMap;
    043    import java.util.Iterator;
    044    import java.util.LinkedList;
    045    import java.util.List;
    046    import java.util.Map;
    047
    048    import javax.servlet.http.HttpServletRequest;
    049    import javax.servlet.http.HttpSession;
    050    import javax.xml.parsers.ParserConfigurationException;
    051    import javax.xml.transform.TransformerException;
    052
    053    import org.deegree.enterprise.control.FormEvent;
    054    import org.deegree.enterprise.control.RPCMember;
    055    import org.deegree.enterprise.control.RPCStruct;
    056    import org.deegree.enterprise.control.RPCWebEvent;
    057    import org.deegree.framework.log.ILogger;
    058    import org.deegree.framework.log.LoggerFactory;
    059    import org.deegree.framework.util.MapUtils;
    060    import org.deegree.framework.util.Parameter;
    061    import org.deegree.framework.xml.XMLFragment;
    062    import org.deegree.i18n.Messages;
    063    import org.deegree.model.crs.CoordinateSystem;
    064    import org.deegree.model.spatialschema.Envelope;
    065    import org.deegree.model.spatialschema.GeometryFactory;
    066    import org.deegree.model.spatialschema.Point;
    067    import org.deegree.portal.Constants;
    068    import org.deegree.portal.PortalException;
    069    import org.deegree.portal.context.ContextException;
    070    import org.deegree.portal.context.Frontend;
    071    import org.deegree.portal.context.GUIArea;
    072    import org.deegree.portal.context.General;
    073    import org.deegree.portal.context.GeneralExtension;
    074    import org.deegree.portal.context.Module;
    075    import org.deegree.portal.context.ViewContext;
    076    import org.deegree.portal.context.XMLFactory;
    077    import org.xml.sax.SAXException;
    078
    079    /**
    080     * Convert the current view context to a full screen mode. It hides all the modules except the map
    081     * and the toolbar. It also keeps whatever changes were made in the original context to the full
    082     * screen context
    083     *
    084     * @author <a href="mailto:elmasry@lat-lon.de">Moataz Elmasry</a>
    085     * @author last edited by: $Author: $
    086     *
    087     * @version $Revision: $, $Date: 1 Jun 2007 10:12:29$
    088     */
    089    public class FullScreenListener extends AbstractContextListener {
    090
    091        private int width = 0;
    092
    093        private Map<String, String> modulesMap = null;
    094
    095        /**
    096         * the path to where the Web Map Context files are found
    097         */
    098        public static final String CONTEXTPATH = "WEB-INF/conf/igeoportal";
    099
    100        private String xslFileName = null;
    101
    102        private HttpSession session = null;
    103
    104        /**
    105         * A <code>String</code> defining the name of the xsl file that defines the transformation
    106         * from a context to html. This must be placed, together with the map context xml and helper xsl
    107         * files, under <code>${context-home}/WEB-INF/conf/igeoportal/</code>.
    108         */
    109        protected static final String DEFAULT_CTXT2HTML = "WEB-INF/conf/igeoportal/context2HTML.xsl";
    110
    111        private static final ILogger LOG = LoggerFactory.getLogger( ResetContextListener.class );
    112
    113        private static final String DISPLAYED_MODULES = "DISPLAYED_MODULES";
    114
    115        private static final String NORMALSCREEN_MAPCONTEXT = "NormalScreenMapContext";
    116
    117        /*
    118         * (non-Javadoc)
    119         *
    120         * @see org.deegree.enterprise.control.WebListener#actionPerformed(org.deegree.enterprise.control.FormEvent)
    121         */
    122        @Override
    123        public void actionPerformed( FormEvent event ) {
    124
    125            RPCWebEvent rpc = (RPCWebEvent) event;
    126
    127            try {
    128                validate( rpc );
    129                validateCntxtProperties();
    130                initialize();
    131            } catch ( PortalException e ) {
    132                LOG.logError( e.getMessage(), e );
    133                e.printStackTrace();
    134                gotoErrorPage( e.getMessage() );
    135                return;
    136            }
    137
    138            try {
    139                ViewContext fullScreenContext = setToFullScreen( rpc );
    140                setCurrentContext( fullScreenContext );
    141            } catch ( Exception e ) {
    142                LOG.logError( e.getMessage(), e );
    143                e.printStackTrace();
    144                gotoErrorPage( e.getMessage() );
    145                return;
    146            }
    147        }
    148
    149        /**
    150         * ValidateRPC looks in the RPCStruct for all needed elements and gotoErrorPage in case an
    151         * element is found or wronglz formated, this is useful so that we won't need to check later for
    152         * anz variables, simply get them and start Working
    153         *
    154         * @param rpc
    155         * @throws PortalException
    156         */
    157        protected void validate( RPCWebEvent rpc )
    158                                throws PortalException {
    159
    160            RPCStruct struct = extractRPCStruct( rpc, 0 );
    161
    162            RPCMember layerListRPC = struct.getMember( "layerList" );
    163            validateLayerList( layerListRPC );
    164
    165            RPCMember bboxRPC = struct.getMember( "boundingBox" );
    166            validateBBox( bboxRPC );
    167        }
    168
    169        /**
    170         * This method checks the context.properties file to make sure that all fields needed are
    171         * available
    172         *
    173         */
    174        protected void validateCntxtProperties()
    175                                throws PortalException {
    176
    177            String displayedModules = ContextMessages.getString( DISPLAYED_MODULES );
    178            if ( displayedModules == null ) {
    179                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE",
    180                                                                ContextMessages.getName(), "DISPLAYED_MODULES" ) );
    181            }
    182
    183            if ( displayedModules.indexOf( "MANDATORY_MODULE_MAP" ) < 0 ) {
    184                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE",
    185                                                                ContextMessages.getName(), "MANDATORY_MODULE_MAP" ) );
    186            }
    187
    188            if ( displayedModules.indexOf( "MANDATORY_MODULE_TOOLBAR" ) < 0 ) {
    189                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE",
    190                                                                ContextMessages.getName(), "MANDATORY_MODULE_TOOLBAR" ) );
    191            }
    192
    193            String mapName = ContextMessages.getString( "MANDATORY_MODULE_MAP" );
    194            if ( mapName == null ) {
    195                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_MAND_PARAM",
    196                                                                ContextMessages.getName(), "MANDATORY_MODULE_MAP" ) );
    197            }
    198
    199            String toolbarName = ContextMessages.getString( "MANDATORY_MODULE_TOOLBAR" );
    200            if ( toolbarName == null ) {
    201                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_MAND_PARAM",
    202                                                                ContextMessages.getName(), "MANDATORY_MODULE_TOOLBAR" ) );
    203            }
    204
    205            int width = Integer.parseInt( ContextMessages.getString( "MAP_WIDTH" ) );
    206            if ( width <= 0 ) {
    207                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE",
    208                                                                ContextMessages.getName(), "MAP_WIDTH" ) );
    209            }
    210
    211            String normalScreen = ContextMessages.getString( "NORMAL_SIZE_SCREEN" );
    212            if ( normalScreen == null ) {
    213                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE",
    214                                                                ContextMessages.getName(), "NORMAL_SIZE_SCREEN" ) );
    215            }
    216        }
    217
    218        /**
    219         * Initializes the global variables
    220         *
    221         * @throws PortalException
    222         */
    223        protected void initialize()
    224                                throws PortalException {
    225
    226            try {
    227                xslFileName = "file://" + getHomePath() + DEFAULT_CTXT2HTML;
    228
    229                width = Integer.parseInt( ContextMessages.getString( "MAP_WIDTH" ) );
    230                session = ( (HttpServletRequest) this.getRequest() ).getSession();
    231
    232                modulesMap = loadModulesNames( DISPLAYED_MODULES );
    233            } catch ( Exception e ) {
    234                LOG.logError( e.getMessage() );
    235                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_INITIALIZE", e ) );
    236            }
    237        }
    238
    239        /**
    240         * Applies the modules read from the context.properties file to the current context using the
    241         * data from the session on the defaultContext
    242         *
    243         * @param rpc
    244         * @return the view context for full screen
    245         * @throws ParserConfigurationException
    246         * @throws PortalException
    247         * @throws ContextException
    248         */
    249        protected ViewContext setToFullScreen( RPCWebEvent rpc )
    250                                throws ParserConfigurationException, PortalException, ContextException {
    251
    252            RPCStruct struct = extractRPCStruct( rpc, 0 );
    253            ViewContext tempContext = applyLayers( struct );
    254
    255            try {
    256                XMLFragment xmlActualContext = XMLFactory.export( tempContext );
    257                // Saving the original Context
    258                session.setAttribute( NORMALSCREEN_MAPCONTEXT, xmlActualContext );
    259            } catch ( ParserConfigurationException e ) {
    260                LOG.logError( e.getMessage() );
    261                throw new ParserConfigurationException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_TRANSFORM" ) );
    262            }
    263            return createFullScreenContext( struct, tempContext );
    264        }
    265
    266        /**
    267         * Takes in viewContext converts it to a html of the viewcontext and display it
    268         *
    269         * @param vc the Viewcontext after convert
    270         * @throws ParserConfigurationException
    271         * @throws TransformerException
    272         * @throws SAXException
    273         * @throws MalformedURLException
    274         * @throws IOException
    275         */
    276        protected void setCurrentContext( ViewContext vc )
    277                                throws ParserConfigurationException, TransformerException, SAXException,
    278                                MalformedURLException, IOException {
    279
    280            try {
    281                XMLFragment xml = XMLFactory.export( vc );
    282                String newHtml = transformToHtmlMapContext( xml, xslFileName );
    283                session.setAttribute( ContextSwitchListener.NEW_CONTEXT_HTML, newHtml );
    284            } catch ( ParserConfigurationException e ) {
    285                LOG.logError( e.getMessage() );
    286                throw new ParserConfigurationException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_TRANSFORM" ) );
    287            }
    288        }
    289
    290        /**
    291         * Gets the current map context from the session and applies the current layers to it.
    292         *
    293         * @param struct
    294         * @return the viewContext after applying the current layers to it
    295         * @throws PortalException
    296         */
    297        private ViewContext applyLayers( RPCStruct struct )
    298                                throws PortalException {
    299
    300            ViewContext tempContext = null;
    301            try {
    302                String sessionId = (String) session.getAttribute( "SESSIONID" );
    303                ViewContext vc = (ViewContext) session.getAttribute( Constants.CURRENTMAPCONTEXT );
    304                tempContext = vc.clone( null, sessionId );
    305
    306                // Applying the layer setting to the current context
    307                RPCMember[] layerList = ( (RPCStruct) struct.getMember( "layerList" ).getValue() ).getMembers();
    308                changeLayerList( tempContext, layerList );
    309
    310            } catch ( PortalException e ) {
    311                // throw new PortalException( Messages.getMessage(
    312                // "IGEO_STD_CNTXT_ERROR_EMPTY_LAYERLIST" ) );
    313                throw e;
    314            } catch ( Exception e ) {
    315                LOG.logError( e.getMessage() );
    316                throw new PortalException( Messages.getMessage( "IGEO_STD_ERROR_UNKNOWN", e ) );
    317            }
    318            return tempContext;
    319        }
    320
    321        /**
    322         * Validates the data in the struct to make sure it contains a valid layerList
    323         *
    324         * @param layerListRPCMember
    325         * @throws PortalException
    326         */
    327        protected void validateLayerList( RPCMember layerListRPCMember )
    328                                throws PortalException {
    329
    330            if ( layerListRPCMember == null || layerListRPCMember.getValue() == null ) {
    331                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_RPC_MEMBER", "layerList" ) );
    332            }
    333
    334            RPCMember[] layerList = null;
    335            try {
    336                layerList = ( (RPCStruct) layerListRPCMember.getValue() ).getMembers();
    337            } catch ( Exception e ) {
    338                LOG.logError( e.getMessage() );
    339                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_WRONG_RPC_MEMBER_VALUE", "layerList" ) );
    340            }
    341
    342            if ( layerList == null || layerList.length < 1 ) {
    343                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_EMPTY_LAYERLIST", "layerList" ) );
    344            }
    345        }
    346
    347        /**
    348         * Validates the data in the struct to make sure it contains a valid bbox
    349         *
    350         * @param bboxRPCMember
    351         * @throws PortalException
    352         */
    353        protected void validateBBox( RPCMember bboxRPCMember )
    354                                throws PortalException {
    355
    356            if ( bboxRPCMember == null || bboxRPCMember.getValue() == null ) {
    357                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_RPC_MEMBER", "boundingBox" ) );
    358            }
    359
    360            RPCStruct bboxStruct = (RPCStruct) bboxRPCMember.getValue();
    361            Double minx = null;
    362            Double miny = null;
    363            Double maxx = null;
    364            Double maxy = null;
    365
    366            RPCMember mem = bboxStruct.getMember( Constants.RPC_BBOXMINX );
    367            if ( mem != null ) {
    368                minx = (Double) mem.getValue();
    369            }
    370            mem = bboxStruct.getMember( Constants.RPC_BBOXMINY );
    371            if ( mem != null ) {
    372                miny = (Double) mem.getValue();
    373            }
    374            mem = bboxStruct.getMember( Constants.RPC_BBOXMAXX );
    375            if ( mem != null ) {
    376                maxx = (Double) mem.getValue();
    377            }
    378            mem = bboxStruct.getMember( Constants.RPC_BBOXMAXY );
    379            if ( mem != null ) {
    380                maxy = (Double) mem.getValue();
    381            }
    382
    383            if ( minx == null || maxx == null || miny == null || maxy == null ) {
    384                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_WRONG_RPC_MEMBER_VALUE", "boundingBox" ) );
    385            }
    386            if ( minx >= maxx || miny >= maxy ) {
    387                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_BBOX_BOUNDARIES" ) );
    388            }
    389        }
    390
    391        /**
    392         * Extracts shown modules names from the context.properties file
    393         *
    394         * @param selectedModules
    395         *            The modules names key as written in the context.properties file
    396         * @return Map contains all the used modules
    397         */
    398        private Map<String, String> loadModulesNames( String selectedModules ) {
    399
    400            String modulesNames = ContextMessages.getString( selectedModules );
    401            Map<String, String> modules = new HashMap<String, String>();
    402            String[] tmpNames = modulesNames.split( ";" );
    403            for ( int i = 0; i < tmpNames.length; i++ ) {
    404                String value = ContextMessages.getString( tmpNames[i] );
    405                if ( tmpNames[i] != null && value != null ) {
    406                    modules.put( tmpNames[i], value );
    407                }
    408            }
    409            return modules;
    410        }
    411
    412        /**
    413         * Sets the given context to FullScreen mode.
    414         *
    415         * @param struct the rpc struct containing the current bbox envelope
    416         * @param vc view context with the layers
    417         * @return The context transformed to the fullScreen size
    418         * @throws ContextException
    419         * @throws PortalException
    420         */
    421        protected ViewContext createFullScreenContext( RPCStruct struct, ViewContext vc )
    422                                throws ContextException, PortalException {
    423
    424            RPCStruct bBoxStruct = (RPCStruct) struct.getMember( "boundingBox" ).getValue();
    425            Envelope envelope = extractBBox( bBoxStruct, null );
    426
    427            String sessionID = (String) session.getAttribute( "SESSIONID" );
    428            ViewContext fullscreenContext = null;
    429            try {
    430                fullscreenContext = vc.clone( null, sessionID );
    431            } catch ( Exception e ) {
    432                throw new ContextException( "The view context couldn't be cloned" );
    433            }
    434            General general = fullscreenContext.getGeneral();
    435            GeneralExtension extension = general.getExtension();
    436            Frontend frontEnd = extension.getFrontend();
    437
    438            // The bbox values are changed here
    439            Point[] points = general.getBoundingBox();
    440            // if there are no 2 points, then nothing happens
    441            if ( points.length == 2 ) {
    442                Rectangle rect = general.getWindow();
    443                rect.width = width; // setting new window width
    444                CoordinateSystem crs = points[0].getCoordinateSystem();
    445                Envelope bbox = MapUtils.ensureAspectRatio( envelope, rect.width, rect.height );
    446
    447                Point[] newPoints = new Point[2];
    448                newPoints[0] = GeometryFactory.createPoint( bbox.getMin(), crs );
    449                newPoints[1] = GeometryFactory.createPoint( bbox.getMax(), crs );
    450
    451                general.setBoundingBox( newPoints );
    452            } else {
    453                throw new ContextException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_VIEWCONTEXT", "bounding box" ) );
    454            }
    455
    456            // Here removing all the side modules
    457            List<GUIArea> contextAreas = new LinkedList<GUIArea>();
    458            // Makign sure we fetched the names right, otherwise we don't have the names to compare with
    459
    460            // Adding GuiAreas to a list to do a for loop
    461            // instead of accessing them individually
    462            GUIArea curArea = null;
    463            if ( ( curArea = frontEnd.getNorth() ) != null ) {
    464                contextAreas.add( curArea );
    465            }
    466            if ( ( curArea = frontEnd.getSouth() ) != null ) {
    467                contextAreas.add( curArea );
    468            }
    469            if ( ( curArea = frontEnd.getEast() ) != null ) {
    470                contextAreas.add( curArea );
    471            }
    472            if ( ( curArea = frontEnd.getWest() ) != null ) {
    473                contextAreas.add( curArea );
    474            }
    475            if ( ( curArea = frontEnd.getCenter() ) != null ) {
    476                contextAreas.add( curArea );
    477            }
    478
    479            Iterator<GUIArea> it = contextAreas.iterator();
    480
    481            // We now know for sure, that will find the map and the toolbar
    482            // since we already called validateCntxtProperties()
    483            boolean mapFound = false;
    484            boolean toolbarFound = false;
    485            while ( it.hasNext() ) {
    486                GUIArea area = it.next();
    487                boolean found = false;
    488
    489                Module[] modules = area.getModules();
    490                for ( int i = 0; i < modules.length; i++ ) {
    491                    // If the module name was in the list of shownModules then keep it
    492                    if ( modulesMap.containsValue( modules[i].getName() ) ) {
    493                        found = true;
    494                        if ( modules[i].getName().compareTo( modulesMap.get( "MANDATORY_MODULE_MAP" ) ) == 0 ) {
    495                            // The map view or the tool bar has been found
    496                            modules[i].setWidth( width );
    497                            mapFound = true;
    498                        }
    499
    500                        if ( modules[i].getName().compareTo( modulesMap.get( "MANDATORY_MODULE_TOOLBAR" ) ) == 0 ) {
    501                            modules[i].setWidth( width );
    502                            toolbarFound = true;
    503                        }
    504                        continue;
    505                    }
    506                    modules[i].setHidden( true );
    507                }
    508                if ( !found ) {
    509                    area.setArea( 0 );
    510                    area.setHidden( true );
    511                }
    512            }
    513
    514            if ( !mapFound ) {
    515                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_MODULE",
    516                                                                modulesMap.get( "MANDATORY_MODULE_MAP" ) ) );
    517            }
    518            if ( !toolbarFound ) {
    519                throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_MODULE",
    520                                                                modulesMap.get( "MANDATORY_MODULE_TOOLBAR" ) ) );
    521            }
    522
    523            // Changing the full screen button to normal size screen button
    524            Module toolBar = frontEnd.getCenter().getModule( "Toolbar" );
    525            if ( toolBar != null ) {
    526                String[] removedBtns = ContextMessages.getString( "REMOVED_BUTTONS" ).split( ";" );
    527
    528                // Remove only the parameters that exist in the hash map
    529                String[] names = toolBar.getParameter().getParameterNames();
    530                for ( int i = 0; i < names.length; i++ ) {
    531                    for ( int j = 0; j < removedBtns.length; j++ ) {
    532                        if ( names[i].indexOf( removedBtns[j] ) >= 0 ) {
    533                            toolBar.getParameter().removeParameter( names[i] );
    534                        }
    535                    }
    536                }
    537            }
    538
    539            Parameter param = new Parameter( ContextMessages.getString( "NORMAL_SIZE_SCREEN" ), "PushButton" );
    540            toolBar.addParameter( param );
    541
    542            return fullscreenContext;
    543        }
    544    }