<?xml version="1.0" encoding="UTF-8"?>
<!--Generated by Squarespace Site Server v5.11.81 (http://www.squarespace.com/) on Tue, 29 May 2012 09:55:46 GMT--><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>Journal</title><link>http://blog.fnord.se/journal/</link><description></description><lastBuildDate>Thu, 17 Feb 2011 14:08:43 +0000</lastBuildDate><copyright></copyright><language>en-US</language><generator>Squarespace Site Server v5.11.81 (http://www.squarespace.com/)</generator><item><title>Starting and configuring a Jetty 7 instance in Equinox</title><category>Hacking</category><dc:creator>Henrik Gustafsson</dc:creator><pubDate>Wed, 16 Feb 2011 13:01:02 +0000</pubDate><link>http://blog.fnord.se/journal/2011/2/16/starting-and-configuring-a-jetty-7-instance-in-equinox.html</link><guid isPermaLink="false">430304:4765042:10499198</guid><description><![CDATA[<p>Starting an embedded Jetty 7 server in Equinox is easy, but getting the right configuration in the right place can be slightly harder.</p>

<p>I am currently using the following Jetty bundles:</p>

<pre><code>org.eclipse.jetty.client
org.eclipse.jetty.continuation
org.eclipse.jetty.deploy
org.eclipse.jetty.http
org.eclipse.jetty.io
org.eclipse.jetty.jmx
org.eclipse.jetty.osgi.boot
org.eclipse.jetty.security
org.eclipse.jetty.server
org.eclipse.jetty.servlet
org.eclipse.jetty.servlets
org.eclipse.jetty.util
org.eclipse.jetty.webapp
org.eclipse.jetty.xml
</code></pre>

<p>Some bundles are required only because I want to support gzip loading, jmx introspection and authentication. What bundles can be removed is left as an exercise to the reader.</p>

<p>Jetty is started by the <code>org.eclipse.jetty.osgi.boot</code> bundle, so I make sure this is auto-started. However, in order for Jetty to become useful I also need to reconfigure it.</p>

<p>When the Jetty boot bundle is activated, it runs the <a href="http://download.eclipse.org/jetty/stable-7/apidocs/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.html#startJettyAtJettyHome%28org.osgi.framework.BundleContext%29" title="startJettyAtJettyHome(org.osgi.framework.BundleContext)">DefaultJettyAtJettyHomeHelper#startJettyAtJettyHome(org.osgi.framework.BundleContext)</a> method and that in turn looks at a few properties to determine where to read the configuration from. We elected to use the <code>jetty.home.bundle</code> property.</p>

<p>Armed with the information gleaned from those docs, and the instructions on how to <a href="http://wiki.eclipse.org/Jetty/Feature/Jetty_OSGi#Injecting_new_server-wide_features_into_jetty-osgi">inject new server-wide features into Jetty-OSGi</a> on the eclipse wiki, I created a fragment bundle that is loaded and activated with <code>org.eclipse.jetty.osgi.boot</code> and modifies the <code>jetty.home.bundle</code> property so the configuration is read from the fragment bundle instead of the one included in the Jetty boot bundle.</p>

<p>To set the property I created a fragment activator (all package names have been changed to protect the innocent):</p>

<pre><code>package jettyconfig;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class FragmentActivator implements BundleActivator {

    @Override
    public void start(BundleContext context) throws Exception {
        // Set jetty.home.bundle to the name of our bundle
        System.setProperty("jetty.home.bundle", "jettyconfig");
    }

    @Override
    public void stop(BundleContext context) throws Exception {
    }
}
</code></pre>

<p>The fragment activator will be executed just before the Jetty boot bundle is activated.</p>

<p>It would also be possible to set this property from the command-line (as is probably more proper), but after some discussion we preferred to do it like this until something better comes along.</p>

<p>The MANIFEST.MF looks like this:</p>

<pre><code>Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Jetty Configuration
Bundle-SymbolicName: jettyconfig
Bundle-Version: 1.0.0.qualifier
Fragment-Host: org.eclipse.jetty.osgi.boot;bundle-version="7.2.2"
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-Vendor: Henrik Gustafsson
</code></pre>

<p>Finally, I could put my config in /etc/jetty.xml in the fragment bundle, and Jetty is started with this configuration. As a starting point for my jetty.xml I used the <a href="http://dev.eclipse.org/viewsvn/viewvc.cgi/jetty/tags/jetty-7.2.2.v20101205/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-osgi-default.xml?view=markup&amp;root=RT_JETTY">jetty-osgi-default.xml</a> file and the notes on the <a href="http://wiki.eclipse.org/Jetty/Reference/jetty.xml">jetty.xml</a> wiki page. In particular I needed a <code>ContextHandlerCollection</code> (or perhaps a OSGiAppProvider) configured for Jetty to pick up the services properly.</p>
]]></description><wfw:commentRss>http://blog.fnord.se/journal/rss-comments-entry-10499198.xml</wfw:commentRss></item><item><title>Adding authentication to a Jetty 7 deployment through jetty-web.xml</title><category>Hacking</category><dc:creator>Henrik Gustafsson</dc:creator><pubDate>Fri, 28 Jan 2011 18:17:26 +0000</pubDate><link>http://blog.fnord.se/journal/2011/1/28/adding-authentication-to-a-jetty-7-deployment-through-jetty.html</link><guid isPermaLink="false">430304:4765042:10268724</guid><description><![CDATA[<p>In a setup similar to the one I wrote about <a href="http://blog.fnord.se/journal/2011/1/26/deploying-a-servlet-in-jetty-7-using-osgi-ds.html">here</a>, we had to add some basic http authentication. To add authentication to a context handler all that is needed is to set a security handler to it. This can be accomplished in at least two ways, <a href="http://docs.codehaus.org/display/JETTY/How+to+Configure+Security+with+Embedded+Jetty">programmatically or using the <code>web.xml</code></a>. The former is a bit ugly and the latter stops us from exposing our servlets using OSGi-DS (see previous post). After some internal discussion we opted for a third variant; using <code>jetty-web.xml</code>. I mean, since we had to put it there, so we might as well put it to good use!</p>

