Build java solution with 4 configurations in one call - java

I have solution with 5 projects:
00-PROJECT - Parent project for whole solution. Other projects are submodeles of this one.
01-INTERFACE - API description library for communications between client and server
02-SERVER - Server application that provides API
03-CLIENT - Client modules that communicate with server application
04-DESKTOP - Desktop application built using SWT GUI library. Communicates with server using client modules from 03-CLIENT.
While I develop this whole solution I need to have embedded 02-SERVER in 04-DESKTOP. This is needed to easy run and debug application in Eclipse IDE because both and client and server are under develop together.
But to deploy application to the client I need to build 02-SERVER and 04-DESKTOP separately. I found solution for prepare deployment .zip - it is maven-assembly-plugin. It assemblies all .jars, configuration files, jasper templates in one .zip (or folder). It works perfect. But one problem appeared when I tried to create deployment package of 04-DESKTOP for several platforms, at least these three: Windows 32bit, Windows 64bit, Linux 64bit (all are used in customer's organization).
One of solutions for 04-DESKTOP is profiles. Maven provide a powerful profiles system. But the problem was that you can run maven with one profile and there is no way to invoke maven for several profiles. The second think is wen I invoke maven to build packages for each profile using parent pom 02-SERVER is recompiled each time and I didn't like this solution.
The my main question was how prepare 5 packages (one server package and 4 desktop packages) with single command? e.g. invoke mvn package in parent project.

I searched for answer for a while. Here are similar questions on stackoverflow.com and answers, but I didn't found answer for my question. After some research and tries I found solution.
I just added 4 projects in solution for each platform I needed. So my solution now has 7 projects:
00-PROJECT
01-INTERFACE
02-SERVER
03-CLIENT
04-DESKTOP
04-DESKTOP-LINUX-x86
04-DESKTOP-LINUX-x64
04-DESKTOP-WIN32-x86
04-DESKTOP-WIN32-x64
There are no source codes in folders in these additional projects. But there is pom.xml in these projects. The build configuration points to 04-DESKTOP sources folder:
<build>
<sourceDirectory>../04-DESKTOP/src</sourceDirectory>
</build>
Because all these 4 projects are modules in main project I can't give them the same artifactId. But maven-jar-plugin by default creates jar with name equals to artifactId. So result jar file name is redefined in maven-jar-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix></classpathPrefix>
<mainClass>net.cloudstock.desktop.app</mainClass>
</manifest>
</archive>
<finalName>net.cloudstock.desktop-${project.version}</finalName>
</configuration>
</plugin>
The whole pom.xml for one of additional projects is:
<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>
<parent>
<!-- Information about parent project -->
<artifactId>net.cloudstock.system</artifactId>
<groupId>net.cloudstock</groupId>
<version>1.0.1</version>
</parent>
<artifactId>net.cloudstock.desktop.win32.x86</artifactId>
<name>Cloudstock Descktop frontend (Windows x86)</name>
<packaging>jar</packaging>
<properties>
<!-- Operation system where this app must run -->
<os>win32</os>
<!-- Processor architecture -->
<arch>x86</arch>
<!-- Variable to point sources to 04-DESKTOP/src folder -->
<desktop.root>../04-DESKTOP</desktop.root>
<!-- I am new in maven, so I can't comment this line -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<!-- Tell to the compiler where sources are -->
<sourceDirectory>${desktop.root}/src</sourceDirectory>
<resources>
<resource>
<directory>src</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix></classpathPrefix>
<mainClass>net.cloudstock.desktop.app</mainClass>
</manifest>
</archive>
<!-- Redefine result jar, because by default its name will be net.cloudstock.desktop.win32.x86-{VERSION}.jar -->
<finalName>net.cloudstock.desktop-${project.version}</finalName>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>${desktop.root}/assembly.xml</descriptor>
</descriptors>
<!-- the name of the zip archive with program that I send to the customer -->
<finalName>net.cloudstock.desktop-${os}-${arch}-${project.version}</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- SWT for Win x86. It differs for different OSes and processors -->
<dependency>
<groupId>org.eclipse.swt</groupId>
<artifactId>org.eclipse.swt.win32.win32.x86</artifactId>
<version>4.3</version>
</dependency>
<!-- Other application deps. They are duplicated in all 04-DESKTOP* projects -->
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>net.cloudstock</groupId>
<artifactId>net.cloudstock.client</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>net.cloudstock</groupId>
<artifactId>net.cloudstock.interface</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jface</groupId>
<artifactId>org.eclipse.jface</artifactId>
<version>3.8.0.v20120521-2329</version>
</dependency>
</dependencies>
</project>
The one thing in this schema is not enough nice is a hack in ${desktop.root}/assembly.xml
You can't tell to maven-assembly-plugin to include artifact jar in assembly because it includes jar with artifactId name. So I added one additional fileSet to include resulting jar from current project:
<fileSets>
<fileSet>
<directory>target</directory>
<outputDirectory>lib/</outputDirectory>
<includes>
<include>net.cloudstock.desktop-${project.version}.jar</include>
</includes>
</fileSet>
...
</fileSets>
An the end I added dependency tag in 04-DESCTOP/pom.xml to include 02-SERVER and four profiles witch are activated by os condition:
<profile>
<id>win-x86-debug</id>
<activation>
<activeByDefault>false</activeByDefault>
<os>
<family>Windows</family>
<arch>x86</arch>
</os>
</activation>
<dependencies>
<dependency>
<groupId>org.eclipse.swt</groupId>
<artifactId>org.eclipse.swt.win32.win32.x86</artifactId>
<version>4.3</version>
</dependency>
</dependencies>
</profile>
Now I develop desktop application in 04-DESCTOP project in Eclipse. I can run and debug whole solution.
When I finish with current iteration and want to send application to the customer I build it using one command from parent project mvn package:
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] ------------------------------------------------------------------------
[INFO] Cloudstock System ..................................... SUCCESS [2.202s]
[INFO] Helper Library by Nicolai Budico ...................... SUCCESS [4.563s]
[INFO] Cloudstock Interface .................................. SUCCESS [2.925s]
[INFO] Cloudstock Server ..................................... SUCCESS [3.835s]
[INFO] Cloudstock Client Backend ............................. SUCCESS [1.120s]
[INFO] Cloudstock Descktop frontend (Windows x86) ............ SUCCESS [9.019s]
[INFO] Cloudstock Descktop frontend (Windows x64) ............ SUCCESS [5.530s]
[INFO] Cloudstock Descktop frontend (Linux x86) .............. SUCCESS [5.158s]
[INFO] Cloudstock Descktop frontend (Linux x64) .............. SUCCESS [4.998s]
[INFO] ------------------------------------------------------------------------
The last think that must be noticed in this solution is that You need to edit 5 pom's if something is changed in desktop application configuration.
Maybe this solution is wrong, maybe it is not so correct, but I am very happy with it. And I really hope this will be helpful for someone.

