[Mulgara-svn] r2077 - in trunk/src: jar/server/java/org/mulgara/server war/descriptor

pag at mulgara.org pag at mulgara.org
Mon Dec 12 23:30:55 UTC 2011


Author: pag
Date: 2011-12-12 23:30:54 +0000 (Mon, 12 Dec 2011)
New Revision: 2077

Added:
   trunk/src/jar/server/java/org/mulgara/server/HttpServicesImpl.java
Modified:
   trunk/src/jar/server/java/org/mulgara/server/EmbeddedMulgaraServer.java
   trunk/src/jar/server/java/org/mulgara/server/HttpServices.java
   trunk/src/war/descriptor/index.jsp
Log:
Factored out usage of HttpServices into an interface, so compilation does not require web libraries if they aren't used

Modified: trunk/src/jar/server/java/org/mulgara/server/EmbeddedMulgaraServer.java
===================================================================
--- trunk/src/jar/server/java/org/mulgara/server/EmbeddedMulgaraServer.java	2011-12-12 17:33:01 UTC (rev 2076)
+++ trunk/src/jar/server/java/org/mulgara/server/EmbeddedMulgaraServer.java	2011-12-12 23:30:54 UTC (rev 2077)
@@ -53,6 +53,7 @@
 import org.mulgara.server.SessionFactory;
 import org.mulgara.store.StoreException;
 import org.mulgara.store.xa.SimpleXAResourceException;
+import org.mulgara.util.Reflect;
 import org.mulgara.util.Rmi;
 import org.mulgara.util.StackTrace;
 import org.mulgara.util.TempDir;
@@ -379,7 +380,7 @@
         // create a HTTP server instance
         if (log.isDebugEnabled()) log.debug("Configuring HTTP server");
         try {
-          webServices = new HttpServices(this, httpHostName, mulgaraConfig);
+          webServices = createHttpServices(this, httpHostName, mulgaraConfig);
         } catch (Exception e) {
           String message = e.getMessage();
           if (message == null) message = StackTrace.throwableToString(e);
@@ -868,6 +869,42 @@
     }
   }
 
+  /**
+   * Create an HttpServices implementation without requiring the source to be available
+   * at compile time. Ensures that the original exception type is thrown.
+   * @param server The server to create the services for.
+   * @param httpHostName The name of the host for the HTTP server.
+   * @param mulgaraConfig The configuration for the server.
+   * @return A new HttpServices object.
+   * @throws IOException Exception setting up with files or network.
+   * @throws SAXException Problem reading XML configurations.
+   * @throws ClassNotFoundException An expected class was not found.
+   * @throws NoSuchMethodException A configured class was not built as expected.
+   * @throws InvocationTargetException A configured class did not behave as expected.
+   * @throws IllegalAccessException A configured class was not accessible.
+   */
+  private static HttpServices createHttpServices(EmbeddedMulgaraServer server, String httpHostName, MulgaraConfig mulgaraConfig)
+        throws IOException, SAXException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+    Class<?> servicesClass = Class.forName(HttpServices.IMPL_CLASS_NAME);
+    try {
+      return (HttpServices)Reflect.newInstance(servicesClass, server, httpHostName, mulgaraConfig);
+    } catch (RuntimeException e) {
+      Throwable wrapped = e.getCause();
+      if (wrapped instanceof IOException) {
+        throw (IOException)wrapped;
+      } else if (wrapped instanceof SAXException) {
+        throw (SAXException)wrapped;
+      } else if (wrapped instanceof ClassNotFoundException) {
+        throw (ClassNotFoundException)wrapped;
+      } else if (wrapped instanceof NoSuchMethodException) {
+        throw (NoSuchMethodException)wrapped;
+      } else if (wrapped instanceof InvocationTargetException) {
+        throw (InvocationTargetException)wrapped;
+      } else if (wrapped instanceof IllegalAccessException) {
+        throw (IllegalAccessException)wrapped;
+      } else throw e;
+    }
+  }
 
   /**
    * Filter class for detecting temporary files created by Mulgara

Modified: trunk/src/jar/server/java/org/mulgara/server/HttpServices.java
===================================================================
--- trunk/src/jar/server/java/org/mulgara/server/HttpServices.java	2011-12-12 17:33:01 UTC (rev 2076)
+++ trunk/src/jar/server/java/org/mulgara/server/HttpServices.java	2011-12-12 23:30:54 UTC (rev 2077)
@@ -1,539 +1,43 @@
 /*
- * The contents of this file are subject to the Open Software License
- * Version 3.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.opensource.org/licenses/osl-3.0.txt
+ * Copyright 2011 Revelytix, Inc.
  *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 package org.mulgara.server;
 
-import static org.eclipse.jetty.servlet.ServletContextHandler.SESSIONS;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.net.URL;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.servlet.Servlet;
-
-import org.apache.log4j.Logger;
-import org.eclipse.jetty.server.AbstractConnector;
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.HandlerContainer;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.ContextHandler;
-import org.eclipse.jetty.server.handler.HandlerCollection;
-import org.eclipse.jetty.server.nio.BlockingChannelConnector;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.webapp.WebAppClassLoader;
-import org.eclipse.jetty.webapp.WebAppContext;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.eclipse.jetty.util.MultiException;
-import org.mulgara.config.JettyConnector;
-import org.mulgara.config.MulgaraConfig;
-import org.mulgara.util.JettyLogger;
-import org.mulgara.util.Reflect;
-import org.mulgara.util.TempDir;
-import org.mulgara.util.functional.Fn1E;
-import org.mulgara.util.functional.Pair;
-import org.xml.sax.SAXException;
-
 /**
  * Manages all the HTTP services provided by a Mulgara server.
  *
- * @created Sep 5, 2008
+ * @created Dec 12, 2011
  * @author Paul Gearon
- * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
- * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
  */
