/*---------------- FILE HEADER ------------------------------------------ This file is part of deegree. Copyright (C) 2001-2006 by: EXSE, Department of Geography, University of Bonn http://www.giub.uni-bonn.de/deegree/ lat/lon GmbH http://www.lat-lon.de This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Andreas Poth lat/lon GmbH Aennchenstr. 19 53177 Bonn Germany E-Mail: poth@lat-lon.de Prof. Dr. Klaus Greve Department of Geography University of Bonn Meckenheimer Allee 166 53115 Bonn Germany E-Mail: greve@giub.uni-bonn.de ---------------------------------------------------------------------------*/ package org.deegree.portal.standard.context.control; import java.io.File; import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.xml.transform.TransformerException; import org.deegree.enterprise.control.FormEvent; import org.deegree.enterprise.control.RPCMember; import org.deegree.enterprise.control.RPCMethodCall; import org.deegree.enterprise.control.RPCParameter; import org.deegree.enterprise.control.RPCStruct; import org.deegree.enterprise.control.RPCUtils; import org.deegree.enterprise.control.RPCWebEvent; import org.deegree.framework.log.ILogger; import org.deegree.framework.log.LoggerFactory; import org.deegree.framework.util.StringTools; import org.deegree.framework.xml.NamespaceContext; import org.deegree.framework.xml.XMLFragment; import org.deegree.framework.xml.XMLTools; import org.deegree.framework.xml.XSLTDocument; import org.deegree.model.spatialschema.Envelope; import org.deegree.ogcbase.CommonNamespaces; import org.deegree.portal.Constants; import org.deegree.portal.context.ViewContext; import org.deegree.portal.context.WebMapContextFactory; import org.deegree.portal.context.XMLFactory; /** * This class handles switch of map contexts. The basic logic is (1) receiving an rpc request with a * context name (xml) and, possibly, a bounding box, (2) transforming this xml using a provided xsl, * and (3) forwarding the result back to the browser. <br/> Most of the action takes place in * <code>doTransformContext</code>, and is delegated to the <code>ContextTransformer</code>.<br/> * In order to perform the transformation from a context xml to a html, a xslt is provided. This is * per default called <code>context2HTML.xsl</code> (see the class member * <code>DEFAULT_CTXT2HTML</code>) and should be put under * <code>${context-home}/WEB-INF/xml/</code>. <br/> * * @author <a href="mailto:taddei@lat-lon.de">Ugo Taddei</a> * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> * * @author last edited by: $Author: mays $ * * @version 1.0. $Revision: 1.18 $, $Date: 2006/11/14 10:19:08 $ * */ public class ContextSwitchListener extends AbstractContextListener { private static final NamespaceContext nsContext = CommonNamespaces.getNamespaceContext(); private static final ILogger LOG = LoggerFactory.getLogger( ContextSwitchListener.class ); /** * A <code>String</code> used as a key value for the new html (of the client). This key is * used in the JSP which output the new(-ly transformed html. */ public static final String NEW_CONTEXT_HTML = "NEW_CONTEXT_HTML"; /** * A <code>String</code> defining the name of the xsl file that defines the transformation * from a context to html. This must be placed, together with the map context xml and helper xsl * files, under <code>${context-home}/WEB-INF/xml/</code>. */ protected static final String DEFAULT_CTXT2HTML = "WEB-INF/conf/igeoportal/context2HTML.xsl"; /** * script to transform a standard WMC document into a deegree WMC */ protected static final String WEBMAPCTXT2HTML = "WEB-INF/conf/igeoportal/defaultcontext.xsl"; /** * @see org.deegree.enterprise.control.WebListener#actionPerformed(org.deegree.enterprise.control.FormEvent) */ public void actionPerformed( FormEvent event ) { RPCMethodCall mc = ( (RPCWebEvent) event ).getRPCMethodCall(); RPCParameter[] pars = mc.getParameters(); RPCStruct struct = (RPCStruct) pars[0].getValue(); // get map context value String curContxt = RPCUtils.getRpcPropertyAsString( struct, "mapContext" ); // now get bbox Envelope bbox = null; RPCMember rpcStruct = struct.getMember( Constants.RPC_BBOX ); if ( rpcStruct != null ) { RPCStruct bboxStruct = (RPCStruct) rpcStruct.getValue(); bbox = extractBBox( bboxStruct ); } // get the servlet path using the session HttpSession session = ( (HttpServletRequest) this.getRequest() ).getSession(); // path to context dir String path2Dir = getHomePath(); // context and xsl files String mapContext = "file://" + path2Dir + "WEB-INF/conf/igeoportal/" + curContxt; String xslFilename = "file://" + path2Dir + DEFAULT_CTXT2HTML; String newHtml = null; String sid = null; try { // read session ID trying different possible sources sid = readSessionID( struct ); // ContextSwitchLister.actionPerformed is the first action that // will be performed if a user enter iGeoPortal. So store the // users sessionID into his HTTP session for futher usage session.setAttribute( "SESSIONID", sid ); // if no sessionID is available the context will be read as // anonymous user which will cause that layers assigned to a // authorized user may will not be parsed correctly XMLFragment xml = getContext( mapContext, bbox, sid ); newHtml = doTransformContext( xslFilename, xml ); } catch ( Exception e ) { LOG.logDebug( e.getMessage(), e ); gotoErrorPage( StringTools.stackTraceToString( e ) ); return; } session.setAttribute( NEW_CONTEXT_HTML, newHtml ); // need to keep a reference to the last context... // often used when changing/saving the shown context try { writeContextToSession( mapContext, sid ); } catch ( Exception e ) { LOG.logError( e.getMessage(), e ); gotoErrorPage( StringTools.stackTraceToString( e ) ); } } /** * writes the context the user choosed to the users session. It can be accessed using * <tt>Constants.CURRENTMAPCONTEXT</tt> key value * * @param context * @throws Exception */ protected void writeContextToSession( String context, String sessionID ) throws Exception { URL ctxtUrl = new URL( context ); ViewContext vc = WebMapContextFactory.createViewContext( ctxtUrl, null, sessionID ); HttpSession session = ( (HttpServletRequest) getRequest() ).getSession(); session.setAttribute( Constants.CURRENTMAPCONTEXT, vc ); } /** * returns the context to be used as a String * * @param context * @param bbox * @return * @throws Exception */ protected XMLFragment getContext( String context, Envelope bbox, String sessionID ) throws Exception { XMLFragment xml = new XMLFragment(); try { LOG.logInfo( "reading context: " + context ); URL ctxtUrl = new URL( context ); if ( bbox == null ) { // no bbox, do it as usual xml.load( ctxtUrl ); } else { ViewContext vc = WebMapContextFactory.createViewContext( ctxtUrl, null, sessionID ); changeBBox( vc, bbox ); xml = XMLFactory.export( vc ); } // if at least one element is present we have a deegree Web Map Context // document; otherwise we have a standard Web Map Context document that // must be transformed into a deegree WMC document List nl = XMLTools.getNodes( xml.getRootElement().getOwnerDocument(), "cntxt:ViewContext/cntxt:General/cntxt:Extension/dgcntxt:IOSettings", nsContext ); if ( nl.size() == 0 ) { xml = transformToDeegreeContext( xml ); } } catch ( Exception e ) { throw e; } return xml; } /** * transforms a standard Web Map Context document to a deegree Web Map Context document * * @param doc * @return * @throws Exception */ private XMLFragment transformToDeegreeContext( XMLFragment xml ) throws Exception { String xslFilename = getHomePath() + WEBMAPCTXT2HTML; File file = new File( xslFilename ); XSLTDocument xslt = new XSLTDocument(); xslt.load( file.toURL() ); xml = xslt.transform( xml ); return xml; } /** * Transforms the context pointed to by <code>context</code> into html using * <code>xsltURL</code> (though this is currently fixed; there's really no need to define * one's wn xsl). * * @param context * the context xml * @param xsl * the transformation xml */ protected String doTransformContext( String xsl, XMLFragment xml ) { StringWriter sw = new StringWriter( 60000 ); try { XSLTDocument xslt = new XSLTDocument(); xslt.load( new URL( xsl ) ); xml = xslt.transform( xml ); xml.write( sw ); } catch ( MalformedURLException e1 ) { LOG.logError( e1.getMessage(), e1 ); gotoErrorPage( "<b>Error creating the context URL: </b>" + e1.getMessage() + "<br/>" + StringTools.stackTraceToString( e1 ) ); } catch ( TransformerException e1 ) { LOG.logError( e1.getMessage(), e1 ); gotoErrorPage( "<b>Error transforming the context: </b>" + e1.getMessage() + "<br/>" + StringTools.stackTraceToString( e1 ) ); } catch ( Exception e1 ) { LOG.logError( e1.getMessage(), e1 ); gotoErrorPage( "<b>Error in context transformer: </b>" + e1.getMessage() + "<br/>" + StringTools.stackTraceToString( e1 ) ); } return sw.toString(); } } /* ******************************************************************** Changes to this class. What the people have been up to: $Log: ContextSwitchListener.java,v $ Revision 1.18 2006/11/14 10:19:08 mays restore changes of revision 1.16 as they where overwritten in 1.17: made writeContextToSession() and getContext() protected to use in subclass Revision 1.17 2006/11/10 15:51:12 plum ap: fixed session handling Revision 1.15 2006/10/17 20:31:18 poth *** empty log message *** Revision 1.14 2006/08/29 20:18:09 poth code for initial accessing a session ID added Revision 1.13 2006/08/29 19:54:14 poth footer corrected Revision 1.12 2006/08/29 19:18:16 poth reading session ID from RPC centralized Revision 1.11 2006/08/27 07:51:04 poth *** empty log message *** Revision 1.10 2006/08/24 17:03:47 poth pass seesionid if available to WebMapContextFactory Revision 1.9 2006/08/24 12:15:52 poth Web Map Context Factory prepared to use User name/password and/or a sessionID requesting resources (Layer) Revision 1.8 2006/05/22 09:30:35 poth *** empty log message *** Revision 1.7 2006/05/16 15:56:36 poth code cleanup ********************************************************************** */