Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.servletservice; import java.io.IOException; import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; /** * A servlet that dispatch to managed sevlets from the context Spring container. * It dispatch to servlets that has the property mountPath, and dispatches to the * servlet with the longest prefix of the request pathInfo. * * This servlet will also initialize and destroy all the servlets that it finds * from the context container. This means that there must only be one dispatcher * servlet, otherwise the managed servlets will be initialized several times. * * @version $Id: DispatcherServlet.java 615890 2008-01-28 14:26:03Z gkossakowski $ * @since 1.0.0 */ public class DispatcherServlet extends HttpServlet { /** By default we use the logger for this class. */ private final Log logger = LogFactory.getLog(getClass()); /** * The startup date of the Spring application context used to setup the {@link #blockServletCollector}. * TODO: Use a better way to reload {@link #blockServletCollector} when RCL is used, see COCOON-2076 */ private long applicationContextStartDate; /** The servlet collector bean */ private Map blockServletCollector; public void init() throws ServletException { this.log("Block dispatcher was initialized successfully."); } protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { final Map mountableServlets = getBlockServletMap(); String path = req.getPathInfo(); if (path == null) { path = ""; } // find the servlet which mount path is the longest prefix of the path info int index = path.length(); Servlet servlet = null; while (servlet == null && index != -1) { path = path.substring(0, index); servlet = (Servlet) mountableServlets.get(path); index = path.lastIndexOf('/'); } //case when servlet is mounted at "/" must be handled separately servlet = servlet == null ? (Servlet) mountableServlets.get("/") : servlet; if (servlet == null) { String message = "No block for " + req.getPathInfo(); res.sendError(HttpServletResponse.SC_NOT_FOUND, message); this.logger.info(message); return; } // Create a dynamic proxy class that overwrites the getServletPath and // getPathInfo methods to provide reasonable values in the called servlet // the dynamic proxy implements all interfaces of the original request HttpServletRequest request = (HttpServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), getInterfaces(req.getClass()), new DynamicProxyRequestHandler(req, path)); if (this.logger.isDebugEnabled()) { this.logger.debug("DispatcherServlet: service servlet=" + servlet + " mountPath=" + path + " servletPath=" + request.getServletPath() + " pathInfo=" + request.getPathInfo()); } servlet.service(request, res); } private void getInterfaces(Set interfaces, Class clazz) { Class[] clazzInterfaces = clazz.getInterfaces(); for (int i = 0; i < clazzInterfaces.length; i++) { //add all interfaces extended by this interface or directly //implemented by this class getInterfaces(interfaces, clazzInterfaces[i]); } // the superclazz is null if class is instanceof Object, is // an interface, a primitive type or void Class superclazz = clazz.getSuperclass(); if (superclazz != null) { //add all interfaces of the superclass to the list getInterfaces(interfaces, superclazz); } interfaces.addAll(Arrays.asList(clazzInterfaces)); } private Class[] getInterfaces(final Class clazz) { Set interfaces = new LinkedHashSet(); getInterfaces(interfaces, clazz); return (Class[]) interfaces.toArray(new Class[interfaces.size()]); } public Map getBlockServletMap() { ApplicationContext applicationContext = WebApplicationContextUtils .getRequiredWebApplicationContext(getServletContext()); if (this.blockServletCollector == null || applicationContext.getStartupDate() != this.applicationContextStartDate) { this.applicationContextStartDate = applicationContext.getStartupDate(); this.blockServletCollector = (Map) applicationContext .getBean("org.apache.cocoon.servletservice.spring.BlockServletMap"); } return blockServletCollector; } }