How does one set a custom WebAppClassLoader in Jetty through config? - java

I am trying to configure a Jetty (6.x) WebAppContext with a custom subclass of WebAppClassLoader. In code (Scala), it's simply this:
val context = new WebAppContext()
val cwacl = new CustomWebAppClassLoader(context)
context.setClassLoader(cwacl)
...
This works fine when embedding Jetty. In production, however, I just deploy a war file to a stand-alone jetty instance, so there's no opportunity to configure things in code like this.
I can't figure out how to do the same thing via Jetty's configuration files. Any help is appreciated.
Bonus: How would you configure maven-jetty-plugin to use the CustomWebAppClassLoader :)

You could use the context config files. There are examples in the contexts/ directory.
This would be something along these lines:
<Configure id="mycontext1" class="org.mortbay.jetty.webapp.WebAppContext">
<Set name="classLoader">
<New class="f.q.n.CustomWebAppClassLoader">
<Arg><Ref id="mycontext1"/></Arg></New>
</Set>
</Configure>
(See the Jetty XML Syntax configuration reference for more details.)

As an alternative to using a context config file, you can set the classloader attributes in the pom.xml file, for jetty >= 8.x e.g. not scanning any class within WEB-INF for faster startup:
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
<configuration>
<webApp>
<webInfIncludeJarPattern>^$</webInfIncludeJarPattern>
</webApp>
<stopKey>foo</stopKey>
<stopPort>9999</stopPort>
</configuration>
</plugin>
</plugins>
Reference: Jetty plugin webapp configuration

Related

Java webapp : How to map/direct webapp to your BASE URL/IP?

Typically when you create a webapp you will access your webapp when you hit the url
<your_IP>/<Project_name>/
Example:
127.0.0.1/MyWebapp/
Question: How do you configure your webapp to run from base URL
Example
127.0.0.1/
Moreover, when the browser navigates to your IP (and not your IP + name of your webapp) you can hit your webpage
Question: Is this a configuration file that needs to be edited in your Application web server?
It depends on your container, but generally you will name your file ROOT.war or specify the context explicitly.
For example, since you've tagged this question with jetty, here is the plugin in my pom.xml for embedded testing using mvn jetty:run. Notice the contextPath element.
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.25</version>
<configuration>
<contextPath>/</contextPath>
<scanIntervalSeconds>5</scanIntervalSeconds>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>8081</port>
<maxIdleTime>60000</maxIdleTime>
</connector>
</connectors>
</configuration>
</plugin>
When I deploy to Tomcat, I simply name my file ROOT.war and drop it into the webapps folder. Note that you'll need to move or remove the existing ROOT content from webapps first.
Doing this will allow you to access your application at http[s]://<host>[:<port>]/ with no extra context needed.
Assuming you're using maven to build your application, you can avoid manually re-naming your WAR by specifying the finalName in your pom.xml.
<build>
<finalName>ROOT</finalName>
[...]
</build>

How to increase Jetty threadpool size with jetty-runner on Heroku?

