View Javadoc

    1   // ========================================================================
    2   // $Id: Invoker.java 3539 2008-08-21 04:46:59Z dyu $
    3   // Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
    4   // ------------------------------------------------------------------------
    5   // Licensed under the Apache License, Version 2.0 (the "License");
    6   // you may not use this file except in compliance with the License.
    7   // You may obtain a copy of the License at
    8   // http://www.apache.org/licenses/LICENSE-2.0
    9   // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  // ========================================================================
    15
    16  package org.mortbay.jetty.servlet;
    17
    18  import java.io.IOException;
    19  import java.util.Enumeration;
    20  import java.util.HashMap;
    21  import java.util.Map;
    22
    23  import javax.servlet.ServletContext;
    24  import javax.servlet.ServletException;
    25  import javax.servlet.UnavailableException;
    26  import javax.servlet.http.HttpServlet;
    27  import javax.servlet.http.HttpServletRequest;
    28  import javax.servlet.http.HttpServletRequestWrapper;
    29  import javax.servlet.http.HttpServletResponse;
    30
    31  import org.mortbay.jetty.Handler;
    32  import org.mortbay.jetty.handler.ContextHandler;
    33  import org.mortbay.jetty.handler.HandlerWrapper;
    34  import org.mortbay.log.Log;
    35  import org.mortbay.util.LazyList;
    36  import org.mortbay.util.URIUtil;
    37  ;
    38
    39  /* ------------------------------------------------------------ */
    40  /**  Dynamic Servlet Invoker.
    41   * This servlet invokes anonymous servlets that have not been defined
    42   * in the web.xml or by other means. The first element of the pathInfo
    43   * of a request passed to the envoker is treated as a servlet name for
    44   * an existing servlet, or as a class name of a new servlet.
    45   * This servlet is normally mapped to /servlet/*
    46   * This servlet support the following initParams:
    47   * <PRE>
    48   *  nonContextServlets       If false, the invoker can only load
    49   *                           servlets from the contexts classloader.
    50   *                           This is false by default and setting this
    51   *                           to true may have security implications.
    52   *
    53   *  verbose                  If true, log dynamic loads
    54   *
    55   *  *                        All other parameters are copied to the
    56   *                           each dynamic servlet as init parameters
    57   * </PRE>
    58   * @version $Id: Invoker.java 3539 2008-08-21 04:46:59Z dyu $
    59   * @author Greg Wilkins (gregw)
    60   */
    61  public class Invoker extends HttpServlet
    62  {
    63
    64      private ContextHandler _contextHandler;
    65      private ServletHandler _servletHandler;
    66      private Map.Entry _invokerEntry;
    67      private Map _parameters;
    68      private boolean _nonContextServlets;
    69      private boolean _verbose;
    70
    71      /* ------------------------------------------------------------ */
    72      public void init()
    73      {
    74          ServletContext config=getServletContext();
    75          _contextHandler=((ContextHandler.SContext)config).getContextHandler();
    76
    77          Handler handler=_contextHandler.getHandler();
    78          while (handler!=null && !(handler instanceof ServletHandler) && (handler instanceof HandlerWrapper))
    79              handler=((HandlerWrapper)handler).getHandler();
    80          _servletHandler = (ServletHandler)handler;
    81          Enumeration e = getInitParameterNames();
    82          while(e.hasMoreElements())
    83          {
    84              String param=(String)e.nextElement();
    85              String value=getInitParameter(param);
    86              String lvalue=value.toLowerCase();
    87              if ("nonContextServlets".equals(param))
    88              {
    89                  _nonContextServlets=value.length()>0 && lvalue.startsWith("t");
    90              }
    91              if ("verbose".equals(param))
    92              {
    93                  _verbose=value.length()>0 && lvalue.startsWith("t");
    94              }
    95              else
    96              {
    97                  if (_parameters==null)
    98                      _parameters=new HashMap();
    99                  _parameters.put(param,value);
    100             }
    101         }
    102     }
    103
    104     /* ------------------------------------------------------------ */
    105     protected void service(HttpServletRequest request, HttpServletResponse response)
    106 	throws ServletException, IOException
    107     {
    108         // Get the requested path and info
    109         boolean included=false;
    110         String servlet_path=(String)request.getAttribute(Dispatcher.__INCLUDE_SERVLET_PATH);
    111         if (servlet_path==null)
    112             servlet_path=request.getServletPath();
    113         else
    114             included=true;
    115         String path_info = (String)request.getAttribute(Dispatcher.__INCLUDE_PATH_INFO);
    116         if (path_info==null)
    117             path_info=request.getPathInfo();
    118
    119         // Get the servlet class
    120         String servlet = path_info;
    121         if (servlet==null || servlet.length()<=1 )
    122         {
    123             response.sendError(404);
    124             return;
    125         }
    126
    127
    128         int i0=servlet.charAt(0)=='/'?1:0;
    129         int i1=servlet.indexOf('/',i0);
    130         servlet=i1<0?servlet.substring(i0):servlet.substring(i0,i1);
    131
    132         // look for a named holder
    133         ServletHolder[] holders = _servletHandler.getServlets();
    134         ServletHolder holder = getHolder (holders, servlet);
    135
    136         if (holder!=null)
    137         {
    138             // Found a named servlet (from a user's web.xml file) so
    139             // now we add a mapping for it
    140             Log.debug("Adding servlet mapping for named servlet:"+servlet+":"+URIUtil.addPaths(servlet_path,servlet)+"/*");
    141             ServletMapping mapping = new ServletMapping();
    142             mapping.setServletName(servlet);
    143             mapping.setPathSpec(URIUtil.addPaths(servlet_path,servlet)+"/*");
    144             _servletHandler.setServletMappings((ServletMapping[])LazyList.addToArray(_servletHandler.getServletMappings(), mapping, ServletMapping.class));
    145         }
    146         else
    147         {
    148             // look for a class mapping
    149             if (servlet.endsWith(".class"))
    150                 servlet=servlet.substring(0,servlet.length()-6);
    151             if (servlet==null || servlet.length()==0)
    152             {
    153                 response.sendError(404);
    154                 return;
    155             }
    156
    157             synchronized(_servletHandler)
    158             {
    159                 // find the entry for the invoker (me)
    160                  _invokerEntry=_servletHandler.getHolderEntry(servlet_path);
    161
    162                 // Check for existing mapping (avoid threaded race).
    163                 String path=URIUtil.addPaths(servlet_path,servlet);
    164                 Map.Entry entry = _servletHandler.getHolderEntry(path);
    165
    166                 if (entry!=null && !entry.equals(_invokerEntry))
    167                 {
    168                     // Use the holder
    169                     holder=(ServletHolder)entry.getValue();
    170                 }
    171                 else
    172                 {
    173                     // Make a holder
    174                     Log.debug("Making new servlet="+servlet+" with path="+path+"/*");
    175                     holder=_servletHandler.addServletWithMapping(servlet, path+"/*");
    176
    177                     if (_parameters!=null)
    178                         holder.setInitParameters(_parameters);
    179
    180                     try {holder.start();}
    181                     catch (Exception e)
    182                     {
    183                         Log.debug(e);
    184                         throw new UnavailableException(e.toString());
    185                     }
    186
    187                     // Check it is from an allowable classloader
    188                     if (!_nonContextServlets)
    189                     {
    190                         Object s=holder.getServlet();
    191
    192                         if (_contextHandler.getClassLoader()!=
    193                             s.getClass().getClassLoader())
    194                         {
    195                             try
    196                             {
    197                                 holder.stop();
    198                             }
    199                             catch (Exception e)
    200                             {
    201                                 Log.ignore(e);
    202                             }
    203
    204                             Log.warn("Dynamic servlet "+s+
    205                                          " not loaded from context "+
    206                                          request.getContextPath());
    207                             throw new UnavailableException("Not in context");
    208                         }
    209                     }
    210
    211                     if (_verbose)
    212                         Log.debug("Dynamic load '"+servlet+"' at "+path);
    213                 }
    214             }
    215         }
    216
    217         if (holder!=null)
    218             holder.handle(new Request(request,included,servlet,servlet_path,path_info),
    219                           response);
    220         else
    221         {
    222             Log.info("Can't find holder for servlet: "+servlet);
    223             response.sendError(404);
    224         }
    225
    226
    227     }
    228
    229     /* ------------------------------------------------------------ */
    230     class Request extends HttpServletRequestWrapper
    231     {
    232         String _servletPath;
    233         String _pathInfo;
    234         boolean _included;
    235
    236         /* ------------------------------------------------------------ */
    237         Request(HttpServletRequest request,
    238                 boolean included,
    239                 String name,
    240                 String servletPath,
    241                 String pathInfo)
    242         {
    243             super(request);
    244             _included=included;
    245             _servletPath=URIUtil.addPaths(servletPath,name);
    246             _pathInfo=pathInfo.substring(name.length()+1);
    247             if (_pathInfo.length()==0)
    248                 _pathInfo=null;
    249         }
    250
    251         /* ------------------------------------------------------------ */
    252         public String getServletPath()
    253         {
    254             if (_included)
    255                 return super.getServletPath();
    256             return _servletPath;
    257         }
    258
    259         /* ------------------------------------------------------------ */
    260         public String getPathInfo()
    261         {
    262             if (_included)
    263                 return super.getPathInfo();
    264             return _pathInfo;
    265         }
    266
    267         /* ------------------------------------------------------------ */
    268         public Object getAttribute(String name)
    269         {
    270             if (_included)
    271             {
    272                 if (name.equals(Dispatcher.__INCLUDE_REQUEST_URI))
    273                     return URIUtil.addPaths(URIUtil.addPaths(getContextPath(),_servletPath),_pathInfo);
    274                 if (name.equals(Dispatcher.__INCLUDE_PATH_INFO))
    275                     return _pathInfo;
    276                 if (name.equals(Dispatcher.__INCLUDE_SERVLET_PATH))
    277                     return _servletPath;
    278             }
    279             return super.getAttribute(name);
    280         }
    281     }
    282
    283
    284     private ServletHolder getHolder(ServletHolder[] holders, String servlet)
    285     {
    286         if (holders == null)
    287             return null;
    288
    289         ServletHolder holder = null;
    290         for (int i=0; holder==null && i<holders.length; i++)
    291         {
    292             if (holders[i].getName().equals(servlet))
    293             {
    294                 holder = holders[i];
    295             }
    296         }
    297         return holder;
    298     }
    299 }