Related

How do I solve an index out of bounds exception using Maven to compile TeaVM?

I'm trying to figure out in the most rudimentary way possible how to use TeaVM to compile a wasm file from a .java file. My .java code is fairly simple and compiles successfully to Javascript if I use the maven .pom file provided on the TeaVM Getting Started page:
package org.teavm;
public class Scorer {
public static void main(String[] args) {
Double score = testScore();
//log(score);
}
//#JSBody(params = { "value" }, script = "console.log('Value is: ' + value)")
//public static native void log(double value);
public static double testScore(){
Double score = 8.0085;
return score;
}
}
My problem comes when I want to do the same thing, but compile it to .wasm instead of .js. (This is why the JSO stuff is commented out from the .java code). My .pom file is as follows:
<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>org.teavm</groupId>
<artifactId>teavm-maven-webapp</artifactId>
<version>0.6.1 </version>
<packaging>war</packaging>
<properties>
<java.version>1.8</java.version>
<teavm.version>0.6.1</teavm.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Emulator of Java class library for TeaVM -->
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-classlib</artifactId>
<version>${teavm.version}</version>
<scope>provided</scope>
</dependency>
<!-- JavaScriptObjects (JSO) - a JavaScript binding for TeaVM -->
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-jso-apis</artifactId>
<version>${teavm.version}</version>
<scope>provided</scope>
</dependency>
<!-- Servlet 3.1 specification -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Configure Java compiler to use Java 8 syntax -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<!-- Configure WAR plugin to include JavaScript !AND WASM! files generated by TeaVM -->
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<webResources>
<resource>
<directory>${project.build.directory}/generated/js</directory>
</resource>
<resource>
<directory>${project.build.directory}/generated/wasm</directory>
</resource>
</webResources>
</configuration>
</plugin>
<!-- Configure TeaVM -->
<plugin>
<groupId>org.teavm</groupId>
<artifactId>teavm-maven-plugin</artifactId>
<version>${teavm.version}</version>
<executions>
<execution>
<id>web-client</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<!-- Directory where TeaVM should put generated files. This configuration conforms to the settings
of the WAR plugin -->
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>
<!-- Main class, containing static void main(String[]) -->
<mainClass>org.teavm.Scorer</mainClass>
<!-- Whether TeaVM should produce minified JavaScript. Can reduce JavaScript file size more than
two times -->
<minifying>false</minifying>
<!-- Whether TeaVM should produce debug information for its built-in debugger -->
<debugInformationGenerated>true</debugInformationGenerated>
<!-- Whether TeaVM should produce source maps file -->
<sourceMapsGenerated>true</sourceMapsGenerated>
<!-- Whether TeaVM should also put source files into output directory,
for compatibility with source maps -->
<sourceFilesCopied>true</sourceFilesCopied>
<!-- Optimization level. Valid values are: SIMPLE, ADVANCED, FULL -->
<optimizationLevel>FULL</optimizationLevel>
<!-- <targetType>WEBASSEMBLY</targetType> -->
</configuration>
</execution>
<execution>
<id>wasm-client</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<!-- Directory where TeaVM should put generated files. This configuration conforms to the settings
of the WAR plugin -->
<targetDirectory>${project.build.directory}/generated/wasm/teavm-wasm</targetDirectory>
<!-- Main class, containing static void main(String[]) -->
<mainClass>org.teavm.Scorer</mainClass>
<!-- Whether TeaVM should produce debug information for its built-in debugger -->
<debugInformationGenerated>true</debugInformationGenerated>
<targetType>WEBASSEMBLY</targetType>
<!-- Optimization level. Valid values are: SIMPLE, ADVANCED, FULL -->
<optimizationLevel>FULL</optimizationLevel>
<minHeapSize>1</minHeapSize>
<maxHeapSize>16</maxHeapSize>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
This is basically a combination of the "Getting Started" .pom file and the .pom file from the benchmark sample located here: https://github.com/konsoletyper/teavm/blob/master/samples/benchmark/pom.xml
I added the second execution block to the teavm plugin configuration section. Everything else in the benchmark .pom looks like it isn't related to .wasm file generation.
When I try to build (using mvn clean package, same as I used for the js-only version of this), I get the following error:
[INFO] Running TeaVM
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.876 s
[INFO] Finished at: 2022-02-24T18:43:21-05:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.teavm:teavm-maven-plugin:0.6.1:compile (wasm-client) on project teavm-maven-webapp: Unexpected error occurred: Array index out of range: 0 -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
Does anyone know what might be causing this? I checked the apache wiki page url in the error log and it doesn't really help. I've never used either TeaVM or Maven before and this has me kind of stumped.

