Detect and weave dependencies automatically with AspectJ - aop

We have a Maven project with multiple compile dependencies and every time a new <dependency> is added, we need to create an equivalent <weaveDependency> entry in
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<weaveDependencies>
<weaveDependency>
<groupId>a-group</groupId>
<artifactId>new-dependency</artifactId>
</weaveDependency>
</weaveDependencies>
<weaveDirectories>
<weaveDirectory>${project.build.directory}/classes/</weaveDirectory>
</weaveDirectories>
<complianceLevel>${java.version}</complianceLevel>
<showWeaveInfo>true</showWeaveInfo>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
This is being done exactly as described in
http://mojo.codehaus.org/aspectj-maven-plugin/examples/weaveJars.html
But this could easily lead to problems if it's needed to weave everything because someone could forget to add the <weaveDependency> after adding a new <dependency>, so is there a way of detecting and weaving all compile dependencies automatically? Maybe with another plugin?

AFAIK there is no such option or plugin, unless you decide to write one or open a ticket for AspectJ Maven.
One question before we continue: Are you really sure you want to weave all dependencies? What about libraries such as JUnit or Log4J in your aspect POM?
The way I usually go about weaving my aspects into the code - if they are production and not just development, debugging or profiling aspects, that is - is that I do it the other way around than you: I use the AspectJ Maven Plugin in each of my modules to directly compile the aspects into my code from source. So in my case each Java module depends on an aspect module, using it as an aspect library. Because usually I have way fewer aspect libs than Java modules, I cannot so easily forget to include them. Okay, I have to do it in each module, but this is a no-brainer with a good IDE (global search and replace on all pom.xml files in my project).
If you really want to do it even more cleanly and nicely, you can use the approach explained in Strategies for using AspectJ in a Maven multi-module reactor, i.e. you create a normal root POM and an aspect root POM which has the root pom as its parent. Then each Java module which needs the aspects can use the aspect root POM as its parent, other Java modules use the root POM directly.
The advantage of compiling the aspects into your artifacts right away is that there are no two class file versions of each artifact: an original without aspects and a woven version with aspects in the aspect module's target directory. The only reason why you would not do it they way I explained is if for some reason you also need artifact versions without aspect code. But then, as I said, you probably use development, debugging or profiling aspects. Be it as it might, you can still use my approach for production aspects and your old approach for the development stuff.

Related

Glassfish OSGI with dependencies, how to?

I have a regular maven jar project, which has dependencies such as the reflection library and I want to
convert it to osgi, what Ive already done.
created a common interface layer in a different (maven) jar
project and added it to the bundle as a dependencies.
changed the type of the osgi-module-to-be to 'bundle'.
created an implementation of BundleActivator
added this plugin the pom:
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-Activator>my.package.MyServiceActivator</Bundle-Activator>
<Export-Package>
my.package.exp.*
</Export-Package>
<Import-Package>
!org.reflections,???
</Import-Package>
<Embed-Dependency>
slf4j-api;scope=compile,???
</Embed-Dependency>
</instructions>
</configuration>
here is where it gets lost, I need to figure out the "Import-Package" and "Embed-Dependency"
and, even more important figure how to deploy it on glassfish as a zip or,
maybe, ORB (or Gogo) so that it will deploy with all it's dependencies jars.
any ideas?
G.
BTW: the org.reflections package is not OSGi ready
It seems you're confused about how OSGi and the Maven Bundle plugin work.
Maybe reading the Felix guide will help you:
http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html
Basically, you should have something like this:
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-Activator>my.package.MyServiceActivator</Bundle-Activator>
<Export-Package>
my.package.exp.*
</Export-Package>
<Import-Package>
!org.reflections*,*
</Import-Package>
<Embed-Dependency>
org.reflections
</Embed-Dependency>
</instructions>
</configuration>
</plugin>
By default (ie. if you just omit it, which is usually the case), your Import-Package instructions would be *, which means anything you refer to in the code which is not in java.* or in your own bundle should be imported. But as you have a dependency on a non-bundle jar you want to embed, you need to tell the plugin that by using the expression !org.reflections*,*, which means you don't want to import the org.reflections package but everything else is fine. You also need to declare that any artifactId called org.reflections should be embedded in the jar by using the Embed-Dependency instruction.
BTW, You most likely don't want to embed your logging framework SLF4J implementation, let alone the API, as just about any OSGi environment should provide a logging implementation for you.
After you package your bundle (mvn package or just mvn install) make sure to check the generated MANIFEST to ensure that it looks like everything is correct (importantly, check the Import-Package packages and see if your environment will have all bundles which provide such packages).
Once you get your bundle set up correctly, deploying it is trivial. Just drop it into your framework's bundle directory, ensure all other bundles you need are also there, and everything should work fine.
As a side note, you might want to consider wrapping the non-bundle JAR you need as a bundle by using PAX-WRAP or just Karaf (just throw a JAR in the deploy folder and you will get it wrapped as an OSGi bundle immediately), for example.

Creating Eclipse plugins from existing jars in an automated build

