Running Jetty 7 on Port 80 With Maven

I think Jetty is one of the best kept secrets in the Java world, in particular for getting a quick container up and running with full integration with Maven for local testing of Java based web applications. I was doing a non-stock configuration of Jetty 7 and Maven today which took way too much Googling to get working (mostly to custom configure the connector), so I thought I’d document the process for those looking for the same thing. If you’re looking how to get Jetty 7 working on Port 80 (particularly on Linux or OS X) with Maven, you’re in the right place. As of the time of writing, the latest stable release of Jetty looks to be 7.1.6.v20100715.

The three minor hurdles to configuring Jetty 7 and Maven are making sure port 80 is not already taken, getting the right connector implementation configured, and running Maven as sudo so that Jetty has permission to run on Port 80. In OS X, you can see if anything is already running on port 80 by running the following command from Terminal:

CODE:
  1. sudo lsof -i -P | grep -i listen

If you’re on OS X and see something running on Port 80 yet you didn’t install a webserver, chances are it’s Sharing. Go to System Preferences > Sharing and disable it. Otherwise, figure out what process is running on port 80 and make it go away.

Now to configure the Jetty Maven plug-in, here is what my configuration looks like which you should replicate in your pom.xml under the plugins section (and adjust to your particular directory structure and desired context):

CODE:
  1. <plugin>
  2.     <groupid>org.mortbay.jetty</groupid>
  3.     <artifactid>jetty-maven-plugin</artifactid>
  4.     <version>7.1.6.v20100715</version>
  5.     <configuration>
  6.         <connectors>
  7.             <connector implementation=“org.eclipse.jetty.server.nio.SelectChannelConnector”>
  8.                 <port>80</port>
  9.             </connector>
  10.         </connectors>
  11.         <webappsourcedirectory>${basedir}/resources/war</webappsourcedirectory>
  12.         <scanintervalseconds>10</scanintervalseconds>
  13.         <webappconfig>
  14.             <contextpath>/</contextpath>
  15.         </webappconfig>
  16.     </configuration>
  17. </plugin>

One of the difficulties I encountered was getting the connector working correctly. Since Maven has moved to be an Eclipse project, the package structure for the connector has changed and thus the reason most of the existing documentation on getting custom connectors to work did not work for me.

The last remaining hurdle to overcome is that running a standard “mvn jetty:run” doesn’t work on OS X (and likely Linux as well). You’ll see the error message “Embedded error: Permission denied”. If you run Maven with error stacktraces enabled, you’ll see an exception that looks like this:

CODE:
  1. [INFO] Jetty server exiting.
  2. [INFO] ————————————————————————
  3. [ERROR] BUILD ERROR
  4. [INFO] ————————————————————————
  5. [INFO] Failure
  6.  
  7. Embedded error: Permission denied
  8. [INFO] ————————————————————————
  9. [INFO] Trace
  10. org.apache.maven.lifecycle.LifecycleExecutionException: Failure
  11.     at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:719)
  12.     at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeStandaloneGoal(DefaultLifecycleExecutor.java:569)
  13.     at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:539)
  14.     at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:387)
  15.     at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:348)
  16.     at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:180)
  17.     at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:328)
  18.     at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:138)
  19.     at org.apache.maven.cli.MavenCli.main(MavenCli.java:362)
  20.     at org.apache.maven.cli.compat.CompatibleMain.main(CompatibleMain.java:60)
  21.     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  22.     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  23.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  24.     at java.lang.reflect.Method.invoke(Method.java:597)
  25.     at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
  26.     at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
  27.     at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
  28.     at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
  29. Caused by: org.apache.maven.plugin.MojoExecutionException: Failure
  30.     at org.mortbay.jetty.plugin.AbstractJettyMojo.startJetty(AbstractJettyMojo.java:462)
  31.     at org.mortbay.jetty.plugin.AbstractJettyMojo.execute(AbstractJettyMojo.java:377)
  32.     at org.mortbay.jetty.plugin.JettyRunMojo.execute(JettyRunMojo.java:577)
  33.     at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:490)
  34.     at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:694)
  35.     … 17 more
  36. Caused by: java.net.SocketException: Permission denied
  37.     at sun.nio.ch.Net.bind(Native Method)
  38.     at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:119)
  39.     at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:59)
  40.     at org.eclipse.jetty.server.nio.SelectChannelConnector.open(SelectChannelConnector.java:209)
  41.     at org.eclipse.jetty.server.nio.SelectChannelConnector.doStart(SelectChannelConnector.java:289)
  42.     at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
  43.     at org.eclipse.jetty.server.Server.doStart(Server.java:253)
  44.     at org.mortbay.jetty.plugin.JettyServer.doStart(JettyServer.java:67)
  45.     at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
  46.     at org.mortbay.jetty.plugin.AbstractJettyMojo.startJetty(AbstractJettyMojo.java:437)
  47.     … 21 more

This is because you need elevated permissions to run applications on lower ports on *nix based systems. Simply run it as sudo, “sudo mvn jetty:run” and you’ll be good to go.

Not a terribly tough problem to overcome on your own, but I thought I’d try and try to save someone some time if they run across the same issues.

This entry was posted in Culture, Languages, Operating Systems, Servers, Tips, Hacks, & Tricks, Tools and tagged , , , , , , , . Bookmark the permalink.

Leave a reply