Embedding Tomcat 7

One of the more anticipated features of Tomcat 7 is the ability to run as an embedded server like Jetty. We use Tomcat 6 in production, but embedded Jetty more and more for running and testing during development (in Eclipse). The Tomcat 7 beta has been out for a while, but there seems to be little documentation out there on how to embed it, other than some suggestions to look at the unit tests for examples. So that’s what I did! First, here is the guts of our original Main method in Jetty:

public static void main(String[] args) throws Exception {
  String weppAppHome = args[0];
  Integer port = Integer.valueOf(args[1]);

  Server server = new Server(port);

  WebAppContext webapp = new WebAppContext();
  webapp.setContextPath("/myapp");
  webapp.setCompactPath(true);

  webapp.setDescriptor(weppAppHome + "/WEB-INF/web.xml");
  webapp.setResourceBase(weppAppHome);
  webapp.setParentLoaderPriority(true);

  server.setHandler(webapp);
  server.start();
  server.join();
}
To switch to Tomcat 7, add these dependencies to your pom.xml:
  • org.apache.tomcat:tomcat-catalina:7.0.0
  • org.apache.tomcat.embed:tomcat-embed-core:7.0.0
  • org.apache.tomcat:tomcat-jasper:7.0.0
Note that the tomcat-jasper pom.xml lists org.eclipse.jdt:ecj:3.5.1 as a dependency, which can’t be found. I had to replace it in our local repository with org.eclipse.jdt.core.compiler:ecj:3.5.1.

UPDATE: This dependency has been fixed in the latest version, 7.0.21.

Here is the Tomcat 7 version:
public static void main(String[] args) throws Exception {
  String appBase = args[0];
  Integer port = Integer.valueOf(args[1]);

  Tomcat tomcat = new Tomcat();
  tomcat.setPort(port);

  tomcat.setBaseDir(".");
  tomcat.getHost().setAppBase(appBase);

  String contextPath = "/myapp";

  // Add AprLifecycleListener
  StandardServer server = (StandardServer)tomcat.getServer();
  AprLifecycleListener listener = new AprLifecycleListener();
  server.addLifecycleListener(listener);

  tomcat.addWebapp(contextPath, appBase);
  tomcat.start();
  tomcat.getServer().await();
}
Without the await() call at the end, the server quits right after it starts, which you may or may not want.

 

Launch it! We normally set up a launch configuration in Eclipse to run it. It’s also easy to run on the command-line using java -jar after you’ve built your jar.

 

This entry was posted in java, software and tagged . Bookmark the permalink.

