How to speed up deployment to Jetty? - java

Deployment to the Jetty server is very slow (around 45 seconds), which is tough for development, so I'm looking for advice on how to speed it up.
I'm using Maven with the Jetty plugin (jetty-maven-plugin), and the jetty:run goal on a vaadin project created from the archetype com.vaadin:vaadin-archetype-application.
I found reference here: wiki.eclipse.org/Jetty/Howto/Avoid_slow_deployment, and it makes sense that this is the problem, because there are many jar files to be scanned (from vaadin framework), but I cannot figure out where to put the xml file, what to name it, and how to get the maven jetty:run goal to use it (and I have tried lots of variations that I could think of!)
Any help is appreciated!

You can configure an individual context in the plugin either by adding attributes/parameters in the web.xml (for some limited things) or using a context xml file that applies to the context, which you need to specify with the contextXml element of the plugin configuration.
See https://www.eclipse.org/jetty/documentation/current/jetty-maven-plugin.html#configuring-your-webapp
P.S. Jetty 9 is a little faster in scanning etc.

Gregw pointed me in the right direction. Here is the complete detail of how I ended up resolving this:
1) I added a file named jetty-web.xml in my src/main/webapp/WEB-INF folder. It contained:
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Call name="setAttribute">
<Arg>org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern</Arg>
<Arg>nothing.jar</Arg>
</Call>
</Configure>
Note at this point I don't have any jars the need scanning, so I just put in a dummy entry of "nothing.jar" as the pattern to match.
2) Edit the jetty-maven-plugin's entry in pom.xml: in the section, I added
<contextXml>${basedir}/src/main/webapp/WEB-INF/jetty-web.xml</contextXml>
Now redeploys happen in just a couple seconds.

Related

Setting up different java system properties for two applications deployed in jetty as a service

I am running jetty(9.2.1) as a service for deploying two applications.
These are the steps that I followed
Started the jetty service
I have two applications to deploy in the same jetty instance. I added two war files in jetty home directory. Created two xml files in 'webapps' folder to set the contextpath and war. The applications got launched in the context path.
But I have two wars to deploy and both these applications need different value for the system property 'appConfigPath'. How can I achieve this?
Solutions tried out
If it was only one application and it is not run as a service, I can run it like this - java -Dappconfig=service.properties -jar start.jar
If there was only one application and it is run as a service, I could specify the system property in start.ini.
Referred this - Jetty - set system property and I tried to add setProperty in the xml files that I created in webapps like below, but it didn't work.
jetty-app1.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/app1</Set>
<Set name="war">/opt/jetty/app1.war</Set>
<Call class="java.lang.System" name="setProperty">
<Arg>appConfigPath</Arg>
<Arg>opt/jetty/service1.properties</Arg>
</Call>
</Configure>
jetty-app2.xml
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/app2</Set>
<Set name="war">/opt/jetty/app2.war</Set>
<Call class="java.lang.System" name="setProperty">
<Arg>appConfigPath</Arg>
<Arg>opt/jetty/service2.properties</Arg>
</Call>
</Configure>
As Andreas said. This isn't possible with Java.
System properties are a stored in a static field of the java.lang.System class. A static field is instantiated once per loaded class. So you can have different instances of a static field in different class loader. Hawever Java "system classes" (java.lang.* and others) are required to be loaded by the root classloader, hence there can be only one java.lang.System class loaded into a JVM, and hence only one value to a given system property inside a JVM.
Basically, what you tried in XML set twice the same property to two different values, and the last one to execute would override the other.
While your requirements (running two app in the same Jetty instance with different system properties) cannot be met, maybe you can relax them:
either use two Jetty instances,
either run those apps with the same system properties (but different configuration, using JNDI or context params, as explained in the question you linked).
Again, as explained in the question you linked (and in Andreas comment): using a system property for configuration in a Java web app is a bug. I would suggest reporting it to whoever made that app and ask them to fix it.

Need in understanding classpath in resource location and variable value set

