How to manage shared resources for several web apps in Maven AND Eclipse? - eclipse

Note: I didn't get any response in the first version of this question, so I modified it to be more generic...
Context
My project is divided into several maven modules and several web-applications. Here is the structure:
my-project
+ pom.xml
+-- commons
+-- persistence
+-- ...
+-- web-app-1
+-- web-app-2
+-- ...
All the web applications share common resources, such as JS, CSS and images files.
Instead of duplicating these resources in each web-app-X, I decided to create another project called web-resources, which is a WAR project.
The structure is then the following one:
my-project
+ pom.xml
+-- commons
+-- persistence
+-- ...
+-- web-app-1
+-- web-app-2
+-- ...
+-- web-resources
+-- pom.xml
+-- src/main/webapp
+-- web.xml (which is almost empty, just need to be present for Maven)
+-- web_resources
+-- css
+-- images
+-- javascript
Maven
In Maven 2 (or Maven 3, as I just migrated my project to maven 3.0.2), this configuration is easy to manage as all web-app-X declare web-resources as a dependency:
<groupId>foo.bar</groupId>
<artifactId>web-app-1</artifactId>
...
<dependencies>
<dependency>
<groupId>foo.bar</groupId>
<artifactId>web-resources</artifactId>
<version>${preclosing-version}</version>
<type>war</type>
</dependency>
...
So when I build my WAR project, it first get the web-resources.war (built just before), unzip it, and build on top of it the web-app-X web-application.
This way, my WAR file will contains also a directory called web-resources/ that contains the shared resources.
This is the war overlay principle.
So on a Maven point of view, everything is fine!
Eclipse
Now, here comes the main problem: having a good Eclipse configuration.
Question: How can I use my current configuration to be managed correctly by Eclipse? In particular, when I deploy any web-app-X in Tomcat using Eclipse...
Note that I want to get the more automatizable (?) configuration, and avoid any manual steps, as this configuration should be used by dozens of developers...
For me, the best solution seems to use the linked resources of Eclipse. Thus, I set the following configuration in my web-app-X pom.xml:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<wtpversion>1.5</wtpversion>
<linkedResources>
<linkedResource>
<name>web_resources</name>
<type>2</type>
<location>${project.basedir}\..\web-resources\src\main\webapp\web_resources</location>
</linkedResource>
</linkedResources>
</configuration>
</plugin>
...
When I run the mvn eclipse:eclipse configuration, it adds succesfully this information in my .project file:
<projectDescription>
...
<linkedResources>
<link>
<name>web_resources</name>
<type>2</type>
<location>C:\dev\project\web-resources\src\main\webapp\web_resources</location>
</link>
</linkedResources>
<projectDescription>
Now, I import my project in Eclipse.
Problem: in Project properties > Java Build Path > Source, I don't see the Link Source present.
I only see my four Maven default directories (src/main/java, src/main/resources, src/test/java and src/test/resources).
What is strange is that when I try to manually add the linked resources, it refuses and says that it already exists...
So when I deploy my web application on my Tomcat in Eclipse, it does not deploy the web_resources directory, and thus I don't get the CSS / JS / images deployed.
After some tests, it seems that I have to do two modifications:
Add the line <classpathentry kind="src" path="web_resources" output="src/main/webapp/web_resources"/> in my .classpath file;
Remove the <project>preclosing-web-resources</project> in the .project file.
Note that using this configuration, Eclipse will copy (and keep synchronization) the content of web_resources project in my web-app-X/src/main/webapp/web_resources, but this is not a problem (this directory is ignored by the SCM).
The only automated solution I found was to create a simple Maven plugin that do the two previous modification, and then run the following command (or use a .bat file):
mvn eclipse:clean eclipse:eclipse myEclipsePlugin:eclipse
Question
Is there a better way to manage such configuration?
Technical information
Java 6, Maven 3.0.2, maven eclipse plugin 2.8, Eclipse 3.3.2 (but I can test with newer version of Eclipse), no m2eclipse plugin.

