<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Le blog de Jean-Eric &#187; Development</title>
	<atom:link href="http://blog.jesc.ch/category/development/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.jesc.ch</link>
	<description>Family and thoughts on life, computers and others</description>
	<lastBuildDate>Wed, 30 Jun 2010 05:38:50 +0000</lastBuildDate>
	<language>fr</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='blog.jesc.ch' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://www.gravatar.com/blavatar/4e0dc4fb3c9a5ab4b437fb316b1aadda?s=96&#038;d=http://s2.wp.com/i/buttonw-com.png</url>
		<title>Le blog de Jean-Eric &#187; Development</title>
		<link>http://blog.jesc.ch</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://blog.jesc.ch/osd.xml" title="Le blog de Jean-Eric" />
	<atom:link rel='hub' href='http://blog.jesc.ch/?pushpress=hub'/>
		<item>
		<title>Embedding Tomcat in Eclipse with Maven, JNDI et tutti quanti!</title>
		<link>http://blog.jesc.ch/2009/05/29/embedding-tomcat-in-eclipse-with-maven-jndi-et-tutti-quanti/</link>
		<comments>http://blog.jesc.ch/2009/05/29/embedding-tomcat-in-eclipse-with-maven-jndi-et-tutti-quanti/#comments</comments>
		<pubDate>Fri, 29 May 2009 11:08:09 +0000</pubDate>
		<dc:creator>Jean-Eric Cuendet</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Travail]]></category>

		<guid isPermaLink="false">http://jesc.wordpress.com/?p=18</guid>
		<description><![CDATA[Context I work at &#171;&#160;Etat de Vaud&#160;&#187; in Switzerland and we have a lot of j2ee Servlet applications which run on Tomcat 6.0.x, that are multi-modules Maven projects. My main concern is about development time, about the time the developer spend (or loose) compiling, packaging, deploying and running the application between 2 &#171;&#160;tests&#160;&#187; Of course, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jesc.ch&blog=442511&post=18&subd=jesc&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<h3>Context</h3>
<p>I work at &laquo;&nbsp;Etat de Vaud&nbsp;&raquo; in Switzerland and we have a lot of j2ee Servlet applications which run on Tomcat 6.0.x, that are <strong>multi-modules Maven projects</strong>.</p>
<p>My main concern is about development time, about the time the developer spend (or loose) compiling, packaging, deploying and running the application between 2 &laquo;&nbsp;tests&nbsp;&raquo;</p>
<p>Of course, we use unit tests extensively here, to develop Services, DAOs and other classes, but when it comes to pure web development (understand JSP) the &laquo;&nbsp;round-trip&nbsp;&raquo; time can become huge.</p>
<p>For example, on one of our project, when the developer change code in a controller (Spring MVC), it must</p>
<ul>
<li>Run maven to compile the code and package the war (~30-60 seconds)</li>
<li>Copy the war to webapps of the Tomcat server (or have a symlink if on Linux)</li>
<li>Then tomcat redeploy the application, including the Spring context (DAOs, Services, SessionFactory) which takes around 30 seconds</li>
</ul>
<p>One code modification, <strong>round-trip time = ~1 minute&#8230;</strong></p>
<p>Compare that to PHP, Ruby on Rails or even Grails which are quite instantaneous!</p>
<p><span id="more-18"></span></p>
<h3>Multi-modules Maven projects</h3>
<p>If you have single modules Maven projects, this is not a problem. Say we have:</p>
<pre>myapp/webapp</pre>
<p>which contains JSP and static contents:</p>
<pre>myapp/webapp/css/...
<pre>myapp/webapp/images/...
myapp/webapp/WEB-INF/jsp/...</pre>
</pre>
<p>You have all your code in one location, say</p>
<pre>
<pre>myapp/src/main/java/...</pre>
</pre>
<p>then Eclipse can output compiled classes to</p>
<pre>
<pre>myapp/webapp/WEB-INF/classes/...</pre>
</pre>
<p>and have your libs in</p>
<pre>
<pre>myapp/webapp/WEB-INF/lib/...</pre>
</pre>
<p>Then you can start tomcat on</p>
<pre>
<pre>myapp/webapp/</pre>
</pre>
<p>And that&#8217;s all.</p>
<p>But when you have Multi-modules Maven projects, then you have Java source files in 2-3 places and Eclipse is unable to write all the compiled classes in one place (myapp/webapp/WEB-INF/classes)</p>
<h3>Embedding Tomcat in Eclipse to the rescue!</h3>
<p>The idea is to embedd Tomcat in Eclipse, so Tomcat is in the same JVM/ClassLoader of Eclipse and Tomcat &laquo;&nbsp;sees&nbsp;&raquo; all the projects, and also all the compiled classes and all the libs that are configured in Eclipse.</p>
<p>Step by step:</p>
<ul>
<li>Create a muli-modules Maven project that have, say, 2 modules : business and web (web depends on business)</li>
<li>Import them in Eclipse using the Maven plugin for Eclipse (http://m2eclipse.codehaus.org/)</li>
<li>You then have 3 projects in Eclipse: base, business and web</li>
<li>At this point, the web project sees all the <strong>classes and libs</strong> from business <strong>and</strong> web</li>
<li>Create a class to Embed Tomcat in Eclipse as I&#8217;ll show below</li>
<li>Run your webapp using that class and you have<strong> instantaneous view of your modifications</strong></li>
</ul>
<h3>Embedded Tomcat, with JNDI data sources</h3>
<p>Tomcat 6.0.x is totally able to Embed itself in your code. The idea, is to create a java main() in the <strong>test part of the web</strong> project (in myapp/src/test/java). It&#8217;s important to create it in the test part, so it won&#8217;t be in your generated WAR, and the needed dependencies (catalina.jar, jsp-api, &#8230;) won&#8217;t be neither in your packaged WAR.</p>
<p>Step by step:</p>
<ul>
<li>Create a class that implements the Embedded part of Tomcat (See below)</li>
<li>Debug it as Java Application (It&#8217;s important to &laquo;&nbsp;Run as Debug&nbsp;&raquo; so Eclipse is able to &laquo;&nbsp;feed&nbsp;&raquo; the webapp with the modified code without restarting the whole application)</li>
</ul>
<p><span style="text-decoration:underline;">Embedded class:</span></p>
<pre>public class TomcatRunner {

 private static final Logger log = Logger.getLogger(TomcatRunner.class);

 private Embedded embedded;
 private String catalinaHome;
 private String pwd;

 public TomcatRunner(String contextPath, String webappDir, String contextXmlPath) throws Exception {

 // Current dir =&gt; ..../myapp/web
 final File file = new File(".");
 pwd = file.getCanonicalPath();

 // Create CATALINA_HOME
 File catalinaHomePath = new File(pwd+"/target/CATALINA_HOME");
 if (!catalinaHomePath.exists()) {
 Assert.isTrue(catalinaHomePath.mkdirs());
 }
 catalinaHome = catalinaHomePath.getCanonicalPath();

 // Create an embedded server
 embedded = new Embedded();
 embedded.setCatalinaHome(catalinaHome);

 // Create an engine
 final Engine engine = embedded.createEngine();
 engine.setDefaultHost("localhost");

 // Create a default virtual host
 final Host host = embedded.createHost("localhost", pwd /*Bas dir for webapps*/);
 engine.addChild(host);

 // The context of myapp
 // myapp/default-web.xmlis the default web.xml used for the context.
 // It contains the JSP and "static content" servlets. You can find that file in apache-tomcat-6.0.18/conf/web.xml
 final Context context = createContext(contextPath, pwd+"/"+webappDir, pwd+"/"+contextXmlPath, "myapp/default-web.xml");
 host.addChild(context);

 // Install the assembled container hierarchy
 embedded.addEngine(engine);

 // Assemble and install a default HTTP connector
 final Connector connector = embedded.createConnector(""/*Default to localhost*/, 8080/*Port to listen*/, false/*Secure*/);
 embedded.addConnector(connector);
 }

 public void start() throws Exception {
 // Start the embedded server
 embedded.start();
 }

 private static Context createContext(String path, String docBase, String contextFilePath, String defaultWebXmlPath) {
 log.debug("Creating context '" + path + "' with docBase '" + docBase + "'");

 StandardContext context = new StandardContext();

 context.setDocBase(docBase);
 context.setPath(path);

 ContextConfig config = new ContextConfig();
 config.setDefaultWebXml(defaultWebXmlPath);
 config.setCustomAuthenticators(null);
 context.addLifecycleListener(config);
 // This is the config of the JDNI datasources
 if (StringUtils.isNotBlank(contextFilePath)) {
 File configFile = new File(contextFilePath);
 context.setConfigFile(configFile.getAbsolutePath());
 }
 return context;
 }

}</pre>
<p>Then you can use it with:</p>
<pre> // A global property configured for the server
 System.setProperty("myapp.appDir", "appDir/devel");

 TomcatRunner runner = new TomcatRunner("/my/app", "webapp", "webapp/META-INF/context.xml");
 runner.start();</pre>
<p>And then start it as &laquo;&nbsp;Debug&nbsp;&raquo;. That&#8217;s it!</p>
<h3>JNDI</h3>
<p>If you have JNDI data sources, you can configure them in the file</p>
<pre>webapp/META-INF/context.xml</pre>
<p><span style="text-decoration:underline;">Example of context.xml:</span></p>
<pre>&lt;Context debug="true" reloadable="true" crossContext="true" antiJARLocking="true"&gt;
   &lt;Resource name="jdbc/myAppDataSource" auth="Container" type="javax.sql.DataSource"
     maxActive="100" maxIdle="30" maxWait="10000"
     validationQuery="select sysdate from dual"
     username="WEB_USER" password="pwd" driverClassName="oracle.jdbc.OracleDriver"
     url="jdbc:oracle:thin:@&lt;server&gt;:1521:orcl"/&gt;
&lt;/Context&gt;</pre>
<h3>Usage</h3>
<p>The goal is to be able to modifiy static content, JSPs or java code and that it is used instantaneously without needing a restart or a manual operation.</p>
<p>To be able to use that Embedded tomcat thing, you need to start it as debug, then browse to http://localhost:8080/my/app</p>
<p>You should then be able to access your application, through the embedded tomcat.</p>
<p><span style="text-decoration:underline;">Static content (CSS, images):</span></p>
<p>Say you modify myapp/webapp/css/myapp.css, the file is directly in the webapp folder so it is reloaded next time you load a page that use that CSS. Idem for images.</p>
<p><span style="text-decoration:underline;">JSPs</span></p>
<p>If Tomcat is configured to recompile JSPs when they are modified (which is the default), then as soon as you modify a JSP, it&#8217;s recompiled the next time you access it.</p>
<p><span style="text-decoration:underline;">Java code</span></p>
<p>This is the greatest part. If you modify java code in Eclipse, eclipse recompiles the java file to the corresponding .class, then also <strong>feed it to the debugger</strong> so the JVM sees the new version. (That works only if you &laquo;&nbsp;Run as Debug&nbsp;&raquo; from Eclipse)</p>
<p>So when you reload your page, the new class is used and the modified code is used. Magic!</p>
<h3>Limitations</h3>
<p>There is one limitation, which is not due to this setup, eclipse or Tomcat. It&#8217;s due to the fact that Java debugger can&#8217;t be feed a class that has &laquo;&nbsp;changed too much&nbsp;&raquo;. Changing too much means that as long as you change code <strong>in a method</strong>, that&#8217;s normally fine. But if you add/remove/rename a class, a class method or a class member, then the debugger is unable to feed it to the JVM through the debugger. Eclipse warns by saying: &laquo;&nbsp;Hot code replaced failed&nbsp;&raquo;, saying that your modified code is not available in the JVM (the old code stays there) and that you should restart your application.</p>
<p>You then need to simply stop the TomcatRunner and restart it.</p>
<p>Another limitation is that if the modified classes was already run and loaded, then it won&#8217;t be reloaded before a server restart. One example, is if you have a class that set up some values in a Singleton, changing the singleton code won&#8217;t change the singleton already in memory. Idem for the spring context.</p>
<h3>Conclusion</h3>
<p>Using this setup change the round-trip time from ~60 seconds to instantaneous, which is great. Due to the limitations above, we must restart the webapp every 3-10 minutes depending which code we are changing, but that&#8217;s acceptable. And remember we use Unit tests for all development, we use that setup only for pure web development (JSPs)</p>
<p><span style="text-decoration:underline;">References:</span></p>
<p>http://www.onjava.com/pub/a/onjava/2002/04/03/tomcat.html</p>
<p>http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/startup/Embedded.html</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jesc.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jesc.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jesc.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jesc.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jesc.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jesc.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jesc.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jesc.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jesc.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jesc.wordpress.com/18/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jesc.ch&blog=442511&post=18&subd=jesc&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://blog.jesc.ch/2009/05/29/embedding-tomcat-in-eclipse-with-maven-jndi-et-tutti-quanti/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/a0bc15a12faa532d9ca600d5b444ccc0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">jesc</media:title>
		</media:content>
	</item>
	</channel>
</rss>