Although I have been working in java for a while, there are many small things I have been ignoring, which at times have become bottleneck in productivity. I have difficulty in understanding this:
This is one of the bean.xml which gets placed in the final .war file (in a web application, built with spring framework).
<context:property-placeholder
location="classpath:/${deploy.env}/com.example.config/db.properties"
ignore-resource-not-found="false" />
I have following doubts:
1) At the time of building the code, i did like this for passing value of deploy.env
mvn clean install -Ddeploy.env=local
I ran the mvn in debug mode and could see this set to local. Now, the thing is, in the .war that gets generated, it is still ${deploy.env} (see above snippet). Doesn't this get replaced in the final .war? If not, then how do we pass the value which we intend to set?
2) what does "classpath:/${deploy.env}/com.example.config/db.properties" mean? Who sets the value of classpath? Are classpath capable of providing the location of resource files as well?
Assuming deploy.set --> local, so would this get translated to:
classpath:"/local/com.example.config/db.properties"
So does this mean db.properties would be present at: /local/com.example.config/db.properties
Any inputs to understand this would be of great help.
deploy.env is either environment variable or system property available to the JVM at run time.
The classpath:/${deploy.env}/com.example.config/db.properties will be resolved at run when your war is running in the container.
Set deploy.env=whatever in the shell from where you starting the tomcat or set in the environment of the user which starts the tomcat.
mvn clean install -Ddeploy.env=local here the deploy.env system property is available at build time. This will not replace the value of your spring config.
classpath is where all your classes and libraries bundled in the war are available along with the tomcat libraries. The spring property configurer will look for the db.properties file in the classpath at location e.g. /local/com.example.config
Spring documentation to learn more
Some explanation on my blog post
As stated in the Oracle Web site: The CLASSPATH variable is one way to tell applications, including the JDK tools, where to look for user classes.
That classpath: is referring to that location in particular, whatever it is, so it will start looking for those resources defined by Spring from that location and on, until it finds the first match.
Also, if you have that as a property in Maven, the value can be replaced with the right plug-in and configuration; not quite useful when you want a build that can be used with many values within those .properties files for different environments.
You can use other prefixes as file:, http:, etcetera. But you are just wondering about classpath:.

WildFly9.0 - adding web service access

I am migrating my RESTful web application from GlassFish4.1 to WildFly9.0 for the first time.
Initially, I suffered deployment issues due Jersey dependencies. To overcome that problem, I simply replaced said project dependencies with RESTEasy equivalents inside of the pom.xml file. In doing so, my application became deployable -- and according to (WildFly_base)/standalone/log, and the applications themselves -- are working as expected.
Additionally, I added a jboss-web.xml configuration file to my WEB-INF folder:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-web PUBLIC "http://www.jboss.org/j2ee/dtd" "http://www.jboss.org/j2ee/dtd/jboss-web_5_0.dtd">
<jboss-web>
<context-root>myprojectstart</context-root>
</jboss-web>
The hello-world page can be reached # http://ipaddress:8080/myprojectstart.
... however, I cannot view my web services # http://ipaddress:8080/myprojectstart/getData, just like I could when using GlassFish-4.1.
So; what am I missing?
Note: I use #annotations like:
#ApplicationPath("/*")
#Path("/getData")
No seperate .xml business here
I don't think RestEasy supports * in ApplicationPath. If you remove that it should work fine.

Why does weblogic not use my deployment plan?