<p>From the start we decided we would want to share the authentication configuration between (most of) the different context handlers we have now exposed as OSGi-services. This means we needed some way of sharing the data that we create. We have the realm file used by the <a href="http://download.eclipse.org/jetty/stable-7/apidocs/index.html?org/eclipse/jetty/security/HashLoginService.html">HashLoginService</a> configurable as a system property, and we could share that, creating new HashLoginService instances in each context handler. However, it gets more complicated if we want to configure some other <a href="http://download.eclipse.org/jetty/stable-7/apidocs/index.html?org/eclipse/jetty/security/LoginService.html">LoginService</a> and use that everywhere. So, we decided to attempt to share the actual LoginService instance. In fact, after some experimentation and refactoring of the xml-files I ended up with being able to share the entire <a href="http://download.eclipse.org/jetty/stable-7/apidocs/index.html?org/eclipse/jetty/security/SecurityHandler.html">SecurityHandler</a> between the services using <a href="http://download.eclipse.org/jetty/stable-7/apidocs/index.html?org/eclipse/jetty/server/Server.html">Server#setAttribute()</a>.</p>

<p>This resulted in the following addition to our <code>jetty.xml</code>:</p>

<pre><code>&lt;?xml version="1.0"?&gt;
&lt;!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
    "http://www.eclipse.org/jetty/configure.dtd"&gt;

