Expandable java system - java

I've been asked to create a java system capable of expand itself by plugins, however i'm a little confused in how exactly should i do that, my initial idea was to create a folder in the system's root path and create a routine that would read that folder and scan for .jar files that can be recognized as plugins (inside the .jar there'll be a .xml file which will be used as the system's signature), then load the files in the classpath at runtime, well this part seems quite easy, i found a lot of material about this subject, but i can't realize how i'll make the plugin access the main system's classes and methods, my initial idea was to pass through the constructor of the plugin, the path for the main system .jar and then load the main .jar in the plugin at runtime but i'm not sure if this is the most efficient approach. Does anybody has an idea?

Related

How can I set my JAR file class path to use an outside folder for dependencies?

I am making a java web application that a hosting service is running for me, and I must recompile and send it to the host every time I make a change. I would like to be able to put all of my libraries in a folder in the host, and only have to compile my jar that will know that its dependencies are next to it.
I have used the IntelliJ IDEA builder located in File > Project Structure. I export all library jars used in a folder next to the main jar named lib, and I have learned about wildcards so I set the classpath to be \lib\*. This did not work and I was thrown a chunky NoClassDefFoundError in my server's console.
I know this must be possible. How should I change my approach?
EDIT: I have researched a bit deeper, and the answer to this question states at the bottom that the wildcard system is not honored in the jar manifest attribute. Do I have to include all files individually (And if so, how?) ?

How to Make Java .jar files be automatically found in any environment

I am trying to add an external library to my Java project. The library files are in .jar format, and every time someone tries to run the project in a different environment, they have to modify the build path so that their environment can find the .jar files.
Is there any way to make it so that the .jar files are automatically found by the build path? Maybe by specifying where in the project the .jar files are located?
Edit: Here is an example -
In my linux environment, the .jar files are located in:
/home/MyUsername\SomeDirectory\workspace\java_project_name\data
In my windows environment, the .jar files are located in:
C:\MyUsername\SomeDirectory\workspace\java_project_name\data
In the example above, the project root directory is "java_project_name", and the .jar files are always in the java_project_name\data folder. Even though this is the case, different environments can't seem to detect that it is always in the same path in relation to the project's root directory.
I have looked in many places on how to do this, and some people told me it isn't possible. This doesn't sound reasonable to me, which is why I am posting this question here.
Thanks in advance for your help!
you can add a ClassPath: entry in your manifest file of the main jar, and use relative paths. As long as the jars are found relative to the main jar it will work.
This issue was one of my main motivators to start using maven.
#YoK nicely quotes here the relevant reasons to this question https://stackoverflow.com/a/3589930/1493954
Here is one the relevant quotes from Benefits of using Maven
Henning
quick project setup, no complicated build.xml files, just a POM and go
all developers in a project use the same jar dependencies due to
centralized POM.
getting a number of reports and metrics for a project
"for free"
reduce the size of source distributions, because jars can
be pulled from a central location
This is a common problem for developement environments.
I myself use the following solution in netbeans [Hope so that it works in your IDE too]:
Create an Ant variable [for e.g. JAR_LOCATION].
Each and every JAR that you refer, must have it's location relative to JAR_LOCATION.
Now, in every development environment that you're gonna use, you can set up the same ANT variable and it'll automatically pick up the JAR.
You can see the example in the given snapshot of netbeans..

How to access Jar file located within source folders?

