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 19package org.eclipse.jetty.servlet; 20 21import java.io.IOException; 22import java.util.Collections; 23import java.util.Enumeration; 24import java.util.HashMap; 25import java.util.HashSet; 26import java.util.Map; 27import java.util.Set; 28 29import javax.servlet.Registration; 30import javax.servlet.ServletContext; 31import javax.servlet.UnavailableException; 32 33import org.eclipse.jetty.server.handler.ContextHandler; 34import org.eclipse.jetty.util.Loader; 35import org.eclipse.jetty.util.component.AbstractLifeCycle; 36import org.eclipse.jetty.util.component.AggregateLifeCycle; 37import org.eclipse.jetty.util.component.Dumpable; 38import org.eclipse.jetty.util.log.Log; 39import org.eclipse.jetty.util.log.Logger; 40 41 42/* --------------------------------------------------------------------- */ 43/** 44 * 45 */ 46public 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 /* ---------------------------------------------------------------- */ 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 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 */ 88 public boolean isInstance() 89 { 90 return _extInstance; 91 } 92 93 /* ------------------------------------------------------------ */ 94 @SuppressWarnings("unchecked") 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 121 public void doStop() 122 throws Exception 123 { 124 if (!_extInstance) 125 _class=null; 126 } 127 128 /* ------------------------------------------------------------ */ 129 public String getClassName() 130 { 131 return _className; 132 } 133 134 /* ------------------------------------------------------------ */ 135 public Class<? extends T> getHeldClass() 136 { 137 return _class; 138 } 139 140 /* ------------------------------------------------------------ */ 141 public String getDisplayName() 142 { 143 return _displayName; 144 } 145 146 /* ---------------------------------------------------------------- */ 147 public String getInitParameter(String param) 148 { 149 if (_initParams==null) 150 return null; 151 return (String)_initParams.get(param); 152 } 153 154 /* ------------------------------------------------------------ */ 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 /* ---------------------------------------------------------------- */ 163 public Map<String,String> getInitParameters() 164 { 165 return _initParams; 166 } 167 168 /* ------------------------------------------------------------ */ 169 public String getName() 170 { 171 return _name; 172 } 173 174 /* ------------------------------------------------------------ */ 175 /** 176 * @return Returns the servletHandler. 177 */ 178 public ServletHandler getServletHandler() 179 { 180 return _servletHandler; 181 } 182 183 /* ------------------------------------------------------------ */ 184 public void destroyInstance(Object instance) 185 throws Exception 186 { 187 } 188 189 /* ------------------------------------------------------------ */ 190 /** 191 * @param className The className to set. 192 */ 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 */ 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 /* ------------------------------------------------------------ */ 217 public void setDisplayName(String name) 218 { 219 _displayName=name; 220 } 221 222 /* ------------------------------------------------------------ */ 223 public void setInitParameter(String param,String value) 224 { 225 _initParams.put(param,value); 226 } 227 228 /* ---------------------------------------------------------------- */ 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 */ 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 */ 251 public void setServletHandler(ServletHandler servletHandler) 252 { 253 _servletHandler = servletHandler; 254 } 255 256 /* ------------------------------------------------------------ */ 257 public void setAsyncSupported(boolean suspendable) 258 { 259 _asyncSupported=suspendable; 260 } 261 262 /* ------------------------------------------------------------ */ 263 public boolean isAsyncSupported() 264 { 265 return _asyncSupported; 266 } 267 268 /* ------------------------------------------------------------ */ 269 public String toString() 270 { 271 return _name; 272 } 273 274 /* ------------------------------------------------------------ */ 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 /* ------------------------------------------------------------ */ 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 /* ------------------------------------------------------------ */ 294 public String dump() 295 { 296 return AggregateLifeCycle.dump(this); 297 } 298 299 /* ------------------------------------------------------------ */ 300 /* ------------------------------------------------------------ */ 301 /* ------------------------------------------------------------ */ 302 protected class HolderConfig 303 { 304 305 /* -------------------------------------------------------- */ 306 public ServletContext getServletContext() 307 { 308 return _servletHandler.getServletContext(); 309 } 310 311 /* -------------------------------------------------------- */ 312 public String getInitParameter(String param) 313 { 314 return Holder.this.getInitParameter(param); 315 } 316 317 /* -------------------------------------------------------- */ 318 public Enumeration getInitParameterNames() 319 { 320 return Holder.this.getInitParameterNames(); 321 } 322 } 323 324 /* -------------------------------------------------------- */ 325 /* -------------------------------------------------------- */ 326 /* -------------------------------------------------------- */ 327 protected class HolderRegistration implements Registration.Dynamic 328 { 329 public void setAsyncSupported(boolean isAsyncSupported) 330 { 331 illegalStateIfContextStarted(); 332 Holder.this.setAsyncSupported(isAsyncSupported); 333 } 334 335 public void setDescription(String description) 336 { 337 if (LOG.isDebugEnabled()) 338 LOG.debug(this+" is "+description); 339 } 340 341 public String getClassName() 342 { 343 return Holder.this.getClassName(); 344 } 345 346 public String getInitParameter(String name) 347 { 348 return Holder.this.getInitParameter(name); 349 } 350 351 public Map<String, String> getInitParameters() 352 { 353 return Holder.this.getInitParameters(); 354 } 355 356 public String getName() 357 { 358 return Holder.this.getName(); 359 } 360 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 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