&lt;Configure id="Server" class="org.eclipse.jetty.server.Server"&gt;

    &lt;!-- old stuff here --&gt;

    &lt;New class="org.eclipse.jetty.security.HashLoginService"
        id="DefaultLoginService"&gt;
        &lt;Set name="name"&gt;MyRealm&lt;/Set&gt;
        &lt;Set name="config"&gt;
            &lt;SystemProperty name="jetty.authrealm"
                default="/etc/webthing/realm.properties" /&gt;
        &lt;/Set&gt;
        &lt;Set name="refreshInterval"&gt;5&lt;/Set&gt;
        &lt;Call name="start"/&gt;
    &lt;/New&gt;

    &lt;New class="org.eclipse.jetty.http.security.Constraint"
        id="DefaultSecurityConstraint"&gt;
        &lt;Set name="authenticate"&gt;true&lt;/Set&gt;
        &lt;Set name="name"&gt;BASIC&lt;/Set&gt;
        &lt;Set name="roles"&gt;
            &lt;Array type="java.lang.String"&gt;
                &lt;Item&gt;admin&lt;/Item&gt;
            &lt;/Array&gt;
        &lt;/Set&gt;
    &lt;/New&gt;

    &lt;New class="org.eclipse.jetty.security.ConstraintSecurityHandler"
        id="DefaultSecurityHandler"&gt;
        &lt;Set name="loginService"&gt;
            &lt;Ref id="DefaultLoginService" /&gt;
        &lt;/Set&gt;
        &lt;Set name="realmName"&gt;MyRealm&lt;/Set&gt;
        &lt;Call name="addConstraintMapping"&gt;
            &lt;Arg&gt;
                &lt;New class="org.eclipse.jetty.security.ConstraintMapping"&gt;
                    &lt;Set name="pathSpec"&gt;/*&lt;/Set&gt;
                    &lt;Set name="constraint"&gt;
                        &lt;Ref id="DefaultSecurityConstraint" /&gt;
                    &lt;/Set&gt;
                &lt;/New&gt;
            &lt;/Arg&gt;
        &lt;/Call&gt;
    &lt;/New&gt;

    &lt;Call name="addBean"&gt;
        &lt;Arg&gt;&lt;Ref id="DefaultLoginService" /&gt;&lt;/Arg&gt;
    &lt;/Call&gt;

    &lt;Call name="setAttribute"&gt;
        &lt;Arg&gt;DefaultSecurityConstraint&lt;/Arg&gt;
        &lt;Arg&gt;&lt;Ref id="DefaultSecurityConstraint" /&gt;&lt;/Arg&gt;
    &lt;/Call&gt;

    &lt;Call name="setAttribute"&gt;
        &lt;Arg&gt;DefaultLoginService&lt;/Arg&gt;
        &lt;Arg&gt;&lt;Ref id="DefaultLoginService" /&gt;&lt;/Arg&gt;
    &lt;/Call&gt;

    &lt;Call name="setAttribute"&gt;
        &lt;Arg&gt;DefaultSecurityHandler&lt;/Arg&gt;
        &lt;Arg&gt;&lt;Ref id="DefaultSecurityHandler" /&gt;&lt;/Arg&gt;
    &lt;/Call&gt;

&lt;/Configure&gt;
</code></pre>

<p>Notice how we set attributes on the server for several of the objects we created. We can't/don't want to reuse the same SecurityHandler everywhere (actually not, read to the end...), but we still want to reuse some of the other parts. This allows us to change some of the settings, but still lets us reconfigure the LoginService from a single place.</p>

<p>Next, I just had to swap the otherwise empty <code>jetty-web.xml</code> for this this:</p>

<pre><code>&lt;?xml version="1.0"?&gt;
&lt;!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
    "http://www.eclipse.org/jetty/configure.dtd"&gt;

&lt;Configure class="test.webthing.WebThing"&gt;
    &lt;Property name="Server"&gt;
        &lt;Call name="getAttribute" id="DefaultSecurityHandler"&gt;
            &lt;Arg&gt;DefaultSecurityHandler&lt;/Arg&gt;
        &lt;/Call&gt;
    &lt;/Property&gt;
    &lt;Set name="securityHandler"&gt;
        &lt;Ref id="DefaultSecurityHandler" /&gt;
    &lt;/Set&gt;
&lt;/Configure&gt;
</code></pre>

<p>Yea, right. Finally. However, once a second component is added, this thing reared its head:</p>

<pre><code>2011-01-31 12:51:11,173 INFO  org.eclipse.jetty.util.log Deployable added: webthing-1.0.0.qualifier/jetty-web.xml
2011-01-31 12:51:11,206 WARN  org.eclipse.jetty.util.log FAILED t.w.WebThing{/hello,null}: java.lang.IllegalStateException: STARTED
2011-01-31 12:51:11,206 WARN  org.eclipse.jetty.util.log Unable to reach node goal: started
java.lang.IllegalStateException: STARTED
    at org.eclipse.jetty.server.handler.HandlerWrapper.setHandler(HandlerWrapper.java:70)
    at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:205)
    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:584)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
    at org.eclipse.jetty.deploy.bindings.StandardStarter.processBinding(StandardStarter.java:36)
    at org.eclipse.jetty.deploy.AppLifeCycle.runBindings(AppLifeCycle.java:180)
    at org.eclipse.jetty.deploy.DeploymentManager.requestAppGoal(DeploymentManager.java:481)
    at org.eclipse.jetty.deploy.DeploymentManager.addApp(DeploymentManager.java:137)
    at org.eclipse.jetty.osgi.boot.OSGiAppProvider.addContext(OSGiAppProvider.java:197)
    at org.eclipse.jetty.osgi.boot.OSGiAppProvider.addContext(OSGiAppProvider.java:179)
    at org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleDeployerHelper.registerContext(WebBundleDeployerHelper.java:400)
    at org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleDeployerHelper.registerContext(WebBundleDeployerHelper.java:348)
    at org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleDeployerHelper.registerContext(WebBundleDeployerHelper.java:308)
    at org.eclipse.jetty.osgi.boot.internal.webapp.JettyContextHandlerServiceTracker.serviceChanged(JettyContextHandlerServiceTracker.java:247)
    at org.eclipse.osgi.internal.serviceregistry.FilteredServiceListener.serviceChanged(FilteredServiceListener.java:104)
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.dispatchEvent(BundleContextImpl.java:933)
    at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:227)
    at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:149)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEventPrivileged(ServiceRegistry.java:756)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEvent(ServiceRegistry.java:711)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.register(ServiceRegistrationImpl.java:130)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.registerService(ServiceRegistry.java:206)
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.registerService(BundleContextImpl.java:507)
    at org.eclipse.equinox.internal.ds.InstanceProcess.registerService(InstanceProcess.java:504)
    at org.eclipse.equinox.internal.ds.InstanceProcess.buildComponents(InstanceProcess.java:212)
    at org.eclipse.equinox.internal.ds.Resolver.buildNewlySatisfied(Resolver.java:441)
    at org.eclipse.equinox.internal.ds.Resolver.enableComponents(Resolver.java:213)
    at org.eclipse.equinox.internal.ds.SCRManager.performWork(SCRManager.java:800)
    at org.eclipse.equinox.internal.ds.SCRManager$QueuedJob.dispatch(SCRManager.java:767)
    at org.eclipse.equinox.internal.ds.WorkThread.run(WorkThread.java:89)
    at org.eclipse.equinox.internal.util.impl.tpt.threadpool.Executor.run(Executor.java:70)
</code></pre>

<p>Turns out it's not a particularly good idea to share the security handler. So, in the end the configuration for the components looked like this:</p>

<pre><code>&lt;?xml version="1.0"  encoding="UTF-8"?&gt;
&lt;!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
    "http://www.eclipse.org/jetty/configure.dtd"&gt;

&lt;Configure class="test.webthing.WebThing"&gt;
    &lt;Property name="Server"&gt;
        &lt;Call name="getAttribute" id="DefaultLoginService"&gt;
            &lt;Arg&gt;DefaultLoginService&lt;/Arg&gt;
        &lt;/Call&gt;
        &lt;Call name="getAttribute" id="DefaultSecurityConstraint"&gt;
            &lt;Arg&gt;DefaultSecurityConstraint&lt;/Arg&gt;
        &lt;/Call&gt;
    &lt;/Property&gt;

    &lt;Set name="securityHandler"&gt;
        &lt;New class="org.eclipse.jetty.security.ConstraintSecurityHandler"&gt;
            &lt;Set name="loginService"&gt;
                &lt;Ref id="DefaultLoginService" /&gt;
            &lt;/Set&gt;
            &lt;Set name="realmName"&gt;MyRealm&lt;/Set&gt;
            &lt;Call name="addConstraintMapping"&gt;
                &lt;Arg&gt;
                    &lt;New class="org.eclipse.jetty.security.ConstraintMapping"&gt;
                        &lt;Set name="pathSpec"&gt;/*&lt;/Set&gt;
                        &lt;Set name="constraint"&gt;
                            &lt;Ref id="DefaultSecurityConstraint" /&gt;
                        &lt;/Set&gt;
                    &lt;/New&gt;
                &lt;/Arg&gt;
            &lt;/Call&gt;
        &lt;/New&gt;
    &lt;/Set&gt;
&lt;/Configure&gt;
</code></pre>

<p>Now, if there were only some nice way of injecting these services into our OSGi-components without going though the Server attributes...</p>

<p>Improvement suggestions and corrections welcome!</p>
]]></description><wfw:commentRss>http://blog.fnord.se/journal/rss-comments-entry-10268724.xml</wfw:commentRss></item><item><title>Deploying a servlet in Jetty 7 using OSGi-DS</title><category>Hacking</category><dc:creator>Henrik Gustafsson</dc:creator><pubDate>Wed, 26 Jan 2011 21:48:33 +0000</pubDate><link>http://blog.fnord.se/journal/2011/1/26/deploying-a-servlet-in-jetty-7-using-osgi-ds.html</link><guid isPermaLink="false">430304:4765042:10241946</guid><description><![CDATA[<p>I recently had to deploy a servlet to an instance of a Jetty 7 (7.2.2 to be precise) server embedded in Equinox. To bootstrap Jetty I used the org.eclipse.jetty.osgi.boot bundle as described on the <a href="http://wiki.eclipse.org/Jetty/Feature/Jetty_OSGi" title="Jetty/Feature/Jetty OSGi">Eclipse Wiki</a>. This bundle is not shipped with 7.2.2 but can be built from source easily.</p>

<p>As it stands, all services in our system runs using OSGi-DS, and I figured it would be neat if I were able to deploy the servlets in a similar fashion.</p>

<p>The servlets themselves are constructed in a non-trivial manner, and had some dependencies on other OSGi-DS-exposed services, so programmatic construction of the servlet instances is preferable for now.</p>

<p>Turns out that's not completely simple or free of hacks, but also not extremely hard.</p>

<p>The org.eclipse.jetty.osgi.boot bundle registers a service tracker looking for services extending org.eclipse.jetty.server.handler.ContextHandler, which basically means that if I just add a <code>&lt;provide interface="org.eclipse.jetty.server.handler.ContextHandler"/&gt;</code> tag to my OSGi service component description I can have Jetty pick up on that automagically.</p>

<p>Yay! Well, almost. This was my first try at a component:</p>

<pre><code>package test.webthing;

import java.util.Map;

import javax.servlet.Servlet;

import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.osgi.service.component.ComponentContext;

public class WebThing extends ServletContextHandler {

    public WebThing() {
        setContextPath("/hello");
    }

    private void addServlet(final Servlet servlet) {
        final ServletHolder holder =
            getServletHandler().newServletHolder();
        holder.setServlet(servlet);
        addServlet(holder, "/");
    }

    public void activate(Map&lt;String, Object&gt; properties)
        throws Exception {
        addServlet(new HelloServlet());
    }
}
</code></pre>

<p>That didn't quite work, however; I got this beauty in the logs:</p>

<pre><code>2011-01-26 23:04:24,302 DEBUG org.eclipse.jetty.osgi.boot FrameworkEvent ERROR
java.lang.IllegalArgumentException: the property contextFilePath is required
    at org.eclipse.jetty.osgi.boot.internal.webapp.JettyContextHandlerServiceTracker.serviceChanged(JettyContextHandlerServiceTracker.java:231)
    at org.eclipse.osgi.internal.serviceregistry.FilteredServiceListener.serviceChanged(FilteredServiceListener.java:104)
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.dispatchEvent(BundleContextImpl.java:933)
    at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:227)
    at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:149)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEventPrivileged(ServiceRegistry.java:756)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEvent(ServiceRegistry.java:711)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.register(ServiceRegistrationImpl.java:130)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.registerService(ServiceRegistry.java:206)
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.registerService(BundleContextImpl.java:507)
    at org.eclipse.equinox.internal.ds.InstanceProcess.registerService(InstanceProcess.java:504)
    at org.eclipse.equinox.internal.ds.InstanceProcess.buildComponents(InstanceProcess.java:212)
    at org.eclipse.equinox.internal.ds.Resolver.buildNewlySatisfied(Resolver.java:441)
    at org.eclipse.equinox.internal.ds.Resolver.enableComponents(Resolver.java:213)
    at org.eclipse.equinox.internal.ds.SCRManager.performWork(SCRManager.java:800)
    at org.eclipse.equinox.internal.ds.SCRManager$QueuedJob.dispatch(SCRManager.java:767)
    at org.eclipse.equinox.internal.ds.WorkThread.run(WorkThread.java:89)
    at org.eclipse.equinox.internal.util.impl.tpt.threadpool.Executor.run(Executor.java:70)
</code></pre>

<p>Ok, so, I set my breakpoints to stun and started debugging. What happened was that in <a href="http://dev.eclipse.org/viewcvs/viewvc.cgi/jetty/tags/jetty-7.2.2.v20101205/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/JettyContextHandlerServiceTracker.java?view=markup&amp;root=RT_JETTY#l137">JettyContextHandlerServiceTracker#serviceChanged()</a> there was a check that required the property "contextFilePath" of the service to be set to something other than null. Digging further revealed that not only did it have to be set to something non-null, it also needed to be a valid <a href="http://wiki.eclipse.org/Jetty/Reference/jetty-web.xml">jetty-web.xml</a>-file. "But Why!?", I exclaimed, but added the property to my component properties and created a dummy jetty-web.xml file:</p>

<pre><code>&lt;?xml version="1.0"  encoding="UTF-8"?&gt;
&lt;!DOCTYPE Configure PUBLIC
  "-//Jetty//Configure//EN"
  "http://www.eclipse.org/jetty/configure.dtd"&gt;

&lt;Configure class="test.webthing.WebThing" /&gt;
</code></pre>

<p>Aha! Progress in the logs!</p>

<pre><code>2011-01-26 22:36:35,763 INFO  org.eclipse.jetty.util.log Deployable added: webthing-1.0.0.qualifier/jetty-web.xml
</code></pre>

<p>And indeed, the servlet works!</p>

<pre><code>$ curl http://localhost:8080/hello/
HELLO
$
</code></pre>

<p>So I modified my component slightly to look like this:</p>

<pre><code>package test.webthing;

import java.util.Map;

import javax.servlet.Servlet;

import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

public class WebThing extends ServletContextHandler {
    private void addServlet(final Servlet servlet) {
        final ServletHolder holder =
            getServletHandler().newServletHolder();
        holder.setServlet(servlet);
        addServlet(holder, "/");
    }

    public void activate(Map&lt;String, Object&gt; properties)
        throws Exception {
        setContextPath(
            (String) properties.get(
                OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH));
        addServlet(new HelloServlet());
    }
}
</code></pre>

<p>and added the contextPath property to my component description (to make it consistent), which now looked like this:</p>

<pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
  activate="activate" configuration-policy="ignore" enabled="true"
  immediate="true" name="test.webthing"&gt;
   &lt;implementation class="test.webthing.WebThing"/&gt;
   &lt;service&gt;
      &lt;provide interface="org.eclipse.jetty.server.handler.ContextHandler"/&gt;
   &lt;/service&gt;
   &lt;property name="contextFilePath" type="String"
     value="/jetty-web.xml"/&gt;
   &lt;property name="contextPath" type="String" value="/hello"/&gt;
&lt;/scr:component&gt;
</code></pre>

<p>Hopefully the requirement for a jetty.xml-file will go away in the future, but for now, I can live with it like this, but if anyone has an idea of how to make it better, let me know!</p>

<p>The "webthing" bundle can be downloaded <a href="http://blog.fnord.se/storage/webthing.tgz">here</a>.</p>
]]></description><wfw:commentRss>http://blog.fnord.se/journal/rss-comments-entry-10241946.xml</wfw:commentRss></item><item><title>A fond farewell to Purple Scout</title><category>Personal</category><dc:creator>Henrik Gustafsson</dc:creator><pubDate>Sat, 28 Aug 2010 03:40:13 +0000</pubDate><link>http://blog.fnord.se/journal/2010/8/28/a-fond-farewell-to-purple-scout.html</link><guid isPermaLink="false">430304:4765042:8701926</guid><description><![CDATA[<p>So, this is it.</p>
<p>I switched on the alarm at the&nbsp;<a href="http://www.purplescout.se/">Purple Scout</a>&nbsp;offices, probably for the last time. A few tears were shed and a few hugs were shared during the latter part of the evening, I'm not ashamed to admit. Purple Scout has been like a second home and family for me for the better part of four years. I pity one and all who have not been so lucky as to have experienced the camaraderie and fellowship associated with being a Purple Scout employee.</p>
<p>Why am I leaving Purple Scout?</p>
<p>All other things being equal, the reasons making the scale tip over to Procera's favor were threefold: First, for various reasons I have never been able to complete a project or product about which I have felt both engaged in and proud of, and the <a href="http://www.proceranetworks.com/products/psm-packetlogic-subscriber-manager.html">PSM</a> project/product might just be it. The next opportunity for a project that I feel so strongly about had I stayed with Purple Scout would most likely be a long way away. It's a personal type of closure that I've yet to achieve. The second reason was more of a pragmatic one. When this project was removed, what was I to do? Certainly there would eventually show up some sort of task that I might perform, but I find it highly unlikely that I would get the same sort of challenges, team dynamics and sense of brotherhood that the PSM-team has. Finally, and by far the most important reason, almost the entire team of my project collectively signed the new employment contracts, with the last member having personal reasons for not doing so. We even sent all of our signed contracts in the same envelope.</p>
<p>And where am I going?</p>
<p>My new employer is <a href="http://www.proceranetworks.com/">Procera Networks</a>. Can they ever provide the same incredible experience? Well, they do have some exciting challenges lined up, first and foremost the next version of our software that we need to finish, but no matter what exciting technical problems they offer, will they live up to the same standards as Purple Scout when it comes to being a good employer and, indeed, a good friend?</p>
<p>Only time will tell, but I suppose the only way of finding out is at the end. Whether I'm about to cry because of people and places I already miss on my way out of the door. I sure hope that will be the case.</p>
<p>Procera certainly does show some promise though! Besides, our team will be quite the horde of Purple People joining Procera, so their resistance will be futile. They will be assimipurpled. Purplimilated. Purplified. Or perhaps they're just that good already. We'll see.</p>
<p>To all of you who make up Purple Scout and its ideals, thank you for the wonderful time we've had, and a special thank you to Johan Str&ouml;mhage and Kasper Aase whose dedication to their employees have been a beacon of light through economic recessions and growth alike.</p>
<p>Suspiciously absent above, but no less instrumental to my experience at Purple Scout is Emil Erlandsson. However, he's part of the swarm of Purple locusts currently preparing our descent upon the unsuspecting Malm&ouml; offices of Procera Networks. I'm not quite done with him yet :)</p>
<p>I wish Purple Scout all the best in the future and I hope to be meeting and working with all of you again!</p>
<p>So&hellip;</p>
<p>&nbsp;</p>
<p><strong>PSM-team is dead, long live PSM-team!</strong></p>
<div></div>]]></description><wfw:commentRss>http://blog.fnord.se/journal/rss-comments-entry-8701926.xml</wfw:commentRss></item><item><title>My opinions on multiple function / method exit points</title><category>Hacking</category><dc:creator>Henrik Gustafsson</dc:creator><pubDate>Wed, 18 Nov 2009 12:13:31 +0000</pubDate><link>http://blog.fnord.se/journal/2009/11/18/my-opinions-on-multiple-function-method-exit-points.html</link><guid isPermaLink="false">430304:4765042:5839758</guid><description><![CDATA[<p>I originally posted this at Stack Overflow as a response to <a href="http://stackoverflow.com/questions/36707/should-a-function-have-only-one-return-statement">this</a> question. Since then some people have asked me the same questions outside, so I figured I should just post it here.</p>

<p>There are good things to say about having a single exit-point, just as there are bad things to say about the inevitable <a href="http://c2.com/cgi/wiki?ArrowAntiPattern">"arrow"</a> programming that results.</p>

<p>If using multiple exit points during input validation or resource allocation, I try to put all the 'error-exits' very visibly at the top of the function.</p>

<p>Both the <a href="http://ssdl-wiki.cs.technion.ac.il/wiki/index.php/Spartan_programming">Spartan Programming</a> article of the "SSDSLPedia" and <a href="http://c2.com/cgi/wiki?SingleFunctionExitPoint">the single function exit point</a> article of the "Portland Pattern Repository's Wiki" have some insightful arguments around this.</p>

<p>If you really want a single exit-point (in any non-exception-enabled language) for example in order to release resources in one single place, I find the careful application of goto to be good; see for example this rather contrived example (compressed to save screen real-estate):</p>

<pre><code>int f(int y) {
    int value = -1;
    void *data = NULL;

    if (y &lt; 0)
        goto clean;

    if ((data = malloc(123)) == NULL)
        goto clean;

    /* More code */

    value = 1;