-public class HttpServices {
+public interface HttpServices {
 
-  /** A virtual typedef for a context starter. */
-  private interface ContextStarter extends Fn1E<Server,Pair<String,String>,IOException> { }
+  /** The name of the primary implementation class. */
+  public static String IMPL_CLASS_NAME = "org.mulgara.server.HttpServicesImpl";
 
-  /** A virtual typedef for a service path. */
-  private class Service extends Pair<String,String> { Service(String f, String s) { super(f,s); } }
-
-  /** The logging category to log to. */
-  protected static final Logger logger = Logger.getLogger(HttpServices.class.getName());
-
-  /** The web application file path. */
-  private final static String WEBAPP_PATH = "webapps";
-
-  /** The Web Services web application file. */
-  private final static String WEBSERVICES_WEBAPP = "webservices.war";
-
-  /** The Web Services path. */
-  private final static String WEBSERVICES_PATH = "webservices";
-
-  /** The Web Query path. */
-  private final static String WEBQUERY_PATH = "webui";
-
-  /** The Web Tutorial path. */
-  private final static String WEBTUTORIAL_PATH = "tutorial";
-
-  /** The sparql path. */
-  private final static String SPARQL_PATH = "sparql";
-
-  /** The tql path. */
-  private final static String TQL_PATH = "tql";
-
-  /** The default service path. */
-  private final static String DEFAULT_SERVICE = WEBQUERY_PATH;
-
-  /** The key to the bound host name in the attribute map of the servlet context. */
-  public final static String BOUND_HOST_NAME_KEY = "boundHostname";
-
-  /** Key to the bound server model uri in the attribute map of the servlet context. */
-  public final static String SERVER_MODEL_URI_KEY = "serverModelURI";
-
-  /** The HTTP server instance. */
-  private final Server httpServer;
-
-  /** The Public HTTP server instance. */
-  private final Server httpPublicServer;
-
-  /** The configuration for the server. */
-  private final MulgaraConfig config;
-
-  /** The name for the host. */
-  private String hostName;
-
-  /** The host server. This may contain information useful to services. */
-  private final EmbeddedMulgaraServer hostServer;
-
-
   /**
-   * Creates the web services object.
-   * @param hostServer The Server that started these Web services.
-   * @param hostName The name of the HTTP host this object is setting up.
-   * @param config The configuration to use.
-   * @throws IOException Exception setting up with files or network.
-   * @throws SAXException Problem reading XML configurations.
-   * @throws ClassNotFoundException An expected class was not found.
-   * @throws NoSuchMethodException A configured class was not built as expected.
-   * @throws InvocationTargetException A configured class did not behave as expected.
-   * @throws IllegalAccessException A configured class was not accessible.
-   */
-  public HttpServices(EmbeddedMulgaraServer hostServer, String hostName, MulgaraConfig config)  throws IOException, SAXException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
-    this.hostServer = hostServer;
-    this.config = config;
-    this.hostName = hostName;
-    assert !config.getJetty().isDisabled();
-    // get servers as a pair so we can set them here. Needed because they are final.
-    Pair<Server,Server> servers = createHttpServers();
-    httpServer = servers.first();
-    httpPublicServer = servers.second();
-  }
-
-
-  /**
    * Starts the web server and all services.
    * @throws ExceptionList Caused by a MultiException in the HTTP Server.
    * @throws Exception Both the server and the services are able to throw exceptions.
    */
-  @SuppressWarnings("unchecked")
-  public void start() throws ExceptionList, Exception {
-    try {
-      if (httpServer != null) httpServer.start();
-      if (httpPublicServer != null) httpPublicServer.start();
-    } catch (MultiException e) {
-      throw new ExceptionList(e.getThrowables());
-    }
-  }
+  public void start() throws ExceptionList, Exception;
 
-
   /**
    * Stops the web server and all services.
    * @throws Exception Both the server and the services are able to throw exceptions.
    */
-  public void stop() throws Exception {
-    try {
-      if (httpServer != null) httpServer.stop();
-    } finally {
-      if (httpPublicServer != null) httpPublicServer.stop();
-    }
-  }
+  public void stop() throws Exception;
 
-
-  /**
-   * Creates an HTTP server.
-   * @return a pair of private/public servers.
-   * @throws IOException if the server configuration cannot be found
-   * @throws SAXException if the HTTP server configuration file is invalid
-   * @throws ClassNotFoundException if the HTTP server configuration file contains a reference to an unkown class
-   * @throws NoSuchMethodException if the HTTP server configuration file contains a reference to an unkown method
-   * @throws InvocationTargetException if an error ocurrs while trying to configure the HTTP server
-   * @throws IllegalAccessException If a class loaded by the server is accessed in an unexpected way.
-   */
-  public Pair<Server,Server> createHttpServers() throws IOException, SAXException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
-    if (logger.isDebugEnabled()) logger.debug("Creating HTTP server instance");
-
-    // Set the magic logging property for Jetty to use Log4j
-    System.setProperty(JettyLogger.LOGGING_CLASS_PROPERTY, JettyLogger.class.getCanonicalName());
-    JettyLogger.setEnabled(false);
-    org.eclipse.jetty.util.log.Log.setLog(new JettyLogger());
-
-    // create and register a new HTTP server
-    Server privateServer = buildAndConfigure(config.getJetty().getConnector(), ServerInfo.getHttpPort());
-    Server publicServer = buildAndConfigure(config.getJetty().getPublicConnector(), ServerInfo.getPublicHttpPort());
-
-
-    if (privateServer != null) {
-      // Accumulator for all the services
-      Map<String,String> privateServices = new HashMap<String,String>();
-
-      // start all the private configured services.
-      for (ContextStarter starter: getContextStarters()) {
-        try {
-          starter.fn(privateServer).addTo(privateServices);
-        } catch (IllegalStateException e) {
-          // not fatal, so just log the problem and go on
-          logger.warn("Unable to start web service", e.getCause());
-        }
-      }
-
-      // we have all the services, so now instantiate the service listing service
-      addWebServiceListingContext(privateServer, privateServices);
-    }
-    
-    if (publicServer != null) {
-      // start the public contexts
-      for (ContextStarter starter: getPublicContextStarters()) {
-        try {
-          starter.fn(publicServer);
-        } catch (IllegalStateException e) {
-          logger.warn("Unable to start public web service", e.getCause());
-        }
-      }
-    }
-
-    // configure the private handlers
-    List<Handler> privateHandlers = Collections.emptyList();
-    if (privateServer != null) {
-      privateHandlers = Arrays.asList(privateServer.getChildHandlers());
-      configureHandlers(privateHandlers, config.getJetty().getConnector());
-    }
-    // configure the private handlers
-    List<Handler> publicHandlers = Collections.emptyList();
-    if (publicServer != null) {
-      publicHandlers = Arrays.asList(publicServer.getChildHandlers());
-      configureHandlers(publicHandlers, config.getJetty().getPublicConnector());
-    }
-
-    // get all the handlers in use by both servers
-    List<Handler> handlers = new ArrayList<Handler>(privateHandlers);
-    handlers.addAll(publicHandlers);
-
-    // add our class loader as the classloader of all contexts, unless this is a webapp in which case we wrap it
-    ClassLoader classLoader = this.getClass().getClassLoader();
-    for (Handler handler: handlers) {
-      if (handler instanceof WebAppContext) ((WebAppContext)handler).setClassLoader(new WebAppClassLoader(classLoader, (WebAppContext)handler));
-      else if (handler instanceof ContextHandler) ((ContextHandler)handler).setClassLoader(classLoader);
-    }
-
-    // return the servers
-    return new Pair<Server,Server>(privateServer, publicServer);
-  }
-
-
-  /**
-   * Create a server object, and configure it.
-   * @param cfg The Jetty configuration for the server.
-   * @return The created server.
-   * @throws UnknownHostException The configured host name is invalid.
-   */
-  Server buildAndConfigure(JettyConnector cfg, int port) throws UnknownHostException {
-    Server s = null;
-    boolean disabled = (cfg != null && cfg.hasDisabled() && cfg.isDisabled());
-    if (!disabled) {
-      if (cfg != null) {
-        s = new Server();
-        addConnector(s, cfg, port);
-      } else {
-        s = new Server(port);
-      }
-    }
-    return s;
-  }
-
-
-  /**
-   * Configure all of the handlers with a connector configuration.
-   * @param handlers The handlers to configure.
-   * @param conCfg The connector configuration to use.
-   */
-  void configureHandlers(List<Handler> handlers, JettyConnector conCfg) {
-    if (conCfg == null) return;
-    for (Handler handler: handlers) {
-      // expect each handler to be an instance of a ContextHandler, but we still check
-      if (handler instanceof ContextHandler) {
-        ContextHandler ctx = (ContextHandler)handler;
-        // test for parameters, and if present, then set on the handler
-        if (conCfg.hasMaxFormContentSize()) {
-          ctx.setMaxFormContentSize(conCfg.getMaxFormContentSize());
-        }
-      }
-    }
-  }
-
-
-  /**
-   * Creates a list of functions for starting contexts.
-   * <strong>This defines the list of services to be run.</strong>
-   * @return A list that can start all the configured contexts.
-   */
-  private List<ContextStarter> getContextStarters() {
-    List<ContextStarter> starters = new ArrayList<ContextStarter>();
-    starters.add(new ContextStarter() { public Service fn(Server s) throws IOException {
-      return addWebServicesWebAppContext(s);
-    } });
-    starters.add(new ContextStarter() { public Service fn(Server s) throws IOException {
-      return addWebQueryContext(s, "User Interface", "org.mulgara.webquery.QueryServlet", WEBQUERY_PATH);
-    } });
-    starters.add(new ContextStarter() { public Service fn(Server s) throws IOException {
-      return addWebQueryContext(s, "User Tutorial", "org.mulgara.webquery.TutorialServlet", WEBTUTORIAL_PATH);
-    } });
-    // expect to get the following from a config file
-    // TODO: create a decent configuration object, instead of just handing out a Server
-    starters.add(new ContextStarter() { public Service fn(Server s) throws IOException {
-      return addServletContext(s, "org.mulgara.protocol.http.SparqlServlet", SPARQL_PATH, "SPARQL HTTP Service");
-    } });
-    starters.add(new ContextStarter() { public Service fn(Server s) throws IOException {
-      return addServletContext(s, "org.mulgara.protocol.http.TqlServlet", TQL_PATH, "TQL HTTP Service");
-    } });
-    return starters;
-  }
-
-
-  /**
-   * Creates a list of functions for starting public contexts.
-   * <strong>This defines the list of services to be run.</strong>
-   * @return A list that can start all the configured contexts.
-   */
-  private List<ContextStarter> getPublicContextStarters() {
-    List<ContextStarter> starters = new ArrayList<ContextStarter>();
-    starters.add(new ContextStarter() { public Service fn(Server s) throws IOException {
-      return addServletContext(s, "org.mulgara.protocol.http.PublicSparqlServlet", SPARQL_PATH, "SPARQL HTTP Service");
-    } });
-    return starters;
-  }
-
-
-  /**
-   * Adds a listener to the <code>httpServer</code>. The listener is created and configured
-   * according to the Jetty configuration.
-   * @param httpServer the server to add the listener to
-   * @param jettyConfig The configuraton for the server. Do not read the port at this point.
-   * @param port The port to listen on. The configuration may have been overriden by this value.
-   * @throws UnknownHostException if an invalid hostname was specified in the Mulgara server configuration
-   */
-  @SuppressWarnings("deprecation")
-  private void addConnector(Server httpServer, JettyConnector jettyConfig, int port) throws UnknownHostException {
-    if (httpServer == null) throw new IllegalArgumentException("Null \"httpServer\" parameter");
-
-    if (logger.isDebugEnabled()) logger.debug("Adding socket listener");
-
-    // create and configure a listener
-    AbstractConnector connector = new BlockingChannelConnector();
-    if ((hostName != null) && !hostName.equals("")) {
-      connector.setHost(hostName);
-      if (logger.isDebugEnabled()) logger.debug("Servlet container listening on host " + hostName);
-    } else {
-      hostName = EmbeddedMulgaraServer.getResolvedLocalHost();
-      if (logger.isDebugEnabled()) logger.debug("Servlet container listening on all host interfaces");
-    }
-
-    // Each connector will get its own thread pool, so that they may be configured separately.
-    // If a connector does not have its own thread pool, it inherits one from the server that it might
-    // share with other connectors.
-    QueuedThreadPool threadPool = new QueuedThreadPool();
-    if (jettyConfig.hasMaxThreads()) {
-      threadPool.setMaxThreads(jettyConfig.getMaxThreads());
-    }
-    connector.setThreadPool(threadPool);
-
-    connector.setPort(port);
-    if (jettyConfig.hasMaxIdleTimeMs()) connector.setMaxIdleTime(jettyConfig.getMaxIdleTimeMs());
-    if (jettyConfig.hasLowResourceMaxIdleTimeMs()) connector.setLowResourceMaxIdleTime(jettyConfig.getLowResourceMaxIdleTimeMs());
-    if (jettyConfig.hasAcceptors()) {
-      int acceptors = jettyConfig.getAcceptors();
-      // Acceptors are part of the thread pool, but they delegate handling of servlet
-      // requests to another thread in the pool.  Therefore, the number of acceptors
-      // must be strictly less than the maximum number of threads in the pool.
-      int acceptorLimit = threadPool.getMaxThreads() - 1;
-      if (acceptors > acceptorLimit) {
-        logger.warn("Acceptor threads set beyond HTTP Server limits. Reducing from" + acceptors + " to " + acceptorLimit);
-        acceptors = acceptorLimit;
-      }
-      connector.setAcceptors(acceptors);
-    }
-
-    // add the listener to the http server
-    httpServer.addConnector(connector);
-  }
-
-
-  /**
-   * Creates the Mulgara Descriptor UI. Once created, a description of the created services is returned.
-   * @return A Service description of the Descriptor services that were started.
-   * @throws IOException if the driver WAR file is not readable
-   */
-  private Service addWebServicesWebAppContext(Server server) throws IOException {
-    // get the URL to the WAR file
-    URL webServicesWebAppURL = ClassLoader.getSystemResource(WEBAPP_PATH + "/" + WEBSERVICES_WEBAPP);
-
-    if (webServicesWebAppURL == null) {
-      logger.warn("Couldn't find resource: " + WEBAPP_PATH + "/" + WEBSERVICES_WEBAPP);
-      return null;
-    }
-
-    String warPath = extractToTemp(WEBAPP_PATH + "/" + WEBSERVICES_WEBAPP);
-    
-    // Add Descriptors and Axis
-    String webPath = "/" + WEBSERVICES_PATH;
-    WebAppContext descriptorWARContext = new WebAppContext(getHandlerCollection(server), warPath, webPath);
-
-    // make some attributes available
-    descriptorWARContext.setAttribute(BOUND_HOST_NAME_KEY, ServerInfo.getBoundHostname());
-    descriptorWARContext.setAttribute(SERVER_MODEL_URI_KEY, ServerInfo.getServerURI().toString());
-
-    // log that we're adding the test webapp context
-    if (logger.isDebugEnabled()) logger.debug("Added Web Services webapp context");
-    return new Service("Web Services", webPath);
-  }
-
-
-  /**
-   * Creates and registers a web servlet. The servlet will need to know the server name.
-   * @param server The server to connect the servlet to.
-   * @param name The human-readable name of the servlet to create.
-   * @param servletClass The name of the class that will perform the servlet functions.
-   * @param servletPath The path on the server for the servlet to be loaded onto.
-   * @return A description of the servlet that was set up.
-   * @throws IOException if the servlet cannot talk to the network.
-   */
-  private Service addWebQueryContext(Server server, String name, String servletClass, String servletPath) throws IOException {
-    if (logger.isDebugEnabled()) logger.debug("Adding Web servlet context: " + name);
-
-    // create the web context
-    try {
-      String rmiName = hostServer.getServerName();
-      Servlet servlet = (Servlet)Reflect.newInstance(Class.forName(servletClass), hostName, rmiName, hostServer);
-      String webPath = "/" + servletPath;
-      new org.eclipse.jetty.servlet.ServletContextHandler(getHandlerCollection(server), webPath, SESSIONS).addServlet(new ServletHolder(servlet), "/*");
-      return new Service(name, webPath);
-    } catch (ClassNotFoundException e) {
-      throw new IllegalStateException("Not configured to use the requested servlet: " + name + "(" + servletClass + ")");
-    }
-  }
-
-
-  /**
-   * Creates a servlet that requires a Server as a constructor parameter. This is similar to {@link #addWebQueryContext(Server, String, String, String)}
-   * except that the servlet does not need to know the server name.
-   * @param server The server to connect the servlet to.
-   * @param servletClass The name of the servlet class.
-   * @param path A relative HTTP path for attaching the servlet. 
-   * @param description A description for the servlet.
-   * @return The Service describing the new servlet.
-   * @throws IOException Due to problems with the file system or the network.
-   * @throws IllegalStateException if an unavailable servlet has been requested.
-   */
-  private Service addServletContext(Server server, String servletClass, String path, String description) throws IOException {
-    if (logger.isDebugEnabled()) logger.debug("Adding " + description + " servlet context");
-
-    // create the web query context
-    try {
-      Servlet servlet = (Servlet)Reflect.newInstance(Class.forName(servletClass), hostServer);
-      String webPath = "/" + path;
-      new org.eclipse.jetty.servlet.ServletContextHandler(getHandlerCollection(server), webPath, SESSIONS).addServlet(new ServletHolder(servlet), "/*");
-      return new Service(description, webPath);
-    } catch (ClassNotFoundException e) {
-      throw new IllegalStateException("Not configured to use the requested servlet: " + description);
-    }
-  }
-
-  /**
-   * Creates the servlet used to list the other servlets.
-   * @param server The server to register this servlet with.
-   * @param services The list of service names and paths.
-   * @throws IOException If the servlet cannot talk to the network.
-   */
-  private void addWebServiceListingContext(Server server, Map<String,String> services) throws IOException {
-    if (logger.isDebugEnabled()) logger.debug("Adding the service lister context");
-    Servlet servlet = new ServiceListingServlet(services, "/" + DEFAULT_SERVICE);
-    new org.eclipse.jetty.servlet.ServletContextHandler(getHandlerCollection(server), "/", SESSIONS).addServlet(new ServletHolder(servlet), "/*");
-  }
-
-  /**
-   * Retrieves a handler collection from the server, setting it if the server does not hold a collection.
-   * @param server The server to get a handler collection from.
-   * @return A handler collection for the server.
-   */
-  private HandlerContainer getHandlerCollection(Server server) {
-    HandlerCollection handlerCollection;
-    Handler handler = server.getHandler();
-    if (handler instanceof HandlerCollection) {
-      handlerCollection = (HandlerCollection)handler;
-    } else {
-      handlerCollection = new HandlerCollection();
-      if (handler != null) handlerCollection.addHandler(handler);
-      server.setHandler(handlerCollection);
-    }
-    return handlerCollection;
-  }
-
-  /**
-   * Extracts a resource from the environment (a jar in the classpath) and writes
-   * this to a file in the working temporary directory.
-   * @param resourceName The name of the resource. This is a relative file path in the jar file.
-   * @return The absolute path of the file the resource is extracted to, or <code>null</code>
-   *         if the resource does not exist.
-   * @throws IOException If there was an error reading the resource, or writing to the extracted file.
-   */
-  private String extractToTemp(String resourceName) throws IOException {
-    // Find the resource
-    URL resourceUrl = ClassLoader.getSystemResource(resourceName);
-    if (resourceUrl == null) return null;
-
-    // open the resource and the file where it will be copied to
-    File outFile = new File(TempDir.getTempDir(), new File(resourceName).getName());
-    logger.info("Extracting: " + resourceUrl + " to " + outFile);
-
-    InputStream in = null;
-    OutputStream out = null;
-    try {
-      in = resourceUrl.openStream();
-      out = new FileOutputStream(outFile);
-  
-      // loop to copy from the resource to the output file
-      byte[] buffer = new byte[10240];
-      int len;
-      while ((len = in.read(buffer)) >= 0) out.write(buffer, 0, len);
-    } finally {
-      if (in != null) in.close();
-      if (out != null) out.close();
-    }
-
-    // return the file that the resource was extracted to
-    return outFile.getAbsolutePath();
-  }
-
-
-}
+}
\ No newline at end of file

