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