clean:
   free(data);
   return value;
}
</code></pre>

<p>Personally I, in general, dislike arrow programming more than I dislike multiple exit-points, although both are useful when applied correctly. The best, of course, is to structure your program to require neither. Breaking down your function into multiple chunks usually help :)</p>

<p>Although when doing so, I find I end up with multiple exit points anyway as in this example, where some larger function has been broken down into several smaller functions:</p>

<pre><code>int g(int y) {
  value = 0;

  if ((value = g0(y, value)) == -1)
    return -1;

  if ((value = g1(y, value)) == -1)
    return -1;

  return g2(y, value);
}
</code></pre>

<p>Depending on the project or coding guidelines, most of the boiler-plate code could be replaced by macros. As a side note, breaking it down this way makes the functions g0, g1 ,g2 very easy to test individually.</p>

<p>Obviously, in an OO and exception-enabled language, I wouldn't use if-statements like that (or at all, if I could get away with it with little enough effort), and the code would be much more plain. And non-arrowy. And most of the non-final returns would probably be exceptions.</p>

<p>In short;</p>

<ul>
<li>Few returns are better than many returns</li>
<li>More than one return is better than huge arrows, and <a href="http://www.refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html">guard clauses</a> are generally ok.</li>
<li>Exceptions could/should probably replace most 'guard clauses' when possible.</li>
</ul>
]]></description><wfw:commentRss>http://blog.fnord.se/journal/rss-comments-entry-5839758.xml</wfw:commentRss></item><item><title>Varför vaccinerade jag mig?</title><category>Personal</category><dc:creator>Henrik Gustafsson</dc:creator><pubDate>Tue, 17 Nov 2009 17:41:34 +0000</pubDate><link>http://blog.fnord.se/journal/2009/11/17/varfor-vaccinerade-jag-mig.html</link><guid isPermaLink="false">430304:4765042:5829790</guid><description><![CDATA[<p>Jag var idag och vaccinerade mig mot <a href="http://en.wikipedia.org/wiki/Pandemic_H1N1/09_virus">A(H1N1)v / nya influensan / svininfluensan / galtfebern</a>, och förutsatt att jag inte drar på mig den riktiga influensan dom närmaste två veckorna (som exempelvis i väntrummet efter vaccinationen där massa människor var samlade på liten yta...barriärvård, tack? :) så bör jag vara rätt safe.</p>