Multi-module JavaFX maven project packaging issue

This is an attempt to create a multi-module JavaFX application with maven.
Given the following structure of the project:
project
| pom1.xml
|_____ Word Generator (Folder)
| pom2.xml
|_____logic (folder)
| WordGenerator
|_____UI (folder)
| pom3.xml
|_____marty
| App
| PrimaryController
| SecondaryController
We have the following structure of the pom files in order of the scheme above:
pom1.xml
<?xml version="1.0" encoding="UTF-8"?>
<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>org.games.marty</groupId>
<artifactId>words</artifactId>
<packaging>pom</packaging>
<version>0.1</version>
<modules>
<module>UI</module>
<module>Word Generator</module>
</modules>
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>16</source>
<target>16</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
pom2.xml
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>words</artifactId>
<groupId>org.games.marty</groupId>
<version>0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>word.generator</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>16</source>
<target>16</target>
</configuration>
</plugin>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>org.games.marty.logic.WordGenerator</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
pom3.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>
<artifactId>UI</artifactId>
<version>0.1</version>
<parent>
<artifactId>words</artifactId>
<groupId>org.games.marty</groupId>
<version>0.1</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>16</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>16</version>
</dependency>
<dependency>
<groupId>org.games.marty</groupId>
<artifactId>word.generator</artifactId>
<version>0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>16</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.6</version>
<executions>
<execution>
<!-- Default configuration for running -->
<!-- Usage: mvn clean javafx:run -->
<id>default-cli</id>
<configuration>
<mainClass>org.games.marty.App</mainClass>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>org.games.marty.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
The way we have attempted to build the application in order for the UI to have access to the WordGenerator logic is to maven package the result from the pom1.xml directive
We get the above error as mentioned earlier:
Error: Could not find or load main class org.games.marty.App
Caused by: java.lang.NoClassDefFoundError: javafx/application/Application
As far as my understanding goes, the JavaFX dependencies are installed throught maven and should be available but they are missing?
Packaging via mvn package using the maven-jar-plugin is not enough
mvn package, by default, is just going to package the jar for your application code, it isn't going to include all of the dependant library code (which is why the dependent code cannot be found when you attempt to run your application).
You could package your application code and dependant libraries using an assembly, as detailed in How can I create an executable JAR with dependencies using Maven?, though that approach is not the only one to solve your problem.
You need to build some kind of runtime image
There are numerous options for building runtime images and I don't know your requirements, so I can't recommend what you should do instead. Example options are:
A zip/tar of your application plus libraries in a separate directory.
The creation of a single jar that includes all dependant code.
Either of solutions 1 or 2, plus the inclusion of a packaged JRE.
A runtime image with your code and libraries which also uses just the custom runtime portions of the JRE and JavaFX modules you need (using jlink).
A native installer for either 3 or 4 (using jpackage + a native installer creation tool, e.g. WIX, RPM, DEB installer creators).
The last method (native installer), is the packaging, distribution, and installation method I would recommend for most non-trivial applications.
You need to research how to do this
To get your solution, you will need to do your own research, and, once you have chosen an approach and toolset, you could create a new question regarding the implementation of that approach, if you continue to have difficulties.
Related resources
How can I create an executable JAR with dependencies using Maven?
openjfx Runtime images documentation
maven shade plugin
Maven Shade JavaFX runtime components are missing
openjfx JavaFX maven plugin
badass runtime plugin
badass jlink plugin
jlink guide
jpackage script
JEP 392: packaging tool
Warning for shaded jars
If you bundle all JavaFX code into a single jar using the maven shade plugin, you will get a warning like the following when you run your application from Java 16+:
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module #28c71909'
This indicates that such a configuration is not supported, and may (and probably will) break in future and perhaps current JavaFX platform revisions. Thus, shaded jars that include JavaFX platform code are not recommended by me, even though such jars might currently work for your deployments.
JavaFX 11+ is built to be used as a set of modules. Configurations are not supported if they do not run the JavaFX platform off of the module path but instead run the platform code off of the classpath (as a shaded jar would).