in my Java project I am using an H2 in-memory database, for which I have to load the JDBC driver when I initialize my application. I want/need to load the H2 .jar file dynamically, so I do the following:
String classname = "org.h2.Driver";
URL u = new URL("jar:file:libs/h2.jar!/");
URLClassLoader ucl = new URLClassLoader(new URL[] { u });
Driver d = (Driver) Class.forName(classname, true, ucl).newInstance();
DriverManager.registerDriver(new DriverShim(d));
When I put the H2 .jar file into a "libs" folder outside my Java source code folder (that is, in Eclipse, this "libs" directory is on the same level as the "src" folder), then this approach works fine. However, unfortunately I have to put this H2 .jar file into a folder within the source code folder tree, but below the main class folder.
For example, my Java package structure looks like this in Eclipse:
<project>/src/my/app/MyApp.java // main class of my application
<project>/src/my/app/sub/package/h2.jar // how to access this?
<project>/libs/h2.jar // loading from here works
I know this is stupid, but unfortunately I have to work with this strange setup. But what I don't know: how can I edit my Java code (listed above) in order to work with this setup?
EDIT: This has to work outside Eclipse as well, so adding the JAR file to the Java Build Path in Eclipse is no option for me.
EDIT2: I already tried to load "jar:file:my/app/sub/package/h2.jar!/", but that did not work for me.
Thanks in advance for all helpful ideas!
Kind regards, Matthias
In some frameworks referring to files inside JARs can be done using the classpath: prefix. I doubt URLClassLoader supports it natively, but it's worth a try (e.g. classpath:/my/app/sub/package/h2.jar). But since that doesn't work with URLClassLoader, here are other ways:
One way to do it would be to write your own ClassLoader which reads the JAR file from classpath (using getResourceAsStream), uncompresses it (using ZipInputStream) to memory (e.g. a map of byte arrays) and loads the classes from there.
Another, slightly easier way, is to read the JAR file from classpath and write it into a temporary file. Then you can use the plain URLClassLoader to load classes from it. This has the disadvantage that the file must be written to a file and the file probably cannot be removed until the JVM exits (unless using Java 7 or higher).
I'm using the second approach (copying to a temp file) in one project, though I'm using it to launch an external process. I would be curious to hear why you have such a requirement. If it's just a matter of having the whole application in one JAR, there are numerous simpler methods for achieving that (Maven Assembly Plugin, Maven Shade Plugin, Jar Jar Links, One-JAR to name a few).
No it's not a homework, but an online build system that uses my classes under my/app/* and several other classes (not from me) to automatically build the whole solution. Anyway, I can't give you more details on the internals of this system, as I don't know them. As said, I simply have to live with it, and that is why I am asking here...
Sounds like you are working in a WTF environment (does it have a name?), so here are some ways to start hacking around it:
Find out more about your environment, especially absolute file paths of the following: directory where the source files are saved, directory where the generated .class files are saved, and the current working directory when the program is run.
If you can get any kind of output of what your program prints during runtime, you can put into your application some debug code where you use File.listFiles() to crawl the machine's directory trees. If you can get output only from what happens when compiling, it might be possible to execute your own code during compile by creating your own annotation processor (apt is part of javac since Java 6), though I'm not sure whether the annotation processor must be compiled first separately.
The working directory can be read from the user.dir system property and the location of class files can be probably gotten from the java.class.path system property (unless custom class loaders are used). There is no guarantee that a JAR file in the source directory would be copied to the classpath, so you might need to do some looking around.
Then when you know the file path of the JAR file, then you can get an URL to it using new File("path/to/h2.jar").toURI().toURL() which you can then pass to URLClassLoader.
If nothing else works, upload the source code of the libraries and compile them together with your project.
In the long run, try to replace the WTF build environment with one that uses a standard build tool (such as Maven) and a common CI server (such as Jenkins). It's normal for projects to have lots of library dependencies, so you shouldn't need to hack around a build environment to use them.

home folder changes when using java classes from matlab

I am writing a java application with a matlab ui. For this I use java objects in matlab as explained here: http://www.mathworks.com/help/techdoc/matlab_external/f4873.html
those java classes reference (using a relative path) to resources in some other folder in the parent map. In eclipse or as an executable jar this all works fine.
The problem is that when classes are used in matlab the homefolder changes. So instead of looking in JAR/resources or PROJECTMAP/resources it looks for the resources in MATLAB/resources and returns a file not found exception.
how I currently solved it is kinda lame:
I simply put a copy of the resource folder in the MATLAB directory which makes the code execute.
Yet this is a poor solution.
What I would want is
1: to include the resource folder in the jar (generated in eclipse) an make it possible to use these classes in matlab (in short: independency current directory)
2: Being able to run the same code from eclipse (to debug/profile...).
3: That the code should execute independantly of the location the jar is in as long as it is added to the matlab classpath. (so the jar does not have to be in a specific folder (eg MATLAB folder))
So I 'simply' need a way to specify the location of the resource folder in my code as to achieve 1,2,3 (1,2 most important).
Not sure how you're reading and what you're doing with these resources (so this might not be the correct solution for your case), but you indeed might want to put these on your classpath. If you put them in their own source folder in eclipse you can setup your build to include them in your jar. (Maven by convention has a /src/main/resources directory that is for sticking arbitrary files into a the compiled jar).
With these resources on the classpath... You can then use the classloader to load files through getClass().getResourceAsStream() or getResource() and run with it.