<p>Innan jag skriver något mer kanske jag ska påpeka att jag inte har någon som helst medicinsk utbildning, så tänk själva och fråga er läkare om något är oklart.</p>

<p>Så varför vaccinerade jag mig? Förutom det uppenbara -- jag har ingen lust att ligga hemma och vara sjuk i flera veckor -- så är det mest en fråga om solidaritet.</p>

<p>Ju fler som vaccinerar sig, ju färre smittvägar har viruset, och ju färre smittvägar ju mindre risk är att personer som inte kan ta vaccinet av diverse anledningar exponeras för smittan, d.v.s <a href="http://en.wikipedia.org/wiki/Herd_immunity">populationsimmuniteten</a> höjs. Mängden människor som inte kan ta vaccinet och mängden människor som riskerar allvarliga effekter överlappar till stor del om man får tro avsnittet <a href="http://www.fass.se/LIF/produktfakta/artikel_produkt.jsp?NplID=20070324000011#contraindication">"Innan du får Pandemrix"</a> i FASS artikel om Pandemrix och frågorna 3 och 17 i ECDCs <a href="http://www.ecdc.europa.eu/en/healthtopics/Documents/0906_Influenza_AH1N1_FAQ.pdf">Frequently asked questions on
pandemic (H1N1) 2009</a>.</p>