Hot deployment of JavaEE applications using Maven-Cargo pluin

I am using maven-cargo plugin for deployment of a very simple JavaEE application.
And I was able to run and deploy to jboss but the hot deployment of the class files and jsps is not working.
(By hot deployment I mean when I change my Java classes then the changes should be reflected in the application without the server being getting restarted.)
For understanding cargo, I went through their documentation:
https://codehaus-cargo.github.io/cargo/Maven2+plugin.html
and various other So links also :
maven - Failed to execute cargo:start
Maven2: Cargo plugin hot deployment & Jonas support
Deploy web application using Cargo plugin to remote server
But none of posts gives an adequate answer to the questions.
I am using following maven goals which I am using to run and deploy my application :
cargo:deploy
cargo:run
Following the configuration done in pom.xml :
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.7.7</version>
<configuration>
<container>
<containerId>jboss71x</containerId>
<type>installed</type>
<home>C:\softwares\jboss\jboss-eap</home>
</container>
<configuration>
<type>existing</type>
<home>C:\softwares\jboss\jboss-eap\standalone</home>
</configuration>
<deployer>
<type>installed</type>
</deployer>
<deployables>
<deployable>
<groupId>com.test</groupId>
<artifactId>test-demo</artifactId>
<type>war</type>
</deployable>
</deployables>
</configuration>
<dependencies>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-controller-client</artifactId>
<version>7.0.2.Final</version>
</dependency>
</dependencies>
</plugin>

Best way to build twice the same webapp with different dependencies using maven

