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

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.

Related

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

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.

What is the use of converting jars to bundles in WAB(OSGI)?

After exploring the OSGi framework, I had developed a sample web application.The Web Application Bundle(.war or .jar) is packaged inside an eba.
The war file contains a bunch of embedded jar files in its WEB-INF/lib
directory.These jars have been converted to OSGi bundles(using maven-bundle-plugin) with the required export and import packages as per the relation between the jars.
Now I have to even mention all these jars(WEB-INF/lib) in the bundle-classpath.
The above works because a bundle(wab is also a bundle) can include one or more jarfiles within it, and use a Bundle-Classpath manifest.mf entry to point to them.
Incase I dont include the jars in the bundle-classpath I get a ClassNotFoundException.
The question is,then there's no point converting the jars to osgi bundles.Obviously all the jars in the WEB-INF/lib are loaded by the same class loader(i.e wab's class loader) ,so then we are not reaping the major benefits of OSGi which is mainly a per bundle classloader concept?
Putting jars inside the WEB-INF/lib is the old-style normal-java way of handling dependencies, and putting them outside the war is the new-style OSGi way of handling them.
By packaging your war's dependencies in WEB-INF/lib, you're treating them as normal jars (remember a bundle is also a jar). So in that case, you're right that there wasn't much point in using bundles.
One of the benefits of using wabs instead of wars is to get away from the dreaded 100 Mb monolithic war. Rather than packaging the bundles inside WEB-INF/lib, try having the war import the packages it needs using Import-Package:, and package the dependencies inside the eba. (If you don't remember to have the war import the packages it needs, you'll get the class not found exceptions you were seeing, because the OSGi container won't know your war needs those packages.)

Maven ships dependencies inside war but not in jar

I have two maven projects, one (I will call it core) is an ejb-jar (ejb) and the other a war (client).
My client project consumes some ejbs inside my core...so far so good.
But I'm getting a ClassNotFoundException inside my core application because it can't find one class from apache-beanutils...I have set this dependency with compile scope in it's pom.xml but it does not get shipped inside the output jar.
When I check my client.war package I see every compile-scoped dependency inside the WEB-INF/lib folder...but in my core.jar I don't see any of it's dependencies...I'm totally confused about this.
Can someone help me? I tried to google it before asking but I didn't find anything useful so far..thanks.
You can use the maven assembly plugin to bundle all the jars in one super jar.
See this: question

Spring Rest Controllers: deployment to Tomcat

I want to develop a RESTful API within my multi-module Spring-based project using Spring Rest. For that purpose, I have a webapp module and some other business/data layer modules. For example, this would be my simplified project structure:
myProject
-- webapp (war-packaged)
-- business (jar-packaged)
-- data (jar-packaged)
Business module depends on data module and so does webapp on business module. Webapp imports successfully every module's application context. Now I want to be able to use some business module classes that do some kind of calculation according to some data retrieved from a DB in order to provide a certain resource. All examples I had a look at were quite simple and this multi-module approach was not covered at all.
What is the problem? As far as I am concerned, Tomcat loads classes in a certain order. Concretely, it first loads WEB-INF/classes and only then WEB-INF/lib (where all webapp dependencies are placed, business module in this case). So, there goes my question. Where should I place my Controller classes? If I place them within the webapp module I won't be able to autowire any business-module bean since Tomcat will throw a ClassNotFoundException when I deploy the webapp war (at least this is the behaviour I have experienced).
The answer is probably easy but I'm quite new to Spring and its world!
Thank you all in advance.
Your business and data jars would go into the WEB-INF/lib directory. Then those jars will automatically be added to the CLASSPATH for your app when you deploy it. You will need to deploy your application as a WAR file.
Ideally, you would build the business and data jars, add them to some repository, and then the build system would pull the proper version of each jar into the WEB-INF/lib directory for you.
And as to the original question, the controller classes go into the webapp/src directory.
Assuming you are using Maven 2. Make sure your assembly creator (e.g. maven war module) is including your dependent .jar files within the final .war file's WEB-INF/lib directory. This should be the default procedure (per: http://maven.apache.org/plugins/maven-war-plugin/war-mojo.html#dependentWarIncludes ). The other concern, then is whether your sub-projects (business and data) are even creating jars so that they could be included in the WAR output.
If you have doubts as to the contents of that war file, browse the listing of it by executing
'jar tvf $WAR_FILENAME' from the command line and by observing the WEB-INF/lib directory contents. You should see your business and data jars in there. Go further by exploding your war file, then browsing the contents of business and data jar (using 'jar xvf $FILENAME' to explode in a new directory).
Hope this helps!

Maven depend specific classes

In the following senario
I'm wrapping an external jar file (read a dependency I've no control over) and wrapping this in a service to be exposed over RMI.
I'd like my service interface to also be exported as a maven dependency however as it will be returning classes defined in the dependency this means that the dependency itself will be used as a dependency of my service interface.
Unfortunatly the origional jar file contains many classes that are not relevant to my exposed service.
Is it possible to depend on just a few classes in that jar file in maven (possibly by extracting and repackaging the few classes that are relevant)?
uberbig_irrelevant.jar
com.uberbig.beans <-- Need this package or a few classes in it.
com.uberbig.everythingElse
Service project includes all of uberbig jar. But exposes a service BeanService which has a call which returns an insance of com.uberbig.beans.IntrestingLightWeightSerialiasbleBean.
Service interface project needs to have a bean definition that looks like
interface BeanFetcher {
public IntrestingLightWeightSerialiasbleBean fetchBeanById(long beanId);
}
So ideally my serviceInterface jar file would only include the BeanFetcher interface. The definition of IntrestingLightWeightSerialiasbleBean and any direct dependencies of IntrestingLightWeightSerialiasbleBean.
The project is for use internally and won't be publically exposed so there should be no problems repackaging so long as the repackaged bean definitions are binary and searially compatable with the external jar file.
Any Suggestions?
Possibly related question Maven depend on project - no jar but classes
Maybe I could use something from the dependency:copy section of the maven-dependency-plugin but I haven't figured out how to do that.
I think you got the plugin right, but not the goal. You should use dependency:unpack instead.
You should be able to use an inclusion filter to extract only the classes you need, and then repack them into your own jar. (The service interface jar if you do it in the service interface project, but you can just as well set up a separate project.)
Create your own repackaged jar and put it in your local repo. And hope you've actually identified all dependencies, accounting for reflection, etc. IMO not really worth it.
You may be able to do it automatically (with the associated increased risk) by using ProGuard/etc. to pull out unused classes etc. That could be done on your own artifact as well, for example, by making an all-in-one jar via jarjar/onejar/etc.

Resources