45 Responses to Embedding Tomcat 7

  1. Pingback: tomcat 7.0 embedded usage : 14024

  2. LYDIA says:

    Tomcat 6 / GREAT!!!!!

  3. Great post.

    the problem with org.eclipse.jdt:ecj:3.5.1 persists in tomcat 7.0.2, which needs org.eclipse.jdt:ecj:3.6 (and maven cant find it). Tomcat 7 has wrong pom.xml or is it expecting another repo?

  4. flym says:

    I’ve just search many post and finally find this.it’s great help!

  5. tom steward says:

    Hi,
    I tried your tomcat 7 example, but when I try to open the URL http://localhost:port/myapp I get a 404 page from tomcat.
    What am I doing wrong?

    • tborthwick says:

      I assume you’re putting a real number into the url instead of the word, ‘port’? It’s hard to say off-hand. I would double check that your appBase is valid.

  6. gcstang says:

    Do you have a running example with source, not sure what to put in or pass in for the appBase or BaseDir settings.

    I’m trying to run this from inside Eclipse.

  7. gcstang says:

    Ok, I finally got this to work in Eclipse but I had to add the following things.

    appBase is set to “.”
    BaseDir is set to “.”
    contextPath is set to “” or “/” (either work)

    For Servlets to be found I had to add this :
    org.apache.catalina.Context ctx = tomcat.addWebapp(contextPath, appBase);
    Tomcat.addServlet(ctx, “test”, “com.eonegroup.servlets.TestBuild”);
    ctx.addServletMapping(“/test”, “test”);

    When I export to a JAR and run it the jsp’s aren’t found, unless I put them into the directory with my JAR instead of in it and of course the Tomcat Embedded Jars aren’t in my main JAR so I have to create a script to run it all by adding all of them to the CLASSPATH then running my main method. There has to be an easier way to do this, right?

  8. Anton says:

    at last, the API looks human-kind
    but still you have to put tons of JARs to into the CLASSPATH to make it work whereas with Jetty it is just jetty.jar..

  9. Pingback: Embedding Tomcat 7 in your App | Outrospective.org

  10. compoasso says:

    Hi,
    The minimal code i found to load a servlet on embedded tomcat 7.
    Need embed core / embed logging juli / embed logging log4j jar for tomcat and servlet-api.jar for servlet.
    MyServlet is a classical HttpServlet class

    public class TestServlet {
    public static void main(String[] args) {
    try {
    Tomcat tomcat = new Tomcat();
    tomcat.setBaseDir(".");
    tomcat.setPort(8090);

    File docBase = new File(".");
    Context ctxt = tomcat.addContext("/", docBase.getAbsolutePath());

    Tomcat.addServlet(ctxt, "servletName", new MyServlet());
    ctxt.addServletMapping("/*", "servletName");

    tomcat.start();
    tomcat.getServer().await();

    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

  11. Scott says:

    Works great. What’s the best way to stop the Tomcat server?

    • tborthwick says:

      I’m usually running the embedded server while debugging in Eclipse so I just kill it from there. The org.apache.catalina.startup.Tomcat class has a stop method which you should be able to use to stop it more gracefully.

  12. WulfgarPro says:

    I have the following in my unit test:

    @BeforeClass
    public static void setUpClass() throws ServletException, LifecycleException, MalformedURLException {
    tomcat = new Tomcat();
    tomcat.setBaseDir(“.”);
    tomcat.setPort(8084);
    Context ctx = tomcat.addWebapp(“/”, System.getProperty(“user.dir”) + “/build/web”);
    tomcat.setHostname(“localhost”);

    File contextFile = new File(System.getProperty(“user.dir”) + “/build/web/META-INF/context.xml”);
    ctx.setConfigFile(contextFile.toURI().toURL());

    tomcat.enableNaming();
    tomcat.start();
    tomcat.getServer().await();
    }

    Without the line: `tomcat.getServer().await();`, Tomcat simply stops. Adding `tomcat.getServer().await();` my unit tests don’t execute.. any idea?

    • tborthwick says:

      You might try shutting down the server in your teardown method. Also, you could check out unit tests in the tomcat source code, which is easy to download, for examples.

  13. Scott says:

    This worked great until I integrated it into my application. Now it wont start-up and it looks like it’s related to class loading. Any easy way to enable a separate class loader for embedded Tomcat or is there a better way?

  14. Rodney Beede says:

    Anyway to point a war file to be deployed for something like tomcat.addWebapp versus a directory or do I have to expand the war file myself?

    • Rodney Beede says:

      Nevermind, I figured it out. I was passing in an invalid path to tomcat.addWebapp which caused my war file to not be found.

    • tborthwick says:

      I haven’t used it, but it looks like you could call addWebApp on a path to a war file in your appBase directory. You might also look at the setUnpackWARs(true), setAutoDeploy(true), and/or setDeployOnStartup(true) methods on the host object.

  15. Denis Pimenov says:

    We are using tomcat 6 and org.apache.catalina.startup.Embedded in our server application, but class Embedded was deprecated in tomcat 7 and was replaced by org.apache.catalina.startup.Tomcat. This class has only one connector , but we use 2 different connectors for http and https (different ports) . What to do ?

    • tborthwick says:

      You could try creating a Connector object for https, then getting the service object off the Tomcat object and calling addConnector() on it. Haven’t tried it but it seems plausible…

  16. Kay says:

    Hey,
    I’ve got to the point where I can run the main class in eclipse but it failed because it couldn’t find the /WEB-INF/myapp-servlet.xml.

    Any hint?

  17. Great post, but unfortunately everything seems to have changed, again. Per the javadoc in Tomcat 7.0.21, you should use org.apache.catalina.startup.Tomcat for embedded apps. With that, you can supposedly set up everything internal to your app, with no need for external Tomcat config files.

    Personally, I don’t trust it not to change. Instead, I’m going to try using org.apache.catalina.startup.Bootstrap, pretending it’s called by the scripts, but really calling main() or whatever from my app. I’ll do my config using the expected Tomcat files and dir structure. Basically, the only thing “different” I’ll be doing is calling Bootstrap from my app’s JVM… That way startup/shutdown is synchronized by nature of the single JVM (I don’t have to worry about coordinating two processes… my app vs. Tomcat), and my JSPs will have access to the objects in my app living in the same JVM, without requiring some form of RMI.

  18. Pingback: 在应用程序中嵌入Tomcat7 | Wenming's Blog

  19. Thanks, I have tried your code snippet with tomcat 7.0.21, The problem with missing org.eclipse.jdt.core.compiler:ecj dependency has been resolved in the new version.

  20. Afkham Azeez says:

    Take a look at http://blog.afkham.org/2011/09/embedding-tomcat-7-bettertomcat.html. This blogpost provides code segments which show how simple it is to embed Tomcat 7

    • tborthwick says:

      It’s not a bad idea to use a wrapper around the Tomcat object, but it’s so simple, you might as well just write your own instead of adding another third-party dependency and learning someone else’s API.

  21. Jan Goyvaerts says:

    I’m trying to pack it all into a self-contained jar file. The ideal format to distribute demo versions and prototypes.

    The trouble is that it seems to expect files on the filesystem for it application base. So WEB-INF can not be a directory in a jar file. Or does it ?

    • Afkham Azeez says:

      Jan,
      Do you mean you want to have a single, self contained jar file which can be used for embedding Tomcat 7?

      The org.wso2.carbon.tomcat OSGi bundle is such a self contained jar file. For details see http://blog.afkham.org/2011/09/embedding-tomcat-7-bettertomcat.html

    • tborthwick says:

      I think you’ll need a war file. I don’t believe you can pack all your app files into a jar but you could take a look at org.apache.catalina.core.StandardHost and how it handles the appBase. A war file would be easy to distribute but not quite as easy as a jar to run.

      • Seetharaman says:

        I am unable to start tomcat server while writing code in Before class.getting below error please advise me how to proceed further
        Test set: com.ticketmaster.venue.authoring.service.impl.VenueAuthoringServiceImplTest
        ——————————————————————————-
        Tests run: 2, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 0.187 sec <<< FAILURE!
        com.ticketmaster.venue.authoring.service.impl.VenueAuthoringServiceImplTest Time elapsed: 0 sec <<< ERROR!
        java.lang.NoSuchMethodError: org.apache.catalina.Context.addLifecycleListener(Lorg/apache/catalina/LifecycleListener;)V
        at org.apache.catalina.startup.Tomcat.addWebapp(Tomcat.java:528)
        at org.apache.catalina.startup.Tomcat.addWebapp(Tomcat.java:513)
        at org.apache.catalina.startup.Tomcat.addWebapp(Tomcat.java:201)

        • tborthwick says:

          With a NoSuchMethodError exception, it looks like you have the wrong version of servlet jars (ie. servlet-api) in your classpath.

  22. davidwaf says:

    This worked for me just fine. Thanks

  23. Surabhi says:

    Thanks for the post. I was trying to make it run since long, your post saved me.

  24. Muthiah says:

    How to get the running instances of tomcat?

    Consider i am going to deploy a web application in the embedded tomcat, I start the tomcat and deployed all the applications. Now I want to stop the running tomcat. Hence I need to getting the running instance of the tomcat. Then only i can stop it. How can I do this?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>