I was following the instructions in https://access.redhat.com/solutions/328513 to test out load-time weaving and I've got the example working without much of an issue.
My issue comes in when I want to weave a dependency that's already provided on the classpath as a JBoss module. I'm trying to gather some performance metrics from one of my project's dependencies but that dependency <scope>provided</scope> since it's already bundled with JBoss.
I can see weaving happen when I do something like #Pointcut("execution(* com.mypackage..*(..))") (so I know it's working on some level) but if I try #Pointcut("execution(* org.slf4j..*(..))") nothing gets woven.
I imagine there's something different happening for modules vs. war/ear deployments but I'm not familiar enough with the classloading process to make much headway. I would assume that since my aspects are provided as a global-module it would be loaded before any other module and then be able to affect their weaving but that doesn't appear to be the case.
Can anyone provide insight as to what's going on here?
Related
I have an OSGi application (Eclipse plugin) that contains several bundles.
I have a com.domain.dependencies bundle that, as the name suggests, contains dependencies. There is NO code in this bundle. The concept is that all 3rd-party dependencies used by 1+ other bundles are contained in this bundle and made available to other bundles within the plugin. This has always worked for the past decade or so that this plugin has evolved.
The above bundle 'pulls in' log4j - an older log4j version 1.x. So, log4j has always been exposed as an available library to other bundles that use com.domain.dependencies.
Due to the recent security issues with log4j2, a company security directive/edict has stated that all use of log4j or log4j2 must be upgraded to log4j2 v2.16.0
Initially I thought I'd just change the declaration in the build.gradle file for com.domain.dependencies to pull in that newer log4j2 but discovered that log4j2 is split in to 'core' and 'api' jars. OK so I tried to use those instead. I then followed the Apache migration steps for moving from log4j 1.x to 2.x, updated all the code etc.
After the above, compilation fails. None of the other bundles 'see' log4j2 as they saw log4j. A bit of Googling and I see people talk about creating OSGi Fragments. What's a Fragment? I've read a bit about them and feel none the wiser when it comes to my issue.
I should point out that my plugin also has a dedicated bundle com.domain.log, which depends on com.domain.dependencies and it's the com.domain.log bundle that contains the log4j.properties file (which also needs tweaking for log4j2). This logging bundle wrapped log4j (and soon to be log4j2) to expose logging features to the other bundles within the plugin.
So when it comes to using fragments, I am confused. I see some articles on the internet suggest at least 2 bundles are required. I don't know if these have to be new, or if I can re-use my existing arrangement of bundles. I struggle to relate those articles to how things are currently set up in my plugin, but I wish to maintain the idea that com.domain.dependencies supplies dependencies to other bundles and has no code of itself, while also having the com.domain.log continue to expose the same logging functionality to the other bundles that need it.
My instinctive feelings are that com.domain.log which exposes logging functionality to my other bundles, should use log4j-api, while com.domain.dependencies should obtain log4j-core (implementation) and expose it to com.domain.log. However, I can imagine too many different ways to try and set this up, and all will fail unless I am doing it the right way. Basically, I need help from somebody who knows how to in an OSGi environment.
So, how should I wire-in log4j2 to mimic the traditional behaviour/functionality in my OSGi environment?
Let me explain first what I mean by necessary libs. I'm creating my first project using the Google App Engine for Java with the official Google Maven Plugin, the main problem that have Maven as a packaging solution (or maybe the Java development as a whole) is that if the dependency tree grows too much, the release process may be harder.
Let me illustrate it with an example. Let's start with the Jackson JSON library (it's a good starting point since it has no parent dependencies), now someone makes a JSON-RPC library and uses Jackson for the JSON serialization/deserialization. Imagine that this library not just provides a JSON-RPC client implementation, but also a server, that means that the POM of this lib will add some Java EE related libraries such us Jetty as dependencies.
Probably the guidelines say that the application should be either divided into modules or mark the server related deps as optional, but you know that many people don't follow the standards.
Now someone need a JSON-RPC client for his/her project, call it Project X, and uses the lib mentioned above, at compile time there will be no problems, Maven will successfully download the required libs and the application will compile fine, but the problem comes when that person wants to release the application. Which dependencies should be distributed along with the package (in a lib folder for example)?
Actually that's something that happened to me, I wasn't too much familiar with Maven so I used the Eclipse Runnable Jar Exporter, that produced jar file with all the maven libs copied to a lb subfolder, so the workaround that I did then was to just delete the libs that looked unnecessary and then tested if the application was still working. If there are classes that are not executed, as far as I know they are not loaded by the ClassLoader so they could be omitted and are unnecessary
I can't use the same trick now since the scenario is much more complex, we are talking of a Java Web Application, not a desktop application like the other one, and the library that I want to include is a Liquid Template Engine, which uses the ANTLR framework to generate the parsers plus Jackson for the JSON handler and Jsoup for HTML parsing.
Which libs should be packaged inside the WEB-INF/lib folder? I'm sure that I will need Jackson for JSON parsing but I'm not so sure about Jsoup, and what about ANTLR, it is necessary or is used just at compile time?
Update: I think I need to re-formulate my question, actually what I want is to determine which dependencies are really necessary for the application, and package those into the app WEB-INF/lib folder
Solution: It seems that the POM file that is packaged in the WAR file of the web app is used once the app is in the Google App Engine production environment to retrieve the necessary dependencies, and probably the appengine:update goal only packages those dependencies that can't be retrieved from the maven central repo, so there is no need to worry about that.
Thanks to David to point this.
You should check Maven's dependency scopes. Here's an extract from the documentation :
There are 6 scopes available:
compile This is the default scope, used if none is specified. Compile
dependencies are available in all classpaths of a project.
Furthermore, those dependencies are propagated to dependent projects.
provided This is much like compile, but indicates you expect the JDK
or a container to provide the dependency at runtime. For example, when
building a web application for the Java Enterprise Edition, you would
set the dependency on the Servlet API and related Java EE APIs to
scope provided because the web container provides those classes. This
scope is only available on the compilation and test classpath, and is
not transitive.
runtime This scope indicates that the dependency is
not required for compilation, but is for execution. It is in the
runtime and test classpaths, but not the compile classpath.
test This
scope indicates that the dependency is not required for normal use of
the application, and is only available for the test compilation and
execution phases.
system This scope is similar to provided except that
you have to provide the JAR which contains it explicitly. The artifact
is always available and is not looked up in a repository.
import (only
available in Maven 2.0.9 or later) This scope is only used on a
dependency of type pom in the section. It
indicates that the specified POM should be replaced with the
dependencies in that POM's section. Since they
are replaced, dependencies with a scope of import do not actually
participate in limiting the transitivity of a dependency.
So in a Maven project, the developer indicates which dependencies should be bundled in the application and which should not.
Basically there are two cases here :
If you're building a web application (WAR or EAR format) and want to deploy it, or if you're building an actual runnable jar, then you will need to bundle it with all the dependencies with scope compile and runtime.
If you're building a library, then you do not package any dependency with your library. Instead you include the pom.xml so that others know what dependency your library requires. For Maven to know how to find the associated POM for a given jar, the best and most common solution is to deploy the library to a Maven repository. Repos have a directory structure that helps Maven find the right version of a library, and find the POM that indicates the required dependencies.
Depending on wether your library is open source or not, you will be able to be hosted for free by some repositories such as Sonatype (complete list here). But you can also setup your own repository either by installing a dedicated software such as Nexus or by configuring a Github project as the repo, as is explained on this blog.
You can exclude any transitive dependency.
For your case, to remove jetty from this json-rpc-library, you need:
<dependency>
<groupId>com.somecomp</groupId>
<artifactId>jsonrpclib</artifactId>
<version>1.0</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
</exclusion>
</exclusions>
</dependency>
See docs: http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html
I'm going to start using dependency injection in my Eclipse plugin. My test plugin depends on the main one and should use different injection context. Production should work fine standalone (it should have its own injection context), but behave differently when used from tests (should use Junit's injection context).
How could I resolve the injector so that a different one is used in production and in tests?
I don't like the idea to somehow inject context manually in a static variable on test start. Is there a better way? Can extensions be somehow used for that?
I know that in e4 there is a solution for that, but I'm bound to Eclipse Indigo for now and could not find quickly how exactly is that done in latest version. A link to injector configuration with an ability to override in test infrastructure in e4 source is appreciated.
I wound up writing my own JUnit runner modeled largely after the Spring JUnit runner, but would highly recommend looking at the Jukito project now.
At this point I try to have one Guice module per feature, so I end up with one Guice module for test that installs the production module and overrides or binds any external dependencies. I keep that test module in a base test class along with the necessary annotation for the JUnit runner, which is very similar to the JukitoModule examples in the link above.
I am attempting to use load-time-weaving to tie perf4j into a program, but it does not seem to be finding aop.xml in my classpath. Either that or it is not weaving the aspect because it is not finding it. I have enabled verbose output from aop.xml but I am not seeing any weaving messages, errors or otherwise. Where does aspectJweaver look for the META-INF/aop.xml? How can I tell which one it is looking for?
I have attempted to use a direct path to import the xml with this, but it hasn't worked. -Dorg.aspectj.weaver.loadtime.configuration=C:\dev\trunk\bin\META-INF\aop.xml
Note: The program works as intended with compile-time-weave, but I would prefer to use load-time-weave. I have also been able to implement load-time-weave using small test cases.
The META-INF folder must be on the root of the classpath. And the META-INF folder must contain the file aop.xml.
For standalone programs, you must start the JVM with a weaving Java agent.
For example:
-javaagent:pathto/aspectjweaver.jar
With Spring:
-javaagent:pathto/spring-agent.jar
You can find more information about it on AspectJ's Development Environment Guide.
If you use a web container, you have to configure the container to do the load-time weaving.
SpringSource's reference guide shows you how to enable load-time weaving with Tomcat.
example:
For logging, my code uses log4j. but other jars my code is dependent upon, uses slf4j instead. So both jars must be in the build path. Unfortunately, its possible for my code to directly use (depend on) slf4j now, either by context-assist, or some other developers changes. I would like any use of slf4j to show up as an error, but my application (and tests) will still need it in the classpath when running.
explanation:
I'd like to find out if this is possible in eclipse. This scenario happens often for me. I'll have a large project, that uses alot of 3rd party libraries. And of course those 3rd party jars have their own dependencies as well. So I have to include all dependencies in the classpath ("build path" in eclipse) for the application and its tests to compile and run (from within eclipse).
But I don't want my code to use all of those jars, just the few direct dependencies I've decided upon myself. So if my code accidentally uses a dependency of a dependency, I want it to show up as a compilation error. Ideally, as class not found, but any error would do.
I know I can manually configure the classpath when running outside of eclipse, and even within eclipse I can modify the classpath for a specific class I'm running (in the run configurations), but thats not manageable if you run alot of individual test cases, or have alot of main() classes.
It sounds like your project has enough dependency relationships that you might consider structuring it with OSGi bundles (plug-ins). Each bundle gets its own classloader and gets to specify what bundles (and optionally what version ranges, etc.) it depends on, what packages it exports, whether it re-exports stuff from its dependencies, etc.
Eclipse itself is structured out of Eclipse plug-ins and fragments, which are just OSGi bundles with an optional tiny bit of additional Eclipse wiring (plugin.xml, which is used to declare Eclipse "extension points" and "extensions") attached. Eclipse thus has fairly good tooling for creating and managing bundles built-in (via the Plug-in Development Environment). Much of what you find out there may lead you to conflate "OSGi bundle" with "plug-in that extends the Eclipse IDE", but the two concepts are quite separable.
The Eclipse tooling does distinguish rather clearly (and sometimes annoyingly, but in the "helpful medicine" way) between the bundles in your build environment vs. the bundles that a particular run configuration includes.
After a few years of living in OSGi land, the default Java "flat classpath" feels weird and even kind of broken to me, largely because (as you've experienced) it throws all JARs into one giant arena and hopes they can sort of work things out. The OSGi environment gives me a lot more control over dependency relationships, and as a "side effect" also naturally demands clarification of those relationships. Between these clear declarations and the tooling's enforcement of them, the project's structure is more obvious to everyone on the team.
if my code accidentally uses a dependency of a dependency, I want it to show up as a compilation error. Ideally, as class not found, but any error would do.
Put your code in one plug-in, your direct dependencies in other plug-ins, their dependencies in other plug-ins, etc. and declare each plug-in's dependencies. Eclipse will immediately do exactly what you want. You won't be offered dependencies' dependencies' contents in autocompletes; you'll get red squiggles and build errors; etc.
Why not use access rules to keep your code clean?
It looks like it would better be managed with maven, integrated in eclipse with m2eclipse.
That way, you can only execute part of the maven build lifecycle, and you can manage separate set of dependencies per build steps.
In my experience it helps to be more resrictive, I made the team filling out (paper) forms why this jar is needed and what license...
and they did rather type in a few lines of code instead of drag along 20 jars to open a file using only one line of code, or another fancy 'feature'.
Using maven could help for a while, but when you first spot jars having names like nightly-build or snapshot, you will know you're in jar-hell.
conclusion: Choose dependencies well
Would using the slf4j-over-log4j jar be useful? That allows using slf4j with actual logging going to log4j.