<p>Som en bieffekt kan man hoppas att inte så många blir sjukskrivna samtidigt pga vaccinet och kan gå till jobbet och bidra till BNP som dom goda löneslavar vi är :)</p>

<p>Enligt mig(!) giltiga ursäkter att inte ta vaccinet</p>

<ul>
<li>Graviditet</li>
<li>Äggallergi</li>
<li>Febersjuk (vilket bara är en temporär ursäkt)</li>
<li>Du har redan haft influensan</li>
<li>Rekommendation från läkare eller sköterska</li>
</ul>

<p>Enligt mig(!) ogiltiga ursäkter</p>

<ul>
<li><a href="http://www.lakemedelsverket.se/alla-nyheter/nyheter-2009/sammanfattning-av-kunskapslaget-for-tiomersal/">Kvicksilver/Tiomersal/Thimerosal är farligt!</a></li>
<li><a href="http://www.lakemedelsverket.se/Alla-nyheter/NYHETER-2009/Sammanstallning-av-inrapporterade-biverkningar-av-Pandemrix-fram-till-10-november-/">Men bieffekterna…!</a></li>
<li>Jag har tappat bort kallelsen (<a href="http://www.krisinformation.se/web/Pages/Page____31603.aspx">Droppa in på ditt närmaste vaccinationsställe!</a>)</li>
<li><a href="http://maps.google.com/">Jag vet inte vart vaccinationsstället ligger</a></li>
<li>Jag sitter ändå bara på min kammare, träffar inget folk etc.</li>
<li>Jag är lat/sprut-rädd/whatever (även om du försöker rationalisera det till något annat!)</li>
<li><a href="http://www.antivaxxers.com/">WAA WAA KONSPIRATION BIG PHARMA ILLUMINATI AUTISM</a></li>
</ul>

