001 /**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements. See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.apache.geronimo.jetty;
019
020 import java.io.IOException;
021 import java.util.Map;
022 import java.util.Set;
023
024 import javax.security.auth.Subject;
025 import javax.servlet.ServletException;
026 import javax.servlet.ServletRequest;
027 import javax.servlet.ServletResponse;
028 import javax.servlet.UnavailableException;
029
030 import org.apache.geronimo.gbean.GBeanInfo;
031 import org.apache.geronimo.gbean.GBeanInfoBuilder;
032 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
033 import org.apache.geronimo.management.Servlet;
034 import org.apache.geronimo.security.Callers;
035 import org.apache.geronimo.security.ContextManager;
036 import org.mortbay.jetty.servlet.ServletHolder;
037
038
039 /**
040 * This ServletHolder's sole purpose is to provide the thread's current
041 * ServletHolder for realms that are interested in the current servlet, e.g.
042 * current servlet name.
043 * <p/>
044 * It is also being our servlet gbean for now. We could gbean-ize the superclass to avoid the thread local access.
045 *
046 * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
047 * @see JAASJettyRealm#isUserInRole(java.security.Principal, String)
048 */
049 public class JettyServletHolder extends ServletHolder implements Servlet {
050 private static final ThreadLocal currentServletName = new ThreadLocal();
051 private final Subject runAsSubject;
052 private final String objectName;
053
054 //todo consider interface instead of this constructor for endpoint use.
055 public JettyServletHolder() {
056 this.objectName = null;
057 this.runAsSubject = null;
058 }
059
060 public JettyServletHolder(String objectName,
061 String servletName,
062 String servletClassName,
063 String jspFile,
064 Map initParams,
065 Integer loadOnStartup,
066 Set servletMappings,
067 Subject runAsSubject,
068 ServletHolder previous, //dependency for startup ordering
069 JettyServletRegistration context) throws Exception {
070 super(context == null ? null : context.getServletHandler(), servletName, servletClassName, jspFile);
071 //context will be null only for use as "default servlet info holder" in deployer.
072
073 if (context != null) {
074 putAll(initParams);
075 if (loadOnStartup != null) {
076 //This has no effect on the actual start order, the gbean references "previous" control that.
077 setInitOrder(loadOnStartup.intValue());
078 }
079 //this now starts the servlet in the appropriate context
080 context.registerServletHolder(this, servletName, servletMappings, objectName);
081 }
082 this.runAsSubject = runAsSubject;
083 this.objectName = objectName;
084 }
085
086 //todo how do we stop/destroy the servlet?
087 //todo is start called twice???
088
089 public String getServletName() {
090 return getName();
091 }
092
093 //TODO probably need to override init and destroy (?) to handle runAsSubject since we are not setting it in the superclass any more.
094
095 /**
096 * Service a request with this servlet. Set the ThreadLocal to hold the
097 * current JettyServletHolder.
098 */
099 public void handle(ServletRequest request, ServletResponse response)
100 throws ServletException, UnavailableException, IOException {
101
102 setCurrentServletName(getServletName());
103 if (runAsSubject == null) {
104 super.handle(request, response);
105 } else {
106 Callers oldCallers = ContextManager.pushNextCaller(runAsSubject);
107 try {
108 super.handle(request, response);
109 } finally {
110 ContextManager.popCallers(oldCallers);
111 }
112 }
113 }
114
115 /**
116 * Provide the thread's current JettyServletHolder
117 *
118 * @return the thread's current JettyServletHolder
119 * @see org.apache.geronimo.jetty.JAASJettyRealm#isUserInRole(java.security.Principal, java.lang.String)
120 */
121 static String getCurrentServletName() {
122 return (String) currentServletName.get();
123 }
124
125 static void setCurrentServletName(String servletName) {
126 currentServletName.set(servletName);
127 }
128
129 public String getObjectName() {
130 return objectName;
131 }
132
133 public boolean isStateManageable() {
134 return false;
135 }
136
137 public boolean isStatisticsProvider() {
138 return false;
139 }
140
141 public boolean isEventProvider() {
142 return false;
143 }
144
145 public static final GBeanInfo GBEAN_INFO;
146
147 static {
148 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(JettyServletHolder.class, NameFactory.SERVLET);
149 //todo replace with interface
150 infoBuilder.addInterface(ServletHolder.class);
151
152 infoBuilder.addAttribute("servletName", String.class, true);
153 infoBuilder.addAttribute("servletClass", String.class, true);
154 infoBuilder.addAttribute("jspFile", String.class, true);
155 infoBuilder.addAttribute("initParams", Map.class, true);
156 infoBuilder.addAttribute("loadOnStartup", Integer.class, true);
157 infoBuilder.addAttribute("servletMappings", Set.class, true);
158 infoBuilder.addAttribute("runAsSubject", Subject.class, true);
159 infoBuilder.addAttribute("objectName", String.class, false);
160 infoBuilder.addInterface(Servlet.class);
161
162 infoBuilder.addReference("Previous", ServletHolder.class, NameFactory.SERVLET);
163 infoBuilder.addReference("JettyServletRegistration", JettyServletRegistration.class, NameFactory.WEB_MODULE);
164
165 infoBuilder.setConstructor(new String[]{"objectName",
166 "servletName",
167 "servletClass",
168 "jspFile",
169 "initParams",
170 "loadOnStartup",
171 "servletMappings",
172 "runAsSubject",
173 "Previous",
174 "JettyServletRegistration"});
175
176 GBEAN_INFO = infoBuilder.getBeanInfo();
177 }
178
179 public static GBeanInfo getGBeanInfo() {
180 return GBEAN_INFO;
181 }
182 }