001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/enterprise/control/ApplicationHandler.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.enterprise.control;
037    
038    import static org.deegree.framework.util.CharsetUtils.getSystemCharset;
039    
040    import java.io.BufferedReader;
041    import java.io.File;
042    import java.io.IOException;
043    import java.io.InputStreamReader;
044    import java.io.Reader;
045    import java.io.StringReader;
046    import java.net.MalformedURLException;
047    import java.net.URL;
048    import java.net.URLDecoder;
049    import java.nio.charset.Charset;
050    import java.util.ArrayList;
051    import java.util.HashMap;
052    import java.util.List;
053    
054    import javax.servlet.ServletRequest;
055    import javax.servlet.http.HttpServletRequest;
056    
057    import org.deegree.datatypes.parameter.GeneralOperationParameterIm;
058    import org.deegree.datatypes.parameter.ParameterValueIm;
059    import org.deegree.framework.log.ILogger;
060    import org.deegree.framework.log.LoggerFactory;
061    import org.deegree.framework.xml.NamespaceContext;
062    import org.deegree.framework.xml.XMLParsingException;
063    import org.deegree.framework.xml.XMLTools;
064    import org.deegree.ogcbase.CommonNamespaces;
065    import org.w3c.dom.Document;
066    import org.w3c.dom.Element;
067    import org.w3c.dom.Node;
068    import org.w3c.dom.NodeList;
069    import org.xml.sax.SAXException;
070    
071    /**
072     * Handler for all web events.
073     *
074     * @author <a href="mailto:tfriebe@gmx.net">Torsten Friebe</a>
075     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
076     * @author last edited by: $Author: mays$
077     *
078     * @version $Revision: 18195 $, $Date: 21.08.2008 19:19:59$
079     */
080    public class ApplicationHandler implements WebListener {
081    
082        private static final ILogger LOG = LoggerFactory.getLogger( ApplicationHandler.class );
083    
084        private static final HashMap<String, Class<?>> handler = new HashMap<String, Class<?>>();
085    
086        private static final HashMap<String, String> handlerNext = new HashMap<String, String>();
087    
088        private static final HashMap<String, String> handlerANext = new HashMap<String, String>();
089    
090        private static final HashMap<String, List<ParameterValueIm>> handlerParam = new HashMap<String, List<ParameterValueIm>>();
091    
092        private static final String EVENT = "event";
093    
094        private static final String NAME = "name";
095    
096        private static final String CLASS = "class";
097    
098        private static final String NEXT = "next";
099    
100        private static final String ALTERNATIVENEXT = "alternativeNext";
101    
102        /**
103         * Creates a new ApplicationHandler object.
104         *
105         * @param configFile
106         * @throws Exception
107         */
108        public ApplicationHandler( String configFile ) throws Exception {
109            ApplicationHandler.initHandler( configFile );
110        }
111    
112        /**
113         * Handles all web action events. Calls the specified listener using the mapping defined in control.xml file.
114         *
115         * @param e
116         *            the action event generated out of the incoming http POST event.
117         */
118        public void actionPerformed( FormEvent e ) {
119            Object source = e.getSource();
120    
121            if ( source instanceof HttpServletRequest ) {
122                HttpServletRequest request = (HttpServletRequest) source;
123    
124                String actionName = request.getParameter( "action" );
125                LOG.logDebug( "Actionname: " + actionName );
126                if ( actionName != null ) {
127                    // handle simple KVP encoded request
128                    try {
129                        if ( "version".equalsIgnoreCase( actionName ) ) {
130                            this.showVersion( request );
131                        } else {
132                            try {
133                                this.delegateToHelper( actionName, e );
134                            } catch ( Exception ex ) {
135                                ex.printStackTrace();
136                                LOG.logError( "Action " + actionName + " is unknown!" );
137                            }
138                        }
139                    } catch ( Exception ex ) {
140                        request.setAttribute( "next", "error.jsp" );
141                        request.setAttribute( "javax.servlet.jsp.jspException", ex );
142                    }
143                } else {
144                    // handle RPC encoded request
145                    try {
146                        RPCMethodCall mc = getMethodCall( request );
147                        e = new RPCWebEvent( e, mc );
148                        this.delegateToHelper( mc.getMethodName(), e );
149                    } catch ( RPCException re ) {
150                        re.printStackTrace();
151                        request.setAttribute( "next", "error.jsp" );
152                        request.setAttribute( "javax.servlet.jsp.jspException", re );
153                    } catch ( Exception ee ) {
154                        ee.printStackTrace();
155                        request.setAttribute( "next", "error.jsp" );
156                        request.setAttribute( "javax.servlet.jsp.jspException", ee );
157                    }
158                }
159            }
160        }
161    
162        /**
163         * extracts the RPC method call from the
164         *
165         * @param request
166         * @return the RPCMethodCall
167         * @throws RPCException
168         */
169        private RPCMethodCall getMethodCall( ServletRequest request )
170                                throws RPCException {
171    
172            String s = request.getParameter( "rpc" );
173    
174            try {
175                if ( s == null ) {
176                    StringBuffer sb = new StringBuffer( 1000 );
177                    try {
178                        BufferedReader br = request.getReader();
179                        String line = null;
180                        while ( ( line = br.readLine() ) != null ) {
181                            sb.append( line );
182                        }
183                        br.close();
184                    } catch ( Exception e ) {
185                        throw new RPCException( "Error reading stream from servlet\n" + e.toString() );
186                    }
187    
188                    s = sb.toString();
189                    LOG.logDebug( "found first (perhaps double) encoded String: " + s );
190                    s = URLDecoder.decode( s, getSystemCharset() );
191                    String[] splitter = s.split( " \t<>" );
192                    if ( splitter.length == 1 ) {
193                        s = URLDecoder.decode( s, getSystemCharset() );
194                        LOG.logDebug( "Decoding a second time: " + s );
195                    }
196    
197                    int pos1 = s.indexOf( "<methodCall>" );
198                    int pos2 = s.indexOf( "</methodCall>" );
199                    if ( pos1 < 0 ) {
200                        throw new RPCException( "request doesn't contain a RPC methodCall" );
201                    }
202                    s = s.substring( pos1, pos2 + 13 );
203                } else {
204                   s = URLDecoder.decode( s, Charset.defaultCharset().displayName() );
205                }
206            } catch ( Exception e ) {
207                e.printStackTrace();
208                throw new RPCException( e.toString() );
209            }
210            LOG.logDebug( "RPC: " + s );
211    
212            return RPCFactory.createRPCMethodCall( new StringReader( s ) );
213    
214        }
215    
216        /**
217         *
218         *
219         * @param action
220         * @param e
221         *
222         * @throws Exception
223         */
224        protected void delegateToHelper( String action, FormEvent e )
225                                throws Exception {
226            action = action.trim();
227            Class<?> cls = ApplicationHandler.handler.get( action );
228            AbstractListener helper = (AbstractListener) cls.newInstance();
229            helper.setNextPage( handlerNext.get( action ) );
230            helper.setDefaultNextPage( handlerNext.get( action ) );
231            helper.setAlternativeNextPage( handlerANext.get( action ) );
232            helper.setInitParameterList( handlerParam.get( action ) );
233            helper.handle( e );
234        }
235    
236        /**
237         *
238         *
239         * @param request
240         */
241        protected void showVersion( ServletRequest request ) {
242            request.setAttribute( "next", "snoopy.jsp" );
243        }
244    
245        /**
246         *
247         *
248         * @param configFile
249         *
250         * @throws IOException
251         * @throws MalformedURLException
252         * @throws SAXException
253         */
254        private static void initHandler( String configFile )
255                                throws IOException, MalformedURLException, SAXException {
256            LOG.logInfo( "Reading event handler configuration file:" + configFile );
257            /*
258             * Read resource into Document...
259             */
260            URL url = new File( configFile ).toURL();
261            Reader reader = new InputStreamReader( url.openStream() );
262            Document doc = XMLTools.parse( reader );
263            /*
264             * Read and create page elements
265             */
266            NodeList nodes = doc.getElementsByTagName( EVENT );
267    
268            for ( int i = 0; i < nodes.getLength(); i++ ) {
269                String name = XMLTools.getAttrValue( nodes.item( i ), null, NAME, null );
270                String cls = XMLTools.getAttrValue( nodes.item( i ), null, CLASS, null );
271                String nextPage = XMLTools.getAttrValue( nodes.item( i ), null, NEXT, null );
272                String anextPage = XMLTools.getAttrValue( nodes.item( i ), null, ALTERNATIVENEXT, null );
273    
274                if ( anextPage == null ) {
275                    anextPage = nextPage;
276                }
277    
278                Class<?> clscls = null;
279                try {
280                    clscls = Class.forName( cls );
281                    handler.put( name.trim(), clscls );
282                    handlerNext.put( name.trim(), nextPage );
283                    handlerANext.put( name.trim(), anextPage );
284                    List<ParameterValueIm> pvList = parseParameters( nodes.item( i ) );
285                    handlerParam.put( name.trim(), pvList );
286                    LOG.logInfo( "Handler '" + clscls + "' bound to event '" + name + "'" );
287                } catch ( Exception ex ) {
288                    ex.printStackTrace();
289                    LOG.logError( "No handler '" + cls + "' specified for event '" + name + "'", ex );
290                    throw new SAXException( "No handler class specified for event:" + name + " " + cls + "\n" + ex );
291                }
292            }
293        }
294    
295        /**
296         * several parameters can be passed to each Listener by adding
297         *
298         * <pre>
299         *   &lt;parameter&gt;
300         *       &lt;name&gt;aName&lt;/name&gt;
301         *       &lt;value&gt;aValue&lt;/value&gt;
302         *   &lt;/parameter&gt;
303         * </pre>
304         *
305         * sections to the corresponding &lt;event&gt; element.
306         *
307         * @param node
308         * @return a List of ParameterValueIm
309         * @throws XMLParsingException
310         */
311        private static List<ParameterValueIm> parseParameters( Node node )
312                                throws XMLParsingException {
313    
314            NamespaceContext nsc = CommonNamespaces.getNamespaceContext();
315            List<Node> nodes = XMLTools.getNodes( node, "parameter", nsc );
316            List<ParameterValueIm> pvs = new ArrayList<ParameterValueIm>();
317            for ( int i = 0; i < nodes.size(); i++ ) {
318                Element element = (Element) nodes.get( i );
319                String name = XMLTools.getRequiredNodeAsString( element, "name", nsc );
320                String value = XMLTools.getRequiredNodeAsString( element, "value", nsc );
321                GeneralOperationParameterIm descriptor = new GeneralOperationParameterIm( name, null, 1, 1 );
322                pvs.add( new ParameterValueIm( descriptor, value ) );
323            }
324    
325            return pvs;
326        }
327    
328    }