001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/enterprise/control/ApplicationHandler.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53177 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     
043     ---------------------------------------------------------------------------*/
044    package org.deegree.enterprise.control;
045    
046    import java.io.BufferedReader;
047    import java.io.File;
048    import java.io.IOException;
049    import java.io.InputStreamReader;
050    import java.io.Reader;
051    import java.io.StringReader;
052    import java.net.MalformedURLException;
053    import java.net.URL;
054    import java.net.URLDecoder;
055    import java.nio.charset.Charset;
056    import java.util.ArrayList;
057    import java.util.HashMap;
058    import java.util.List;
059    
060    import javax.servlet.ServletRequest;
061    import javax.servlet.http.HttpServletRequest;
062    
063    import org.deegree.datatypes.parameter.GeneralOperationParameterIm;
064    import org.deegree.datatypes.parameter.ParameterValueIm;
065    import org.deegree.framework.log.ILogger;
066    import org.deegree.framework.log.LoggerFactory;
067    import org.deegree.framework.xml.NamespaceContext;
068    import org.deegree.framework.xml.XMLParsingException;
069    import org.deegree.framework.xml.XMLTools;
070    import org.deegree.ogcbase.CommonNamespaces;
071    import org.w3c.dom.Document;
072    import org.w3c.dom.Element;
073    import org.w3c.dom.Node;
074    import org.w3c.dom.NodeList;
075    import org.xml.sax.SAXException;
076    
077    /**
078     * Handler for all web events.
079     * 
080     * @author <a href="mailto:tfriebe@gmx.net">Torsten Friebe</a>
081     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
082     * 
083     * @version $Revision: $, $Date: 15.10.2007 15:39:10$
084     */
085    public class ApplicationHandler implements WebListener {
086    
087        private static final ILogger LOG = LoggerFactory.getLogger( ApplicationHandler.class );
088    
089        private static final HashMap<String, Class> handler = new HashMap<String, Class>();
090    
091        private static final HashMap<String, String> handlerNext = new HashMap<String, String>();
092    
093        private static final HashMap<String, String> handlerANext = new HashMap<String, String>();
094    
095        private static final HashMap<String, List<ParameterValueIm>> handlerParam = new HashMap<String, List<ParameterValueIm>>();
096    
097        private static final String EVENT = "event";
098    
099        private static final String NAME = "name";
100    
101        private static final String CLASS = "class";
102    
103        private static final String NEXT = "next";
104    
105        private static final String ALTERNATIVENEXT = "alternativeNext";
106    
107        /**
108         * Creates a new ApplicationHandler object.
109         * 
110         * @param configFile
111         * @throws Exception
112         */
113        public ApplicationHandler( String configFile ) throws Exception {
114            ApplicationHandler.initHandler( configFile );
115        }
116    
117        /**
118         * Handles all web action events. Calls the specified listener using the mapping defined in
119         * control.xml file.
120         * 
121         * @param e
122         *            the action event generated out of the incoming http POST event.
123         */
124        public void actionPerformed( FormEvent e ) {
125            Object source = e.getSource();
126    
127            if ( source instanceof HttpServletRequest ) {
128                HttpServletRequest request = (HttpServletRequest) source;
129    
130                String actionName = request.getParameter( "action" );
131                LOG.logDebug( "Actionname: " + actionName );
132                if ( actionName != null ) {
133                    // handle simple KVP encoded request
134                    try {
135                        if ( "version".equalsIgnoreCase( actionName ) ) {
136                            this.showVersion( request );
137                        } else {
138                            try {
139                                this.delegateToHelper( actionName, e );
140                            } catch ( Exception ex ) {
141                                ex.printStackTrace();
142                                LOG.logError( "Action " + actionName + " is unknown!" );
143                            }
144                        }
145                    } catch ( Exception ex ) {
146                        request.setAttribute( "next", "error.jsp" );
147                        request.setAttribute( "javax.servlet.jsp.jspException", ex );
148                    }
149                } else {
150                    // handle RPC encoded request
151                    try {
152                        RPCMethodCall mc = getMethodCall( request );
153                        e = new RPCWebEvent( e, mc );
154                        this.delegateToHelper( mc.getMethodName(), e );
155                    } catch ( RPCException re ) {
156                        re.printStackTrace();
157                        request.setAttribute( "next", "error.jsp" );
158                        request.setAttribute( "javax.servlet.jsp.jspException", re );
159                    } catch ( Exception ee ) {
160                        ee.printStackTrace();
161                        request.setAttribute( "next", "error.jsp" );
162                        request.setAttribute( "javax.servlet.jsp.jspException", ee );
163                    }
164                }
165            }
166        }
167    
168        /**
169         * extracts the RPC method call from the
170         * 
171         * @param request
172         * @return the RPCMethodCall
173         * @throws RPCException
174         */
175        private RPCMethodCall getMethodCall( ServletRequest request )
176                                throws RPCException {
177            
178            String s = request.getParameter( "rpc" );
179            
180            try {
181                if ( s == null ) {
182                    StringBuffer sb = new StringBuffer( 1000 );
183                    try {
184                        BufferedReader br = request.getReader();
185                        String line = null;
186                        while ( ( line = br.readLine() ) != null ) {
187                            sb.append( line );
188                        }
189                        br.close();
190                    } catch ( Exception e ) {
191                        throw new RPCException( "Error reading stream from servlet\n" + e.toString() );
192                    }
193    
194                    s = sb.toString();
195                    LOG.logDebug( "found first (perhaps double) encoded String: " +  s );                
196                    s = URLDecoder.decode( s, Charset.defaultCharset().name() );
197                    String[] splitter = s.split( " \t<>" );
198                    if( splitter.length == 1 ){
199                            s = URLDecoder.decode( s, Charset.defaultCharset().name() );
200                            LOG.logDebug( "Decoding a second time: " +  s );
201                    }
202                    
203                    int pos1 = s.indexOf( "<methodCall>" );
204                    int pos2 = s.indexOf( "</methodCall>" );
205                    if ( pos1 < 0 ) {
206                        throw new RPCException( "request doesn't contain a RPC methodCall" );
207                    }
208                    s = s.substring( pos1, pos2 + 13 );
209                } else {
210                    s = URLDecoder.decode( s, Charset.defaultCharset().name() );
211                }
212            } catch ( Exception e ) {
213                e.printStackTrace();
214                throw new RPCException( e.toString() );
215            }
216    
217            LOG.logDebug( "RPC: " + s );
218            
219            return RPCFactory.createRPCMethodCall( new StringReader( s ) );
220    
221        }
222    
223        /**
224         * 
225         * 
226         * @param action
227         * @param e
228         * 
229         * @throws Exception
230         */
231        protected void delegateToHelper( String action, FormEvent e )
232                                throws Exception {
233            action = action.trim();
234            Class cls = ApplicationHandler.handler.get( action );
235            AbstractListener helper = (AbstractListener) cls.newInstance();
236            helper.setNextPage( handlerNext.get( action ) );
237            helper.setDefaultNextPage( handlerNext.get( action ) );
238            helper.setAlternativeNextPage( handlerANext.get( action ) );
239            helper.setInitParameterList( handlerParam.get( action ) );
240            helper.handle( e );
241        }
242    
243        /**
244         * 
245         * 
246         * @param request
247         */
248        protected void showVersion( ServletRequest request ) {
249            request.setAttribute( "next", "snoopy.jsp" );
250        }
251    
252        /**
253         * 
254         * 
255         * @param configFile
256         * 
257         * @throws IOException
258         * @throws MalformedURLException
259         * @throws SAXException
260         */
261        private static void initHandler( String configFile )
262                                throws IOException, MalformedURLException, SAXException {
263            LOG.logInfo( "Reading event handler configuration file:" + configFile );
264            /*
265             * Read resource into Document...
266             */
267            URL url = new File( configFile ).toURL();
268            Reader reader = new InputStreamReader( url.openStream() );
269            Document doc = XMLTools.parse( reader );
270            /*
271             * Read and create page elements
272             */
273            NodeList nodes = doc.getElementsByTagName( EVENT );
274    
275            for ( int i = 0; i < nodes.getLength(); i++ ) {
276                String name = XMLTools.getAttrValue( nodes.item( i ), null, NAME, null );
277                String cls = XMLTools.getAttrValue( nodes.item( i ), null, CLASS, null );
278                String nextPage = XMLTools.getAttrValue( nodes.item( i ), null, NEXT, null );
279                String anextPage = XMLTools.getAttrValue( nodes.item( i ), null, ALTERNATIVENEXT, null );
280    
281                if ( anextPage == null ) {
282                    anextPage = nextPage;
283                }
284    
285                Class clscls = null;
286                try {
287                    clscls = Class.forName( cls );
288                    handler.put( name.trim(), clscls );
289                    handlerNext.put( name.trim(), nextPage );
290                    handlerANext.put( name.trim(), anextPage );
291                    List<ParameterValueIm> pvList = parseParameters( nodes.item( i ) );
292                    handlerParam.put( name.trim(), pvList );
293                    LOG.logInfo( "Handler '" + clscls + "' bound to event '" + name + "'" );
294                } catch ( Exception ex ) {
295                    ex.printStackTrace();
296                    LOG.logError( "No handler '" + cls + "' specified for event '" + name + "'", ex );
297                    throw new SAXException( "No handler class specified for event:" + name + " " + cls + "\n" + ex );
298                }
299            }
300        }
301    
302        /**
303         * several parameters can be passed to each Listener by adding
304         * 
305         * <pre>
306         *   &lt;parameter&gt;
307         *       &lt;name&gt;aName&lt;/name&gt;
308         *       &lt;value&gt;aValue&lt;/value&gt;
309         *   &lt;/parameter&gt;
310         * </pre>
311         * 
312         * sections to the corresponding &lt;event&gt; element.
313         * 
314         * @param node
315         * @return a List of ParameterValueIm
316         * @throws XMLParsingException
317         */
318        private static List<ParameterValueIm> parseParameters( Node node )
319                                throws XMLParsingException {
320    
321            NamespaceContext nsc = CommonNamespaces.getNamespaceContext();
322            List nodes = XMLTools.getNodes( node, "parameter", nsc );
323            List<ParameterValueIm> pvs = new ArrayList<ParameterValueIm>();
324            for ( int i = 0; i < nodes.size(); i++ ) {
325                Element element = (Element) nodes.get( i );
326                String name = XMLTools.getRequiredNodeAsString( element, "name", nsc );
327                String value = XMLTools.getRequiredNodeAsString( element, "value", nsc );
328                GeneralOperationParameterIm descriptor = new GeneralOperationParameterIm( name, null, 1, 1 );
329                pvs.add( new ParameterValueIm( descriptor, value ) );
330            }
331    
332            return pvs;
333        }
334    
335    }