I have a Java (Spring MVC) webapp running on Heroku. It uses the setup described in this article:
Getting Started with Spring MVC Hibernate on Heroku
It looks like Jetty by default uses just one thread. Given this Heroku & jetty-runner setup, what is the simplest way to increase the threadpool size?
NB: I do not have any custom Jetty related code (so it's unclear how I'd apply the advice e.g. at: How to use setThreadPool() in Jetty). If possible, I'd prefer to keep it that way. Everything Jetty-related is now in Procfile and pom.xml (see below).
Can I set the threadpool size with some jetty-runner parameter or config option? If I need to create a Jetty config file, how do I make Heroku/jetty-runner use it?
Procfile:
web: java $JAVA_OPTS -jar target/dependency/jetty-runner.jar --port $PORT target/*.war
pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-runner</artifactId>
<version>8.1.10.v20130312</version>
<destFileName>jetty-runner.jar</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
What solved it for me (a Spring, not Jetty issue)
I was wrong when I wrote this in the question:
It looks like Jetty by default uses just one thread.
This turned out to be purely a Spring issue. In applicationContext.xml, I changed
<task:annotation-driven/>
into
<task:annotation-driven scheduler="scheduler-pool"/>
<task:scheduler id="scheduler-pool" pool-size="5"/>
... and different #Scheduled tasks now happily run in separate threads like scheduler-pool-1 or scheduler-pool-3.
How to tweak Jetty threadpool configs (with jetty-runner)
(Before I realised my problem was not a Jetty issue, I had already looked into how Jetty threadpools are configured. Documenting that here; maybe it is useful to someone.)
Create a jetty.xml config file (somewhere like src/main/resources so that it gets copied to the compilation target dir), and customise it to your liking.
Example (probably a poor one):
<?xml version="1.0"?>
<!-- For some reason, must use org.eclipse classes,
even though we depend on org.mortbay Jetty... -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Set name="ThreadPool">
<New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<Set name="minThreads">3</Set>
<Set name="maxThreads">5</Set>
</New>
</Set>
</Configure>
Then, tell jetty-runner to use that config file with the --config switch. So for example in Heroku's Procfile, add --config target/classes/jetty.xml:
web: java $JAVA_OPTS -jar target/dependency/jetty-runner.jar --config target/classes/jetty.xml --port $PORT target/*.war
If you also happen to be using jetty-maven-plugin, you can tell it to use your custom Jetty config by adding this under <configuration> in pom.xml:
<jettyConfig>target/classes/jetty.xml</jettyConfig>

Possible to run two webapps at once when developing with Maven/Eclipse?

Here's the problem: we build webapps for clients. We also have an "admin" webapp that modifies some client data structures. Because of the nature of the data, both webapps have to run in the same JVM.
This is no problem in production; you just put two webapps in the same app server.
We've recently switched to a Mavenish way of laying out webapps, though, and Maven wants one webapp per project. In Eclipse it's a problem, because if you run the different webapps independently, they'll be in separate JVMs.
We're trying to use the jetty-maven-plugin to do webapp testing, but could switch to something else if it would solve this problem.
Yes, you can :) It's done by identifying one WAR module as the primary, copying all the other WARs into the primary's target dir, making a jetty.xml and telling Maven Jetty Plugin to use the jetty.xml. Here's how to copy the other WARs using Maven dependency plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.foo</groupId>
<artifactId>bar</artifactId>
<version>${project.version}</version>
<type>war</type>
<overWrite>true</overWrite>
<outputDirectory>target/</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
You'll need to have the com.foo:bar dependency defined in the POM as well. Here's the contents of jetty.xml:
<?xml version="1.0"?>
<!-- =========================================================== -->
<!-- Set handler Collection Structure -->
<!-- =========================================================== -->
<Set name="handler">
<New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
<Set name="handlers">
<Array type="org.eclipse.jetty.server.Handler">
<Item>
<New class="org.eclipse.jetty.server.handler.ContextHandlerCollection"
id="Contexts">
<Set name="handlers">
<Array type="org.eclipse.jetty.server.Handler">
<Item>
<New id="FooWebHandler"
class="org.eclipse.jetty.webapp.WebAppContext"/>
</Item>
</Array>
</Set>
</New>
</Item>
</Array>
</Set>
</New>
</Set>
<Ref id="FooWebHandler">
<Set name="contextPath">/foo</Set>
<Set name="war">
target/bar-${project.version}.war
</Set>
</Ref>
And here's how to tell Maven Jetty plugin to use the new jetty.xml:
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
<configuration>
<jettyConfig>${basedir}/jetty.xml</jettyConfig>
</configuration>
Now kick off jetty:run-war goal from Eclipse and you should see all WARs deploying in one Maven Jetty plugin instance. I run this from command line and it works there, YMMV with Eclipse.
You can do this via the jetty-maven-plugin directly, without modifying jetty.xml:
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
<scanIntervalSeconds>5</scanIntervalSeconds>
<webApp>
<contextPath>/</contextPath>
</webApp>
<contextHandlers>
<contextHandler implementation="org.eclipse.jetty.maven.plugin.JettyWebAppContext">
<war>${project.basedir}/../secondProject.war</war>
<contextPath>/cc</contextPath>
</contextHandler>
</contextHandlers>
</configuration>
<executions>
...
</executions>
</plugin>
You don't have to modify jetty.xml file(s) at all to use this successfully, and you don't need to copy the war file either. (although you may wish to build the second war as part of this build, see maven-invoker-plugin)
Documentation here: http://www.eclipse.org/jetty/documentation/9.2.2.v20140723/jetty-maven-plugin.html#running-more-than-one-webapp
Here's to give an example for ccleve's answer.
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration;
...
public static void main(String[] args) throws Exception {
...
Server server = new Server(port);
HandlerCollection handlers = new HandlerCollection();
WebAppContext frontEndWebappContext = new WebAppContext(
"src/main/webapp", "/test"
);
handlers.addHandler(frontEndWebappContext);
String serviceWebappBasePath = {absolute_path_to_other_webapp};
WebAppContext serviceWebappContext = new WebAppContext(
serviceWebappBasePath + "/main/webapp", "/"
);
handlers.addHandler(serviceWebappContext);
XmlConfiguration conf = new XmlConfiguration(new File(
serviceWebappBasePath + "test/webapp/WEB-INF/jetty-web.xml")
.toURI().toURL().openStream());
conf.configure(serviceWebappContext);
server.setHandler(handlers);
server.start();
...
In this case there is front-end webapp that is mounted to "/test" and a service webapp that is mounted on "/". We also include jetty-web.xml of the service app.
In your case, that launcher that you would create should be located in the "src/test" folder since it shouldn't be included in your war because you use want it for test purposes only.
You may also have to add dependency to the service webapp in scope test in the pom file of the front end webapp :
<dependency>
<groupId>{service_group}</groupId>
<artifactId>{service_artifact_id}</artifactId>
<version>{service_version}</version>
<scope>test</scope>
</dependency>
or/and
<dependency>
<groupId>{service_group}</groupId>
<artifactId>{service_artifact_id}</artifactId>
<type>test-jar</type>
<version>{service_version}</version>
<scope>test</scope>
</dependency>
I don't have that much experience with Maven/Jetty; but I do have experience with Tomcat on Eclipse; so we're both at least doing something with servlets on Eclipse.
At any rate, I don't know if you've made projects or not using any of the project templates in Eclipse, but I made mine using the Dynamic Web Project template. I haven't done two web apps before; but if you were to make two of these projects, and then in the Eclipse servers tab, make a new server and add both projects to it, you might be able to accomplish your goals.
When you do Run As...you're basically just running the default run configuration that Eclipse has for your project setup. But if you deploy both of your projects to one server in your dev environment, and then select that server and hit start and it should just start it on the one JVM; similar to your production environment.
Like I said though; I'm not using Jetty and I've never used the server setup guide with Jetty so I wouldn't know if this would work for you or not. So I hope this is helpful - but I won't be too terribly surprised if it isn't.
Answering my own question:
It appears that this just isn't possible. The workaround that we've come up with is to write a little embedded jetty code and launch it from within our app. Jetty allows you to add multiple webapps programmatically. It also allows you to create multiple resource bases, that is, directories, per webapp, which enables overlays. So far, it works great.

Running web app in both Jetty and Tomcat

I have a web app which in production I run on Tomcat. It uses the MySQL connector, however it is not bundled up with the war, rather it is included under Tomcat's common lib directory, so that I can access the data source through JNDI.
I would like to do something similar with Jetty (while developing), and more precisely Jetty + Maven. Is there a way for me to include the mysql-connector jar in the classpath when running Jetty through Maven (i.e. not have it bundled in the war file)?
Also I should note that I am using Maven for my build process and have the mysql-connector specified as "provided" scope.
Additinally to previous answer:
you have to add to your jetty plugin in maven config dependency:
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
<configuration>
<stopKey>blah-blah-blah</stopKey>
<stopPort>9966</stopPort>
<webAppConfig>
<contextPath>/</contextPath>
</webAppConfig>
<jettyEnvXml>${basedir}/src/jetty-env.xml</jettyEnvXml>
</configuration>
<dependencies>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.4-701.jdbc4</version>
</dependency>
</dependencies>
</plugin>
And then you can use provided scope at main project dependencies. I did it right now, and it works. Thank you for your question (and Nishant too)
Does not directly answer your question but since I love portability in webapps my war will contain the connector jar and a connection pool (e.g the super duper c3p0). That means that the container will not manage the database connection for me anymore nor will I use JNDI to describe the connection properties. But the webapp is now 100% portable and predictable on tomcat, jetty, resin, jboss etc.
<Configure class="org.mortbay.jetty.webapp.WebAppContext">
<New class="org.mortbay.jetty.plus.naming.Resource">
<Arg>hd-props</Arg>
<Arg>
<New class="java.util.Properties">
<Call name="load">
<Arg>
<New class="java.io.FileReader">
<Arg>cfg/dev-local.properties</Arg>
</New>
</Arg>
</Call>
</New>
</Arg>
</New>
It is a jetty-env.xml, which points to .properties file, which contains all the connect params to DB.
<bean id="jndi" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/hd-props"/>
</bean>
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="jndi"/>
</bean>
It is a spring config (i'm using spring too)
And then, I call mvn jetty:run, and it works fine...
Perhaps you could try using Maven .war overlays for this purpose, though I don't know if they work with other dependencies.
So basically your project would be
parent
|---- original-war
|---- new-war
Where your original-war project has the mysql dependency as <scope>provided</scope> but the the new-war module is just a pom that has a <packaging>war</packaging>, depends on the original war (for the overlay) has the mysql dependency with the compile scope, and runs the jetty plugin (leave the jetty plugin out of the original-war module). If this works, then you'll have to deal with the minor inconvenience of doing your development in one module but whatever testing you are doing in maven within another module.

Howto pass Java system properties to maven-cargo container

I'm preparing a maven2 web project for continuous integration. I use the maven cargo plugin to automatically deploy the WAR to Tomcat6x before running integration tests.
My code depends on some system properties which are set with MAVEN_OPTS=-Dfoo=bar. Unfortunately these properties are missing when the application is deployed to Tomcat:
System.getProperty("foo"); // null, when deployed to container by maven-cargo
How can I pass these properties to Tomcat?
You should be able to do this by using the systemProperties tag in the container definition of the plugin:
<container>
[...]
<systemProperties>
<MAVEN_OPTS>-Dfoo=bar</MAVEN_OPTS>
</systemProperties>
</container>
Or you can set this in a setenv.sh (on linux) file in your $CATALINA_HOME/bin/ directory. If this file does not exist you should create it and add the following line:
MAVEN_OPTS=-Dfoo=bar
Hope this helps.
You should be able to do this by using the systemProperties tag in the container definition of the plugin:
<container>
<systemProperties>
<foo>bar</foo>
</systemProperties>
</container>
this is equivalent to pass -Dfoo=bar in command line or in another option.

Categories

Resources