<p>På bloggen <a href="http://tankebrott.wordpress.com/">Tankebrott</a> görs ett mer grundligt jobb än vad jag gör i att reda ut det hela <a href="http://tankebrott.wordpress.com/2009/10/20/skeptikerskolan-del-10-lathund-till-vaccin-och-svininfluensa/">här</a>.</p>

<p>För den som har intresse i att följa influensans utveckling kan jag rekommendera <a href="http://www.ecdc.europa.eu/en/healthtopics/Pages/Influenza_A(H1N1)_Outbreak.aspx">ECDCs site om H1N1-pandemin</a> samt Smittskyddsinstitutets <a href="http://www.smittskyddsinstitutet.se/publikationer/smis-nyhetsbrev/influensarapporter/sasongen-20092010/">influensarapport-sida</a> för information som inte är helt <a href="http://tankebrott.wordpress.com/2009/10/28/medias-ansvar-2/">förstörd</a> av <a href="http://tankebrott.wordpress.com/2009/10/30/medias-ansvar-del-2-samvetslosa-opportunister/">kvällspressen</a>.</p>

<p>Så har du inte vaccinerat dig än, så gå till ditt närmaste vaccinationsställe och få din skattefinansierade immunförsvarsuppgradering! </p>

<p>Och på vägen dit, i väntrummet och på hemresan kan jag rekommendera att lyssna på <a href="http://www.theskepticsguide.org/archive/podcastinfo.aspx?mid=1&amp;pid=10001">The Skeptics Guide To The Universe H1N1-special</a>.</p>
]]></description><wfw:commentRss>http://blog.fnord.se/journal/rss-comments-entry-5829790.xml</wfw:commentRss></item><item><title>Trying out the picture gallery</title><category>Personal</category><dc:creator>Henrik Gustafsson</dc:creator><pubDate>Thu, 24 Sep 2009 19:23:23 +0000</pubDate><link>http://blog.fnord.se/journal/2009/9/24/trying-out-the-picture-gallery.html</link><guid isPermaLink="false">430304:4765042:5287002</guid><description><![CDATA[<p>I figured it'd be neat to be able to post pictures from time to time etc, so I tried out the photo gallery with a handful of pictures I took this spring. Try it out on the <a href="http://blog.fnord.se/pictures/">Pictures</a> page.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></description><wfw:commentRss>http://blog.fnord.se/journal/rss-comments-entry-5287002.xml</wfw:commentRss></item><item><title>Overused Extract Method refactoring</title><category>Hacking</category><dc:creator>Henrik Gustafsson</dc:creator><pubDate>Mon, 21 Sep 2009 20:57:31 +0000</pubDate><link>http://blog.fnord.se/journal/2009/9/21/overused-extract-method-refactoring.html</link><guid isPermaLink="false">430304:4765042:5257324</guid><description><![CDATA[<p>I was reading the ObjectMentor blogs the other day, and came across a post called <a href="http://blog.objectmentor.com/articles/2009/09/11/one-thing-extract-till-you-drop">"One Thing: Extract till you Drop"</a> by Robert C. Martin. I definitely see the point of using extract method to a great extent in order to clarify the extent of the program, but I felt that example went a bit too far for a number of reasons.</p>

