How to deploy javaagent with 3rd party libs dependencies - java

We wrote a javaagent to help developers debugging. But, before releasing this tool, we still have some questions about the deployment of java-agent.
User may use the agent with some tomcat applications. The agent uses Premain method to transform classes. We use javassist 3.18.2-GA to insert codes. We currently add javassist.jar into Boot-Class-Path in MANIFEST.MF. And We put both the agent and javassist.jar into tomcat's lib directory.
The questions are:
Well, as least, it works. But is that the correct way to deploy agents and dependencies for tomcat applications?
Because most tomcat applications using hibernate which also using javassist 3.18.2-GA, so it's ok right now. But as my understanding, 3.20 is not completely compatible with 3.18.2. Suggest someone had update the javassist to a higher version, will the agent or the application crash due to the conflict between the 2 different javassist's.

A javaagent is added and run on the VM's class path. Therefore, you have the following options:
Add the dependencies to the classpath when starting up the VM such as you would when deploying a normal application. For an application container like Tomcat, this would be the appropriate directory for such dependencies.
Bundle the dependencies with the agent using a tool like fatjar. Doing so, you can also use the Maven Shade plugin to transfer dependencies into a different namespace to avoid version conflicts.
Use the Instrumentation API to manually append the dependencies before running your actual agent application.

Related

Best way to execute embedded Jetty

I have a web application that is structured into a standard war. I want to use embedded Jetty server as my servlet container. Since this is all one code base, I figured that the main() that executes the Jetty server would also be in my war with the rest of the code.
So how do I go about executing my main(), which is in the war, to launch the Jetty server? I looked at the examples but the examples do not have this setup, which to me seems like a normal setup.
Would the Jetty server need to be told where the war file is (the war file that happens to be where its also located) or would Jetty by default find and check WEB-INF for the various XML files what Jetty processes?
I see something close to this using the Jetty Maven Plugin, but the consensus is that that plugin is not for production.
I was able to setup an executable file easily using the Maven plugin called Jetty Console Maven Plugin There is not much documentation about how to use it on the Internet. The author, simplercity, took down their blog entry for how to use it. But I did find one post on stackoverflow on how to use it.
The current version of this plugin is 1.55. It can be found here. One issue that I encountered is that while most of the artifacts that are required for this plugin are on version 1.55 one of them, jetty-console-ajp-plugin, is on version 1.53. This caused a problem for me because when I had all the other plugins set to 1.55 there was a signer exception error I got when I tried to execute my war. I found the solution in this stackoverflow answer. The fix was to use only 1.53 version of all the plugins. There might be a better solution that allows you to use 1.55 with 1.53 ajp-plugin. Other than that the plugin worked great and I implore the author of Jetty Console Maven Plugin to either bring his blog post on how to use it back up or create new documentation for it.
To execute a standalone application in Java it doesn't need to be a war. A jar is fine enough. A war contains information about how a web archive/application should be deployer into a J2EE container. When you run it standalone this isn't necessary. The main method will be enough. You can have a look at maven shade plugin. It will help you build a runnable jar.
(As a sidenote - a runnable jar is a rather simple thing. The manifest file of the jar file needs to contain the key MainClass and that is it.)

Java import from root of jar

I've used a 17 version of Guava for my library project and extracted it into the jar. Other project uses my library but it also has a much older version of Guava. When I try to run application, it ignores new Guava and causes errors like
java.lang.NoSuchMethodError: com.google.common.cache.CacheBuilder.maximumSize(J)Lcom/google/common/cache/CacheBuilder;
How to force my project to use a new Guava and application to use an old?
I am assuming that your project and applications are distinct entities.Also, by Project I assume that you are referring to an Eclipse/IntelliJ/Netbeans project
You would need to set the correct classpaths for the Project and your application separately.
If you are using the IDE to debug your project, your project would need to include the new JAR that you have downloaded. Each IDE has it's own mechanism for adding dependencies to the Project's classpath and hence you would want to refer to the documentation related to that IDE.
For your application you can launch it as java MyApp -cp "path to the old JAR". If you are packaging your application as a JAR, make sure you are packaging the older version of Guava.
Hope this helps.
Edit based on the discussion with the owner of the question
The query here is similar to this SO query. The right way to hence resolve this issue would be either install a Custom ClassLoader or use OSGi

