Showing posts with label Jetty. Show all posts
Showing posts with label Jetty. Show all posts

Thursday, April 1, 2010

DataSource in Jetty through JNDI

Prerequesite: Please ensure JNDI is configured properly and you can pass parameters to Jetty via JNDI.

First, you need to add the used libraries to Jettys classpath. In my case, I wanted commons-dbcp (alternative: c3p0) over an H2 database, so I added the following to my pom.xml


      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>7.0.1.v20091125</version>
        <dependencies>
          <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
          </dependency>
          <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.2.131</version>
          </dependency>
        </dependencies>
      </plugin>

On Jetty standalone, I copied the libraries to the lib/ext directory and added ext to the options in start.ini. Please note that commons-dbcp also requires commons-pool.

Next, add the configuration of your DataSource to jetty-env.xml:


<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure id="thisfile" class="org.eclipse.jetty.webapp.WebAppContext">
  <New class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg><Ref id="thisfile"/></Arg>
    <Arg>jdbc/nameOfMyDatabase</Arg>
    <Arg>
      <New class="org.apache.commons.dbcp.BasicDataSource">
        <Set name="url">jdbc:h2:/path/to/your/DataBase</Set>
      </New>
    </Arg>
  </New>
</Configure>

To actually have access to the datasource, you also need modify web.xml to declare that you want a resource unter this name:


  <resource-ref>
    <res-ref-name>jdbc/nameOfMyDatabase</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

The database is now available as DataSource at java:/comp/env/jdbc/nameOfMyDatabase and can be used directly in tools such as hibernate by setting hibernate.connection.datasource to this value.

Background: Hibernate did not properly release the database connection when the WebApp shut down. This resulted in Exceptions when trying to undeploy and deploy the webapp without killing Jetty, as the embedded database existed both in the old and the new context. By moving the connection out of the WebApp, and into Jetty's responsibility, the embedded database driver now only exists in Jetty's context. Adding the connection pool is just decoration.

Passing parameters to Jetty 7 via JNDI

If you have the jetty-maven-plugin properly configured in the pom.xml, then everything is already set up.

For Jetty Standalone, please see my other post about configuring JNDI in jetty standalone.

Passing parameters through JNDI proved to be very simple. In src/main/webapp/WEB-INF create a file jetty-env.xml, with the following contents:


<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure id="thisfile" class="org.eclipse.jetty.webapp.WebAppContext">
  <New class="org.eclipse.jetty.plus.jndi.EnvEntry">
    <Arg><Ref id="thisfile"/></Arg>
    <Arg>paramname</Arg>
    <Arg type="java.lang.String">A sample parameter value</Arg>
    <Arg type="boolean">false</Arg>
  </New>
</Configure>

You can then load your parameter through the standard naming context:


import javax.naming.Context;
import javax.naming.InitialContext;
...
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
String param = (String) envCtx.lookup("paramname");

Of course, you can add other parameters, rename paramname to something that makes more sense, or use other data types. Please note: Jetty supports more datatypes than required by the J2EE standard.

Configuring Jetty 7 standalone for JNDI

Configuring Jetty 7 for JNDI can be a bit tricky. If you miss any of these points, you may end up passing JNDI parameters, but they will not be available in your webapp.

  1. Ensure the plus libraries are loaded. You can to this by adding the option plus in Jetty's start.ini
  2. Ensure jetty is configured to use the plus configuration classes. You can do this by adding the following inside the context, or the jetty-env.xml:
      <Set name="ConfigurationClasses">
        <Array id="plusConfig" type="java.lang.String">
          <Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item>
          <Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
          <Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
          <Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
          <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
          <Item>org.eclipse.jetty.plus.webapp.Configuration</Item>
          <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
          <Item>org.eclipse.jetty.webapp.TagLibConfiguration</Item>
        </Array>
      </Set>
    

    The documentation suggests adding etc/jetty-plus.xml to the startup, which would make this configuration available as plusConfig to refer to. This did not work on my machine.

You can now continue with Passing parameters to Jetty 7 via JNDI.

Wednesday, February 10, 2010

Jetty 7 maven plugin authentication realms

The configuration directive UserRealm seems to no longer work with the jetty 7 maven plugin (jetty-maven-plugin). I received the following error:

java.lang.IllegalStateException: No LoginService for org.eclipse.jetty.security.authentication.BasicAuthenticator@4095c5ec in ConstraintSecurityHandler@28f52a14@