Starting with Servlet 3.0, you can share resources by putting them within the src/main/resources/META-INF/resources directory.
When the webapp deploys, Servlet 3.0 makes those resources available from the context path. For example, in your case...
web-resources
-- src
---- main
------ resources
-------- META-INF
---------- resources
------------ css
-------------- global.css
------------ images
-------------- background.png
Let's assume that my_project has a dependency on web-resources and is deployed to the url http://my.localhost:8080/myProject.
With that configuration, the following URLs will resolve to the correct resources:
http://my.localhost:8080/myProject/css/global.css
http://my.localhost:8080/myProject/images/background.png
IF you have a name conflict between the resources and your actual application, the application will win.
Be sure your web.xml states you are using Servlet 3.0
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">

You might want to take a look at this blog post. It covers a method for sharing resources using maven:
http://www.sonatype.com/people/2008/04/how-to-share-resources-across-projects-in-maven/

Related

Maven Jetty plugin, how to hot deploy code changs in dependent projects?

I have a war project that depends on another jar project in the same directory.
Now I want to start the war project in jetty with maven, and want it to hot swap changes in the dependent project so that the chagnes take effect immediately. My plugin config looks like this:
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<webAppSourceDirectory>${project.basedir}/src/main/resources</webAppSourceDirectory>
<classesDirectory>${project.basedir}/src/main/java</classesDirectory>
<webApp>
<contextPath>/</contextPath>
<descriptor>${basedir}/src/main/resources/WEB-INF/web.xml</descriptor>
</webApp>
</configuration>
</plugin>
How can i do it please? any pointer is appreciated.
First thing to point out...
You don't want to do this, as JAR reloading is poorly supported by Java itself, it will tend to want to cache the JAR and its contents on first use (standard behavior of the URLClassLoader). Replacing the JAR at runtime requires extra work, and sometimes even that is not possible without incurring some sort of memory leak (see the the various Leak Preventers that Jetty ships with for some hidden nasties in this area). Be prepared for OOM or other issues if you rely on this.
Now, with that out of the way ...
Hot Deployment on Jetty works by detecting/scanning for changes in the webapp and performing a webapp restart.
This works great with content, like html, js, css, etc.
Project JAR dependencies, which will wind up as part of the WEB-INF/lib structure, are part of the Jetty WebAppContext's [WebAppClassLoader].
This WebAppClassLoader is populated from information provided by Maven's artifact resolution system, which on a normal command line build resolves to content via the Maven local repository system. If you are using maven from Eclipse, the resolution of these artifacts might be other projects in your Eclipse workspace (more on this later)
To demonstrate, this is the minimal configuration for scanning for changes every 2 seconds on your webapp.
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.1.0.v20131115</version>
<configuration>
<scanIntervalSeconds>2</scanIntervalSeconds>
<webAppConfig>
<contextPath>/</contextPath>
</webAppConfig>
</configuration>
</plugin>
Lets say you have a dependant project, a jar file under the maven artifact coordinates of com.company:component:jar:1.0-SNAPSHOT.
That means the WebAppContext was loaded with a WebAppClassLoader reference to a URL of file://${user.dir}/.m2/repository/com/company/component/1.0-SNAPSHOT/component-1.0-SNAPSHOT.jar and only changes to that file will cause a hot deploy / reload.
Its simple enough on a command line in your /component/ directory to just issue a mvn clean install and see your webapp reload, but under Eclipse and its m2e plugin, a code change to the component project does not automatically represent a change to the jar file in your local repository.
In fact, m2e can be configured to swap out maven artifact references via the local repository for ones in your eclipse workspace. You need to be aware of theses settings to have success with your hot deploy / reload efforts.
Tip for figuring out your active WebAppClassloader contents
Add the following file to your war project.
src/main/jetty/dump.xml
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
"http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Set name="dumpAfterStart">true</Set>
</Configure>
And change your jetty-maven-plugin configuration to add ...
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
...
<jettyXml>src/main/jetty/dump.xml</jettyXml>
</configuration>
</plugin>
Now when your server starts, look for the extra output, particularly the WebAppClassLoader references.
...(snip)...
| | |
| | +> WebAppClassLoader=Web App Live#39714203
| | | +- file:/home/joakim/code/stackoverflow/samples/webapp-live/target/classes/
| | | +- file:/home/joakim/.m2/repository/org/eclipse/jetty/demo/component/1.0-SNAPSHOT/component-1.0-SNAPSHOT.jar
| | | +- ClassRealm[plugin>org.eclipse.jetty:jetty-maven-plugin:9.1.0.v20131115, parent: sun.misc.Launcher$AppClassLoader#77fe0d66]
...(/snip)...
You can see that my jetty:run has a reference to the component via the local repository.

Integrate Maven with existing Java Project using Eclipse

I have created this Java project using struts, hibernate in Eclipse Helios,
Now I want to integrate this project with Maven how to do it?
I have installed Maven In Eclipse already.
Tutorials, blogs, websites that I have found so far are explaining integration of some project into Maven outside Eclipse and then importing it in Eclipse or crreation of New project with Maven.None of them so far addressing my Problem.
As I mentioned I have created a project in Eclipse already Now I just want to integrate it with Maven, how to do it?
In eclipse you can easily convert a java project in a maven one right clicking on project -> configure -> convert to maven project.
While an IDE "importer" can sometimes be handy, it is not required to turn a project in Eclipse into a maven project. Basically all you just need is to add a pom.xml file and follow maven's conventions - or configure it.
By using the maven-eclipse-plugin it is actually possible have a maven itself generate the necessary files to integrate your maven project with eclipse:
Start from the command line
Go to your project's root
Create a new pom.xml file from a simple template or initiate a new project folder structure (including a pom) using mvn archetype:generate
Type mvn eclipse:eclipse.
Then maven has generated the necessary files to integrate with eclipse.
That said, maven by convention expects a certain folder structure of your Java project. It looks like this:
my-app
|-- pom.xml
`-- src
|-- main
| `-- java
| `-- com
| `-- mycompany
| `-- app
| `-- App.java
`-- test
`-- java
`-- com
`-- mycompany
`-- app
`-- AppTest.java
So unless you already have this structure, you need to move your source code to main/java (and unit test code to test/java).
Further if your project has dependencies to other projects; then you need to express these dependencies in Maven's pom.xml file. If your dependency projects are stored in the Maven Central this is particularly easy. To express a dependency to e.g. Apache Commons - you would add this to your pom.xml:
<project>
...
<dependencies>
...
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
...
</dependencies>
...
</project>
After these initial attempts to integrate your project with maven, you can try to build with mvn compile from either the command line - or using the m2eclipse plugin for Eclipse.

Beginner's Guide to Setup Xuggler

To work with Xuggler you need xuggle-xuggler-5.4.jar. According to the people who made this, most users only need the above-mentioned JAR file. However, this is what they say about using Xuggler without Maven or Ivy:
Using Xuggler WITHOUT Apache Maven or Apache Ivy
What are you... stuck
in 2003? Anyway, if you insist on this, Xuggler's pre-compiled
binaries (including native versions) can be found here. Make sure that
xuggle-xuggler.jar and its dependencies are included in your Java
classpath. See the xuggle-xugger-*.pom file distributed with the
version of Xuggler that you use to find the (small) set of dependent
jars, and download them as well.
I downloaded the xuggle-xuggler.jar file for the latest version, 5.4 but I don't understand the pom file for it.
What dependencies is he talking about?
Next, how do I download these dependencies ?
Once I get these dependencies, how do I start working in Eclipse?
Update After Downloading Dependencies
I have the following directory structure:
xuggle-xuggler-5.4.jar is stored in E:\xuggle
the various xuggler dependencies are stored in E:\xuggle\xuggle-dependencies
Question:
How do I start working with Xuggler in Eclipse? What paths do I have to set and what values do these paths have?
The following files list the other jars which xuggle depends upon:
ivy.xml
pom.xml
You can read these and then manually retrieve them from the appropriate repository, but I would submit it's simpler to start using a dependency manager.
You asked how to download these dependencies, well ivy has a convenient command-line mode of operation. (See example below)
Eclipse integration is very tough.... Once you've downloaded the jar you could try and generate the ".classpath" file or just manually add each jar via the Eclipse GUI.
The reason I don't recommend this approach is because there are Eclipse plugins for both Maven and Ivy that would do this for you automatically.
Example
Run ivy from command-line as follows:
java -jar ivy.jar -settings ivysettings.xml -dependency xuggle xuggle-xuggler 5.4 -retrieve "lib/[artifact]-[revision].[ext]"
It will retrieve xuggle and all its dependencies into a "lib" directory as follows:
├── ivysettings.xml
└── lib
├── commons-cli-1.1.jar
├── logback-classic-1.0.0.jar
├── logback-core-1.0.0.jar
├── slf4j-api-1.6.4.jar
└── xuggle-xuggler-5.4.jar
ivysettings.xml
This file tells ivy to retrieve jars from either Maven Central, or the Maven repository provided by the Xuggle project.
<ivysettings>
<settings defaultResolver="repos" />
<resolvers>
<chain name="repos">
<ibiblio name="central" m2compatible="true"/>
<ibiblio name="xuggle" m2compatible="true" root="http://xuggle.googlecode.com/svn/trunk/repo/share/java"/>
</chain>
</resolvers>
</ivysettings>
Don't fight Maven, embrace it. These days all major build systems are maven compatible (Maven, Ivy, Gradle, Grape, Buildr ...). But you can use Maven from Eclipse:
create a file called pom.xml with this content:
<project>
<groupId>com.foo<groupId> <!-- change these -->
<artifactId>foo</artifactId> <!-- parameters to whatever -->
<version>1.0-SNAPSHOT</version><!-- you like -->
<repositories>
<repository>
<id>xuggle repo</id>
<url>http://xuggle.googlecode.com/svn/trunk/repo/share/java/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>xuggle</groupId>
<artifactId>xuggle-xuggler</artifactId>
<version>5.2</version>
</dependency>
</dependencies>
</project>
Install the m2e extension and, from Eclipse, do "File > Import ... > Existing Maven Projects". In the dialog, select the Folder that contains the pom.xml.
Make sure that the Folder's layout is like this:
pom.xml
src/main/java // sources go here
src/test/java // test sources go here
Then you should have a working Eclipse project with the required dependencies.
Update after your update:
You can see the dependencies when you look at this file: http://xuggle.googlecode.com/svn/trunk/repo/share/java/xuggle/xuggle-xuggler/5.2/xuggle-xuggler-5.2.pom
commons-cli (a utility library for command line processing)
logback (a logging framework)
junit (a testingframework)
Maven will take care of loading these dependencies for you. So will Eclipse, if you use the m2e plugin as suggested above.
If you absolutely don't want to do that, you will have to download the dependencies manually. Look at the pom file above, note the names and versions of the dependencies, look them up at http://mvnrepository.com/ and download them there, e.g. this is the page for slf4j-api: http://mvnrepository.com/artifact/org.slf4j/slf4j-api/1.6.4

Cannot create a maven project from my archetype

I'm developing projects in Eclipse and I'm using maven, so I've created a new archetype, using the 'maven-archetype-archetype' Archetype, but once I try to create a new project with the my new archetype, I get the following error message in Eclipse:
The META-INF/maven/archetype.xml descriptor cannot be found.
Any idea what could the reason be?
Update:
My archetype.xml file:
<archetype>
<id>test-archetype</id>
<sources>
<source>src/</source>
</sources>
<testSources>
<source>test/</source>
</testSources>
</archetype>
My pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>$my.group.id</groupId>
<artifactId>$test-archetype</artifactId>
<version>$0.0.1</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
The folder structure is as described:
archetype
|-- pom.xml
`-- src
`-- main
`-- resources
|-- META-INF
| `-- maven
| `--archetype.xml
`-- archetype-resources
|-- pom.xml
`-- src
`-- test
Adam.
I had exactly the same problem where Eclipse would report that the archetype.xml could not be found even though it did exist in the correct location. I did finally get it working after restarting Eclipse. It seems that if the archetype project is installed/deployed in the same Eclipse session as where it is used to create a project that it error.
The problem is that you (or Eclipse) would appear to be using "mvn archetype:create" command to create the new project which has been deprecated.
You should instead be using "mvn archetype:generate"
See http://maven.apache.org/archetype/maven-archetype-plugin/plugin-info.html
If you are using Eclipse try to use Eclipse IAM, it has simple wizard and ready solution for maven, and good integration with eclipse.
This appears to be a bug relating to Maven Repositories within eclipse. Maybe it is fixed in newer versions of eclipse.
Here is a work around:
When generating a new archetype, increment the archetype version (e.g. from 0.0.1-SNAPSHOT to 0.0.2-SNAPSHOT). After mvn install the new archetype version will appear in Workspace Projects, but not Local Repository.
Rebuild Index on the Local Repository. The new archetype version will now appear in Local Repository and is available for use.
I've tried this again recently, now that I'm much more experienced with Maven, and the result was the same, there is an issue with making archetypes, as far as I can see, perhaps Eclipse bug, or miss configuration, but whatever I tried, it didn't do the trick.

Porting a tomcat web project from eclipse ganymede to intellij 8.1

I have a standard (I think) web project developed with the eclipse IDE. I wish to port it to Intellij idea 8.1 - I think that, among other things, it has better taglib support.
My project structure is as follows:
Project Folder
./src [java source files etc.]
./conf [configuration files - log4j, spring beans...]
./buid [ant files]
./WebContent
./WebContent/images [image files]
./WebContent/META-INF
./WebContent/META-INF/context.xml
./WebContent/pages [.jsp+.html files]
./WebContent/scripts [.js files]
./WebContent/skins [.css files]
./WebContent/WEB-INF
./WebContent/WEB-INF/classes [.class files]
./WebContent/WEB-INF/lib [.jar files]
./WebContent/WEB-INF/tags [.tag files]
./WebContent/WEB-INF/web.xml
I can't seem to get this project configured with my local tomcat server (version: apache-tomcat-6.0.18).
I think that a good answer would be a standard, step by step, cookbook answer as to how to port (and perhaps how to correctly define a tomcat web application within intellij idea).
Thanks all!
I think the first step would be to create a stand-alone build file which will produce a WAR. Do this before attempting to import the project into InteliJ.
I would use Maven. Creating a maven POM file to create a WAR is almost trivial and you can easily override the the default locations for your src, conf, and web content to match you existing src directory. Then test the build by deploying your newly Maven created WAR to Tomcat. I wouldn't think this first task would take more than a half day (at most a full day).
IntelliJ has a built in utility to import Maven projects. Then you should be off and running....
Regardless of the IDE you finally settle on, your project will be much better off in the long run for the Maven migration.
You initial Maven POM file will look something like this...
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yourcompany.yourapp</groupId>
<artifactId>yourapp</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>Your project name here</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
*** other dependencies here ***
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<resources>
<resource>
<directory>conf</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0</version>
<configuration>
<webResources>
<resource>
<!-- this is relative to the pom.xml directory -->
<directory>WebContent</directory>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
*** This is an example POM only... It's just meant to get you started and may not work "as is".
Start off by creating an empty web application for tomcat, within IntelliJ - and make sure that it deploys correctly
This will produce a directory structure that you should then be able to copy your source files/web assets into.
The thing that you'll probably need to handle differently is the lib files - don't store these directly in the WEB-INF directory, as keeping them in a separate 'library' area, and allowing the IDE to include them in the WAR at build time is generally a better approach, as it promotes re-use across projects.
The key thing to aim for is to not try to set your project up to completely mirror a tomcat application, as the build process will pull together the various parts for you. It all breaks down into 3 sections...
Static assets - images, config files and jsp files (Ok, I know JSP files are kinda dynamic)
Java classes - source code that you write yourself (The IDE will compile these and place them in the appropriate location)
Java Libraries - third party code that you compile against (Again the IDE will place these in the appropriate location)
There are a few bits of configuration, within the project file, that you'll need to tweak to suit your needs, but it's generally straightforward.
By default, log4j will look for it's configuration file (either log4j.xml or log4j.properties) from the classpath of your application. So this means you should place it in WEB-INF\classes, or you can specify a different location with the environment variable log4j.configuration. See the log4j manual.
What IDE you use should have no impact on the structure of your application when it gets deployed to your servlet container. It sounds like maybe you were relying on Eclipse to package the files in a specific way - this is probably a bad practice. Are you using an actual build script?