Google Apps Marketplace JAR and GAE

When you use the Google-Eclipse plugin to create a new Web Application Project, and you select the option to "Add support for listing on Google Apps Marketplace", the plugin automatically adds an apps-marketplace.jar file on your classpath.
Does this - at any point in time, for any reason - ever need to be bundled with your WAR? I ask because it contains a bundled version of SLF4J that is causing JAR hell issues with other dependencies that use a different version of SLF4J.
I bundled it into my WAR because I thought it was necessary, but if its something that is just used by the plugin, or is perhaps available as some service to GAE apps when they're running in production, then I don't need it and would like to remove it as a dependency. Thanks in advance.
This jar is not needed. You can remove it from your build path and your WAR directory. We need to fix the plugin so that it gets rid of this jar.
I have a feeling it was first added in to make it easy to access certain Google APIs from your Marketplace app. It included a bunch of classes for handling OAuth. However, I think that all of the classes in here are basically deprecated, and there are better ways to make these Api calls now.

automated osgi bundle development with netbeans 7.1

I'm currently developing a maven osgi bundle using Netbeans 7.1. While its easy to create new maven osgi bundle project from netbeans, I've been struggling about how I would run it. Simply running it from netbeans gives me an error that tells me there is missing requirement (missing slf4j for example).
Then I tried a different way. I ran equinox in a terminal and then manually install my project jar to it. But then I must also resolve all the dependencies manually.
Is there any way to automatically download all the required dependencies from an OSGI bundle and install it to a running OSGI framework?
thanx before
AFAIK there's no automation for OSGi in Netbeans (though I may well be wrong). The support you may have seen in Eclipse is only for Eclipse plugins not vanilla OSGi.
Your best bet is to go for some integrating testing or launch via a maven goal, pax-exam or bndtools or even pax-runner will allow you to launch from IDE/maven.
However I don't know of anything that will automatically resolve all dependencies (transitive dependencies and implementations of APIs you depend on would be problematic)
Its a big pain, no question about it. What I used to do was to do a full build (and if you've configured your manifests correctly should include all necessary dependencies) which will generate the necessary jar. I then wired my Tomcat to pick up the jar from my target repository and configured it to hotswap automatically.
Its a matter of preference if you want to run your app server from within your netbeans but I preferred to execute a separate instance of tomcat outside of my IDE. It'll work either way tho.

Specifiy classpath for maven

Quite new to maven here so let me explain first what I am trying to do:
We have certain JAR files which will not be added to the repo. This is because they are specific to Oracle ADF and are already placed on our application server. There is only 1 version to be used for all apps at anyone time. In order to compile though, we need to have these on the class path. There are a LOT of these JARS, so if we were to upgrade to a newer version of ADF, we would have to go into every application and redefine some pretty redundant dependencies. So again, my goal is to just add these JARs to the classpath, since we will control what version is actually used elsewhere.
So basically, I want to just add every JAR in a given network directory (of which devs do not have permission to modify) to maven's classpath for when it compiles. And without putting any of these JAR files in a repository. And of course, these JARs are not to be packaged into any EAR/WAR.
edit:
Amongst other reasons why I do not want to add these to the corporate repo is that:
These JARs are not used by anything else. There are a lot of them, uncommon and exclusive to Oracle.
There will only be one version of a given JAR used at anyone time. There will never be the case where Application A depends on 1.0 and Application B depends on 1.1. Both App A and B will depend on either 1.1 or 1.2 solely.
We are planning to maintain 100+ applications. That is a lot of pom.xml files, meaning anytime we upgrade Oracle ADF, if any dependency wasn't correctly specified (via human error) we will have to fix each mistake every time we edit those 100+ pom.xml files for an upgrade.
I see three options:
Put the dependencies in a repository (could be a file repository as described in this answer) and declare them with a scope provided.
Use the dirty system scope trick (i.e. declare the dependencies with a system scope and set the path to the jars in your file system.
Little variation of #2: create a jar with a MANIFEST.MF referencing all the jars (using a relative path) and declare a dependency on this almost empty jar with a system scope.
The clean way is option #1 but others would work too in your case. Option #3 seems be the closest to what you're looking for.
Update: To clarify option #3
Let's say you have a directory with a.jar and b.jar. Create a c.jar with a Class-Path entry in its META-INF/MANIFEST.MF listing other jars, something like this:
Class-Path: ./a.jar ./b.jar
Then declare a dependency in your POM on c (and only on c) with a system scope, other jars will become "visible" without having to explicitly list them in your POM (sure, you need to declare them in the manifest but this can be very easily scripted).
Although you explicitly stated you don't want them in the repository, your reasons are not justified. Here's my suggestion:
install these jars in your repostory
add them as maven dependencies, with <scope>provided</scope>. This means that they are provided by your runtime (the application server) and will not be included in your artifacts (war/ear)
Check this similar question
It is advisable that an organization that's using maven extensively has its own repository. You can see Nexus. Then you can install these jars in your repository and all developers will use them, rather than having the jars in each local repository only.
(The "ugliest" option would be not to use maven at all, put put the jars on a relative location and add them to the classpath of the project, submitting the classpath properties file (depending on the IDE))
if you are developing ADF (10g / 11g I guess) components, I suppose you'll be using JDeveloper as IDE. JDeveloper comes with a very rich Library Management Tool that allows you to define which libaries are required for compiling or which ones should be packaged for deployment. I I suppose you will already know how to add libraries to projects and indicate in the deployment profile which ones should be picked while packaging. If you want to keep your libraries out of maven, maybe this could be the best approach. Let´s say the libraries you refer too are the "Webcenter" ones, using this approach will guarantee you you have the adequate libraries as JDeveloper will come with the right version libraries.
Nevertheless, as you are using maven I would not recommend to keep some libraries out of control and maven repositories. I´d recommend choose between maven and Oracle JDeveloper library management. In our current project we are working with JDeveloper ADF 11g (and WebCenter) and we use maven, it simply make us library management easier. At the end of the day, we will have a big amount of third party libraries (say Apache, Spring, etc.) that are useful to be managed by maven and not so many Oracle libraries really required for compiling in the IDE (as you would only need the API ones and not their implementations). Our approach has been to add the Oracle libraries to our maven repository whenever they are required and let maven to control the whole dependency management.
As others say in their answers if you don´t want the dependencies to be included in any of your artifacts use <scope>provided</scope>. Once you configure your development environment you will be grateful maven does the work and you can (almost) forget about dependency management. To build the JDeveloper IDE files we are using the maven jdev plugin, so mvn jdev:jdev would build generate our project files and set up dependencies on libraries and among them to compile properly.
Updated:
Of course, you need to refer to ADF libraries in your pom files. In our project we just refer to the ones used on each application, say ADF Tag Libraries or a specific service, not the whole ADF/WebCenter stack. For this purpose use the "provided" scope. You can still let JDeveloper to manage your libraries, but we have found that it's simpler to either have a 100% JDeveloper libraries approach or a 100% maven approach. If you go with the maven approach it will take you some time to build your local repo at first, but once that's done it's very easy to maintain, and the whole cycle (development, build, test, packaging and deployment) will be simpler, having a more consistent configuration. It's true that in a future you'll have to update to later ADF versions, but as your repository structure will already be defined it should be something fast. For future upgrades I'd recommend to keep the ADF version as a property on the top pom, that will allow you to switch faster to a new version.

Categories

Resources