    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/portal/portlet/enterprise/WMCUpdateServlet.java $
    002    /*----------------------------------------------------------------------------
    003     This file is part of deegree, http://deegree.org/
    004     Copyright (C) 2001-2009 by:
    005       Department of Geography, University of Bonn
    006     and
    007       lat/lon GmbH
    008
    009     This library is free software; you can redistribute it and/or modify it under
    010     the terms of the GNU Lesser General Public License as published by the Free
    011     Software Foundation; either version 2.1 of the License, or (at your option)
    012     any later version.
    013     This library is distributed in the hope that it will be useful, but WITHOUT
    014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
    016     details.
    017     You should have received a copy of the GNU Lesser General Public License
    018     along with this library; if not, write to the Free Software Foundation, Inc.,
    019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    020
    021     Contact information:
    022
    023     lat/lon GmbH
    024     Aennchenstr. 19, 53177 Bonn
    025     Germany
    026     http://lat-lon.de/
    027
    028     Department of Geography, University of Bonn
    029     Prof. Dr. Klaus Greve
    030     Postfach 1147, 53001 Bonn
    031     Germany
    032     http://www.geographie.uni-bonn.de/deegree/
    033
    034     e-mail: info@deegree.org
    035    ----------------------------------------------------------------------------*/
    036    package org.deegree.portal.portlet.enterprise;
    037
    038    import java.io.IOException;
    039    import java.net.URL;
    040    import java.util.List;
    041    import java.util.Map;
    042
    043    import javax.servlet.ServletException;
    044    import javax.servlet.http.HttpServlet;
    045    import javax.servlet.http.HttpServletRequest;
    046    import javax.servlet.http.HttpServletResponse;
    047
    048    import org.deegree.framework.log.ILogger;
    049    import org.deegree.framework.log.LoggerFactory;
    050    import org.deegree.framework.util.KVP2Map;
    051    import org.deegree.framework.util.StringPair;
    052    import org.deegree.framework.util.StringTools;
    053    import org.deegree.model.crs.CoordinateSystem;
    054    import org.deegree.model.spatialschema.Envelope;
    055    import org.deegree.model.spatialschema.GeometryFactory;
    056    import org.deegree.model.spatialschema.Point;
    057    import org.deegree.portal.PortalUtils;
    058    import org.deegree.portal.context.ContextException;
    059    import org.deegree.portal.context.Layer;
    060    import org.deegree.portal.context.LayerList;
    061    import org.deegree.portal.context.Node;
    062    import org.deegree.portal.context.ViewContext;
    063    import org.deegree.portal.portlet.modules.actions.IGeoPortalPortletPerform;
    064
    065    /**
    066     * The servlet will be used to update a map model (Web Map Context) in the background (using an
    067     * invisible iframe) from an iGeoPortal Portlet Edition
    068     *
    069     *
    070     * @version $Revision: 18195 $
    071     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
    072     * @author last edited by: $Author: mschneider $
    073     *
    074     * @version 1.0. $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
    075     *
    076     * @since 2.0
    077     */
    078    public class WMCUpdateServlet extends HttpServlet {
    079
    080        private static final long serialVersionUID = 2927537039728672671L;
    081
    082        private static final ILogger LOG = LoggerFactory.getLogger( WMCUpdateServlet.class );
    083
    084        @Override
    085        public void init()
    086                                throws ServletException {
    087            super.init();
    088        }
    089
    090        @Override
    091        protected void doGet( HttpServletRequest request, HttpServletResponse response )
    092                                throws ServletException, IOException {
    093
    094            doPost( request, response );
    095        }
    096
    097        @Override
    098        protected void doPost( HttpServletRequest request, HttpServletResponse response )
    099                                throws ServletException, IOException {
    100
    101            Map<String, String> parameter = KVP2Map.toMap( request );
    102
    103            String mm = parameter.get( "MAPPORTLET" );
    104            String nodeValue = parameter.get( "NODE" );
    105            String action = parameter.get( "ACTION" );
    106
    107            LOG.logDebug( "parameter: " + parameter );
    108
    109            IGeoPortalPortletPerform igeo = new IGeoPortalPortletPerform( request, null, getServletContext() );
    110
    111            try {
    112                // Handle ajax/iframe requests.
    113                // All arguments are passed via a parameter map, see the handelXxxXxx
    114                // static methods for the accepted parameters.
    115
    116                // The parameter NODE identifies the affected node/layer:
    117                // nodes are passed as 'node-xx' where xx is the number/id
    118                // layers are passed as 'layername|serveraddress'
    119                if ( action != null && mm != null && nodeValue != null ) {
    120                    ViewContext vc = igeo.getCurrentViewContext( mm );
    121
    122                    // send parts of a layer tree
    123                    if ( action.equalsIgnoreCase( "TREEDATA" ) ) {
    124                        // writes into response stream
    125                        handleTreeData( parameter, vc, response );
    126                        return;
    127                    }
    128
    129                    // handle actions on nodes/layers
    130                    boolean repaintMap = true;
    131                    if ( action.equalsIgnoreCase( "MOVENODE" ) ) {
    132                        repaintMap = handleMoveNode( parameter, vc );
    133                    } else if ( action.equalsIgnoreCase( "ADDNODE" ) ) {
    134                        String nextNodeID = handleAddNode( parameter, vc );
    135                        request.setAttribute( "NEXTNODEID", nextNodeID );
    136                        repaintMap = false;
    137                    } else if ( action.equalsIgnoreCase( "REMOVENODE" ) ) {
    138                        handleRemoveNode( parameter, vc );
    139                    } else if ( action.equalsIgnoreCase( "RENAMENODE" ) ) {
    140                        handleRenameNode( parameter, vc );
    141                        repaintMap = false;
    142                    } else if ( action.equalsIgnoreCase( "SETVISIBILITY" ) ) {
    143                        handleSetVisibility( parameter, vc );
    144                    }
    145                    if ( repaintMap ) {
    146                        // if the visible layers changed,
    147                        // send new baserequests to client ( see igeoportal/enterprise.jsp)
    148                        request.setAttribute( "UPDATE_BASEREQUESTS", true );
    149                        request.setAttribute( "VIEWCONTEXT", vc );
    150                    }
    151                } else if ( mm != null ) {
    152                    // update bbox
    153                    ViewContext vc = igeo.getCurrentViewContext( mm );
    154
    155                    String bbox = parameter.get( IGeoPortalPortletPerform.PARAM_BBOX );
    156
    157                    if ( bbox != null && vc != null ) {
    158                        double[] coords = StringTools.toArrayDouble( bbox, "," );
    159                        CoordinateSystem crs = vc.getGeneral().getBoundingBox()[0].getCoordinateSystem();
    160                        Point[] pt = new Point[2];
    161                        pt[0] = GeometryFactory.createPoint( coords[0], coords[1], crs );
    162                        pt[1] = GeometryFactory.createPoint( coords[2], coords[3], crs );
    163                        try {
    164                            vc.getGeneral().setBoundingBox( pt );
    165                        } catch ( ContextException should_never_happen ) {
    166                            //nottin
    167                        }
    168                        List<Envelope> history = (List<Envelope>) request.getSession().getAttribute(
    169                                                                                                     IGeoPortalPortletPerform.SESSION_HISTORY );
    170                        int p = (Integer) request.getSession().getAttribute(
    171                                                                             IGeoPortalPortletPerform.SESSION_HISTORYPOSITION );
    172                        Envelope current = history.get( p );
    173                        Envelope env = GeometryFactory.createEnvelope( coords[0], coords[1], coords[2], coords[3], null );
    174                        if ( current == null || !current.equals( env ) ) {
    175                            p++;
    176                            history.add( p, env );
    177                            request.getSession().setAttribute( IGeoPortalPortletPerform.SESSION_HISTORYPOSITION, p );
    178                        }
    179                    }
    180
    181                    if ( bbox != null && parameter.get( "LAYERS" ) != null ) {
    182                        // just change layerlist if the request contains a BBOX parameter
    183                        // and at least one layer because other wise it will be the initial call;
    184                        Layer[] layers = vc.getLayerList().getLayers();
    185                        String ly =  parameter.get( "LAYERS" );
    186                        StringBuffer sb = new StringBuffer( 100 );
    187                        for ( int i = 0; i < layers.length; i++ ) {
    188                            sb.append( layers[i].getName() ).append( '|' );
    189                            sb.append( layers[i].getServer().getOnlineResource() );
    190                            if ( ly.indexOf( sb.toString() ) > -1 ) {
    191                                layers[i].setHidden( false );
    192                            } else {
    193                                layers[i].setHidden( true );
    194                            }
    195                            sb.delete( 0, sb.length() );
    196                        }
    197                        igeo.setCurrentMapContext( vc, mm );
    198                    }
    199                } else {
    200                    System.out.println( "no mapmodel defined in request; ensure that parameter 'MAPPORTLET' is defined!" );
    201                }
    202            } catch ( Exception e ) {
    203                e.printStackTrace();
    204                LOG.logError( "could not update WMC: " + e.getMessage(), e );
    205            }
    206            request.setAttribute( "ACTION", getInitParameter( "ACTION" ) );
    207
    208            request.getRequestDispatcher( "igeoportal/enterprise.jsp" ).forward( request, response );
    209        }
    210
    211        /**
    212         * moves a node/layer to a new position used parameters: NODE, BEFORENODE, PARENTNODE
    213         *
    214         * @return true if moved layer/node was visible and a repaint is necessary
    215         */
    216        private static boolean handleMoveNode( Map<String, String> parameter, ViewContext vc ) {
    217            int nodeID = getNodeID( parameter, "NODE" );
    218            boolean visibleLayer;
    219            if ( nodeID != -1 ) { // move a node
    220                int beforeNodeID = getNodeID( parameter, "BEFORENODE" );
    221                int parentNodeID = getNodeID( parameter, "PARENTNODE" );
    222                vc.getLayerList().moveNodes( nodeID, beforeNodeID );
    223                Node node = vc.getGeneral().getExtension().getLayerTreeRoot().getNode( nodeID );
    224                Node parent;
    225                if ( parentNodeID == -1 ) {
    226                    parent = vc.getGeneral().getExtension().getLayerTreeRoot();
    227                } else {
    228                    parent = vc.getGeneral().getExtension().getLayerTreeRoot().getNode( parentNodeID );
    229                }
    230                node.getParent().removeNode( nodeID );
    231                node.setParent( parent );
    232                int beforeNodeIndex = parent.getIndex( beforeNodeID );
    233                if ( beforeNodeIndex == -1 ) {
    234                    parent.appendNode( node );
    235                } else {
    236                    parent.insertNode( node, beforeNodeIndex );
    237                }
    238                visibleLayer = PortalUtils.hasNodeVisibleLayers( vc, nodeID );
    239            } else { // move a layer with layer/servername
    240                StringPair layerName = getLayer( parameter, "NODE" );
    241                StringPair beforeLayerName = getLayer( parameter, "BEFORENODE" );
    242                int parentNodeId = getNodeID( parameter, "PARENTNODE" );
    243                Layer layer = vc.getLayerList().getLayer( layerName.first, layerName.second );
    244                layer.getExtension().setParentNodeId( parentNodeId );
    245                Layer beforeLayer = null;
    246                if ( beforeLayerName.second != "" ) {
    247                    beforeLayer = vc.getLayerList().getLayer( beforeLayerName.first, beforeLayerName.second );
    248                }
    249                vc.getLayerList().move( layer, beforeLayer );
    250                visibleLayer = !layer.isHidden();
    251            }
    252            return visibleLayer;
    253        }
    254
    255        /**
    256         * rename a node used parameters: NODE and NODETITLE
    257         */
    258        private static void handleRenameNode( Map<String, String> parameter, ViewContext vc )
    259                                throws ContextException {
    260            int nodeID = getNodeID( parameter, "NODE" );
    261            String title = parameter.get( "NODETITLE" );
    262            if ( title != null ) {
    263                if ( nodeID != -1 ) {
    264                    vc.getGeneral().getExtension().getLayerTreeRoot().getNode( nodeID ).setTitle( title );
    265                }
    266            }
    267        }
    268
    269        /**
    270         * removes a layer/node. when a node is removed, all child nodes/layers will be removed too used
    271         * parameters: NODE
    272         */
    273        private static void handleRemoveNode( Map<String, String> parameter, ViewContext vc ) {
    274            int nodeID = getNodeID( parameter, "NODE" );
    275            if ( nodeID != -1 ) {
    276                vc.getLayerList().removeLayers( nodeID );
    277                vc.getGeneral().getExtension().getLayerTreeRoot().removeNode( nodeID );
    278            } else {
    279                StringPair layer = getLayer( parameter, "NODE" );
    280                vc.getLayerList().removeLayer( layer.first, layer.second );
    281            }
    282        }
    283
    284        /**
    285         * adds a new node to the context used parameters: NODE, NODETITLE, PARENTNODE
    286         *
    287         * @return id for the next new node
    288         */
    289        private static String handleAddNode( Map<String, String> parameter, ViewContext vc )
    290                                throws ContextException {
    291            int nodeID = getNodeID( parameter, "NODE" );
    292            int parentNodeID = getNodeID( parameter, "PARENTNODE" );
    293            String nodeTitle = parameter.get( "NODETITLE" );
    294            if ( nodeTitle == null ) {
    295                nodeTitle = "";
    296            }
    297            Node root = vc.getGeneral().getExtension().getLayerTreeRoot();
    298            if ( parentNodeID != -1 ) {
    299                root = root.getNode( parentNodeID );
    300            }
    301            Node newNode = new Node( nodeID, root, nodeTitle, true, true );
    302            root.insertNode( newNode, 0 );
    303            String nextNodeID = "node-" + ( root.getMaxNodeId() + 1 );
    304            return nextNodeID;
    305        }
    306
    307        /**
    308         * sets visibility for layers or complete nodes used parameters: HIDDEN (boolean) and NODE
    309         */
    310        private static void handleSetVisibility( Map<String, String> parameter, ViewContext vc ) {
    311            boolean hidden = Boolean.parseBoolean( parameter.get( "HIDDEN" ) );
    312            int nodeID = getNodeID( parameter, "NODE" );
    313            if ( nodeID != -1 ) { // change complete node
    314                PortalUtils.setVisibility( vc, nodeID, hidden );
    315            } else { // change single layer
    316                StringPair layerName = getLayer( parameter, "NODE" );
    317                Layer layer = vc.getLayerList().getLayer( layerName.first, layerName.second );
    318                layer.setHidden( hidden );
    319            }
    320        }
    321
    322        /**
    323         * sends layer/node data for requested node as JSON to response stream used parameters: NODE
    324         */
    325        private static void handleTreeData( Map<String, String> parameter, ViewContext vc, HttpServletResponse response )
    326                                throws IOException {
    327            StringBuilder sb = new StringBuilder();
    328            sb.append( '[' );
    329
    330            LayerList layerList = vc.getLayerList();
    331            String nodeValue = parameter.get( "NODE" );
    332            // root node
    333            if ( nodeValue.equals( "/" ) ) {
    334                // return all nodes for root
    335                Node[] nodes = vc.getGeneral().getExtension().getLayerTreeRoot().getNodes();
    336                for ( Node n : nodes ) {
    337                    boolean hidden = !PortalUtils.hasNodeVisibleLayers( vc, n.getId() );
    338                    sb.append( String.format( "{'text': '%s', 'iconCls': 'folder', 'id':'node-%s', "
    339                                              + "'leaf': false, 'checked': %s, 'expanded': true},", n.getTitle(),
    340                                              n.getId(), hidden ? "false" : "true" ) );
    341                }
    342            } else {
    343                int nodeID = getNodeID( parameter, "NODE" );
    344                if ( nodeID != -1 ) {
    345                    // first add the nodes...
    346                    Node[] nodes = vc.getGeneral().getExtension().getLayerTreeRoot().getNode( nodeID ).getNodes();
    347                    for ( Node n : nodes ) {
    348                        boolean hidden = !PortalUtils.hasNodeVisibleLayers( vc, n.getId() );
    349                        sb.append( String.format( "{'text': '%s', 'iconCls': 'folder', 'id':'node-%s', "
    350                                                  + "'leaf': false, 'checked': %s},", n.getTitle(), n.getId(),
    351                                                  hidden ? "false" : "true" ) );
    352                    }
    353                    // ...then all layers for this node
    354                    for ( Layer layer : layerList.getLayersByNodeId( nodeID ) ) {
    355                        if ( layer.getServer().getCapabilities() != null ) {
    356                            URL s = null;
    357                            if ( layer.getStyleList().getCurrentStyle().getLegendURL() != null ) {
    358                                s = layer.getStyleList().getCurrentStyle().getLegendURL().getOnlineResource();
    359                            }
    360                            sb.append( String.format(
    361                                                      "{'text': '%s', 'id':'%s', 'leaf': true, 'checked': %s, 'img': '%s'},",
    362                                                      layer.getTitle(), layer.getName() + '|'
    363                                                                        + layer.getServer().getOnlineResource(),
    364                                                      layer.isHidden() ? "false" : "true", s ) );
    365                        }
    366                    }
    367                }
    368            }
    369            sb.append( ']' );
    370            String fixedDemoOutput = sb.toString();
    371            response.setContentType( "application/json" );
    372            response.setCharacterEncoding( "utf-8" );
    373            response.getWriter().write( fixedDemoOutput );
    374        }
    375
    376        /**
    377         * extracts the numeric node id from the node id sting (eg. (String)node-42 -> (int)42)
    378         *
    379         * @param parameter
    380         *            the parameter map
    381         * @param paramName
    382         *            key of the parameter
    383         * @return the node id or -1, if not found
    384         */
    385        private static int getNodeID( Map<String, String> parameter, String paramName ) {
    386            String paramValue = parameter.get( paramName.toUpperCase() );
    387            int nodeID = -1;
    388            if ( paramValue != null && paramValue.startsWith( "node-" ) ) {
    389                nodeID = Integer.parseInt( paramValue.substring( paramValue.lastIndexOf( '-' ) + 1 ) );
    390            }
    391            return nodeID;
    392        }
    393
    394        /**
    395         * extracts the layer and servername from a node id
    396         *
    397         * @param parameter
    398         *            the parameter map
    399         * @param paramName
    400         *            key of the parameter
    401         * @return the layer (first) and servername (second)
    402         */
    403        private static StringPair getLayer( Map<String, String> parameter, String paramName ) {
    404            String paramValue = parameter.get( paramName.toUpperCase() );
    405            StringPair result = new StringPair();
    406            if ( paramValue != null ) {
    407                String[] values = paramValue.split( "\\|", 2 );
    408                result.first = values[0];
    409                if ( values.length == 2 ) {
    410                    result.second = values[1];
    411                } else {
    412                    result.second = "";
    413                }
    414            }
    415            return result;
    416        }
    417
    418    }