Changeset 4221


Ignore:
Timestamp:
Apr 14, 2008, 2:40:57 PM (15 years ago)
Author:
Nicklas Nordborg
Message:

References #988: Add support for servlets in extensions

The main feature is now working.

Location:
trunk
Files:
3 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/config/dist/web.xml

    r4187 r4221  
    167167    <load-on-startup>1</load-on-startup>
    168168  </servlet>
    169 
     169  <servlet-mapping>
     170    <servlet-name>ExtensionsServlet</servlet-name>
     171    <url-pattern>*.servlet</url-pattern>
     172  </servlet-mapping>
     173 
    170174  <!-- The CompileAll servlet used to compile all JSP pages -->
    171175  <!-- EXPERIMENTAL!! -->
  • trunk/doc/src/docbook/developerdoc/extensions.xml

    r4208 r4221  
    709709    </para>
    710710   
     711    <note>
     712      <para>
     713      Unfortunately, the custom JSP page can't use classes that
     714      are located in the extension's JAR file. The reason is that the
     715      JAR file is not known to Tomcat and Tomcat will not look there to
     716      try to find classes. The current workaround is to place classes need
     717      by JSP pages in a separate JAR file that is then installed into
     718      the <filename>WEB-INF/lib</filename> folder. This requires a restart
     719      of Tomcat.
     720      </para>
     721    </note>
     722   
    711723    <sect2 id="extensions_developer.resources.scripts">
    712724      <title>Javascript and stylesheets</title>
     
    11071119  </sect1>
    11081120 
     1121  <sect1 id="extensions_developer.servlets">
     1122    <title>Custom servlets</title>
     1123    <para>
     1124      It is possible for an extension to include servlets without having
     1125      to register those servlets in Tomcat's <filename>WEB-INF/web.xml</filename>
     1126      file. The extension needs to be in a JAR file as usual. The servlet class
     1127      should be located in the JAR file following regular Java conventions.
     1128      Eg. The class <classname>my.domain.ServletClass</classname> should
     1129      be located at <filename>my/domain/ServletClass.class</filename>. You
     1130      also need to create a second XML file that contains the servlet
     1131      definitions at <filename>META-INF/servlets.xml</filename>. The format for
     1132      defining servlets in this file is very similar to how servlets are
     1133      defined in the <filename>web.xml</filename> file. Here is an example:
     1134    </para>
     1135   
     1136    <programlisting language="xml">
     1137<![CDATA[
     1138<?xml version="1.0" encoding="UTF-8" ?>
     1139<servlets xmlns="http://base.thep.lu.se/servlets.xsd">
     1140   <servlet>
     1141      <servlet-name>HelloWorld</servlet-name>
     1142      <servlet-class>net.sf.basedb.examples.extensions.HelloWorldServlet</servlet-class>
     1143      <init-param>
     1144         <param-name>template</param-name>
     1145         <param-value>Hello {user}! Welcome to the Servlet world!</param-value>
     1146      </init-param>
     1147   </servlet>
     1148</servlets>
     1149]]>
     1150</programlisting>
     1151
     1152    <para>
     1153      The <sgmltag class="starttag">servlets</sgmltag> tag is the root tag and is
     1154      needed to set up the namespace and schema validation. This may contain
     1155      any number of <sgmltag class="starttag">servlet</sgmltag> tags, each one
     1156      defining a single servlet.
     1157    </para>
     1158   
     1159    <para>
     1160      The <sgmltag class="starttag">servlet-name</sgmltag> tag contains the name
     1161      of the servlet. This is a required tag and must be unique among the servlets
     1162      defined by this extension. Other extensions may use the same name without any
     1163      problems.
     1164    </para>
     1165   
     1166    <para>
     1167      The <sgmltag class="starttag">servlet-class</sgmltag> tag contains the name
     1168      of implementing class. This is required and the class must implement
     1169      the <interfacename>Servlet</interfacename> interface and have a public,
     1170      no-argument constructor. We recommend that servlet implementations instead
     1171      extends the <classname>HttpServlet</classname> class. This will make the
     1172      servlet programming easier.
     1173    </para>
     1174   
     1175    <para>
     1176      A servlet may have any number <sgmltag class="starttag">init-param</sgmltag>
     1177      tags, containing initialisation parameters for the servlet. Here is the
     1178      code for the servlet references in the above example.
     1179    </para>
     1180
     1181    <programlisting language="java">
     1182<![CDATA[
     1183public class HelloWorldServlet
     1184   extends HttpServlet
     1185{
     1186   private String template;
     1187   public HelloWorldServlet()
     1188   {}
     1189
     1190   @Override
     1191   public void init()
     1192      throws ServletException
     1193   {
     1194      ServletConfig cfg = getServletConfig();
     1195      template = cfg.getInitParameter("template");
     1196      if (template == null) template = "Hello {user}.";
     1197   }
     1198
     1199   @Override
     1200   protected void doGet(HttpServletRequest request, HttpServletResponse response)
     1201      throws ServletException, IOException
     1202   {
     1203      final SessionControl sc = Base.getExistingSessionControl(request, true);
     1204      final DbControl dc = sc.newDbControl();
     1205      try
     1206      {
     1207         User current = User.getById(dc, sc.getLoggedInUserId());
     1208         PrintWriter out = response.getWriter();
     1209         out.print(template.replace("{user}", current.getName()));
     1210      }
     1211      finally
     1212      {
     1213         if (dc != null) dc.close();
     1214      }
     1215   }
     1216   @Override
     1217   protected void doPost(HttpServletRequest req, HttpServletResponse resp)
     1218      throws ServletException, IOException
     1219   {
     1220      doGet(req, resp);
     1221   }
     1222}
     1223]]>
     1224</programlisting>
     1225
     1226    <para>
     1227      Invoking the servlet is done with a URL that is constructed like:
     1228      <filename>$HOME$/[servlet-name].servlet</filename>, where <code>$HOME$</code>
     1229      is the home directory of the extension.
     1230    </para>
     1231
     1232    <programlisting language="xml">
     1233<![CDATA[
     1234<extension
     1235   id="net.sf.basedb.clients.web.menu.extensions.helloservletworld"
     1236   extends="net.sf.basedb.clients.web.menu.extensions"
     1237   >
     1238   <index>5</index>
     1239   <about>
     1240      <name>Hello Servlet world</name>
     1241      <description>
     1242         This example uses a custom Servlet page to display the
     1243         "Hello world" message instead of a javascript popup.
     1244      </description>
     1245   </about>
     1246   <action-factory>
     1247      <factory-class>
     1248         net.sf.basedb.clients.web.extensions.menu.FixedMenuItemFactory
     1249      </factory-class>
     1250      <parameters>
     1251         <title>Hello Servlet world!</title>
     1252         <tooltip>Opens a Servlet generated page with the message</tooltip>
     1253         <onClick>
     1254           Main.openPopup('$HOME$/HelloWorld.servlet?ID=' + getSessionId(), 'HelloServletWorld', 400, 300)
     1255         </onClick>
     1256         <icon>~/images/servlet.png</icon>
     1257      </parameters>
     1258   </action-factory>
     1259</extension>
     1260]]>
     1261</programlisting>
     1262   
     1263    <note>
     1264      <para>
     1265        To keep things as simple as possible, a new instance of the servlet
     1266        class is created for each request. If the servlet needs complex or
     1267        expensive initialisation, that should be externalised to other
     1268        classes that the servlet can use.
     1269      </para>
     1270    </note>
     1271   
     1272  </sect1>
     1273 
    11091274</chapter>
  • trunk/src/clients/web/net/sf/basedb/clients/web/Base.java

    r4071 r4221  
    117117    throws BaseException
    118118  {
     119    return getSessionControl(pageContext.getRequest(), create);
     120  }
     121
     122  /**
     123    Get a new or existing <code>SessionControl</code> object
     124    given a <code>ServletRequest</code> instance. This method will get
     125    the <code>ID</code> parameter from the page URL and
     126    try to retrieve the corresponding object from the
     127    BASE {@link Application}. If no {@link SessionControl}
     128    object exists, a new one will be created if the <code>create</code>
     129    parameter is TRUE.
     130 
     131    @param request The Servlet <code>request</code> variable
     132    @param create If a new <code>SessionControl</code> should be created or not
     133    @return A <code>SessionControl</code> object
     134    @throws BaseException If there is an error
     135    @since 2.7
     136  */
     137  public static final SessionControl getSessionControl(ServletRequest request, boolean create)
     138  {
    119139    SessionControl sc = null;
    120     String id = pageContext.getRequest().getParameter("ID");
    121     if (id == null && pageContext.getRequest().getAttribute("ID") instanceof String)
    122     {
    123       id = (String)pageContext.getRequest().getAttribute("ID");
    124     }
    125     String remoteId = pageContext.getRequest().getRemoteAddr();
     140    String id = request.getParameter("ID");
     141    if (id == null && request.getAttribute("ID") instanceof String)
     142    {
     143      id = (String)request.getAttribute("ID");
     144    }
     145    String remoteId = request.getRemoteAddr();
    126146    try
    127147    {
     
    138158    return sc == null && create ? Application.newSessionControl("net.sf.basedb.clients.web", remoteId, id) : sc;
    139159  }
    140 
     160 
    141161  /**
    142162    Get an existing {@link SessionControl} object
     
    157177    throws NotLoggedInException, BaseException
    158178  {
    159     SessionControl sc = getSessionControl(pageContext, false);
     179    return getExistingSessionControl(pageContext.getRequest(), checkLoggedIn);
     180  }
     181
     182  /**
     183    Get an existing {@link SessionControl} object
     184    given a <code>ServletRequest</code> object and optionally check that a user is logged in.
     185    This method will get the <code>ID</code> parameter from the page URL and
     186    try to retrieve the corresponding object from the
     187    {@link Application} and check that a user is logged in if
     188    the <code>checkLoggedIn</code> parameter is TRUE.
     189 
     190    @param request The Servlet <code>request</code> variable
     191    @param checkLoggedIn If the method should check if a user is logged in or not
     192    @return A <code>SessionControl</code> object
     193    @throws NotLoggedInException If a <code>SessionControl</code> object isn't found
     194      or no user is logged in
     195    @throws BaseException If there is another error
     196    @since 2.7
     197  */
     198  public static final SessionControl getExistingSessionControl(ServletRequest request, boolean checkLoggedIn)
     199    throws NotLoggedInException, BaseException
     200  {
     201    SessionControl sc = getSessionControl(request, false);
    160202    if (sc == null || (checkLoggedIn && !sc.isLoggedIn()))
    161203    {
     
    164206    return sc;
    165207  }
    166 
     208 
     209 
    167210  /**
    168211    Get an existing {@link SessionControl} object given
     
    192235    throws PermissionDeniedException, NotLoggedInException, BaseException
    193236  {
    194     SessionControl sc = getExistingSessionControl(pageContext, true);
     237    return getExistingSessionControl(pageContext.getRequest(), permission, itemType);
     238  }
     239
     240  /**
     241    Get an existing {@link SessionControl} object given
     242    a <code>ServletRequest</code> and check for generic (role-based)
     243    permission to an item type.
     244 
     245    This method will get the <code>ID</code> parameter from the page URL and
     246    try to retrieve the corresponding object from the {@link Application}.
     247    Then it checks that a user is logged in and that the logged in user has the
     248    specified permission for item type. If {@link Permission#DENIED} is specified,
     249    this method checks that the logged in user haven't been denied acces to
     250    those items.
     251 
     252    @param request The Servlet <code>request</code> variable
     253    @param permission The permission to check for, use one of the codes
     254      defined by the {@link Permission} class
     255    @param itemType The code for the item type to check for the permission,
     256      use one of the values defined by the {@link Item} class
     257    @return A <code>SessionControl</code> object
     258    @throws PermissionDeniedException If the logged in user doesn't have the
     259      requested permission
     260    @throws NotLoggedInException If no user is logged in or a <code>SessionControl</code>
     261      object not is found
     262    @throws BaseException If there is another error
     263    @since 2.7
     264  */
     265  public static final SessionControl getExistingSessionControl(ServletRequest request,
     266    Permission permission, Item itemType)
     267    throws PermissionDeniedException, NotLoggedInException, BaseException
     268  {
     269    SessionControl sc = getExistingSessionControl(request, true);
    195270    boolean hasPermission = sc.hasPermission(permission, itemType);
    196271    boolean checkDenied = permission == Permission.DENIED;
     
    200275    }
    201276    return sc;
    202   }
    203 
     277  } 
     278 
    204279  /**
    205280    Same as: <code>getAndSetCurrentContext(sc, itemType, "", pageContext, defaultContext, false)</code>.
    206281    @see #getAndSetCurrentContext(SessionControl, Item, String, PageContext, ItemContext, boolean)
    207282  */
    208   public static ItemContext getAndSetCurrentContext(SessionControl sc, Item itemType, PageContext pageContext, ItemContext defaultContext)
     283  public static ItemContext getAndSetCurrentContext(SessionControl sc, Item itemType,
     284      PageContext pageContext, ItemContext defaultContext)
    209285  {
    210286    return getAndSetCurrentContext(sc, itemType, "", pageContext, defaultContext, false);
     
    215291    @see #getAndSetCurrentContext(SessionControl, Item, String, PageContext, ItemContext, boolean)
    216292  */
    217   public static ItemContext getAndSetCurrentContext(SessionControl sc, Item itemType, PageContext pageContext, ItemContext defaultContext, boolean resetTemporary)
     293  public static ItemContext getAndSetCurrentContext(SessionControl sc, Item itemType,
     294      PageContext pageContext, ItemContext defaultContext, boolean resetTemporary)
    218295  {
    219296    return getAndSetCurrentContext(sc, itemType, "", pageContext, defaultContext, resetTemporary);
     
    224301    @see #getAndSetCurrentContext(SessionControl, Item, String, PageContext, ItemContext, boolean)
    225302  */
    226   public static ItemContext getAndSetCurrentContext(SessionControl sc, Item itemType, String subContext, PageContext pageContext, ItemContext defaultContext)
    227   {
    228     return getAndSetCurrentContext(sc, itemType, subContext, pageContext, defaultContext, false);
     303  public static ItemContext getAndSetCurrentContext(SessionControl sc, Item itemType,
     304      String subContext, PageContext pageContext, ItemContext defaultContext)
     305  {
     306    return getAndSetCurrentContext(sc, itemType, subContext, pageContext,
     307        defaultContext, false);
     308  }
     309 
     310  /**
     311    @see #getAndSetCurrentContext(SessionControl, Item, String, ServletRequest, ItemContext, boolean)
     312  */
     313  public static ItemContext getAndSetCurrentContext(SessionControl sc, Item itemType,
     314    String subContext, PageContext pageContext, ItemContext defaultContext, boolean resetTemporary)
     315  {
     316    ServletRequest request = pageContext == null ? null : pageContext.getRequest();
     317    return getAndSetCurrentContext(sc, itemType, subContext, request,
     318        defaultContext, resetTemporary);
    229319  }
    230320 
     
    241331     
    242332    <li>The following settings are only updated if they are available in the
    243       pageContext object's request parameters:
     333      request parameters:
    244334     
    245335      <table>
     
    343433    @param itemType The type of item to get the context for
    344434    @param subContext The name of the subcontext
    345     @param pageContext A <code>PageContext</code> object to get request
    346       information from, or null if the curren context shouldn't be updated
     435    @param request A <code>ServletRequest</code> object to get request
     436      information from, or null if the current context shouldn't be updated
    347437    @param defaultContext A default context to copy information from if a current context
    348438      doesn't exist
     
    350440      example the 'exclude' filter which is only used in popup windows
    351441    @return an updated {@link net.sf.basedb.core.ItemContext} object.
     442    @since 2.7
    352443  */
    353444  @SuppressWarnings("unchecked")
    354   public static ItemContext getAndSetCurrentContext(SessionControl sc, Item itemType, String subContext, PageContext pageContext, ItemContext defaultContext, boolean resetTemporary)
     445  public static ItemContext getAndSetCurrentContext(SessionControl sc, Item itemType,
     446    String subContext, ServletRequest request, ItemContext defaultContext, boolean resetTemporary)
    355447  {
    356448    ItemContext cc = sc.getCurrentContext(itemType, subContext, defaultContext);
     
    395487      cc.setObject("defaultColumns", defaultContext.getObject("defaultColumns"));
    396488    }
    397     if (pageContext != null)
    398     {
    399       ServletRequest request = pageContext.getRequest();
     489    if (request != null)
     490    {
    400491
    401492      // If the filter has changed we must return to the first page
  • trunk/src/clients/web/net/sf/basedb/clients/web/extensions/ExtensionsControl.java

    r4207 r4221  
    2525import java.io.File;
    2626import java.util.Collections;
     27import java.util.EnumSet;
    2728import java.util.Iterator;
    2829import java.util.Set;
    2930import java.util.TimerTask;
    3031
     32import javax.servlet.ServletContext;
    3133import javax.servlet.jsp.PageContext;
    3234
     
    9092  private static Settings settings;
    9193 
     94  // The Servlet Context provided by the web server
     95  private static ServletContext servletContext;
     96 
    9297  // Automatic check for new/updated/deleted extensions
    9398  private static TimerTask autoInstallTask;
     
    103108    {@link ExtensionsServlet} when the web server starts up.
    104109  */
    105   public static synchronized void init(ExtensionsDirectory directory)
     110  public static synchronized void init(ExtensionsDirectory directory,
     111    ServletContext servletContext)
    106112  {
    107113    if (initialised) return;
     
    118124   
    119125    // Install extensions
    120     lastScanResults = extensionsDir.installAndUpdateExtensions(registry, false, false);
     126    lastScanResults = extensionsDir.installAndUpdateExtensions(registry,
     127      servletContext, false, false);
    121128    initAutoInstaller();
    122129    initialised = true;
     
    161168    web client application is needed.
    162169   
    163     @param dc The DbControl to use for database access and permission checks
     170    @param dc The DbControl to use for database access and
     171      permission checks, or null to only get read permission
    164172    @return An extensions control instance
    165173  */
    166174  public static ExtensionsControl get(DbControl dc)
    167175  {
    168     SessionControl sc = dc.getSessionControl();
    169     Client c = Client.getById(dc, sc.getClientId());
    170     return new ExtensionsControl(c.getPermissions());
     176    Set<Permission> permissions = null;
     177    if (dc != null)
     178    {
     179      SessionControl sc = dc.getSessionControl();
     180      Client c = Client.getById(dc, sc.getClientId());
     181      permissions = c.getPermissions();
     182    }
     183    else
     184    {
     185      permissions = EnumSet.of(Permission.READ);
     186    }
     187    return new ExtensionsControl(permissions);
    171188  }
    172189 
     
    259276    checkPermission(Permission.WRITE, "extensions");
    260277    lastScanResults =
    261       extensionsDir.installAndUpdateExtensions(registry, true, forceUpdate);
     278      extensionsDir.installAndUpdateExtensions(registry, servletContext, true, forceUpdate);
    262279    return lastScanResults;
    263280  }
     
    508525      log.debug("Checking for new/updated/deleted extensions");
    509526      int autoInstall = settings.getAutoInstall();
    510       lastScanResults = extensionsDir.installAndUpdateExtensions(registry, false, false);
     527      lastScanResults = extensionsDir.installAndUpdateExtensions(registry,
     528          servletContext, false, false);
    511529      nextAutoScan = autoInstall > 0 ?
    512530        System.currentTimeMillis() + autoInstall * 1000L : 0;
  • trunk/src/clients/web/net/sf/basedb/clients/web/extensions/ExtensionsDirectory.java

    r4207 r4221  
    3636import java.util.TreeMap;
    3737import java.util.regex.Pattern;
     38
     39import javax.servlet.ServletContext;
    3840
    3941import net.sf.basedb.util.RegexpFileFilter;
     
    239241    @return The result of the scan
    240242  */
    241   public synchronized ScanResults installAndUpdateExtensions(Registry registry,
    242     boolean manualScan, boolean forceUpdate)
     243  synchronized ScanResults installAndUpdateExtensions(Registry registry,
     244    ServletContext servletContext, boolean manualScan, boolean forceUpdate)
    243245  {
    244246    log.info("Begin scan for new/updated/deleted extensions");
     
    276278        extractResources(forceUpdate, results);
    277279       
    278         // 5. Register new and updated extensions with the registry
     280        // 5. Load servlets
     281        loadServlets(servletContext, forceUpdate, results);
     282       
     283        // 6. Register new and updated extensions with the registry
    279284        registerExtensions(registry, forceUpdate, results);
    280285      }
     
    538543 
    539544  /**
     545    Load servlet definitions from JAR files. Servlets should be
     546    defined in META-INF/servlets.xml.
     547  */
     548  private void loadServlets(ServletContext servletContext, boolean forceUpdate, ScanResults results)
     549  {
     550    for (ExtensionsFile extFile : installedFiles.values())
     551    {
     552      // Do not load servlets from files with an error
     553      if (extFile.hasError()) continue;
     554     
     555      try
     556      {
     557        if (forceUpdate || extFile.isModified())
     558        {
     559          int numServlets = extFile.loadServlets(servletContext);
     560          if (numServlets > 0)
     561          {
     562            results.addMessage(extFile,
     563                numServlets + " servlets defined successfully.");
     564          }
     565        }
     566      }
     567      catch (Throwable ex)
     568      {
     569        extFile.setError(true);
     570        results.addErrorMessage(extFile, "Could not load servlets: " + ex.getMessage());
     571        log.error("Could not load servlets from " + extFile.getName(), ex);
     572      }
     573    }
     574  }
     575
     576 
     577  /**
    540578    Register extensions with the registry. Unless forceUpdate is TRUE only
    541579    new and modified extensions are registered. Extensions files that has
  • trunk/src/clients/web/net/sf/basedb/clients/web/extensions/ExtensionsFile.java

    r4202 r4221  
    3232import java.util.ArrayList;
    3333import java.util.Collections;
     34import java.util.HashMap;
    3435import java.util.Iterator;
    3536import java.util.List;
     37import java.util.Map;
    3638import java.util.regex.Matcher;
    3739import java.util.regex.Pattern;
     
    3941import java.util.zip.ZipFile;
    4042import java.util.zip.ZipInputStream;
     43
     44import javax.servlet.ServletContext;
    4145
    4246import net.sf.basedb.core.plugin.About;
     
    7781  private About about;
    7882  private boolean hasError;
     83 
     84  private Map<String, ServletWrapper> servlets;
    7985 
    8086  /**
     
    423429    return about;
    424430  }
     431 
     432 
     433   
     434  /**
     435    Load servlet definitions from a JAR file.
     436  */
     437  int loadServlets(ServletContext context)
     438  {
     439    if (!isJar) return 0;
     440    log.info("Loading servlets from JAR file: " + file.getName());
     441    InputStream in = null;
     442    ZipFile zipFile = null;
     443    int numServlets = 0;
     444    try
     445    {
     446      zipFile = new ZipFile(file);
     447      ZipEntry zipEntry = zipFile.getEntry("META-INF/servlets.xml");
     448      if (zipEntry == null)
     449      {
     450        log.info("META-INF/servlets.xml not found in file: " + file.getName());
     451        return 0;
     452      }
     453     
     454      if (servlets == null) servlets = new HashMap<String, ServletWrapper>();
     455      servlets.clear();
     456      in = zipFile.getInputStream(zipEntry);
     457     
     458      ClassLoader jarLoader = JarClassLoader.getInstance(file.getAbsolutePath(), true);
     459     
     460      ServletLoader servletLoader = new ServletLoader();
     461      servletLoader.loadXmlFile(in, file.getName(), jarLoader, true);
     462      for (ServletWrapper wrapper : servletLoader.getServlets())
     463      {
     464        wrapper.setServletContext(context);
     465        servlets.put(wrapper.getServletName(), wrapper);
     466        numServlets++;
     467      }
     468    }
     469    catch (Exception ex)
     470    {
     471      log.error("Error loading servlets from JAR file: " + file, ex);
     472      throw new RuntimeException("Error loading servlets from '" + file + "': " +
     473        ex.getMessage(), ex);
     474    }
     475    finally
     476    {
     477      try
     478      {
     479        if (in != null) in.close();
     480        if (zipFile != null) zipFile.close();
     481      }
     482      catch (IOException ex)
     483      {}
     484    }
     485    log.info(numServlets + " servlets loaded from JAR file: " + file.getName());
     486    return numServlets;
     487  }
     488 
    425489 
    426490  /**
     
    637701  }
    638702 
     703  /**
     704    Get a servlet that has been defined in this JAR file.
     705    @param servletName The name of the servlet, specified by the
     706      &lt;servlet-name&gt; tag in the XML file.
     707    @return A wrapper that can be used to invoke the servlet,
     708      or null if not servlet with the given name exists
     709  */
     710  public ServletWrapper getServlet(String servletName)
     711  {
     712    return servlets == null ? null : servlets.get(servletName);
     713  }
    639714 
    640715}
  • trunk/src/clients/web/net/sf/basedb/clients/web/servlet/ExtensionsServlet.java

    r4198 r4221  
    2424
    2525import java.io.File;
     26import java.io.IOException;
     27import java.util.regex.Matcher;
     28import java.util.regex.Pattern;
    2629
    2730import javax.servlet.ServletConfig;
     
    2932import javax.servlet.ServletException;
    3033import javax.servlet.http.HttpServlet;
     34import javax.servlet.http.HttpServletRequest;
     35import javax.servlet.http.HttpServletResponse;
    3136
    3237import net.sf.basedb.clients.web.extensions.ExtensionsControl;
    3338import net.sf.basedb.clients.web.extensions.ExtensionsDirectory;
     39import net.sf.basedb.clients.web.extensions.ExtensionsFile;
     40import net.sf.basedb.clients.web.extensions.ServletWrapper;
    3441
    3542/**
     
    3845  <code>&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;</code>
    3946  option in the web.xml file. When the servlet is loaded it will initialise the
    40   {@link ExtensionsControl} class. This servlet is not used to handle
    41   any requests.
     47  {@link ExtensionsControl} class.
     48  <p>
     49 
     50  This servlet is also acting as a proxy for requests to extension defined
     51  servlets. Such servlets are defined in <code>META-INF/servlets.xml</code>
     52  in the extension JAR file. A request to a servlet must have the following
     53  URL pattern:
     54  <code>/extensions/[jar-name]/[servlet-name].servlet</code>
    4255 
    4356  @author nicklas
     
    6679    ExtensionsDirectory extensions = new ExtensionsDirectory(
    6780        extensionsDir, resourcesDir, rootUrl, rootUrl + ExtensionsControl.RESOURCES_URL);
    68     ExtensionsControl.init(extensions);
     81    ExtensionsControl.init(extensions, context);
    6982  }
    7083
     84  /**
     85    Path to servlet must match: /extensions/[jar-file-name]/[servlet-name].servlet
     86    group(1) = JAR name, group(2) = Servlet name
     87  */
     88  private static final Pattern PATH_MATCH =
     89    Pattern.compile(ExtensionsControl.RESOURCES_URL + "/([^/]+)/(.+)\\.servlet");
     90 
     91  @Override
     92  protected void doGet(HttpServletRequest request, HttpServletResponse response)
     93    throws ServletException, IOException
     94  {
     95   
     96    String servletPath = request.getServletPath();
     97    Matcher m = PATH_MATCH.matcher(servletPath);
     98    if (!m.matches())
     99    {
     100      response.sendError(HttpServletResponse.SC_NOT_FOUND, servletPath);
     101      return;
     102    }
     103   
     104    String jarName = m.group(1);
     105    String servletName = m.group(2);
     106    ExtensionsControl ec = ExtensionsControl.get(null);
     107    ExtensionsFile file = ec.getFile(jarName);
     108    if (file == null)
     109    {
     110      response.sendError(HttpServletResponse.SC_NOT_FOUND, servletPath);
     111      return;
     112    }
     113    else if (!file.isJar())
     114    {
     115      response.sendError(HttpServletResponse.SC_BAD_REQUEST, servletPath + " is not a JAR file.");
     116      return;
     117    }
     118 
     119    ServletWrapper wrapper = file.getServlet(servletName);
     120    if (wrapper == null)
     121    {
     122      response.sendError(HttpServletResponse.SC_NOT_FOUND, servletPath);
     123      return;
     124    }
     125    wrapper.service(request, response);
     126  }
     127
     128  @Override
     129  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
     130    throws ServletException, IOException
     131  {
     132    doGet(req, resp);
     133  }
     134 
    71135}
Note: See TracChangeset for help on using the changeset viewer.