How to deploy multi-module maven spring boot application on OpenShift - maven

I have a multi-module spring-boot project that I want to deploy on Openshift, where I have installed Jenkins as well. Source code is hosted in Github.
Each module consists in a war, in order to have a microservices structure:
<modules>
<module>xyz-common</module>
<module>xyz-data-services</module> <!--a REST service to interact with mongodb-->
<module>xyz-batch-importer</module> <!--a service to import files into Mongo-->
<module>xyz-frontend</module>
</modules>
I found tutorial to deploy single spring-boot application, but I cannot figure out how this applies to a multi-module maven project.

If you want to work with multi-module maven project on openshift, then you have to tell openshift how to build them. You can achieve this task by defining build environment variables or writing custom build scripts which can be interpreted by Openshift.
For both method you can follow this tutorial:
If you want to work with first method, you can tell openshift to use additional maven commands while building process by defining "MAVEN_ARGS_APPEND" variable for build config.
So when the build operation starts on openshift, it will tell Maven that build the application with these additional parameters.
Define additional build environment variables that listed below to deploy war modules independently:
MAVEN_ARGS_APPEND: -pl modulename --also-make
ARTIFACT_DIR: modulename/target/
MODULE_DIR: modulename
In here "-pl" command provides to build "xyz-data-services" with its all dependencies. So if your "xyz-data-services" module has dependency to "xyz-common", then maven will build "xyz-common", create related artifacts for "xyz-data-services" ,package them together and deploy "xyz-data-services" as war on the pod.
In your case, suppose that you want to package "xyz-data-services" module and "xyz-front-end" module as war and deploy them.
Case 1:
If you want to make these modules self deployable, then you have to create two applications which will run on different pods.
First application will have these build environment variables:
MAVEN_ARGS_APPEND: -pl xyz-data-services --also-make
ARTIFACT_DIR: xyz-data-services/target/
MODULE_DIR: xyz-data-services
And the second one will have these guys:
MAVEN_ARGS_APPEND: -pl xyz-front-end --also-make
ARTIFACT_DIR: xyz-front-end/target/
MODULE_DIR: xyz-front-end
Case 2:
If you want to deploy these modules into same pod, then you can add an additional module to your project which packages both wars into single ear and define the variables for this ear.
So let this ear be "webapp", your parent pom will look like;
...
<modules>
<module>xyz-common</module>
<module>xyz-data-services</module>
<module>xyz-batch-importer</module>
<module>xyz-frontend</module>
<module>xyz-webapp</module>
</modules>
...
and the xyz-webapp pom will look like;
....
<artifactId>xyz-webapp-</artifactId>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>xyz-common</artifactId>
<version>${project.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>xyz-data-services</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>xyz-frontend</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
</dependencies>
....
So your build environment variables will be;
MAVEN_ARGS_APPEND: -pl xyz-webapp --also-make
ARTIFACT_DIR: xyz-webapp/target/
MODULE_DIR: xyz-webapp
If you want to work with just single war and single pod then;
Case 3:
You can just package front-end application as war and declare dependencies to other modules which all packaged as ".jars"
You can go on with which case do you want. It's important here that it depends on your "microservices" implementation. Because the "microservice" term and the implementation is not explicitly defined and it can vary on the architecture or some business requirements, it's your decision that packaging front-end,api,backend together or manage them independently.

Related

Intellij Spring maven install error "package does not exist"

Intellij version : Community 2019.2.3
Maven : 3.6.2
Spring : 2.2.0
I am trying to create a very simple Spring maven project with two sub-modules (one independent and another one dependent on independent one).
Root module - testmultimodule
Independent module - independent
Dependent module - dependent
testmultimodule pom.xml has all Spring related declaration and module definition
<modules>
<module>independent</module>
<module>dependant</module>
</modules>
Independent poom.xml is simplest and . only has parent maven declaration
<parent>
<artifactId>testmultimodule</artifactId>
<groupId>in.org.app</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
dependent module pom.xml has the dependency declaration as below to independent module
<dependencies>
<dependency>
<groupId>in.org.app</groupId>
<artifactId>independent</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
I have created a Test class under dependent module and using a User object from independent module. Initially, without the above dependency declaration, asa usual there was compilcation error.
As soon as I add the dependency and builld the project within Intellij IDE with the option "Build Prooject" option from "Build" menu, it successfully builds.
However, if I try to use Maven install option within Intellij right side window option. It always fails stating Error:(3,33) java: package in.org.app.independent.bo does not exist .
I am providing the GitHub URL for the test project , if you want to take a look and test by yourself.
GIT URL:
https://github.com/DhruboB/testmultimodule
I have tried all sort of tweaking found in internet so far e.g.
clearing Intellij Cache & restarting, mvn -U clean install, mvn scope verification, proxy etc.
Any further idea to resolve this? I need to solve this in the Community version of Intellij.
Your parent project includes the definition for the spring-boot-maven-plugin. This leads to each project defining this as a parent to be repacked to an executable JAR by this plugin. This repackaged JAR isn't useable as a dependency in another project.
Either you need to change the configuration of the spring-boot-maven-plugin for the project you want to use as a dependency. This is explained here in the Spring Boot Reference Guide. You now basically have 2 jars from this project, one plain and one executable.
If you don't need that project to be an executable JAR file then just move the spring-boot-maven-plugin to the project that needs to be. All other projects will no be basic JAR files again.
See also How to add a dependency to a Spring Boot Jar in another project?

One Spring Boot project, deploy to both JAR or WAR

Is there a way to have a single Spring Boot project be packagable into both JAR and WAR without changing the pom.xml or the application source?
I've read Converting a Spring Boot JAR Application to a WAR, but it converts the project to WAR and it loses the ability to be packaged as JAR.
I don't expect mvn package to do both. What I want is something like mvn i-want-a-jar and it would package the project as JAR. Or I could run mvn i-want-a-war and it would package the project as WAR.
Is this possible?
I managed to do it by adding
<packaging>${packaging.type}</packaging>
to the POM file and then setting different profiles for JAR and WAR:
<profiles>
<profile>
<id>jar</id>
<properties>
<packaging.type>jar</packaging.type>
</properties>
</profile>
<profile>
<id>war</id>
<properties>
<packaging.type>war</packaging.type>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
</profiles>
Now mvn package -P war produces a WAR and mvn package -P jar produces a JAR.
Another option is to create separate modules for JAR and WAR, but I didn't go that route.
What's wrong with a WAR file that's executable? Isn't that what you really need?
P.S. like
java -jar name.war
We've recently had a similar requirement, where an existing Spring Boot based project that was originally packaged as an executable Jar needed to support Tomcat and WildFly deployments.
Due to some dependencies used in this project (for example WebJars), a simple switch to WAR package wasn't an option since some of those dependencies were required for WildFly (VFS support) but not for other deployment.
The solution was to restructure the project modules in a way that core module contained the actual project but without having Spring Boot’s plugin applied, while several package modules would depend on core module and configure deployment artifact specifics (Boot and other plugins, deployment specific dependencies etc.).
That way project build was able to generate multiple deployment artifacts (Boot's executable JAR, traditional WAR and WildFly specific WAR) in a single build run.
In case anyone finds this useful, the sample project to demonstrate the approach is available on Github. The project can be built by either Gradle or Maven.

Maven EAR project for multiple application servers

I have a EAR project that I want automatize the building process using maven exclusively.
The EAR project has
Standard jar modules
Web modules
EJB modules
RAR modules
To be able to execute the product in Jboss 4.2.3 and WebSphere 7 the EJB and RAR descriptors must be configured in different way. Also we have one jar library for each app server.
What I want is to be able to build one EAR for each apps server using the same projects, and for that I need
Include a JAR module depending of the app server
Use the customized descriptor in the EJB/RAR modules depending of
the app server
Package all this customized modules in an EAR
Can this be done using the same set of project in maven?
Sure. Have a look at profiles in maven. They allow you to adjust various things (from the link) like:
<repositories>
<pluginRepositories>
<dependencies>
<plugins>
<properties> (not actually available in the main POM, but used behind the scenes)
<modules>
<reporting>
<dependencyManagement>
<distributionManagement>
a subset of the element, which consists of:
<defaultGoal>
<resources>
<testResources>
<finalName>
The best is to create separate modules like ear-websphere, or ear-jboss and make an appropriate pom file which contains the needed configuration for maven-ear-plugin.

Maven dependency project export

I am using Spring in two 2 projects. First, I have a "web" project which depends on my second project that is a normal java project with maven nature enabled that I named "core".
So, in my "web" project I just add the reference of my "core" project:
<dependency>
<groupId>com.stackoverflow</groupId>
<artifactId>core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>jar</type>
</dependency>
If I set the property "useProjectReferences" to false like here, everything works fine, But I am in developing phase, I don't wanna run maven install everytime I have a change in my "core" project.
I am running my projects in tomcat, so I can't package them in ear. All that I want is Maven export my "src/main/resources" source folder to Spring be able to find my coreContext.xml and bind my beans. What I have tried in my "core" pom.xml:
<build>
<resources>
<resource>
<directory>${basedir}src/main/resources</directory>
<targetPath>${basedir}WEB-INF/resources</targetPath>
</resource>
...
I tried to use shade-plugin but without success too. Any tip would be appreciated.
My suggestion would be to create a Multi Module Maven Project which contains both the core and web projects.

Skipping Maven Test Dependency

I am working on a project that use maven for building. What I am trying to do is to skip the test dependency. Basically running the maven build without the presence of artifact in my maven repository.
eg
<artifactId>example</artifactId>
<scope>test</scope>
This is from the pom file of my project and I have to maven build my project without having artifact example.
I have searched for solution such as use "-DskipTests=true" or "-Dmaven.test.skip=true". In my case they did skip the running of the tests but it still complains missing dependency file.
Does anyone know a way to run maven build without having to have test artifact in the maven repository?
Thanks.
See https://issues.apache.org/jira/browse/MNG-4192. I think the only way around it is to move the test-scoped dependency into a Maven profile.
Here is an example:
<profile>
<id>test-with-extra-dependency</id>
<dependencies>
<dependency>
<groupId>org.example.groupid</groupId>
<artifactId>artifact-id</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
You should now be able to run a build without tests:
mvn clean install -Dmaven.test.skip=true -DskipTests=true
After that you can run the tests with the profile enabled:
mvn test --activate-profiles test-with-extra-dependency
I wouldn't advise it, but this can be useful in case of a circular dependency between the current module and the test dependency, i.e. you can build the module, then build the test dependency using the build result, and finally test the module with the test dependency. If you find yourself wanting to do that, please try to restructure your project to eliminate the circular dependency (eg by moving the tests to a third module).

Resources