1 // 2 // ======================================================================== 3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 4 // ------------------------------------------------------------------------ 5 // All rights reserved. This program and the accompanying materials 6 // are made available under the terms of the Eclipse Public License v1.0 7 // and Apache License v2.0 which accompanies this distribution. 8 // 9 // The Eclipse Public License is available at 10 // http://www.eclipse.org/legal/epl-v10.html 11 // 12 // The Apache License v2.0 is available at 13 // http://www.opensource.org/licenses/apache2.0.php 14 // 15 // You may elect to redistribute this code under either of these licenses. 16 // ======================================================================== 17 // 18 19 package org.eclipse.jetty.servlet; 20 21 import java.io.IOException; 22 import java.util.Collections; 23 import java.util.Enumeration; 24 import java.util.HashMap; 25 import java.util.HashSet; 26 import java.util.Map; 27 import java.util.Set; 28 29 import javax.servlet.Registration; 30 import javax.servlet.ServletContext; 31 import javax.servlet.UnavailableException; 32 33 import org.eclipse.jetty.server.handler.ContextHandler; 34 import org.eclipse.jetty.util.Loader; 35 import org.eclipse.jetty.util.component.AbstractLifeCycle; 36 import org.eclipse.jetty.util.component.AggregateLifeCycle; 37 import org.eclipse.jetty.util.component.Dumpable; 38 import org.eclipse.jetty.util.log.Log; 39 import org.eclipse.jetty.util.log.Logger; 40 41 42 /* --------------------------------------------------------------------- */ 43 /** 44 * 45 */ 46 public class Holder<T> extends AbstractLifeCycle implements Dumpable 47 { 48 public enum Source { EMBEDDED, JAVAX_API, DESCRIPTOR, ANNOTATION }; 49 final private Source _source; 50 private static final Logger LOG = Log.getLogger(Holder.class); 51 52 protected transient Class<? extends T> _class; 53 protected final Map<String,String> _initParams=new HashMap<String,String>(3); 54 protected String _className; 55 protected String _displayName; 56 protected boolean _extInstance; 57 protected boolean _asyncSupported; 58 59 /* ---------------------------------------------------------------- */ 60 protected String _name; 61 protected ServletHandler _servletHandler; 62 63 /* ---------------------------------------------------------------- */ Holder(Source source)64 protected Holder(Source source) 65 { 66 _source=source; 67 switch(_source) 68 { 69 case JAVAX_API: 70 case DESCRIPTOR: 71 case ANNOTATION: 72 _asyncSupported=false; 73 break; 74 default: 75 _asyncSupported=true; 76 } 77 } 78 getSource()79 public Source getSource() 80 { 81 return _source; 82 } 83 84 /* ------------------------------------------------------------ */ 85 /** 86 * @return True if this holder was created for a specific instance. 87 */ isInstance()88 public boolean isInstance() 89 { 90 return _extInstance; 91 } 92 93 /* ------------------------------------------------------------ */ 94 @SuppressWarnings("unchecked") doStart()95 public void doStart() 96 throws Exception 97 { 98 //if no class already loaded and no classname, make servlet permanently unavailable 99 if (_class==null && (_className==null || _className.equals(""))) 100 throw new UnavailableException("No class for Servlet or Filter for "+_name); 101 102 //try to load class 103 if (_class==null) 104 { 105 try 106 { 107 _class=Loader.loadClass(Holder.class, _className); 108 if(LOG.isDebugEnabled()) 109 LOG.debug("Holding {}",_class); 110 } 111 catch (Exception e) 112 { 113 LOG.warn(e); 114 throw new UnavailableException(e.getMessage()); 115 } 116 } 117 } 118 119 /* ------------------------------------------------------------ */ 120 @Override doStop()121 public void doStop() 122 throws Exception 123 { 124 if (!_extInstance) 125 _class=null; 126 } 127 128 /* ------------------------------------------------------------ */ getClassName()129 public String getClassName() 130 { 131 return _className; 132 } 133 134 /* ------------------------------------------------------------ */ getHeldClass()135 public Class<? extends T> getHeldClass() 136 { 137 return _class; 138 } 139 140 /* ------------------------------------------------------------ */ getDisplayName()141 public String getDisplayName() 142 { 143 return _displayName; 144 } 145 146 /* ---------------------------------------------------------------- */ getInitParameter(String param)147 public String getInitParameter(String param) 148 { 149 if (_initParams==null) 150 return null; 151 return (String)_initParams.get(param); 152 } 153 154 /* ------------------------------------------------------------ */ getInitParameterNames()155 public Enumeration getInitParameterNames() 156 { 157 if (_initParams==null) 158 return Collections.enumeration(Collections.EMPTY_LIST); 159 return Collections.enumeration(_initParams.keySet()); 160 } 161 162 /* ---------------------------------------------------------------- */ getInitParameters()163 public Map<String,String> getInitParameters() 164 { 165 return _initParams; 166 } 167 168 /* ------------------------------------------------------------ */ getName()169 public String getName() 170 { 171 return _name; 172 } 173 174 /* ------------------------------------------------------------ */ 175 /** 176 * @return Returns the servletHandler. 177 */ getServletHandler()178 public ServletHandler getServletHandler() 179 { 180 return _servletHandler; 181 } 182 183 /* ------------------------------------------------------------ */ destroyInstance(Object instance)184 public void destroyInstance(Object instance) 185 throws Exception 186 { 187 } 188 189 /* ------------------------------------------------------------ */ 190 /** 191 * @param className The className to set. 192 */ setClassName(String className)193 public void setClassName(String className) 194 { 195 _className = className; 196 _class=null; 197 if (_name==null) 198 _name=className+"-"+Integer.toHexString(this.hashCode()); 199 } 200 201 /* ------------------------------------------------------------ */ 202 /** 203 * @param held The class to hold 204 */ setHeldClass(Class<? extends T> held)205 public void setHeldClass(Class<? extends T> held) 206 { 207 _class=held; 208 if (held!=null) 209 { 210 _className=held.getName(); 211 if (_name==null) 212 _name=held.getName()+"-"+Integer.toHexString(this.hashCode()); 213 } 214 } 215 216 /* ------------------------------------------------------------ */ setDisplayName(String name)217 public void setDisplayName(String name) 218 { 219 _displayName=name; 220 } 221 222 /* ------------------------------------------------------------ */ setInitParameter(String param,String value)223 public void setInitParameter(String param,String value) 224 { 225 _initParams.put(param,value); 226 } 227 228 /* ---------------------------------------------------------------- */ setInitParameters(Map<String,String> map)229 public void setInitParameters(Map<String,String> map) 230 { 231 _initParams.clear(); 232 _initParams.putAll(map); 233 } 234 235 /* ------------------------------------------------------------ */ 236 /** 237 * The name is a primary key for the held object. 238 * Ensure that the name is set BEFORE adding a Holder 239 * (eg ServletHolder or FilterHolder) to a ServletHandler. 240 * @param name The name to set. 241 */ setName(String name)242 public void setName(String name) 243 { 244 _name = name; 245 } 246 247 /* ------------------------------------------------------------ */ 248 /** 249 * @param servletHandler The {@link ServletHandler} that will handle requests dispatched to this servlet. 250 */ setServletHandler(ServletHandler servletHandler)251 public void setServletHandler(ServletHandler servletHandler) 252 { 253 _servletHandler = servletHandler; 254 } 255 256 /* ------------------------------------------------------------ */ setAsyncSupported(boolean suspendable)257 public void setAsyncSupported(boolean suspendable) 258 { 259 _asyncSupported=suspendable; 260 } 261 262 /* ------------------------------------------------------------ */ isAsyncSupported()263 public boolean isAsyncSupported() 264 { 265 return _asyncSupported; 266 } 267 268 /* ------------------------------------------------------------ */ toString()269 public String toString() 270 { 271 return _name; 272 } 273 274 /* ------------------------------------------------------------ */ illegalStateIfContextStarted()275 protected void illegalStateIfContextStarted() 276 { 277 if (_servletHandler!=null) 278 { 279 ContextHandler.Context context=(ContextHandler.Context)_servletHandler.getServletContext(); 280 if (context!=null && context.getContextHandler().isStarted()) 281 throw new IllegalStateException("Started"); 282 } 283 } 284 285 /* ------------------------------------------------------------ */ dump(Appendable out, String indent)286 public void dump(Appendable out, String indent) throws IOException 287 { 288 out.append(_name).append("==").append(_className) 289 .append(" - ").append(AbstractLifeCycle.getState(this)).append("\n"); 290 AggregateLifeCycle.dump(out,indent,_initParams.entrySet()); 291 } 292 293 /* ------------------------------------------------------------ */ dump()294 public String dump() 295 { 296 return AggregateLifeCycle.dump(this); 297 } 298 299 /* ------------------------------------------------------------ */ 300 /* ------------------------------------------------------------ */ 301 /* ------------------------------------------------------------ */ 302 protected class HolderConfig 303 { 304 305 /* -------------------------------------------------------- */ getServletContext()306 public ServletContext getServletContext() 307 { 308 return _servletHandler.getServletContext(); 309 } 310 311 /* -------------------------------------------------------- */ getInitParameter(String param)312 public String getInitParameter(String param) 313 { 314 return Holder.this.getInitParameter(param); 315 } 316 317 /* -------------------------------------------------------- */ getInitParameterNames()318 public Enumeration getInitParameterNames() 319 { 320 return Holder.this.getInitParameterNames(); 321 } 322 } 323 324 /* -------------------------------------------------------- */ 325 /* -------------------------------------------------------- */ 326 /* -------------------------------------------------------- */ 327 protected class HolderRegistration implements Registration.Dynamic 328 { setAsyncSupported(boolean isAsyncSupported)329 public void setAsyncSupported(boolean isAsyncSupported) 330 { 331 illegalStateIfContextStarted(); 332 Holder.this.setAsyncSupported(isAsyncSupported); 333 } 334 setDescription(String description)335 public void setDescription(String description) 336 { 337 if (LOG.isDebugEnabled()) 338 LOG.debug(this+" is "+description); 339 } 340 getClassName()341 public String getClassName() 342 { 343 return Holder.this.getClassName(); 344 } 345 getInitParameter(String name)346 public String getInitParameter(String name) 347 { 348 return Holder.this.getInitParameter(name); 349 } 350 getInitParameters()351 public Map<String, String> getInitParameters() 352 { 353 return Holder.this.getInitParameters(); 354 } 355 getName()356 public String getName() 357 { 358 return Holder.this.getName(); 359 } 360 setInitParameter(String name, String value)361 public boolean setInitParameter(String name, String value) 362 { 363 illegalStateIfContextStarted(); 364 if (name == null) { 365 throw new IllegalArgumentException("init parameter name required"); 366 } 367 if (value == null) { 368 throw new IllegalArgumentException("non-null value required for init parameter " + name); 369 } 370 if (Holder.this.getInitParameter(name)!=null) 371 return false; 372 Holder.this.setInitParameter(name,value); 373 return true; 374 } 375 setInitParameters(Map<String, String> initParameters)376 public Set<String> setInitParameters(Map<String, String> initParameters) 377 { 378 illegalStateIfContextStarted(); 379 Set<String> clash=null; 380 for (Map.Entry<String, String> entry : initParameters.entrySet()) 381 { 382 if (entry.getKey() == null) { 383 throw new IllegalArgumentException("init parameter name required"); 384 } 385 if (entry.getValue() == null) { 386 throw new IllegalArgumentException("non-null value required for init parameter " + entry.getKey()); 387 } 388 if (Holder.this.getInitParameter(entry.getKey())!=null) 389 { 390 if (clash==null) 391 clash=new HashSet<String>(); 392 clash.add(entry.getKey()); 393 } 394 } 395 if (clash!=null) 396 return clash; 397 Holder.this.getInitParameters().putAll(initParameters); 398 return Collections.emptySet(); 399 } 400 401 402 } 403 } 404 405 406 407 408 409