I have a maven project with a webapp for which I need two versions, each one having its own set of dependencies. The intent is to support two different (and conflicting) versions of a storage client. The webapp code, configuration file and anything but certain libraries is the same in both cases. The right client is loaded at runtime : I just need to drop the right jar (and its dependencies) in the lib folder of the webapp.
If I deploy the dependencies manually, I lose the opportunity to check for version conflicts (which I do when I build a maven project with all its dependencies correctly set).
I do not want to deploy the webapp(s) on the maven repository since it is not a library and it only makes a big archive (mainly because of the embedded dependencies) that consumes space for nothing. Thus, to build the final wars, I cannot add a dependency on the webapp project.
I do not want to duplicate the common webapp class files and configuration files in two different modules. It would make future evolutions more difficult because of the necessary synchronization between the two modules each time one file is updated.
Any suggestion on how to solve this ?
Note that the best solution should allow to build both wars at once.
Use Maven profiles.
http://maven.apache.org/guides/introduction/introduction-to-profiles.html
You can put certain dependencies into certain profiles and activate/deactivate them through the command line with the -P parameter.
I guess defining two profiles in your pom might do the trick :
<project [...]>
[...]
<profiles>
<profile>
<id>storage1</id>
<dependencies>
<dependency>
<groupId>my.group.storage</groupId>
<artifactId>thisOne</artifactId>
<version>13</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>storage2</id>
<dependencies>
<dependency>
<groupId>my.group.storage</groupId>
<artifactId>thisOtherOne</artifactId>
<version>37</version>
</dependency>
</dependencies>
</profile>
</profiles>
[...]
</project>
Call one or the other with mvn -P storage1 or mvn -P storage2. You can also make one active by default, use activation triggers based on other properties, etc.
Here's their introduction article.
In the end, I did not use profiles. There was an issue building both webapp versions at once.
Instead I used war overlays https://maven.apache.org/plugins/maven-war-plugin/overlays.html.
First, I created a skinny war version of the webapp. The skinny war does not include libraries nor META-INF files. Only resources like configuration files. The webapp classes are packaged in a jar (using the attachedClasses configuration option of the maven-war-plugin). I do not mind having this war deployed since it is very lightweigth. Here is the configuration of the maven-war-plugin :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<outputFileNameMapping>#{groupId}#.#{artifactId}#-#{version}##{dashClassifier?}#.#{extension}#</outputFileNameMapping>
<attachClasses>true</attachClasses>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
<packagingExcludes>WEB-INF/classes/**/*,WEB-INF/lib/*</packagingExcludes>
</configuration>
</plugin>
Then, I created 2 additional modules, one for each flavour of the webapp. In the dependencies, I set :
- the webapp as a dependency of type war
- the jar of the webapp classes
- the storage client library
That way, maven checks for dependency conflicts in all the libraries. The webapp classes are imported through the dependency. The overlay war is used to build the final war. No duplicate code between the 2 flavours of the webapp. Only the client dependency changes between the 2 pom files. Here is an excerpt of one of them :
<dependencies>
<dependency>
<groupId>com.storage</groupId>
<artifactId>client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.group.id</groupId>
<artifactId>webapp</artifactId>
<version>${project.version}</version>
<classifier>classes</classifier>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.group.id</groupId>
<artifactId>webapp</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>

Error when deploying site of a maven multi module project with FTP

I have a multi module project. When I launch mvn site:deploy, the deployment of the base module works fine, but it fails to create the directory of the module sites on the FTP server:
[INFO] Error uploading site
Embedded error: Required directory: '/myremoteftprepository/myproject-mymodule' is missing
When I create the missing directory by hand, it works fine, but I would like to avoid that. It is surprising that the deploy command do not create it. Do you how to force this directory creation? Is it a bug in the wagon-ftp plugin?
FYI, here is my POM:
<build>
<extensions>
<!-- Enabling the use of FTP -->
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ftp</artifactId>
<version>1.0</version>
</extension>
</extensions>
</build>
I have chosen to include the javadoc with:
<reporting>
<plugins>
<!-- include javadoc in the site -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8</version>
<configuration>
<show>public</show>
</configuration>
</plugin>
</plugins>
</reporting>
and
<distributionManagement>
<site>
<id>site</id>
<name>maven site</name>
<url>ftp://ftp.blabla.org/myremoteftprepository</url>
</site>
</distributionManagement>
and my settings.xml is good.
You should not launch the site:deploy goal, but rather the site-deploy Maven lifecycle phase e.g. like that
mvn clean install site-deploy
and also make sure that the latest version of your wagon transport is used (2.2).
Also for javadoc plugin you should configure it as reporting plugin under the configuration of the maven site plugin.
With the most recent version of wagon-ftp (2.2), it works.

Categories

Resources