View Javadoc

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