Easiest way to manage my CLASSPATH?

I'm beginning to play with Clojure a bit and my Java experience is pretty limited. I'm coming from the dynamic world of Ruby and OO, so the functional side of things is very interesting!
Anyway, as I discover libraries and various tools for use (and the tutorial files for the Pragmatic Clojure Book), everything typically calls for placing files in the CLASSPATH in order for Clojure to see the library for use.
Is there such thing as good CLASSPATH practice? Would I ever want to only have a CLASSPATH with just the external libraries of files I need or can I go ahead toss any library or file I would ever need in a directory and simply define it as my CLASSPATH and only require what's needed?
If it helps, I'm an OSX and Emacs user (Using slime and swank-clojure).
I recommend using leiningen and lein-swank to manage this. You can start a REPL in the directory and connect to it from Emacs.
Personally, I'm using a variant of a clojure-project elisp function by Phil Hagelberg, see source in this post to the Clojure group. It sets up the classpath appropriately for the project you'll be working on, then launches SLIME. (EDIT: You'll need to change the value which gets assigned to swank-clojure-jar-path to point to clojure.jar. I'm using (expand-file-name "~/.clojure/clojure.jar") as the default.)
To answer the question about having everything on the classpath all the time vs only throwing in what's needed: to the best of my knowledge, nothing will actually break if you take the first approach (I know I do that for experimental purposes), but apparently things might break with the first approach (see cjstehno's comment below) and in a proper project I find the second to be cleaner. At some point it'll be necessary to determine what libs are being used (and which versions of them), if only to tell leiningen (or maven) about it -- why not keep tabs on it as you go.
We are using Clojure and use a number of infrastructure tools, especially Eclipse (IDE) (http://en.wikipedia.org/wiki/Eclipse_%28software%29) and maven (http://en.wikipedia.org/wiki/Apache_Maven). maven manages libraries and jar dependencies so if you have a number of these and they are likely to grow start using maven.
In answer to your original question you can just put your jars in one directory and you can access them by name every time you run. But you will benefit from the tools...
If you are just exploring then Eclipse will probably manage your jar files fairly painlessly. You can add these to the project as required through the Build Path -> Configure Build Path option.
As your work progresses you will possibly wish to split it into Projects which Eclipse supports so you can add your (or other projects) to your Build Path.
If you use external Clojure libraries look to see if they have been packaged as maven projects (they will have a pom.xml file). The POM will give a list of dependencies.
#
The usual CLASSPATH practice for Java is to put only the jar files needed for a project into this projects class path, which means to have potentially different class paths for diffent projects. This is usually managed by the IDE as part of it's project properties.
Since you are using Emacs and thus probably don't have or use something like projects it might be more convinient for you to set up and use a single global class path for all your clojure related stuff or maybe even simply put all the needed jar files into the java2se/jre/lib/ext directory of your java installation.
The two main problems that could arise from having unneded jar files in your class path are: 1. it has a minor negative impact on the start up time of the JVM and 2. it becomes more difficult to make sure that you are not having classes with different versions in the same class path (i.e. different classes with the same package and name in different jar files).
Since Java SE 1.6 (or JDK 1.6) you can include class path entries by wildcard. If your class files live in .\bin, and your library jar files live in .\lib, then on Windows you could define your class path like this:
set CLASSPATH=bin;lib\*;
This will let you add jar files into the .\lib directory and they will automatically be added to the class path for new instances of the JRE.
See this link for details: Setting the class path
Prior to JDK 1.6 you had to add each jar file onto the ClassPath individually.
I just discovered this bit which I need to give a shot:
(setq swank-clojure-extra-classpaths (list "/class/path/1" "/class/path/2" "/class/path/3" "etc"))
clojure-contrib/launchers/bash/clj-env-dir has an interesting property that you can point it at a directory and it will basically include anything in there. In the past I've had a ~/classpath directory which I would dump any jars into and link any commonly used directories and it worked great. Very simple way to dump and use. Now I tend to use Maven clojure-maven-plugin and that works well also though can be a bit tedious when you just want to muck around with some ideas.

Categories

Resources