<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-856633414943362678</id><updated>2011-08-01T22:51:03.893-04:00</updated><category term='osgi'/><title type='text'>The 'foo' in 'foobar'</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mwnorman.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/856633414943362678/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mwnorman.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Mike Norman</name><uri>http://www.blogger.com/profile/02938548382263095170</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>1</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-856633414943362678.post-4975491136019872271</id><published>2010-09-21T11:09:00.018-04:00</published><updated>2010-09-21T15:16:31.092-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='osgi'/><title type='text'>Overriding the built-in Java HTTPServer under OSGi</title><content type='html'>I've been using Java SE 6's 'containerless' &lt;a href="http://java.sun.com/javase/6/docs/api/javax/xml/ws/Endpoint.html"&gt;javax.xml.ws.Endpoint&lt;/a&gt;&lt;br /&gt;for some time now to build complete end-to-end JAX-WS testcases.&lt;br /&gt;&lt;br /&gt;For example, a simple 'Provider' needs only a few Web Services annotations:&lt;br /&gt;&lt;pre class="brush:java"&gt;&lt;br /&gt;package test;&lt;br /&gt;...&lt;br /&gt;import javax.xml.soap.SOAPMessage;&lt;br /&gt;import javax.xml.ws.Provider;&lt;br /&gt;import javax.xml.ws.WebServiceProvider;&lt;br /&gt;import javax.xml.ws.Service;&lt;br /&gt;import javax.xml.ws.ServiceMode;&lt;br /&gt;import static javax.xml.ws.Service.Mode.MESSAGE;&lt;br /&gt;import static javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING;&lt;br /&gt;&lt;br /&gt;@WebServiceProvider(&lt;br /&gt; targetNamespace = "urn:testService",&lt;br /&gt; serviceName = "testService",&lt;br /&gt; portName = "testServicePort"&lt;br /&gt;)&lt;br /&gt;@ServiceMode(MESSAGE)&lt;br /&gt;public class TestProvider implements Provider&amp;lt;SOAPMessage&amp;gt; {&lt;br /&gt;...&lt;br /&gt;  public SOAPMessage invoke(SOAPMessage request) {&lt;br /&gt;      ... parse SOAPMessage request&lt;br /&gt;      ... return SOAPMessage response&lt;br /&gt;  }&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;a href="http://wiki.eclipse.org/EclipseLink/Examples/DBWS/AdvancedJavase6Containerless"&gt;EclipseLink DBWS&lt;/a&gt; can be used to parse the incoming &lt;tt&gt;SOAPMessage&lt;/tt&gt; as well as generate the response.&lt;br /&gt;&lt;br /&gt;JUnit annotations can be mixed-in along with the Web Services annotations:&lt;br /&gt;&lt;pre class="brush:java"&gt;&lt;br /&gt;  static final String ENDPOINT_ADDRESS =  "http://localhost:9999/test";&lt;br /&gt;&lt;br /&gt;  //JUnit4 fixtures&lt;br /&gt;  static Service testService = null;&lt;br /&gt;&lt;br /&gt;  @BeforeClass&lt;br /&gt;  public static void setup() throws Exception {&lt;br /&gt;      Endpoint endpoint = Endpoint.create(new TestProvider());&lt;br /&gt;      endpoint.publish(ENDPOINT_ADDRESS);&lt;br /&gt;      WebServiceProvider testProvider =&lt;br /&gt;          TestProvider.class.getAnnotation(WebServiceProvider.class);&lt;br /&gt;      String serviceNamespace = testProvider.targetNamespace();&lt;br /&gt;      String serviceName = testProvider.serviceName();&lt;br /&gt;      String portName = testProvider.portName();&lt;br /&gt;      QName serviceQName = new QName(serviceNamespace, serviceName);&lt;br /&gt;      QName portQName = new QName(serviceNamespace, portName);&lt;br /&gt;      Service testService = Service.create(serviceQName);&lt;br /&gt;      testService.addPort(portQName, SOAP11HTTP_BINDING, ENDPOINT_ADDRESS);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Test&lt;br /&gt;  public void aTest() throws Exception {&lt;br /&gt;      MessageFactory factory = MessageFactory.newInstance();&lt;br /&gt;      SOAPMessage request = factory.createMessage();&lt;br /&gt;      SOAPPart part = request.getSOAPPart();&lt;br /&gt;      DOMSource domSource = new DOMSource(&lt;br /&gt;          getDocumentBuilder().parse(new InputSource(new StringReader(&lt;br /&gt;          "&amp;lt;SOAP-ENV:Envelope ... SOAP message content ...&amp;lt;/SOAP-ENV:Envelope&amp;gt;"))));&lt;br /&gt;      part.setContent(domSource);&lt;br /&gt;      Dispatch&amp;lt;SOAPMessage&gt; dispatch = testService.createDispatch(portQName, SOAPMessage.class,&lt;br /&gt;          Service.Mode.MESSAGE);&lt;br /&gt;      SOAPMessage response = dispatch.invoke(request);&lt;br /&gt;      ...&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I find it very convenient to have server, client and tests all in a single class.&lt;br /&gt;&lt;br /&gt;Behind-the-scenes, the &lt;a href="http://java.sun.com/javase/6/docs/api/javax/xml/ws/Service.html"&gt;javax.xml.ws.Service&lt;/a&gt; is backed by an internal class&lt;br /&gt;&lt;tt&gt;com.sun.net.httpserver.HttpServer&lt;/tt&gt;. Unfortunately, this class has some&lt;br /&gt;issues (&lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6675392"&gt;6675392&lt;/a&gt;, &lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6946825"&gt;6946825&lt;/a&gt;) that make it not my first choice for production work.&lt;br /&gt;&lt;br /&gt;Wouldn't it be great if the simple and easy up-front API could be maintained&lt;br /&gt;while behind-the-scenes the Server implementation could be swapped-out?&lt;br /&gt;&lt;br /&gt;The answer of course is that you can! There is a SPI to override the Server&lt;br /&gt;implementation, either via a 'services' file&lt;br /&gt;&lt;tt&gt;META-INF/services/com.sun.net.httpserver.HttpServerProvider&lt;/tt&gt;&lt;br /&gt;or via a system property:&lt;br /&gt;&lt;pre class="brush:bash"&gt;-Dcom.sun.net.httpserver.HttpServerProvider=org.eclipse.jetty.jaxws2spi.JettyHttpServerProvider&lt;br /&gt;&lt;/pre&gt;(the example above replaces the built-in HTTPServer with Jetty)&lt;br /&gt;&lt;br /&gt;I've been helping a customer use &lt;a href="http://wiki.eclipse.org/EclipseLink/Development/DBWS/OSGi"&gt;EclipseLink DBWS under OSGi&lt;/a&gt; and discovered an issue with the above SPI. The implementation of the SPI class &lt;a href="http://java.sun.com/javase/6/docs/jre/api/net/httpserver/spec/com/sun/net/httpserver/spi/HttpServerProvider.html"&gt;com.sun.net.httpserver.spi.HttpServerProvider&lt;/a&gt; only looks on the System classpath:&lt;br /&gt;&lt;pre class="brush:java"&gt;&lt;br /&gt;private static boolean loadProviderFromProperty() {&lt;br /&gt;  String cn = System.getProperty("com.sun.net.httpserver.HttpServerProvider");&lt;br /&gt;  if (cn == null)&lt;br /&gt;      return false;&lt;br /&gt;  try {&lt;br /&gt;      Class c = Class.forName(cn, true, ClassLoader.getSystemClassLoader());&lt;br /&gt;      provider = (HttpServerProvider)c.newInstance();&lt;br /&gt;      return true;&lt;br /&gt;  }&lt;br /&gt;  ....&lt;br /&gt;&lt;/pre&gt;This will not work when running under OSGi as the System classpath cannot&lt;br /&gt;find any user classes (only BundleClassLoaders can).&lt;br /&gt;/*&lt;br /&gt;&lt;pre class="brush:java"&gt; * Copyright 2005 Sun Microsystems, Inc.  All Rights Reserved.&lt;br /&gt;* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.&lt;br /&gt;*&lt;br /&gt;* This code is free software; you can redistribute it and/or modify it&lt;br /&gt;* under the terms of the GNU General Public License version 2 only, as&lt;br /&gt;* published by the Free Software Foundation.  Sun designates this&lt;br /&gt;* particular file as subject to the "Classpath" exception as provided&lt;br /&gt;* by Sun in the LICENSE file that accompanied this code.&lt;br /&gt;*&lt;br /&gt;* This code is distributed in the hope that it will be useful, but WITHOUT&lt;br /&gt;* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or&lt;br /&gt;* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License&lt;br /&gt;* version 2 for more details (a copy is included in the LICENSE file that&lt;br /&gt;* accompanied this code).&lt;br /&gt;*&lt;br /&gt;* You should have received a copy of the GNU General Public License version&lt;br /&gt;* 2 along with this work; if not, write to the Free Software Foundation,&lt;br /&gt;* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.&lt;br /&gt;*&lt;br /&gt;* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,&lt;br /&gt;* CA 95054 USA or visit www.sun.com if you need additional information or&lt;br /&gt;* have any questions.&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;package com.sun.net.httpserver.spi;&lt;br /&gt;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;import java.net.InetSocketAddress;&lt;br /&gt;import java.security.AccessController;&lt;br /&gt;import java.security.PrivilegedAction;&lt;br /&gt;import java.util.Iterator;&lt;br /&gt;&lt;br /&gt;import sun.misc.Service;&lt;br /&gt;import sun.misc.ServiceConfigurationError;&lt;br /&gt;&lt;br /&gt;import com.sun.net.httpserver.HttpServer;&lt;br /&gt;import com.sun.net.httpserver.HttpsServer;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Service provider class for HttpServer.&lt;br /&gt;* Sub-classes of HttpServerProvider provide an implementation of {@link HttpServer} and&lt;br /&gt;* associated classes. Applications do not normally use this class.&lt;br /&gt;* See {@link #provider()} for how providers are found and loaded.&lt;br /&gt;*/&lt;br /&gt;@SuppressWarnings("restriction")&lt;br /&gt;public abstract class HttpServerProvider {&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * creates a HttpServer from this provider&lt;br /&gt;   * @param addr the address to bind to. May be &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt;&lt;br /&gt;   * @param backlog the socket backlog. A value of &amp;lt;code&amp;gt;zero&amp;lt;/code&amp;gt; means the systems default&lt;br /&gt;   */&lt;br /&gt;  public abstract HttpServer createHttpServer (InetSocketAddress addr, int backlog) throws IOException;&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * creates a HttpsServer from this provider&lt;br /&gt;   * @param addr the address to bind to. May be &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt;&lt;br /&gt;   * @param backlog the socket backlog. A value of &amp;lt;code&amp;gt;zero&amp;lt;/code&amp;gt; means the systems default&lt;br /&gt;   */&lt;br /&gt;  public abstract HttpsServer createHttpsServer (InetSocketAddress addr, int backlog) throws IOException;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  private static final Object lock = new Object();&lt;br /&gt;  private static HttpServerProvider provider = null;&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * Initializes a new instance of this class.  &amp;lt;/p&amp;gt;&lt;br /&gt;   *&lt;br /&gt;   * @throws  SecurityException&lt;br /&gt;   *          If a security manager has been installed and it denies&lt;br /&gt;   *          {@link RuntimePermission}&amp;lt;tt&amp;gt;("httpServerProvider")&amp;lt;/tt&amp;gt;&lt;br /&gt;   */&lt;br /&gt;  protected HttpServerProvider() {&lt;br /&gt;      SecurityManager sm = System.getSecurityManager();&lt;br /&gt;      if (sm != null)&lt;br /&gt;          sm.checkPermission(new RuntimePermission("httpServerProvider"));&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private static boolean loadProviderFromProperty() {&lt;br /&gt;      String cn = System.getProperty("com.sun.net.httpserver.HttpServerProvider");&lt;br /&gt;      if (cn == null)&lt;br /&gt;          return false;&lt;br /&gt;      try {&lt;br /&gt;          ClassLoader cl = Thread.currentThread().getContextClassLoader();&lt;br /&gt;          if (cl == null) {&lt;br /&gt;              cl = ClassLoader.getSystemClassLoader();&lt;br /&gt;          }&lt;br /&gt;          Class&amp;lt;?&amp;gt; c = Class.forName(cn, true, cl);&lt;br /&gt;          provider = (HttpServerProvider)c.newInstance();&lt;br /&gt;          return true;&lt;br /&gt;      } catch (ClassNotFoundException x) {&lt;br /&gt;          throw new ServiceConfigurationError(x);&lt;br /&gt;      } catch (IllegalAccessException x) {&lt;br /&gt;          throw new ServiceConfigurationError(x);&lt;br /&gt;      } catch (InstantiationException x) {&lt;br /&gt;          throw new ServiceConfigurationError(x);&lt;br /&gt;      } catch (SecurityException x) {&lt;br /&gt;          throw new ServiceConfigurationError(x);&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private static boolean loadProviderAsService() {&lt;br /&gt;      ClassLoader cl = Thread.currentThread().getContextClassLoader();&lt;br /&gt;      if (cl == null) {&lt;br /&gt;          cl = ClassLoader.getSystemClassLoader();&lt;br /&gt;      }&lt;br /&gt;      Iterator&amp;lt;?&amp;gt; i = Service.providers(HttpServerProvider.class, cl);&lt;br /&gt;      for (;;) {&lt;br /&gt;          try {&lt;br /&gt;              if (!i.hasNext())&lt;br /&gt;                  return false;&lt;br /&gt;              provider = (HttpServerProvider)i.next();&lt;br /&gt;              return true;&lt;br /&gt;          } catch (ServiceConfigurationError sce) {&lt;br /&gt;              if (sce.getCause() instanceof SecurityException) {&lt;br /&gt;                  // Ignore the security exception, try the next provider&lt;br /&gt;                  continue;&lt;br /&gt;              }&lt;br /&gt;              throw sce;&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * Returns the system wide default HttpServerProvider for this invocation of&lt;br /&gt;   * the Java virtual machine.&lt;br /&gt;   *&lt;br /&gt;   * &amp;lt;p&amp;gt; The first invocation of this method locates the default provider&lt;br /&gt;   * object as follows: &amp;lt;/p&amp;gt;&lt;br /&gt;   *&lt;br /&gt;   * &amp;lt;ol&amp;gt;&lt;br /&gt;   *&lt;br /&gt;   *   &amp;lt;li&amp;gt;&amp;lt;p&amp;gt; If the system property&lt;br /&gt;   *   &amp;lt;tt&amp;gt;com.sun.net.httpserver.HttpServerProvider&amp;lt;/tt&amp;gt; is defined then it is&lt;br /&gt;   *   taken to be the fully-qualified name of a concrete provider class.&lt;br /&gt;   *   The class is loaded and instantiated; if this process fails then an&lt;br /&gt;   *   unspecified unchecked error or exception is thrown.  &amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;   *&lt;br /&gt;   *   &amp;lt;li&amp;gt;&amp;lt;p&amp;gt; If a provider class has been installed in a jar file that is&lt;br /&gt;   *   visible to the system class loader, and that jar file contains a&lt;br /&gt;   *   provider-configuration file named&lt;br /&gt;   *   &amp;lt;tt&amp;gt;com.sun.net.httpserver.HttpServerProvider&amp;lt;/tt&amp;gt; in the resource&lt;br /&gt;   *   directory &amp;lt;tt&amp;gt;META-INF/services&amp;lt;/tt&amp;gt;, then the first class name&lt;br /&gt;   *   specified in that file is taken.  The class is loaded and&lt;br /&gt;   *   instantiated; if this process fails then an unspecified unchecked error or exception is&lt;br /&gt;   *   thrown.  &amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;   *&lt;br /&gt;   *   &amp;lt;li&amp;gt;&amp;lt;p&amp;gt; Finally, if no provider has been specified by any of the above&lt;br /&gt;   *   means then the system-default provider class is instantiated and the&lt;br /&gt;   *   result is returned.  &amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;   *&lt;br /&gt;   * &amp;lt;/ol&amp;gt;&lt;br /&gt;   *&lt;br /&gt;   * &amp;lt;p&amp;gt; Subsequent invocations of this method return the provider that was&lt;br /&gt;   * returned by the first invocation.  &amp;lt;/p&amp;gt;&lt;br /&gt;   *&lt;br /&gt;   * @return  The system-wide default HttpServerProvider&lt;br /&gt;   */&lt;br /&gt;  public static HttpServerProvider provider () {&lt;br /&gt;      synchronized (lock) {&lt;br /&gt;          if (provider != null)&lt;br /&gt;              return provider;&lt;br /&gt;          return (HttpServerProvider)AccessController&lt;br /&gt;              .doPrivileged(new PrivilegedAction&amp;lt;Object&amp;gt;() {&lt;br /&gt;                      public Object run() {&lt;br /&gt;                          if (loadProviderFromProperty())&lt;br /&gt;                              return provider;&lt;br /&gt;                          if (loadProviderAsService())&lt;br /&gt;                              return provider;&lt;br /&gt;                          provider = new sun.net.httpserver.DefaultHttpServerProvider();&lt;br /&gt;                          return provider;&lt;br /&gt;                      }&lt;br /&gt;                  });&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I have opened a &lt;a href="https://bugs.openjdk.java.net/show_bug.cgi?id=100152"&gt;bug&lt;/a&gt; against OpenJDK, but until this  issue is addressed, the&lt;br /&gt;built-in &lt;tt&gt;HttpServerProvider&lt;/tt&gt; needs to be overridden. The replacement code&lt;br /&gt;is packaged into a jar file (e.g. &lt;tt&gt;http_server_spi.jar&lt;/tt&gt;) and &lt;b&gt;pre-pended&lt;/b&gt; to the bootclassloader so as to override the  built-in version:&lt;br /&gt;&lt;pre class="brush:bash"&gt;&lt;br /&gt;-Xbootclasspath/p:/path/to/http_server_spi.jar&lt;br /&gt;            ^^^^ /p means pre-pend&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/856633414943362678-4975491136019872271?l=mwnorman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mwnorman.blogspot.com/feeds/4975491136019872271/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=856633414943362678&amp;postID=4975491136019872271' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/856633414943362678/posts/default/4975491136019872271'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/856633414943362678/posts/default/4975491136019872271'/><link rel='alternate' type='text/html' href='http://mwnorman.blogspot.com/2010/09/overriding-built-in-java-httpserver.html' title='Overriding the built-in Java HTTPServer under OSGi'/><author><name>Mike Norman</name><uri>http://www.blogger.com/profile/02938548382263095170</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
