001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.geronimo.console.servlet; 018 019 import org.apache.commons.logging.Log; 020 import org.apache.commons.logging.LogFactory; 021 import org.apache.geronimo.console.gbean.ContextForward; 022 import org.apache.geronimo.gbean.AbstractName; 023 import org.apache.geronimo.gbean.AbstractNameQuery; 024 import org.apache.geronimo.kernel.Kernel; 025 import org.apache.geronimo.kernel.KernelRegistry; 026 import org.apache.geronimo.kernel.lifecycle.LifecycleAdapter; 027 import org.apache.geronimo.kernel.lifecycle.LifecycleListener; 028 029 import javax.servlet.RequestDispatcher; 030 import javax.servlet.ServletConfig; 031 import javax.servlet.ServletContext; 032 import javax.servlet.ServletException; 033 import javax.servlet.http.HttpServlet; 034 import javax.servlet.http.HttpServletRequest; 035 import javax.servlet.http.HttpServletResponse; 036 import java.io.IOException; 037 import java.util.HashMap; 038 import java.util.Iterator; 039 import java.util.Map; 040 import java.util.Set; 041 042 /** 043 * Servlet that forwards GET and POST requests to a servlet in an alternate 044 * context. The servlet path and alternate context are defined in GBeans of 045 * type ContextForward, and this one servlet handles the forwarding for all 046 * those different paths. 047 * 048 * NOTE: This does not work for DWR, because it changes the request path info 049 * while forwarding, and DWR requires the exact initial request info in order 050 * to construct URLs in the data that it returns. It should work to forward 051 * to most typical servlets, JSPs, and static content. 052 */ 053 public class GenericForwardServlet extends HttpServlet { 054 private final static Log log = LogFactory.getLog(GenericForwardServlet.class); 055 private Map forwards = new HashMap(); // Maps a prefix String to ForwardData 056 private Kernel kernel; 057 private LifecycleListener listener; 058 059 public void init(ServletConfig config) throws ServletException { 060 super.init(config); 061 062 kernel = KernelRegistry.getSingleKernel(); 063 AbstractNameQuery query = new AbstractNameQuery(ContextForward.class.getName()); 064 Set set = kernel.listGBeans(query); 065 for (Iterator it = set.iterator(); it.hasNext();) { 066 AbstractName name = (AbstractName) it.next(); 067 addGBean(name); 068 } 069 kernel.getLifecycleMonitor().addLifecycleListener(listener = new LifecycleAdapter() { 070 public void running(AbstractName abstractName) { 071 addGBean(abstractName); 072 } 073 074 public void stopping(AbstractName abstractName) { 075 removeGBean(abstractName); 076 } 077 078 public void stopped(AbstractName abstractName) { 079 removeGBean(abstractName); 080 } 081 082 public void failed(AbstractName abstractName) { 083 removeGBean(abstractName); 084 } 085 086 public void unloaded(AbstractName abstractName) { 087 removeGBean(abstractName); 088 } 089 }, query); 090 } 091 092 public void destroy() { 093 if(listener != null) { 094 kernel.getLifecycleMonitor().removeLifecycleListener(listener); 095 listener = null; 096 } 097 } 098 099 private void addGBean(AbstractName name) { 100 ContextForward forward = (ContextForward) kernel.getProxyManager().createProxy(name, ContextForward.class); 101 forwards.put(forward.getPortalPathPrefix(), new ForwardData(getServletContext().getContext(forward.getPortletContextPath()), 102 forward.getPortletServletPath(), name)); 103 } 104 105 private void removeGBean(AbstractName name) { 106 for (Iterator it = forwards.entrySet().iterator(); it.hasNext();) { 107 Map.Entry entry = (Map.Entry) it.next(); 108 ForwardData data = (ForwardData) entry.getValue(); 109 if(data.getGbean().equals(name)) { 110 it.remove(); 111 break; 112 } 113 } 114 } 115 116 public void doGet(HttpServletRequest req, HttpServletResponse resp) 117 throws ServletException, IOException { 118 doPost(req, resp); 119 } 120 121 public void doPost(HttpServletRequest req, HttpServletResponse resp) 122 throws ServletException, IOException { 123 String path = req.getPathInfo(); 124 if(path == null) { 125 log.error("Unable to forward request; no path information provided. Path is used to identify where to forward to."); 126 return; 127 } 128 ForwardData forward = null; 129 for (Iterator it = forwards.keySet().iterator(); it.hasNext();) { 130 String prefix = (String) it.next(); 131 if(path.startsWith(prefix)) { 132 forward = (ForwardData) forwards.get(prefix); 133 path = path.substring(prefix.length()); 134 } 135 } 136 if(forward == null) { 137 log.error("Unable to forward URL "+path+"; does not match any known ContextForward definitions."); 138 return; 139 } 140 if(!path.equals("") && !path.startsWith("/")) path = "/"+path; 141 String queryString = req.getQueryString(); 142 if (queryString != null) { 143 path += "?" + queryString; 144 } 145 path = forward.getServletPath()+path; 146 RequestDispatcher dispatcher = forward.getForwardContext().getRequestDispatcher(path); 147 dispatcher.forward(req, resp); 148 } 149 150 private static class ForwardData { 151 private ServletContext forwardContext; 152 private String servletPath; 153 private AbstractName gbean; 154 155 public ForwardData(ServletContext forwardContext, String servletPath, AbstractName gbean) { 156 this.forwardContext = forwardContext; 157 this.servletPath = servletPath; 158 this.gbean = gbean; 159 } 160 161 public ServletContext getForwardContext() { 162 return forwardContext; 163 } 164 165 public String getServletPath() { 166 return servletPath; 167 } 168 169 public AbstractName getGbean() { 170 return gbean; 171 } 172 } 173 }