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.
Related
I want to use Maven to handle artifact generation for the different local and testing regions. I believe I can use different profiles but I am not certain.
In Maven can I select different directories to select files used on packaging (such as application.properties)? How would I set that up?
An idea of what I want is to have a the following folders for resources in my project
local
build server
dev
sys
prod
Each folder should contain a different version of application.resources which is a file in Spring that can be used to handle hard-coded strings for use in variables. For local builds- our developers also work on different operating systems. Should I require I want to make it seamless on different OS' also.
Key outcomes would be:
Control Maven lifecycle phases from inside the IDE (IntelliJ)
Not complicate phases and team processes
Keep things as consistent for each developer
Make the different configurations per developer/region appear invisible when running a phase e.g. install
Ideally I would have my project set up according to best practices (Duvall, Matyas, Glover).
We provide different properties currently but not by way of different folders. We do this
via a mix of
Spring's PropertyPlaceholderConfigurer
Maven profiles (something we use to build our Dev environment),
Build Server (TeamCity in our case)
Maven phases to produce the correct artifact
start-up and build arguments
My understanding of what we do is limited, but hopefully this serves as a useful example for others and maybe myself to consider.
We provide parameters, as you'll see below, to point to different property files.
Each property file has configuration for a region/environment. I'll explain the current use
as best I can in-case it provides some use to others.
To use Maven profiles we have created a profile in our pom identified as development which includes a region configuration property called env. I don't yet know entirely how that is being used yet in our project however you'll see below our POM includes the a Maven Compiler plugin and a Maven Tomcat plugin.
Day to day, as developers we run our our applications locally on Tomcat from within IntelliJ
and provide the env property. On start-up the env property is provided as an argument to
set to classpath*:dev-common.properties.
This file is a properties configuration file - setting placeholder values for our different
regions.
The value of env is made available to our PropertyPlaceholderConfigurer
Example 1 - Implementation of Maven profile in pom.xml:
The implementation of a profile in our pom is:
<profile>
<id>development</id>
<activation>
<property>
<name>env</name>
<value>development</value>
</property>
</activation>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.0-SNAPSHOT</version>
...
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
Example 2 - Property placeholder configurer for normal build:
We also make use ofa Spring component, a PropertyPlaceholderConfigurer. We use this in collaboration with a build argument to set up a classpath pointer to resource files.
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>
${env}
</value>
</list>
</property>
Example 3 - Property placeholder configurer for test:
We have Spring Contexts specifically set up for integration testing which also use the PropertyPlaceholderConfigurer. These are picked up by a integration testing class using a combination of #ContextConfiguration(locations = {"classpath:test-dataexchange-application-context.xml"}) and #RunWith(SpringJUnit4ClassRunner.class)).
In the testing context we configure the PropertyPlaceholderConfigurer as follows to pick up the properties of an integration testing region:
<bean id="testpropertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:dev-local-common.properties</value>
</list>
</property>
Other notes:
We make use of Team City for build management but I have not seen how these settings are
used there, if they are at all. I can conceive there's an ability to combine the above approaches together to aid Continuous Integration and Delivery.
I do not see where the profile identified as development is being used. It is something I
must follow up with my fellow team members.
Resources:
Building for different environments at the Maven Project site.
Maven 3 does not allow configuration of a profile outside of a pom or settings.xml (the Maven configuration file) and says that users who used these external settings should now put them inside of settings.xml
If you are using Spring boot, there is an easy way of doing this.
Create two profiles in maven, and set a property in each profile with the name of the Spring profile you want to execute.
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<!-- Default spring profile to use -->
<spring.profiles.active>dev</spring.profiles.active>
<!-- Default environment -->
<environment>develop</environment>
</properties>
</profile>
Inside your application.properties, add this property:
spring.profiles.active=${spring.profiles.active}
Create an application.property for each profile, using this pattern application-profile.properties. For example:
application-dev.properties
application-prod.properties
Be sure to active filtering in the resource plugin:
...
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
...
Another way is to create a file during the execution of maven called activeprofile.properties. Spring boot looks this file to load the active profile. You can create this file as follows:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>prepare-package</phase>
<configuration>
<target>
<echo message="spring.profiles.active=${spring.profiles.active}" file="target/classes/config/activeprofile.properties" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<configuration>
</configuration>
</plugin>
Aim to generate an artifact for each environment at one time on the central server (CI/Build server), aim to generate an artifact and start/test the application with one click locally, provide a consistent easy to learn way to check out and run your build, and check in and configure your CI.
You can use profiles in Maven and utilize Maven targets to achieve the right build using a build server which in our case is TeamCity.
Use property placeholder configurer in Spring context with an application.resources file for each region and a filename mask e.g. application-resources-${region}.
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>
Is there a tool which takes a Java File what describes a REST service as a parameter and generates a wadl file out of that.
I had the same problem: was using RESTeasy and wanted to find a way to generate the WADL automatically.
Did some research and came to the solution below.
1. Add this to your pom.xml:
<build>
<plugins>
<plugin>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>maven-wadl-plugin</artifactId>
<version>1.17</version>
<executions>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
<phase>${javadoc-phase}</phase>
</execution>
</executions>
<configuration>
<wadlFile>${project.build.outputDirectory}/application.wadl
</wadlFile>
<formatWadlFile>true</formatWadlFile>
<baseUri>http://example.com:8080/rest</baseUri>
<packagesResourceConfig>
<param>com.example.rs.resource</param>
</packagesResourceConfig>
<wadlGenerators>
<wadlGeneratorDescription>
<className>com.sun.jersey.server.wadl.generators.WadlGeneratorApplicationDoc
</className>
<properties>
<property>
<name>applicationDocsFile</name>
<value>${basedir}/src/main/doc/application-doc.xml</value>
</property>
</properties>
</wadlGeneratorDescription>
<wadlGeneratorDescription>
<className>com.sun.jersey.server.wadl.generators.WadlGeneratorGrammarsSupport
</className>
<properties>
<property>
<name>grammarsFile</name>
<value>${basedir}/src/main/doc/application-grammars.xml</value>
</property>
</properties>
</wadlGeneratorDescription>
</wadlGenerators>
</configuration>
</plugin>
</plugins>
</build>
Pay attention to the buildUri and packagesResourceConfig elements. You have to change them to reflect your project's configuration. You may also want to change the plugin's version (I used 1.17).
2. Create a /doc folder and add some files.
Create the src/main/doc/ folder and create the two files below.
File: application-doc.xml
Content:
<?xml version="1.0" encoding="UTF-8"?>
<applicationDocs targetNamespace="http://wadl.dev.java.net/2009/02">
<doc xml:lang="en" title="A message in the WADL">This is added to the start of the generated application.wadl</doc>
</applicationDocs>
File: application-grammars.xml
Content:
<?xml version="1.0" encoding="UTF-8" ?>
<grammars xmlns="http://wadl.dev.java.net/2009/02" />
3. Run the maven command.
Go to the project folder and run the following command:
$ mvn compile com.sun.jersey.contribs:maven-wadl-plugin:generate
The files \target\classes\application.wadl (the WADL itself) and \target\classes\xsd0.xsd (the schema of the resources - it's used by the application.wadl) should be generated.
Edit and use them as you wish.
PS.: Bear in mind that this is a very simple use of the maven-wadl-plugin. It can do a lot more. To know it better, please refer to the zip file mentioned in the other answer (by Pavel Bucek).
Yes, please see gerenate-wadl [1] sample from Jersey samples (look for maven-wadl-plugin).
[1] http://search.maven.org/remotecontent?filepath=com/sun/jersey/samples/generate-wadl/1.12/generate-wadl-1.12-project.zip
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.
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