// $Id: OGCServletController.java,v 1.66 2006/11/22 14:06:26 schmitz Exp $ /*---------------- 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 53115 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.enterprise.servlet; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.InetAddress; import java.net.URL; import java.text.MessageFormat; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.deegree.enterprise.AbstractOGCServlet; import org.deegree.enterprise.ServiceException; import org.deegree.framework.log.ILogger; import org.deegree.framework.log.LoggerFactory; import org.deegree.framework.util.KVP2Map; import org.deegree.framework.util.StringTools; import org.deegree.framework.util.WebappResourceResolver; import org.deegree.framework.version.Version; import org.deegree.framework.xml.XMLFragment; import org.deegree.ogcwebservices.ExceptionReport; import org.deegree.ogcwebservices.OGCRequestFactory; import org.deegree.ogcwebservices.OGCWebServiceException; import org.deegree.ogcwebservices.OGCWebServiceRequest; import org.deegree.owscommon.XMLFactory; /** * An <code>OGCServletController</code> handles all incoming requests. The controller for all OGC * service requests. Dispatcher to specific handler for WMS, WFS and other. * * @author <a href="mailto:tfr@users.sourceforge.net">Torsten Friebe </a> * * @author last edited by: $Author: schmitz $ * * @see <a * href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/FrontController.html">Front * controller </a> */ public class OGCServletController extends AbstractOGCServlet { /** * address is the url of the client which requests. */ public static String address = null; private static final long serialVersionUID = -4461759017823581221L; private static final ILogger LOG = LoggerFactory.getLogger( OGCServletController.class ); private static final String SERVICE = "services"; private static final String HANDLER_CLASS = ".handler"; private static final String HANDLER_CONF = ".config"; private static final Map<Class, String> SERVICE_FACTORIES_MAPPINGS = new HashMap<Class, String>(); private static final String ERR_MSG = "Can't set configuration for {0}"; /** * * * @param request * @param response * @throws ServiceException * @TODO refactor and optimize code for initializing handler */ public void doService( HttpServletRequest request, HttpServletResponse response ) throws ServiceException { Long time = new Long( System.currentTimeMillis() ); LOG.logInfo( StringTools.concat( 500, "Incoming request from ", request.getRemoteAddr(), "/", request.getRemoteHost(), " - ", time ) ); address = request.getRequestURL().toString(); LOG.logInfo( StringTools.concat( 500, "requested server address: ", address ) ); try { OGCWebServiceRequest ogcRequest = OGCRequestFactory.create( request ); LOG.logInfo( StringTools.concat( 500, "Handling request '", ogcRequest.getId(), "' from '", request.getRemoteAddr(), "' to service: '", ogcRequest.getServiceName(), "'" ) ); // get service from request String service = ogcRequest.getServiceName().toUpperCase(); // get handler instance ServiceDispatcher handler = ServiceLookup.getInstance().getHandler( service ); // dispatch request to specific handler handler.perform( ogcRequest, response ); } catch ( OGCWebServiceException e ) { LOG.logError( e.getMessage(), e ); sendException( response, e, request ); } catch ( ServiceException e ) { if ( e.getNestedException() instanceof OGCWebServiceException ) { sendException( response, (OGCWebServiceException) e.getNestedException(), request ); } else { sendException( response, new OGCWebServiceException( this.getClass().getName(), e.getMessage() ), request ); } LOG.logError( e.getMessage(), e ); } catch ( Exception e ) { e.printStackTrace(); LOG.logError( e.getMessage(), e ); throw new ServiceException( e ); } } /** * Sends the passed <tt>OGCWebServiceException</tt> to the calling client. * * @param response * @param e */ private void sendException( HttpServletResponse response, OGCWebServiceException e, HttpServletRequest request ) { LOG.logInfo( "Sending OGCWebServiceException to client." ); ExceptionReport report = new ExceptionReport( new OGCWebServiceException[] { e } ); // according to the JavaDoc, the map always has this type Map<String, String[]> map = request.getParameterMap(); boolean isWMS130 = false; for ( String str : map.keySet() ) { if ( str.equalsIgnoreCase( "version" ) ) { String[] version = map.get( str ); if ( version != null && version.length > 0 && version[0].equals( "1.3.0" ) ) { isWMS130 = true; } } } try { XMLFragment doc; if ( isWMS130 ) { response.setContentType( "text/xml" ); doc = XMLFactory.exportNS( report ); } else { response.setContentType( "application/vnd.ogc.se_xml" ); doc = XMLFactory.export( report ); } OutputStream os = response.getOutputStream(); doc.write( os ); os.close(); } catch ( Exception ex ) { LOG.logError( "ERROR: " + ex.getMessage(), ex ); } } /** * * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, * javax.servlet.http.HttpServletResponse) */ @Override protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { LOG.logDebug( "query string ", request.getQueryString() ); try { if ( request.getParameter( "RELOADDEEGREE" ) != null ) { reloadServices( request, response ); } else { this.doService( request, response ); } } catch ( ServiceException e ) { LOG.logError( e.getMessage(), e ); this.handleException( e.getMessage(), e, response ); } } /** * * @param request * @param response * @throws ServletException * @throws IOException */ private void reloadServices( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { Map map = KVP2Map.toMap( request ); String user = (String) map.get( "USER" ); String password = (String) map.get( "PASSWORD" ); String message = null; if ( getInitParameter( "USER" ) != null && getInitParameter( "PASSWORD" ) != null && getInitParameter( "USER" ).equals( user ) && getInitParameter( "PASSWORD" ).equals( password ) ) { initServices( getServletContext() ); ctDestroyed(); message = Messages.getString( "OGCServletController.reloadsuccess" ); } else { message = Messages.getString( "OGCServletController.reloadfailed" ); } PrintWriter pw = response.getWriter(); pw.print( message ); pw.flush(); pw.close(); } /* * (non-Javadoc) * * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, * javax.servlet.http.HttpServletResponse) */ @Override protected void doPost( HttpServletRequest arg0, HttpServletResponse arg1 ) throws ServletException, IOException { try { this.doService( arg0, arg1 ); } catch ( ServiceException e ) { LOG.logError( e.getMessage(), e ); this.handleException( e.getMessage(), e, arg1 ); } } /** * @see javax.servlet.GenericServlet#init() */ @Override public void init() throws ServletException { super.init(); LOG.logDebug( "Logger for " + this.getClass().getName() + " initialized." ); SERVICE_FACTORIES_MAPPINGS.put( CSWHandler.class, "org.deegree.ogcwebservices.csw.CSWFactory" ); SERVICE_FACTORIES_MAPPINGS.put( WFSHandler.class, "org.deegree.ogcwebservices.wfs.WFServiceFactory" ); SERVICE_FACTORIES_MAPPINGS.put( WCSHandler.class, "org.deegree.ogcwebservices.wcs.WCServiceFactory" ); SERVICE_FACTORIES_MAPPINGS.put( WMSHandler.class, "org.deegree.ogcwebservices.wms.WMServiceFactory" ); SERVICE_FACTORIES_MAPPINGS.put( SOSHandler.class, "org.deegree.ogcwebservices.sos.SOServiceFactory" ); SERVICE_FACTORIES_MAPPINGS.put( WPVSHandler.class, "org.deegree.ogcwebservices.wpvs.WPVServiceFactory" ); SERVICE_FACTORIES_MAPPINGS.put( WMPSHandler.class, "org.deegree.ogcwebservices.wmps.WMPServiceFactory" ); SERVICE_FACTORIES_MAPPINGS.put( WPSHandler.class, "org.deegree.ogcwebservices.wps.WPServiceFactory" ); SERVICE_FACTORIES_MAPPINGS.put( WASSHandler.class, "org.deegree.ogcwebservices.wass.common.WASServiceFactory" ); LOG.logInfo( "Starting deegree version " + Version.getVersion() + " on server: " + this.getServletContext().getServerInfo() + " / Java version: " + System.getProperty( "java.version" ) ); LOG.logInfo( "Initializing OGC services in context " + this.getServletContext().getServletContextName() + " and real path " + this.getServletContext().getRealPath( "/index.jsp" ) ); this.initServices( getServletContext() ); LOG.logInfo( "Installed OGC services: " + this.getServiceList() + " on server:" ); try { LOG.logInfo( "- IP: " + InetAddress.getLocalHost().getHostAddress() ); LOG.logInfo( "- Host name: " + InetAddress.getLocalHost().getHostName() ); LOG.logInfo( "- Domain name: " + InetAddress.getLocalHost().getCanonicalHostName() ); } catch ( Exception e ) { LOG.logError( e.getMessage(), e ); } //Sets the attributes for tomcat -> application.getAttribute(); in jsp sites this.getServletContext().setAttribute( "deegree_ogc_services", this.getServiceList() ); } private void initServices( ServletContext context ) throws ServletException { // get list of OGC services String serviceList = this.getRequiredInitParameter( SERVICE ); String[] serviceNames = StringTools.toArray( serviceList, ",", false ); ServiceLookup lookup = ServiceLookup.getInstance(); for ( int i = 0; i < serviceNames.length; i++ ) { LOG.logInfo( StringTools.concat( 100, "- Initializing ", serviceNames[i].toUpperCase(), " -" ) ); try { String className = this.getRequiredInitParameter( serviceNames[i] + HANDLER_CLASS ); Class handlerClzz = Class.forName( className ); // initialize each service factory String s = this.getRequiredInitParameter( serviceNames[i] + HANDLER_CONF ); URL serviceConfigurationURL = WebappResourceResolver.resolveFileLocation( s, context, LOG ); // set configuration LOG.logInfo( StringTools.concat( 300, "Reading configuration for ", serviceNames[i].toUpperCase(), " from URL: '", serviceConfigurationURL, "'." ) ); String factoryClassName = SERVICE_FACTORIES_MAPPINGS.get( handlerClzz ); Class factory = Class.forName( factoryClassName ); Method method = factory.getMethod( "setConfiguration", new Class[] { URL.class } ); method.invoke( factory, new Object[] { serviceConfigurationURL } ); // put handler to available service list lookup.addService( serviceNames[i].toUpperCase(), handlerClzz ); LOG.logInfo( StringTools.concat( 300, serviceNames[i].toUpperCase(), " successfully initialized." ) ); } catch ( ServletException e ) { LOG.logError( e.getMessage(), e ); } catch ( InvocationTargetException e ) { e.getTargetException().printStackTrace(); LOG.logError( this.produceMessage( ERR_MSG, new Object[] { serviceNames[i] } ), e ); } catch ( Exception e ) { LOG.logError( "Can't initialize OGC service:" + serviceNames[i], e ); } } } private String getRequiredInitParameter( String name ) throws ServletException { String paramValue = getInitParameter( name ); if ( paramValue == null ) { String msg = "Required init parameter '" + name + "' missing in web.xml"; LOG.logError( msg ); throw new ServletException( msg ); } return paramValue; } /** * @return the services, separated by "," */ private String getServiceList() { StringBuffer buf = new StringBuffer(); ServiceLookup lookup = ServiceLookup.getInstance(); for ( Iterator iter = lookup.getIterator(); iter.hasNext(); ) { String serviceName = (String) iter.next(); buf.append( serviceName ); if ( iter.hasNext() ) { buf.append( ',' ); } } return buf.toString(); } /** * Formats the provided string and the args array into a String using MessageFormat. * @param pattern * @param args * @return the message to present the client. */ private String produceMessage( String pattern, Object[] args ) { return new MessageFormat( pattern ).format( args ); } /** * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent) */ public void ctDestroyed() { LOG.logInfo( "Stopping context: " ); ServiceLookup lookup = ServiceLookup.getInstance(); for ( Iterator iter = lookup.getIterator(); iter.hasNext(); ) { String serviceName = (String) iter.next(); LOG.logInfo( "Stopping service " + serviceName ); try { String s = SERVICE_FACTORIES_MAPPINGS.get( lookup.getService( serviceName ) ); Class clzz = Class.forName( s ); // TODO stop and reset all service instances Method[] methods = clzz.getMethods(); for ( int j = 0; j < methods.length; j++ ) { if ( methods[j].getName().equals( "reset" ) ) { Object[] args = new Object[0]; methods[j].invoke( clzz.newInstance(), args ); } } } catch ( Exception e ) { LOG.logError( e.getMessage(), e ); } } } /** * @see javax.servlet.Servlet#destroy() */ @Override public void destroy() { super.destroy(); } }/* ******************************************************************** Changes to this class. What the people have been up to: $Log: OGCServletController.java,v $ Revision 1.66 2006/11/22 14:06:26 schmitz Fixed some minor details in the WMS example configuration. Added CRS:84 to proj4. Fixed exception handling for WMS. Revision 1.65 2006/10/31 20:07:13 poth not used code removed Revision 1.64 2006/09/23 09:01:53 poth *** empty log message *** Revision 1.63 2006/09/08 15:14:38 schmitz Updated the core of deegree to use the HttpServletRequest methods to create the KVP maps, and not to try to parse as XML every time. Updated the tests to create maps for testing instead of strings. Updated the OWSProxy subsystem to use ServletRequest classes instead of strings for request dispatching. Revision 1.62 2006/09/08 08:42:02 schmitz Updated the WMS to be 1.1.1 conformant once again. Cleaned up the WMS code. Added cite WMS test data. Revision 1.61 2006/08/17 20:08:57 poth code formating Revision 1.60 2006/07/26 18:50:54 mschneider Improved log messages. Revision 1.59 2006/07/23 10:05:54 poth setting content type for Http responses enhanced by adding charset (for mime types text/plain and text/xml) Revision 1.58 2006/07/21 09:33:10 poth setting character encoding changed Revision 1.57 2006/07/12 14:46:15 poth comment footer added ********************************************************************** */