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 }