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 }