I am having some trouble trying to adjust the deployment settings of our application in weblogic. I feel what I'm trying to do ought to be quite simple, but it's not working as expected.
I am just trying to override the context-root in weblogic.xml and the JNDI name for the data source, so these can both be configured at deployment time.
I have removed the application.xml from the ear file, so that shouldn't be affecting the overrides.
What I have so far:
weblogic.xml:
<context-root>mosaic</context-root>
<resource-description>
<res-ref-name>jdbc/LogicalDS</res-ref-name>
<jndi-name>LogicalDS</jndi-name>
</resource-description>
web.xml
<resource-ref>
<description>A logical reference to the datasource - mapped in deployment plan</description>
<res-ref-name>jdbc/LogicalDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
plan.xml
<?xml version="1.0" encoding="UTF-8"?>
<wls:deployment-plan xmlns:wls="http://xmlns.oracle.com/weblogic/deployment-plan" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/weblogic/deployment-plan http://xmlns.oracle.com/weblogic/deployment-plan/1.0/deployment-plan.xsd http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/j2ee_1_4.xsd" global-variables="true">
<!--weblogic-version:10.3.5-->
<wls:application-name>mosaic.ear</wls:application-name>
<wls:variable-definition>
<wls:variable>
<wls:name>datasource_name</wls:name>
<wls:value xsi:nil="true"></wls:value>
<wls:description>The name of the datasource to map to the mosaic application</wls:description>
</wls:variable>
<wls:variable>
<wls:name>new_context_root</wls:name>
<wls:value xsi:nil="true"></wls:value>
<wls:description>URL to deploy Mosaic at</wls:description>
</wls:variable>
</wls:variable-definition>
<wls:module-override>
<wls:module-name>mosaic.war</wls:module-name>
<wls:module-type>war</wls:module-type>
<wls:module-descriptor>
<wls:root-element>weblogic-web-app</wls:root-element>
<wls:uri>WEB-INF/weblogic.xml</wls:uri>
<wls:variable-assignment>
<wls:name>new_context_root</wls:name>
<wls:xpath>/weblogic-web-app/context-root</wls:xpath>
<wls:operation>replace</wls:operation>
</wls:variable-assignment>
<wls:variable-assignment>
<wls:description>Data source for mosaic application</wls:description>
<wls:name>datasource_name</wls:name>
<wls:xpath>/weblogic-web-app/resource-env-description/resource-env-ref-name</wls:xpath>
<wls:operation>replace</wls:operation>
</wls:variable-assignment>
<wls:variable-assignment>
<wls:name>datasource_name</wls:name>
<wls:xpath>/weblogic-web-app/resource-description/[res-ref-name="jdbc/LogicalDS"]/jndi-name</wls:xpath>
<wls:operation>replace</wls:operation>
</wls:variable-assignment>
</wls:module-descriptor>
</wls:module-override>
</wls:deployment-plan>
Nothing happens when I use the deployment plan, and none of the variables appear under the Deployment Plan configuration screens in the admin console. From what I understand, I should at least be asked for these variables, since I have specified that they are null in the deployment plan.
When I use WLST to browse the tree, I find that the runtime configuration just stays as the values in the deployment descriptors.
I have verified the deployment plan is being used in the general tab of the admin console.
Can anyone help me find out what I am doing wrong here ?
I see that you have "datasource_name" variable replacement twice. Is that intended? Your xpath appears to be incorrect:
resource-description/[res-ref-name=
etc.
Should it be:
resource-description[res-ref-name=
etc.
My suggestion is to change one thing at at time, for example, the web app context first, and test. The web app context can be also set in the admin console, so you should see the value there.
There are few good articles about deployment plan:
https://blogs.oracle.com/jamesbayer/entry/11gr1_update_and_a_deployment
http://m-button.blogspot.com/2008/08/how-to-use-deployment-plan.html
A good resource mapping doc:
http://docs.oracle.com/cd/E15523_01/web.1111/e13737/packagedjdbc.htm
(look for the diagram near the bottom).
Is your variable a "replace" or "define"?

Can I create a custom classpath on a per application basis in Tomcat

For some applications I use ZK, others Hibernate, other Apache Commons, etc.
I don't want to deploy a 75MB war file, just because it uses lots of libraries.
I don't want to add the libraries to my tomcat lib folder, or nor the classpath to it's configuration as I may have an old application using library x.1 and another application using library x.2
For this reason, it would be great to have something in the web.xml or context.xml where I say something like:
<classpath>/usr/local/tomcat/custom-libs/zk-5.0.4</classpath>
Note: The above is pseudo-code
From Tomcat 7 there is no mention of not being able to use the VirtualWebappLoader in production. I tried it and it works like a dream. Simply add the following to META-INF/context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/websandbox">
<Loader className="org.apache.catalina.loader.VirtualWebappLoader"
virtualClasspath="/usr/.../*.jar;/usr/.../*.jar"/>
</Context>
In Netbeans, under packaging, I just untick all the packages, taking the .war size down to nothing, make sure the dependencies are in the correct folders on the server and upload. Yey! No more 100 MB WAR file.
Addition #Spider answer.
Tomcat Context hold Loader element. According to docs deployment descriptor (what in <Context> tag) can be placed in:
$CATALINA_BASE/conf/server.xml - bad - require server restarts in order to reread config
$CATALINA_BASE/conf/context.xml - bad - shared across all applications
$CATALINA_BASE/work/$APP.war:/META-INF/context.xml - bad - require repackaging in order to change config
$CATALINA_BASE/work/[enginename]/[hostname]/$APP/META-INF/context.xml - nice, but see last option!!
$CATALINA_BASE/webapps/$APP/META-INF/context.xml - nice, but see last option!!
$CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xml - best - completely out of application and automatically scanned for changes!!!
Here my config which demonstrate how to use development version of project files out of $CATALINA_BASE hierarchy (note that I place this file into src/test/resources dir and intruct Maven to preprocess ${basedir} placeholders through pom.xml <filtering>true</filtering> so after build in new environment I copy it to $CATALINA_BASE/conf/Catalina/localhost/$APP.xml):
<Context docBase="${basedir}/src/main/webapp"
reloadable="true">
<!-- http://tomcat.apache.org/tomcat-7.0-doc/config/context.html -->
<Resources className="org.apache.naming.resources.VirtualDirContext"
extraResourcePaths="/WEB-INF/classes=${basedir}/target/classes,/WEB-INF/lib=${basedir}/target/${project.build.finalName}/WEB-INF/lib"/>
<Loader className="org.apache.catalina.loader.VirtualWebappLoader"
virtualClasspath="${basedir}/target/classes;${basedir}/target/${project.build.finalName}/WEB-INF/lib"/>
<JarScanner scanAllDirectories="true"/>
<!-- Use development version of JS/CSS files. -->
<Parameter name="min" value="dev"/>
<Environment name="app.devel.ldap" value="USER" type="java.lang.String" override="true"/>
<Environment name="app.devel.permitAll" value="true" type="java.lang.String" override="true"/>
</Context>
UPDATE Tomcat 8 change syntax for <Resources> and <Loader> elements, corresponding part now look like:
<Resources>
<PostResources className="org.apache.catalina.webresources.DirResourceSet"
webAppMount="/WEB-INF/classes" base="${basedir}/target/classes" />
<PostResources className="org.apache.catalina.webresources.DirResourceSet"
webAppMount="/WEB-INF/lib" base="${basedir}/target/${project.build.finalName}/WEB-INF/lib" />
</Resources>
Another a bit hacky alternative.
You can write a 5-6 line custom class loader which derives from urlclassloader, and simply adds your classpath jars using addUrl() method.
Then set it as the context class loader of the thread in your application code.
Thread.setContextClassLoader(new CustomClassloader(path, parentClassLoader)
where parent class loader typically is
Thread.getContextClassloader()
This is what the META-INF/context.xml file can be used for. You defined your own WebappLoader, which loads classes for your particular webapp. This is the reference I used: http://tomcat.apache.org/tomcat-5.5-doc/config/loader.html (Edit: for Tomcat 6: http://tomcat.apache.org/tomcat-6.0-doc/config/loader.html, for Tomcat 7: http://tomcat.apache.org/tomcat-7.0-doc/config/loader.html)
Also this fellow here seems to post a solution to your exact problem (example included): http://java.dzone.com/articles/extending-tomcat-webapploader

Categories