I want to make the build process for my Eclipse RCP plugin fully automatic. It has some third-party jar dependencies (available from Maven repositories) which are not distributed as OSGi bundles, and currently I use the "Eclipse plugin from existing JAR archives" wizard to convert them manually. Can PDEBuild or Maven/Tycho (or perhaps some other build system) do it as a step of the build?
Peter Tillemans mentioned the PAX wrap jar command in this post
The Maven bundle plugin from Apache Felix may be worth a look, too.
Maybe the Bundlor tool from SpringSource can handle the creation of osgi bundles from jar, too.
Checkout the p2-maven-plugin developed by me. It's an open-source, community-friendly plugin that handles:
the wrap of the jars that are not OSGi bundles (that's fully customizable)
the generation a fully functional p2-update site that may be consumed in the Eclipse PDE
the generation of the corresponding source bundles (it generates source bundles for all the bundles)
Details and the documentation could be find here: http://projects.reficio.org/p2-maven-plugin/manual.html
Sample usage:
<plugin>
<groupId>org.reficio</groupId>
<artifactId>p2-maven-plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>
<executions>
<execution>
<id>default-cli</id>
<configuration>
<artifacts>
<!-- specify your depencies here -->
<!-- groupId:artifactId:version -->
<artifact><id>commons-io:commons-io:2.1</id></artifact>
<artifact><id>commons-lang:commons-lang:2.4</id></artifact>
<artifact><id>commons-lang:commons-lang:2.5</id></artifact>
<artifact><id>commons-lang:commons-lang:2.6</id></artifact>
<artifact><id>org.apache.commons:commons-lang3:3.1</id></artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
Take a look on the differences between the thirdparty jar and its bundled equivalence. It's just an additional plugin.xml and a few extra lines in the manifest.
Write your own code for bundling jars.

Maven Plugin error

Im a new user in maven. I have few doubts.
I have some BAT files that has to executed via maven
While executing my default commands, I need to echo the status like "Started first task"
When the task gets failed user should get error message popup etc.,
Automatic repository update through maven
Maven calling ant to build *.war
Copying the new created build file(*.war) to local folder with date/time
Auto upload/deploy from build machine to server
Testing particular URLs/products to test the site flow
Sending mail regarding deployment status
Below is my example pom.xml, which trying only (a)
<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.example.maven</groupId>
<artifactId>test</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>test</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<!--echo>Starting CVS Update</echo-->
<configuration>
<tasks>
<exec>
<directory>D:\</directory>
<executable>"D:\test.bat"</executable>
<!--failonerror="true" -->
<!-- optional -->
<!--workingDirectory>"cd C:\repo\projects\mcsandbox"</workingDirectory-->
</exec>
</tasks>
</configuration>
</plugin>
</plugins>
</build>
</project>
I guess this is not the expected answer but I don't think that you're on the right path and I don't see the point of using Maven the way you'd like to use it. From your description, my impression is that you aren't really adopting Maven but rather trying to insert something existing into it and, believe me, this isn't the easiest way to get started with Maven:
This is going to add an extra layer of complexity.
This requires a deeper understanding of the way maven works than "just" adopting it.
You're going to fight against the tool (and there are good chances that the tool will win).
This will generate more troubles than benefits.
I don't really know where to start so I'll just try to quickly cover your points first:
I have some BAT files that has to executed via maven
This is possible but this is not really the Maven way (depending on the logic, you should move it to Maven or keep it outside maven), and I don't think this is going to be very robust (might be wrong though). On top of that, this already requires some knowledge of the build lifecycle (where to hook things) and of plugin configuration. And from what I've seen (I do not mean to be rude), you don't have it.
While executing my default commands, I need to echo the status like "Started first task"
This is not how things work with Maven. Maven isn't procedural like Ant, Maven has conventions, Maven is declarative, Maven has a lifecycle.
When the task gets failed user should get error message popup etc.,
User? Popup? Maven is not really targeted at end users, Maven is a developer tool and what you get in case of an error is a message in a console.
Automatic repository update through maven
Do you mean a CVS update? This is not impossible but is usually not Maven's job (it's more a Continuous Integration engine task).
Maven calling ant to build *.war
This is possible using the Maven Antrun Plugin but that's not the spirit and may go against some maven rules (like one artifact per project). Also, Maven will not magically be aware of things built by Ant. Why don't you just stick with Ant?
Copying the new created build file(*.war) to local folder with date/time
Possible. But that's not how things work by default.
Auto upload/deploy from build machine to server
Maven has plugins (e.g. Cargo) that can help at doing this but you have to tell him to.
Testing particular URLs/products to test the site flow
Maven itself won't do that. But it can run (integration) tests doing that.
Sending mail regarding deployment status
That's not maven's responsibility (more a Continuous Integration engine task).
My global feeling is that you are thinking too much Ant oriented and maybe expecting too much from Maven. Maven is different, it doesn't really work the way you described, it doesn't work like Ant. My recommendation would be to either fully migrate to Maven and adopt its philosophy or to stick with your current Ant solution (and maybe consider using the Maven Ant Tasks or Ivy to leverage things such as dependency management, artifact deployment).
See also
How to convert from Ant to Maven (...)
Differences between Ant and Maven
Maven: The Definitive Guide