<ol>
<li>The names of the extracted methods made very little sense. Even when knowing what the class does it is hard to figure out the difference between <code>replaceAllSymbols()</code> and <code>replaceAllInstances()</code> and their relations to the other methods. You actually need to read them all in order to puzzle together the call-graph.</li>
<li>It introduces mutability in the class quite unnecessarily making reuse of the instance impossible.</li>
<li>Some of the extracted methods have strangely asymmetric abstraction levels.</li>
</ol>

<p>There are also some other issues regarding efficiency and thread-safeness that I reacted strongly to, especially since they are so easy to avoid.</p>

<p>When implementing it myself I thought about the scenarios when this would be used, and I could find two main ones. The first is to use this to iterate over different strings using the same dictionary and the second is to iterate over different dictionaries using the same string. Not knowing anything about the use-case I went for the former.</p>

<p>I made an attempt to improve it in the comments, but I was tired and messed it up a bit. Normally I probably would have solved the same problem in a manner closer to this:</p>

<pre><code>public class SymbolReplacer {
    private static final Pattern pattern =
        Pattern.compile("\\$([a-zA-Z]\\w*)");

    private final SymbolLookup lookup;

    SymbolReplacer(SymbolLookup lookup) {
        this.lookup = lookup;
    }

    public String replace(CharSequence stringToReplace) {
        final Matcher matcher = pattern.matcher(stringToReplace);
        return buildReplacement(matcher).toString();
    }

    private StringBuffer buildReplacement(Matcher matcher) {
        final int bufferLength =
            matcher.regionEnd() - matcher.regionStart();
        final StringBuffer buffer =
            new StringBuffer(bufferLength);

        fillBuffer(matcher, buffer);
        return buffer;
    }

    private void fillBuffer(Matcher matcher, StringBuffer buffer) {
        while (matcher.find())
            matcher.appendReplacement(buffer,
                getMatchReplacement(matcher));
        matcher.appendTail(buffer);
    }

    public String getMatchReplacement(Matcher matcher) {
        final String expansion =
            lookup.lookupValue(matcher.group(1));
        return (expansion != null) ?
            expansion :
            Matcher.quoteReplacement(matcher.group(0));
    }
}
</code></pre>

<p>I introduced the interface <code>SymbolLookup</code> as a replacement for the secret <code>getSymbol()</code> method. There are a few things I would like to fix in this as well; the <code>getMatchReplacement()</code> method is not as clear as I would have liked, and the line of abstraction between the different methods/layers is not well defined. Still, provided that SymbolLookup is thread-safe, so is this class. Also, you can reuse the instance to iterate over many strings.</p>
]]></description><wfw:commentRss>http://blog.fnord.se/journal/rss-comments-entry-5257324.xml</wfw:commentRss></item></channel></rss>
