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     }
220 
221     /* ------------------------------------------------------------ */
222     /**
223      * @param held The class to hold
224      */
225     public void setHeldClass(Class<? extends T> held)
226     {
227         _class=held;
228         if (held!=null)
229         {
230             _className=held.getName();
231             if (_name==null)
232                 _name=held.getName()+"-"+this.hashCode();
233         }
234     }
235 
236     /* ------------------------------------------------------------ */
237     public void setDisplayName(String name)
238     {
239         _displayName=name;
240     }
241 
242     /* ------------------------------------------------------------ */
243     public void setInitParameter(String param,String value)
244     {
245         _initParams.put(param,value);
246     }
247 
248     /* ---------------------------------------------------------------- */
249     public void setInitParameters(Map<String,String> map)
250     {
251         _initParams.clear();
252         _initParams.putAll(map);
253     }
254 
255     /* ------------------------------------------------------------ */
256     /**
257      * The name is a primary key for the held object.
258      * Ensure that the name is set BEFORE adding a Holder
259      * (eg ServletHolder or FilterHolder) to a ServletHandler.
260      * @param name The name to set.
261      */
262     public void setName(String name)
263     {
264         _name = name;
265     }
266 
267     /* ------------------------------------------------------------ */
268     /**
269      * @param servletHandler The {@link ServletHandler} that will handle requests dispatched to this servlet.
270      */
271     public void setServletHandler(ServletHandler servletHandler)
272     {
273         _servletHandler = servletHandler;
274     }
275 
276     /* ------------------------------------------------------------ */
277     public void setAsyncSupported(boolean suspendable)
278     {
279         _asyncSupported=suspendable;
280     }
281 
282     /* ------------------------------------------------------------ */
283     public boolean isAsyncSupported()
284     {
285         return _asyncSupported;
286     }
287 
288     /* ------------------------------------------------------------ */
289     protected void illegalStateIfContextStarted()
290     {
291         if (_servletHandler!=null)
292         {
293             ServletContext context=_servletHandler.getServletContext();
294             if ((context instanceof ContextHandler.Context) && ((ContextHandler.Context)context).getContextHandler().isStarted())
295                 throw new IllegalStateException("Started");
296         }
297     }
298 
299     /* ------------------------------------------------------------ */
300     @Override
301     public void dump(Appendable out, String indent) throws IOException
302     {
303         out.append(toString())
304         .append(" - ").append(AbstractLifeCycle.getState(this)).append("\n");
305         ContainerLifeCycle.dump(out,indent,_initParams.entrySet());
306     }
307 
308     /* ------------------------------------------------------------ */
309     @Override
310     public String dump()
311     {
312         return ContainerLifeCycle.dump(this);
313     }
314 
315     /* ------------------------------------------------------------ */
316     @Override
317     public String toString()
318     {
319         return String.format("%s@%x==%s",_name,hashCode(),_className);
320     }
321     
322     /* ------------------------------------------------------------ */
323     /* ------------------------------------------------------------ */
324     /* ------------------------------------------------------------ */
325     protected class HolderConfig
326     {
327 
328         /* -------------------------------------------------------- */
329         public ServletContext getServletContext()
330         {
331             return _servletHandler.getServletContext();
332         }
333 
334         /* -------------------------------------------------------- */
335         public String getInitParameter(String param)
336         {
337             return Holder.this.getInitParameter(param);
338         }
339 
340         /* -------------------------------------------------------- */
341         public Enumeration getInitParameterNames()
342         {
343             return Holder.this.getInitParameterNames();
344         }
345     }
346 
347     /* -------------------------------------------------------- */
348     /* -------------------------------------------------------- */
349     /* -------------------------------------------------------- */
350     protected class HolderRegistration implements Registration.Dynamic
351     {
352         public void setAsyncSupported(boolean isAsyncSupported)
353         {
354             illegalStateIfContextStarted();
355             Holder.this.setAsyncSupported(isAsyncSupported);
356         }
357 
358         public void setDescription(String description)
359         {
360             if (LOG.isDebugEnabled())
361                 LOG.debug(this+" is "+description);
362         }
363 
364         public String getClassName()
365         {
366             return Holder.this.getClassName();
367         }
368 
369         public String getInitParameter(String name)
370         {
371             return Holder.this.getInitParameter(name);
372         }
373 
374         public Map<String, String> getInitParameters()
375         {
376             return Holder.this.getInitParameters();
377         }
378 
379         public String getName()
380         {
381             return Holder.this.getName();
382         }
383 
384         public boolean setInitParameter(String name, String value)
385         {
386             illegalStateIfContextStarted();
387             if (name == null) {
388                 throw new IllegalArgumentException("init parameter name required");
389             }
390             if (value == null) {
391                 throw new IllegalArgumentException("non-null value required for init parameter " + name);
392             }
393             if (Holder.this.getInitParameter(name)!=null)
394                 return false;
395             Holder.this.setInitParameter(name,value);
396             return true;
397         }
398 
399         public Set<String> setInitParameters(Map<String, String> initParameters)
400         {
401             illegalStateIfContextStarted();
402             Set<String> clash=null;
403             for (Map.Entry<String, String> entry : initParameters.entrySet())
404             {
405                 if (entry.getKey() == null) {
406                     throw new IllegalArgumentException("init parameter name required");
407                 }
408                 if (entry.getValue() == null) {
409                     throw new IllegalArgumentException("non-null value required for init parameter " + entry.getKey());
410                 }
411                 if (Holder.this.getInitParameter(entry.getKey())!=null)
412                 {
413                     if (clash==null)
414                         clash=new HashSet<String>();
415                     clash.add(entry.getKey());
416                 }
417             }
418             if (clash!=null)
419                 return clash;
420             Holder.this.getInitParameters().putAll(initParameters);
421             return Collections.emptySet();
422         }
423 
424 
425     }
426 }
427 
428 
429 
430 
431