Simple Mavenization of existing Ant build files

If you have an existing ant file, what is the best way to convert the project to Maven. I've checked out things like fAnt, but if I'm going to mess with this stuff, I might as well go full-bore for Maven. I expected something to exist that can just start the pom.xml for me based on the existing build.xml, but I haven't found anything yet. Suggestions?
I don't know any good automated way to do such a migration because things may just be too different so I would do it manually, step by step, and keep the existing ant build in parallel of the future new one until the whole migration is done (from both technical and human points of view).
First, refactor the existing Ant build to align it on Maven conventions:
Make things modular: if your existing build is a big monolithic build producing several artifacts from a single source tree, break it down into separate modules, one for each artifact.
Update directory structure: Maven comes with a standard directory layout and, while it is possible to customize this layout (i.e. to configure plugins for another layout), this is not really recommended and is more a source of troubles than benefits. So I'd move existing app sources, configuration files, tests, etc to match Maven's layout (e.g. src/main/java for application sources, etc).
Then, start to create the Maven build:
Create POMs for each module: Create a POM, declare external libraries as Maven dependencies (maybe add them to a corporate repository, using an enterprise repository is a good practice in an enterprise context anyway), add dependencies between modules.
Finalize the multi-modules build: Add parent(s) POM(s) and inheritance/aggregating relationships. Test that there is no regression with the created artifacts.
You could do this work in a separate VCS branch if you don't want to change anything until the work is done and create scripts to move things. And when ready, merge the Maven specific stuff and apply the scripts.
You could run the Ant script from Maven with the maven-antrun-plugin. Your pom.xml would look something like this:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-nodeps</artifactId>
<version>${ant-nodeps.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>init</id>
<phase>compile</phase>
<configuration>
<tasks>
<!-- Ant code goes here -->
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</build>
</project>
That way you can start to move your dependencies into Maven, and reference them in the Ant script like so
${com.foo.bar:my-lib:jar}
Then just start slowly moving pieces of your Ant into pure Maven stuff.

How can I merge multiple OSGi bundles with BND / Maven-BND-plugin?

I'm using some off-the-shelf OSGi bundles in my application and would like to repackage them together with additional packages that are not yet OSGi compatible into a new bundle.
Case in point is EclipseLink, which is available as several OSGi bundles, most of which are optional, depending on what you want to do. I want to pick those bundles that are relevant for me, add database drivers (for example the MySQl JDBC connector) and repackage them into a new bundle that is easier to deploy.
I'm using the maven-bundle-plugin from Apache Felix. I set up a new Maven project without source code, added the four eclipselink and the mysql connector as dependencies and tried the following:
use the <Embed-Dependency> and <Embed-Transitive> instructions to include all dependencies in one bundle. Problem: Optional dependencies from the eclipselink bundles (for example, javax.mail.internet) become required as the plugin rewrites the manifest. The original bundles contain "resolution=optional" in the manifest and thus work well without.
use the manifest goal of the plugin and a jar-with-dependencies assembly, but that gives me basically the same result, only with more work.
used the bundleall goal of the plugin, which is not quite what I want, because it creates separate bundles again. Even worse, because now these bundles don't have their dependencies inside.
I'm going to face similar issues with Struts 2. I'm not going to be obsessive about this, and just go with a whole bunch of separate third-party bundles, but if I can package them more neatly, I would really like to. I'm aware that a point of OSGi is modularity, so creating big bundles kind of defeats that, but I feel that if your modules are tightly coupled anyway, you might as well put them into a single bundle.
Of course, I could manually tweak the manifests, but I definitely don't want to.
As omerkudat says, this is probably not a good practice to encourage, but as you have your reasons, this is a way you could do a poor-man's merge.
Assuming you are handling the OSGi manifest yourself, you only really need to get all the classes from the bundles and jars into the target/classes directory before the package phase.
You can do this with either of the dependency plugin's unpack-dependencies or unpack goals. I'd use the unpack-dependencies if you want to process all the project dependencies (or those following a certain naming patter or in a certain groupId) and the unpack goal if you want to have fine control over the artifacts to be unpacked (at the expense of a verbose POM). I'll assume unpack in my example. Each unpack is output to the project's outputDirectory (i.e. target/classes).
Note this will overwrite duplicate artifacts from each package in the order they're downloaded, so the manifests will be clobbering each other. To ensure your artifacts are managed correctly, I would bind the unpack goal to an early phase so that your src/main/resources are copied on top of the unpacked contents and not overwritten. In the sample below this phase is generate-resources, so it will happen after your local compile. If you need to overwrite any of the classes, use an earlier phase to unpack the dependencies such as generate-sources
My sample below unpacks the contents of junit-3.8.1 and commons-io 1.4 (just the first two dependencies I had declarations for) into target/classes before the project's resources are copied there. Note that the versions are defined in my dependencies section. If you haven't got the bundles/jars declared as dependencies you'll need to declare the version in the artifactItem as well.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>generate-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<overWrite>false</overWrite>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
</artifactItem>
<artifactItem>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<overWrite>false</overWrite>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
</artifactItem>
</artifactItems>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</execution>
</executions>
</plugin>