What is the best way to structure maven projects to make a client jar? - maven

New to maven here...coming from the ant world
I need to create a client jar with a few files that will give my client the ability to write to my Db and make rest calls to my services.
These are mainly classes that wrap a Rest connection and db client.
Is it possible to produce this artifact as a side effect of my main maven project ?
Eg: main project produces a bundle when I run mvn package, but I'd like to produce the client jar by providing some other parameters....

What you need here is a multi-module maven project.
The structure goes like this:
-- Parent Module
----- Child 1 Module
----- Child 2 module
Here you can have all your code/files of your main app in child 1 module and put all the code/files for the client in the child 2 module.
The parent module is just an aggregator which produces an artifact of type pom. Whereas each of your child modules will produce individual jars.
You can then you the second jar in your client.
For a detailed understanding how multi-module project works, check this link.

The standard Maven way is "one project, one jar". This means that the cleanest way to achieve your goal is to set up a multi-module project where you have one module for your "normal" jar and one for your "client" jar. But there are other possibilities:
If you are talking about an ejb, you can use the maven-ejb-plugin and create a client artifact. Unfortunately, both artifacts then share the same pom (and, therefore, the same dependencies).
You can use the maven-assembly-plugin to assemble a set of files and deploy them as side artifact (same problem as in (1)).
You can use the maven-install-plugin and maven-deploy-plugin to install/deploy entirely different artifacts along with your main artifact. These artifacts need to be created before, e.g. by a custom maven plugin.

Related

Call a flow of one mule project in another mule project

I have a mule project-A where in I need to call a flow from another mule project-B. I have added <classifier>mule-plugin</classifier> in the project-B's pom. And I have added a dependency with project-B's group-Id, version, artifact-Id, classifier in project-A's pom and also created an "import" config in project-A with flow name of project-B which I want to use. Still I am unable to call the flow of project-B in project-A
If you are implementing this to just test in your local machine, then follow the below steps. You can also look at the concept of Mule Domain Project, which does resource sharing for those apps falling under the same domain ; enabling you to call other apps flow-refs, global configurations and more.
Note : All this below said has to be in Mule 4.
First, export your Project-B as a mule deployable jar.
Steps
Right click on Project-A and goto - > mule
Add a maven dependency.
Choose your Project-B.jar from your local repository and
add.
This will get your project imported as a maven dependency
in your pom.xml file.
Make sure your jar added under your project libraries of 'A' in
the package explorer.
Goto to the global elements of Project-A and select import
configurations.
Add the Import configuration to your elements and specify
your Project-B main XML file you want to use in Project-A.
Finally refresh/restart your main project and check if you can
reference the flows.
If you still can't get this work, try updating to the latest version of studio, like 4.3.1 which is a much stable version.
Detailed explanation is given here -> Mule Shared Projects
Update
You can also try doing the same in your cloudhub runtime. You don't need a Domain project concept to do this. Basically you kind of imported your Project-B into Project-A completely ; Altogether making it a one mashed up Mega project.

How to deploy child module without also deploying parent module?

I have a project with a parent aggregator module and 3 children modules.
I don't know if this is a bug for me or just how Maven works, but I am currently unable to deploy one of my children modules without also deploying the respective parent. When I try to import the child module on another project of mine, Maven throws an error saying it can't resolve the parent. If I deploy both to my Nexus, it works perfectly. Do I always have to deploy both?
Yes.
You always need the parent POM as well.
When Maven need to "use" a module, it needs to resolve it.
If this module has ancestors it needs to access to every ones to resolve it.
OR you will face somethings like :
Could not resolve dependencies for project org.projectB:childA-Consumer:jar:0.1.0:
Failed to collect dependencies at org.projectA:childA:jar:0.1.0:
Failed to read artifact descriptor for org.projectA:childA:jar:0.1.0:
Could not find artifact org.projectA:parent:pom:0.1.0
Solution 1 : Deploy the parent
The common way is to deploy the parent, so this way when you consume your module maven will be able to find ancestors and so resolve your module's pom.
But lot of users seems to consider this as not so satisfying. (There are many question about that on stackoverflow ...)
Solution 2 : Parent != Aggregator
Most of the time in multi-module project, the aggregator pom is also the parent pom but this is 2 different concepts.
parent : is about sharing configuration with inheritance.
aggregator : is about building several modules at same time.
(more details about aggregator vs parent differences)
So, you can have an aggregator with several children and each child has no parent.
This way you don't have to deploy your aggregator.
Drawback you can not use inheritance to share config between modules.
Note that this is not a drawback for everyones, some consider that using inheritance and so parent is not good idea. 😅
Solution 3 : Use Maven Flatten Plugin
Currently poms contains 2 kind of information :
how to build the artifact,
how to consume it (e.g. dependencies).
Maven 5 will maybe clarify this and so you could have a different pom in your released artifacts and in your source code.
Using Maven 3, there is a plugin which aims to do that : flatten-maven-plugin
It aims to generate a pom.xml consumers oriented.
Among others, parent relationship is resolved, flattened and removed.
This way, you can use parents to share configuration between modules (with inheritance) and not deploy your aggregator and/or parents .
Drawback, you could maybe face issues with some other maven plug-in interaction ? 🤷
Some tips you need to know if you wan to use flatten-maven-plugin :
flatten cleangoal is no more useful.
how to fix url, scm url, scm connection and scm developerConnection resolution.