Fixing this involved:

  • Creating a jetty configuration file, such as the following:


    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
    <Configure class="org.eclipse.jetty.webapp.WebAppContext">
      <Get name="securityHandler">
        <Set name="loginService">
          <New class="org.eclipse.jetty.security.HashLoginService">
            <Set name="name">YourSecurityRealmHere</Set>
            <Set name="config">src/test/resources/jetty-realm.properties</Set>
            <Call name="start"/>
          </New>
        </Set>
        <Set name="checkWelcomeFiles">true</Set>
      </Get>
    </Configure>

    To be saved as src/test/resources/jetty-test.xml

  • Create a src/test/resources/jetty-realm.properties with your Jetty 7 password file.

  • Updating the jetty configuration in my pom.xml:

          <plugin>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>jetty-maven-plugin</artifactId>
            <version>7.0.1.v20091125</version>
            <configuration>
              <webAppXml>src/test/resources/jetty-test.xml</webAppXml>
            </configuration>
            <dependencies>
              <dependency>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-servlets</artifactId>
                <version>7.0.1.v20091125</version>
              </dependency>
            </dependencies>
          </plugin>
    

    The important entry is webAppXML. The extra dependency to jetty-servlets was added to support GZip in Jetty 7.

Jetty seems to ignore webdefault.xml

If just tried to edit webdefaults.xml to disable directory views, and the change was not reflected in my webapp. The reason: webdefaults.xml is not read by default, but must be explicitly added to the context of the webapp:


 <Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set>

And suddenly all changes in webdefaults.xml are applied.

Wednesday, January 27, 2010

Enabling JSP support in Jetty 7

As Jetty 6 failed to use the port inherited from xinetd, I have to use Jetty 7. Unfortunately Jetty is missing the JSP support by default. Here is how to enable it:

  1. Download the Jetty 6 distribution.
  2. Copy the jsp-2.1 folder to the Jetty 7 lib/ folder.
  3. You can check if it works by running java -jar start.jar --list-options
  4. Edit start.ini to include jsp-2.1 in the OPTIONS line.

Jetty 6 vs. Jetty 7

There are several differences between Jetty 6 and Jetty 7:

  • Most classes have been renamed from org.mortbay to org.eclipse and sometimes moved to a different path. Find the new class names in the Jetty 7 JavaDoc. This applies to most settings in jetty.xml and web.xml.
  • Jetty 7 comes with fewer plugins. Important extras such as JSP support are missing from the standard distribution.
  • Jetty 7 includes several bugfixes. Example: Taking a port from xinetd did not work with Jetty 6 on my machine.

More information is at the Porting to Jetty 7 page.

Jetty 7 gzip Filter

Jetty includes a gzip-filter for dynamic compression of contents, thus saving bandwidth and enabling your site to load faster (especially important if you have a lot of javascript).

To configure it, add the follwing filter definition to your web.xml:


  <filter>
    <filter-name>GzipFilter</filter-name>
    <filter-class>org.eclipse.jetty.servlets.GzipFilter</filter-class>
    <init-param>
      <param-name>mimeTypes</param-name>
      <param-value>text/html,text/plain,text/xml,application/xhtml+xml,text/css,application/javascript,image/svg+xml</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>GzipFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping> 

Please note: This configuration is for Jetty 7. For Jetty 6 change the filter to org.mortbay.servlet.GzipFilter.

Jettys missing passwd.sh

Jetty comes with a very nice Password encrypting command. Unfortunately, there is no passwd.sh to call it, and you have to manually find out where it is defined. Also, the documentation is for Jetty 6 only, and the names of the classes and libraries have changed in Jetty 7.

Here is the missing passwd.sh for Jetty 7:


#!/bin/bash

# look for JETTY_HOME
if [ -z "$JETTY_HOME" ] 
then
  cd $(dirname "$0")
  JETTY_HOME_1=$(pwd)
  cd - > /dev/null
  JETTY_HOME_1=$(dirname "$JETTY_HOME_1")
  JETTY_HOME=${JETTY_HOME_1} 
fi

java -cp $JETTY_HOME/lib/jetty-http-7.0.1.v20091125.jar:\
$JETTY_HOME/lib/jetty-util-7.0.1.v20091125.jar \
org.eclipse.jetty.http.security.Password $*

Please note that the JETTY_HOME detection is also changed from the original jetty shell scripts to be more sane.

Tuesday, January 26, 2010

Jetty vs. Tomcat

When setting up a new webserver, I decided to evaluate Jetty as an alternative to Tomcat. I have previousely used Tomcat, and was content with it. Here is what I've found:
Both:
  • Implement recent JSP and Servlet standards
  • Can easily run .WAR files
  • Are pretty fast when serving content (speed comparisons on the web show only minor differences)
Pro Jetty:
  • Jetty uses less memory
  • Jetty seams more "lightweight"
Pro Tomcat:
  • Tomcat is very well documented - Jetty Documentation is sparse and targeted towards Java developers. The Jetty config file is (intentionally) like coding
  • I know Tomcat by now
As the machine I am using now is low on memory, I decided to give Jetty a try. However, installing it was not easy. But that's a topic for the next post.