Added: trunk/src/jar/server/java/org/mulgara/server/HttpServicesImpl.java
===================================================================
--- trunk/src/jar/server/java/org/mulgara/server/HttpServicesImpl.java	                        (rev 0)
+++ trunk/src/jar/server/java/org/mulgara/server/HttpServicesImpl.java	2011-12-12 23:30:54 UTC (rev 2077)
@@ -0,0 +1,540 @@
+/*
+ * Copyright 2008 Fedora Commons, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.mulgara.server;
+
+import static org.eclipse.jetty.servlet.ServletContextHandler.SESSIONS;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.Servlet;
+
+import org.apache.log4j.Logger;
+import org.eclipse.jetty.server.AbstractConnector;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HandlerContainer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.server.nio.BlockingChannelConnector;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.webapp.WebAppClassLoader;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.eclipse.jetty.util.MultiException;
+import org.mulgara.config.JettyConnector;
+import org.mulgara.config.MulgaraConfig;
+import org.mulgara.util.JettyLogger;
+import org.mulgara.util.Reflect;
+import org.mulgara.util.TempDir;
+import org.mulgara.util.functional.Fn1E;
+import org.mulgara.util.functional.Pair;
+import org.xml.sax.SAXException;
+
+/**
+ * Manages all the HTTP services provided by a Mulgara server.
+ *
+ * @created Sep 5, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ */
+public class HttpServicesImpl implements HttpServices {
+
+  /** A virtual typedef for a context starter. */
+  private interface ContextStarter extends Fn1E<Server,Pair<String,String>,IOException> { }
+
+  /** A virtual typedef for a service path. */
+  private class Service extends Pair<String,String> { Service(String f, String s) { super(f,s); } }
+
+  /** The logging category to log to. */
+  protected static final Logger logger = Logger.getLogger(HttpServicesImpl.class.getName());
+
+  /** The web application file path. */
+  private final static String WEBAPP_PATH = "webapps";
+
+  /** The Web Services web application file. */
+  private final static String WEBSERVICES_WEBAPP = "webservices.war";
+
+  /** The Web Services path. */
+  private final static String WEBSERVICES_PATH = "webservices";
+
+  /** The Web Query path. */
+  private final static String WEBQUERY_PATH = "webui";
+
+  /** The Web Tutorial path. */
+  private final static String WEBTUTORIAL_PATH = "tutorial";
+
+  /** The sparql path. */
+  private final static String SPARQL_PATH = "sparql";
+
+  /** The tql path. */
+  private final static String TQL_PATH = "tql";
+
+  /** The default service path. */
+  private final static String DEFAULT_SERVICE = WEBQUERY_PATH;
+
+  /** The key to the bound host name in the attribute map of the servlet context. */
+  public final static String BOUND_HOST_NAME_KEY = "boundHostname";
+
+  /** Key to the bound server model uri in the attribute map of the servlet context. */
+  public final static String SERVER_MODEL_URI_KEY = "serverModelURI";
+
+  /** The HTTP server instance. */
+  private final Server httpServer;
+
+  /** The Public HTTP server instance. */
+  private final Server httpPublicServer;
+
+  /** The configuration for the server. */
+  private final MulgaraConfig config;
+
+  /** The name for the host. */
+  private String hostName;
+
+  /** The host server. This may contain information useful to services. */
+  private final EmbeddedMulgaraServer hostServer;
+
+
+  /**
+   * Creates the web services object.
+   * @param hostServer The Server that started these Web services.
+   * @param hostName The name of the HTTP host this object is setting up.
+   * @param config The configuration to use.
+   * @throws IOException Exception setting up with files or network.
+   * @throws SAXException Problem reading XML configurations.
+   * @throws ClassNotFoundException An expected class was not found.
+   * @throws NoSuchMethodException A configured class was not built as expected.
+   * @throws InvocationTargetException A configured class did not behave as expected.
+   * @throws IllegalAccessException A configured class was not accessible.
+   */
+  public HttpServicesImpl(EmbeddedMulgaraServer hostServer, String hostName, MulgaraConfig config)  throws IOException, SAXException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+    this.hostServer = hostServer;
+    this.config = config;
+    this.hostName = hostName;
+    assert !config.getJetty().isDisabled();
+    // get servers as a pair so we can set them here. Needed because they are final.
+    Pair<Server,Server> servers = createHttpServers();
+    httpServer = servers.first();
+    httpPublicServer = servers.second();
+  }
+
+
+  /**
+   * @see org.mulgara.server.HttpServices#start()
+   */
+  @SuppressWarnings("unchecked")
+  public void start() throws ExceptionList, Exception {
+    try {
+      if (httpServer != null) httpServer.start();
+      if (httpPublicServer != null) httpPublicServer.start();
+    } catch (MultiException e) {
+      throw new ExceptionList(e.getThrowables());
+    }
+  }
+
+
+  /**
+   * @see org.mulgara.server.HttpServices#stop()
+   */
+  public void stop() throws Exception {
+    try {
+      if (httpServer != null) httpServer.stop();
+    } finally {
+      if (httpPublicServer != null) httpPublicServer.stop();
+    }
+  }
+
+
+  /**
+   * Creates an HTTP server.
+   * @return a pair of private/public servers.
+   * @throws IOException if the server configuration cannot be found
+   * @throws SAXException if the HTTP server configuration file is invalid
+   * @throws ClassNotFoundException if the HTTP server configuration file contains a reference to an unkown class
+   * @throws NoSuchMethodException if the HTTP server configuration file contains a reference to an unkown method
+   * @throws InvocationTargetException if an error ocurrs while trying to configure the HTTP server
+   * @throws IllegalAccessException If a class loaded by the server is accessed in an unexpected way.
+   */
+   Pair<Server,Server> createHttpServers() throws IOException, SAXException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+    if (logger.isDebugEnabled()) logger.debug("Creating HTTP server instance");
+
+    // Set the magic logging property for Jetty to use Log4j
+    System.setProperty(JettyLogger.LOGGING_CLASS_PROPERTY, JettyLogger.class.getCanonicalName());
+    JettyLogger.setEnabled(false);
+    org.eclipse.jetty.util.log.Log.setLog(new JettyLogger());
+
+    // create and register a new HTTP server
+    Server privateServer = buildAndConfigure(config.getJetty().getConnector(), ServerInfo.getHttpPort());
+    Server publicServer = buildAndConfigure(config.getJetty().getPublicConnector(), ServerInfo.getPublicHttpPort());
+
+
+    if (privateServer != null) {
+      // Accumulator for all the services
+      Map<String,String> privateServices = new HashMap<String,String>();
+
+      // start all the private configured services.
+      for (ContextStarter starter: getContextStarters()) {
+        try {
+          starter.fn(privateServer).addTo(privateServices);
+        } catch (IllegalStateException e) {
+          // not fatal, so just log the problem and go on
+          logger.warn("Unable to start web service", e.getCause());
+        }
+      }
+
+      // we have all the services, so now instantiate the service listing service
+      addWebServiceListingContext(privateServer, privateServices);
+    }
+    
+    if (publicServer != null) {
+      // start the public contexts
+      for (ContextStarter starter: getPublicContextStarters()) {
+        try {
+          starter.fn(publicServer);
+        } catch (IllegalStateException e) {
+          logger.warn("Unable to start public web service", e.getCause());
+        }
+      }
+    }
+
+    // configure the private handlers
+    List<Handler> privateHandlers = Collections.emptyList();
+    if (privateServer != null) {
+      privateHandlers = Arrays.asList(privateServer.getChildHandlers());
+      configureHandlers(privateHandlers, config.getJetty().getConnector());
+    }
+    // configure the private handlers
+    List<Handler> publicHandlers = Collections.emptyList();
+    if (publicServer != null) {
+      publicHandlers = Arrays.asList(publicServer.getChildHandlers());
+      configureHandlers(publicHandlers, config.getJetty().getPublicConnector());
+    }
+
+    // get all the handlers in use by both servers
+    List<Handler> handlers = new ArrayList<Handler>(privateHandlers);
+    handlers.addAll(publicHandlers);
+
+    // add our class loader as the classloader of all contexts, unless this is a webapp in which case we wrap it
+    ClassLoader classLoader = this.getClass().getClassLoader();
+    for (Handler handler: handlers) {
+      if (handler instanceof WebAppContext) ((WebAppContext)handler).setClassLoader(new WebAppClassLoader(classLoader, (WebAppContext)handler));
+      else if (handler instanceof ContextHandler) ((ContextHandler)handler).setClassLoader(classLoader);
+    }
+
+    // return the servers
+    return new Pair<Server,Server>(privateServer, publicServer);
+  }
+
+
+  /**
+   * Create a server object, and configure it.
+   * @param cfg The Jetty configuration for the server.
+   * @return The created server.
+   * @throws UnknownHostException The configured host name is invalid.
+   */
+  Server buildAndConfigure(JettyConnector cfg, int port) throws UnknownHostException {
+    Server s = null;
+    boolean disabled = (cfg != null && cfg.hasDisabled() && cfg.isDisabled());
+    if (!disabled) {
+      if (cfg != null) {
+        s = new Server();
+        addConnector(s, cfg, port);
+      } else {
+        s = new Server(port);
+      }
+    }
+    return s;
+  }
+
+
+  /**
+   * Configure all of the handlers with a connector configuration.
+   * @param handlers The handlers to configure.
+   * @param conCfg The connector configuration to use.
+   */
+  void configureHandlers(List<Handler> handlers, JettyConnector conCfg) {
+    if (conCfg == null) return;
+    for (Handler handler: handlers) {
+      // expect each handler to be an instance of a ContextHandler, but we still check
+      if (handler instanceof ContextHandler) {
+        ContextHandler ctx = (ContextHandler)handler;
+        // test for parameters, and if present, then set on the handler
+        if (conCfg.hasMaxFormContentSize()) {
+          ctx.setMaxFormContentSize(conCfg.getMaxFormContentSize());
+        }
+      }
+    }
+  }
+
+
+  /**
+   * Creates a list of functions for starting contexts.
+   * <strong>This defines the list of services to be run.</strong>
+   * @return A list that can start all the configured contexts.
+   */
+  private List<ContextStarter> getContextStarters() {
+    List<ContextStarter> starters = new ArrayList<ContextStarter>();
+    starters.add(new ContextStarter() { public Service fn(Server s) throws IOException {
+      return addWebServicesWebAppContext(s);
+    } });
+    starters.add(new ContextStarter() { public Service fn(Server s) throws IOException {
+      return addWebQueryContext(s, "User Interface", "org.mulgara.webquery.QueryServlet", WEBQUERY_PATH);
+    } });
+    starters.add(new ContextStarter() { public Service fn(Server s) throws IOException {
+      return addWebQueryContext(s, "User Tutorial", "org.mulgara.webquery.TutorialServlet", WEBTUTORIAL_PATH);
+    } });
+    // expect to get the following from a config file
+    // TODO: create a decent configuration object, instead of just handing out a Server
+    starters.add(new ContextStarter() { public Service fn(Server s) throws IOException {
+      return addServletContext(s, "org.mulgara.protocol.http.SparqlServlet", SPARQL_PATH, "SPARQL HTTP Service");
+    } });
+    starters.add(new ContextStarter() { public Service fn(Server s) throws IOException {
+      return addServletContext(s, "org.mulgara.protocol.http.TqlServlet", TQL_PATH, "TQL HTTP Service");
+    } });
+    return starters;
+  }
+
+
+  /**
+   * Creates a list of functions for starting public contexts.
+   * <strong>This defines the list of services to be run.</strong>
+   * @return A list that can start all the configured contexts.
+   */
+  private List<ContextStarter> getPublicContextStarters() {
+    List<ContextStarter> starters = new ArrayList<ContextStarter>();
+    starters.add(new ContextStarter() { public Service fn(Server s) throws IOException {
+      return addServletContext(s, "org.mulgara.protocol.http.PublicSparqlServlet", SPARQL_PATH, "SPARQL HTTP Service");
+    } });
+    return starters;
+  }
+
+
+  /**
+   * Adds a listener to the <code>httpServer</code>. The listener is created and configured
+   * according to the Jetty configuration.
+   * @param httpServer the server to add the listener to
+   * @param jettyConfig The configuraton for the server. Do not read the port at this point.
+   * @param port The port to listen on. The configuration may have been overriden by this value.
+   * @throws UnknownHostException if an invalid hostname was specified in the Mulgara server configuration
+   */
+  @SuppressWarnings("deprecation")
+  private void addConnector(Server httpServer, JettyConnector jettyConfig, int port) throws UnknownHostException {
+    if (httpServer == null) throw new IllegalArgumentException("Null \"httpServer\" parameter");
+
+    if (logger.isDebugEnabled()) logger.debug("Adding socket listener");
+
+    // create and configure a listener
+    AbstractConnector connector = new BlockingChannelConnector();
+    if ((hostName != null) && !hostName.equals("")) {
+      connector.setHost(hostName);
+      if (logger.isDebugEnabled()) logger.debug("Servlet container listening on host " + hostName);
+    } else {
+      hostName = EmbeddedMulgaraServer.getResolvedLocalHost();
+      if (logger.isDebugEnabled()) logger.debug("Servlet container listening on all host interfaces");
+    }
+
+    // Each connector will get its own thread pool, so that they may be configured separately.
+    // If a connector does not have its own thread pool, it inherits one from the server that it might
+    // share with other connectors.
+    QueuedThreadPool threadPool = new QueuedThreadPool();
+    if (jettyConfig.hasMaxThreads()) {
+      threadPool.setMaxThreads(jettyConfig.getMaxThreads());
+    }
+    connector.setThreadPool(threadPool);
+
+    connector.setPort(port);
+    if (jettyConfig.hasMaxIdleTimeMs()) connector.setMaxIdleTime(jettyConfig.getMaxIdleTimeMs());
+    if (jettyConfig.hasLowResourceMaxIdleTimeMs()) connector.setLowResourceMaxIdleTime(jettyConfig.getLowResourceMaxIdleTimeMs());
+    if (jettyConfig.hasAcceptors()) {
+      int acceptors = jettyConfig.getAcceptors();
+      // Acceptors are part of the thread pool, but they delegate handling of servlet
+      // requests to another thread in the pool.  Therefore, the number of acceptors
+      // must be strictly less than the maximum number of threads in the pool.
+      int acceptorLimit = threadPool.getMaxThreads() - 1;
+      if (acceptors > acceptorLimit) {
+        logger.warn("Acceptor threads set beyond HTTP Server limits. Reducing from" + acceptors + " to " + acceptorLimit);
+        acceptors = acceptorLimit;
+      }
+      connector.setAcceptors(acceptors);
+    }
+
+    // add the listener to the http server
+    httpServer.addConnector(connector);
+  }
+
+
+  /**
+   * Creates the Mulgara Descriptor UI. Once created, a description of the created services is returned.
+   * @return A Service description of the Descriptor services that were started.
+   * @throws IOException if the driver WAR file is not readable
+   */
+  private Service addWebServicesWebAppContext(Server server) throws IOException {
+    // get the URL to the WAR file
+    URL webServicesWebAppURL = ClassLoader.getSystemResource(WEBAPP_PATH + "/" + WEBSERVICES_WEBAPP);
+
+    if (webServicesWebAppURL == null) {
+      logger.warn("Couldn't find resource: " + WEBAPP_PATH + "/" + WEBSERVICES_WEBAPP);
+      return null;
+    }
+
+    String warPath = extractToTemp(WEBAPP_PATH + "/" + WEBSERVICES_WEBAPP);
+    
+    // Add Descriptors and Axis
+    String webPath = "/" + WEBSERVICES_PATH;
+    WebAppContext descriptorWARContext = new WebAppContext(getHandlerCollection(server), warPath, webPath);
+
+    // make some attributes available
+    descriptorWARContext.setAttribute(BOUND_HOST_NAME_KEY, ServerInfo.getBoundHostname());
+    descriptorWARContext.setAttribute(SERVER_MODEL_URI_KEY, ServerInfo.getServerURI().toString());
+
+    // log that we're adding the test webapp context
+    if (logger.isDebugEnabled()) logger.debug("Added Web Services webapp context");
+    return new Service("Web Services", webPath);
+  }
+
+
+  /**
+   * Creates and registers a web servlet. The servlet will need to know the server name.
+   * @param server The server to connect the servlet to.
+   * @param name The human-readable name of the servlet to create.
+   * @param servletClass The name of the class that will perform the servlet functions.
+   * @param servletPath The path on the server for the servlet to be loaded onto.
+   * @return A description of the servlet that was set up.
+   * @throws IOException if the servlet cannot talk to the network.
+   */
+  private Service addWebQueryContext(Server server, String name, String servletClass, String servletPath) throws IOException {
+    if (logger.isDebugEnabled()) logger.debug("Adding Web servlet context: " + name);
+
+    // create the web context
+    try {
+      String rmiName = hostServer.getServerName();
+      Servlet servlet = (Servlet)Reflect.newInstance(Class.forName(servletClass), hostName, rmiName, hostServer);
+      String webPath = "/" + servletPath;
+      new org.eclipse.jetty.servlet.ServletContextHandler(getHandlerCollection(server), webPath, SESSIONS).addServlet(new ServletHolder(servlet), "/*");
+      return new Service(name, webPath);
+    } catch (ClassNotFoundException e) {
+      throw new IllegalStateException("Not configured to use the requested servlet: " + name + "(" + servletClass + ")");
+    }
+  }
+
+
+  /**
+   * Creates a servlet that requires a Server as a constructor parameter. This is similar to {@link #addWebQueryContext(Server, String, String, String)}
+   * except that the servlet does not need to know the server name.
+   * @param server The server to connect the servlet to.
+   * @param servletClass The name of the servlet class.
+   * @param path A relative HTTP path for attaching the servlet. 
+   * @param description A description for the servlet.
+   * @return The Service describing the new servlet.
+   * @throws IOException Due to problems with the file system or the network.
+   * @throws IllegalStateException if an unavailable servlet has been requested.
+   */
+  private Service addServletContext(Server server, String servletClass, String path, String description) throws IOException {
+    if (logger.isDebugEnabled()) logger.debug("Adding " + description + " servlet context");
+
+    // create the web query context
+    try {
+      Servlet servlet = (Servlet)Reflect.newInstance(Class.forName(servletClass), hostServer);
+      String webPath = "/" + path;
+      new org.eclipse.jetty.servlet.ServletContextHandler(getHandlerCollection(server), webPath, SESSIONS).addServlet(new ServletHolder(servlet), "/*");
+      return new Service(description, webPath);
+    } catch (ClassNotFoundException e) {
+      throw new IllegalStateException("Not configured to use the requested servlet: " + description);
+    }
+  }
+
+  /**
+   * Creates the servlet used to list the other servlets.
+   * @param server The server to register this servlet with.
+   * @param services The list of service names and paths.
+   * @throws IOException If the servlet cannot talk to the network.
+   */
+  private void addWebServiceListingContext(Server server, Map<String,String> services) throws IOException {
+    if (logger.isDebugEnabled()) logger.debug("Adding the service lister context");
+    Servlet servlet = new ServiceListingServlet(services, "/" + DEFAULT_SERVICE);
+    new org.eclipse.jetty.servlet.ServletContextHandler(getHandlerCollection(server), "/", SESSIONS).addServlet(new ServletHolder(servlet), "/*");
+  }
+
+  /**
+   * Retrieves a handler collection from the server, setting it if the server does not hold a collection.
+   * @param server The server to get a handler collection from.
+   * @return A handler collection for the server.
+   */
+  private HandlerContainer getHandlerCollection(Server server) {
+    HandlerCollection handlerCollection;
+    Handler handler = server.getHandler();
+    if (handler instanceof HandlerCollection) {
+      handlerCollection = (HandlerCollection)handler;
+    } else {
+      handlerCollection = new HandlerCollection();
+      if (handler != null) handlerCollection.addHandler(handler);
+      server.setHandler(handlerCollection);
+    }
+    return handlerCollection;
+  }
+
+  /**
+   * Extracts a resource from the environment (a jar in the classpath) and writes
+   * this to a file in the working temporary directory.
+   * @param resourceName The name of the resource. This is a relative file path in the jar file.
+   * @return The absolute path of the file the resource is extracted to, or <code>null</code>
+   *         if the resource does not exist.
+   * @throws IOException If there was an error reading the resource, or writing to the extracted file.
+   */
+  private String extractToTemp(String resourceName) throws IOException {
+    // Find the resource
+    URL resourceUrl = ClassLoader.getSystemResource(resourceName);
+    if (resourceUrl == null) return null;
+
+    // open the resource and the file where it will be copied to
+    File outFile = new File(TempDir.getTempDir(), new File(resourceName).getName());
+    logger.info("Extracting: " + resourceUrl + " to " + outFile);
+
+    InputStream in = null;
+    OutputStream out = null;
+    try {
+      in = resourceUrl.openStream();
+      out = new FileOutputStream(outFile);
+  
+      // loop to copy from the resource to the output file
+      byte[] buffer = new byte[10240];
+      int len;
+      while ((len = in.read(buffer)) >= 0) out.write(buffer, 0, len);
+    } finally {
+      if (in != null) in.close();
+      if (out != null) out.close();
+    }
+
+    // return the file that the resource was extracted to
+    return outFile.getAbsolutePath();
+  }
+
+
+}

