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