Can you externalize maven plugin configuration using composition?

I want to define a plugin configuration along with dependencies in the separate project B, then attach it to other project A so I can run phases/goals from the project B from project A. Is this even possible with maven?
You can run goals from plugins from the repository, if you give the full qualified name of the plugin, i.e.
groupId:artifactId:version:goal
If you want to use the short form, you either need to add it to your (parent) pom or to your settings.xml.

maven skinnyWars does not remove ejb jars from WEB-INF\lib\

I've stumbled across maven topic skinnyWars at http://maven.apache.org/plugins/maven-ear-plugin/examples/skinny-wars.html. As described, I can use this method to move selected dependencies from WAR module to EAR module. They will be available for all other WAR modules located in EAR.
As I have discovered the dependencies which are moved must be declared in EAR module and have to be included in META-INF\lib catalog. That does not apply for EJB modules, which are located in root catalog of EAR module.
My question is how to remove duplicated EJB modules from WARs and point the reference to those located in EAR file?
The structure right now is like this:
\-EAR
-ejb.jar
-META-INF\lib
-shared libraries
-web.war
-WEB-INF\lib
-ejb.jar
-other non-shared libraries
I've answered a similar question: How to make maven place all jars common to wars inside the same EAR to EAR root?
Unfortunately this doesn't seem to work for ejb modules. They'll get duplicated as you have already mentioned.
One thing you can additionally use is a configuration for the maven-war-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
</configuration>
</plugin>
This will completly erase everything from the WAR's lib folder but it can also have its drawbacks in cases where you have to deploy the WAR additionally itself on a separate machine without the surrounding EAR.
The problem here is that it is not the same to reference an EJB from the ear module which will be used to deploy it into the server than to reference it from a client which needs the EJB classes to interface with the server.
If you include the dependency in an ear module, it will consider you are declaring an EJB module to be deployed. It will place it in the root of the EAR and declare it in application.xml.
If you include the dependency, for example, in a war module, you will get exactly the same artifact, but it will be considered as a library and placed in WEB-INF/lib.
Now, when you are generating the skinny wars, the explicit dependency to the ejb module does not match the dependency in the WAR, as Maven does not consider them to be the same thing. This results in the JAR being kept in the WAR/s which use it.
The only solution I know is to always generate a client artifact for the ejb module, even if the client artifact will be identical to the main artifact.
Now, you only use a <type>ejb</type> dependency in the EAR. For clients, you always use a <type>ejb-client</type> one.
To remove the client from the WAR/s and locate it in the lib directory of the EAR, you have to explicitly add the dependency to the ear module.
So, you will have two dependencies to the ejb module in your ear module: one to the ejb itself and one to the client. The first one will place the EJB in the root of the EAR and declare it in application.xml. The second one will place the client in the lib directory of the EAR and update WAR/s manifest/s, if necessary.
But if client and main artifacts are identical, you get it duplicated?
The short answer is yes. The long answer is yes. It does get duplicated, but only once, and not in every WAR using it. I don't think there is a clean way to avoid this and I'm not sure it makes sense conceptually. You could, of course, use packagingExcludes and customise manifests, but it makes sense to have the JAR twice.
If your client JAR is really thinner (for example, only the interfaces) having the WAR/s reference the client JAR effectively disallows them to access to EJB implementations, which is always a good idea.
You can consider the identical JAR's as a special case of the previous one and it makes conceptual sense to keep them separate.
So, my recommendation is to always generate a client artifact for the ejb and proceed as explained. There are always things you can exclude from it, be at the very least any unneeded non-class files such as package.html or ejb-jar.xml.

Multiple reusable modules in maven

I have a couple of java modules set up in IDEA and I am wanting to mavenize them. These java modules use classes from one another.
I was not quite sure how I should take up this and I decide to add modules on a maven project using IDEA. Hence first I created a maven project, let's name it pm1 which has a class let's name it TempClass1. Now this class can be used in other maven project. Hence I added another maven module - pm11 and tried to use TempClass1 with in pm11. It worked and I notices that IDEA had added module dependency of pm1 in pm11. So whole structure looks as -
But now when I do mvn test from pm11 then it fails with error message package package1 does not exist and it looks to me that it is because package1 is in a different maven project. And I am not sure how I could use classes which reside in a different maven project. I hope I am clear in my question.
You can use classes of other maven projects, as long as there's a proper maven dependency defined in pom.xml. Ensure that the dependency is defined and its' scope is either undefined or relevant (You may have problems if the scope is provided for example).

Resources