Modified: trunk/src/war/descriptor/index.jsp
===================================================================
--- trunk/src/war/descriptor/index.jsp	2011-12-12 17:33:01 UTC (rev 2076)
+++ trunk/src/war/descriptor/index.jsp	2011-12-12 23:30:54 UTC (rev 2077)
@@ -1,25 +1,23 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<%@ page import="java.net.*, org.mulgara.server.HttpServices" %>
-<%
-
-String hostname = null;
+<%@ page import="java.net.*, org.mu
+  String hostname = null;
 String currentHostUrl = null;
 try {
 
   if (hostname == null) {
-    hostname = (String)getServletContext().getAttribute(HttpServices.BOUND_HOST_NAME_KEY);
+    hostname = (String)getServletContext().getAttribute(HttpServicesImpl.BOUND_HOST_NAME_KEY);
     
     // determine the requesting URL
     currentHostUrl = HttpUtils.getRequestURL(request).toString();
 
     // check it to see if the hostname is in it
     if (!currentHostUrl.startsWith("http://" + hostname + ":")) {
-      String configuredHostUrl = currentHostUrl.replaceFirst("http://[a-zA-Z0-9.]*:", 
-          "http://" + hostname + ":");
+  String configuredHostUrl = currentHostUrl.replaceFirst("http://[a-zA-Z0-9.]*:", 
+      "http://" + hostname + ":");
 
-      // do redirect
-      response.sendRedirect(configuredHostUrl);
+  // do redirect
+  response.sendRedirect(configuredHostUrl);
     }
   }
 
@@ -28,7 +26,8 @@
 }
 
 String URL2Here = currentHostUrl.substring(0, currentHostUrl.length() - "index.jsp".length());
-String descriptorModel = (String)getServletContext().getAttribute(HttpServices.SERVER_MODEL_URI_KEY) + "#descriptors";
+String descriptorModel = (String)getServletContext().getAttribute(HttpServicesImpl.SERVER_MODEL_URI_KEY) + "#descriptors";
+ERVER_MODEL_URI_KEY) + "#descriptors";
   
 %>
 



More information about the Mulgara-svn mailing list