Choosing what native library to load depending on system setup - java

In our OSGi code, we are using Bundle-NativeCode manifest headers to choose what native libraries to load for Windows or Linux.
The problem arises when one of the libraries we need to use depends on a specific version of an already installed library (GLIBC is currently at version 2.12 in Ubuntu and 2.11 in Debian). Is there a way to identify the installed Linux flavor, or at least the version of a specific library with the Bundle-NativeCode properties? Do you know any other way around this? (please note that osname and osversion only give us "Linux" and the linux kernel version respectively, which is not enough)
Thanks!

No, the OSGi native code filtering does not provide that level of dependency for externally sourced packages. Other than trying to include the specific version of your dependency in the bundle as well (which of course wouldn't work with glibc) you can't achieve this through the Native-Code alone.
One alternative is to not use the Native-Code and instead use your bundle to load the fragment code on demand, by using a different name. So you have Linux\Glibc\211 and Linux\Glibc\212, and then based on the runtime of your bundle's startup, can manually call the System.loadLibrary() yourself.

Related

Testing for Java SDK

I am writing an application in Java. Does a Java SDK have to be installed to run the application from the command line? If so, can I package the SDK with the application to be installed when installing the application?
From Java 9 onwards you can use jlink to produce a custom JRE for your application. The JRE includes a copy of the java command and (only) the libraries / classes that your application needs. It will be platform specific.
From Java 14 onwards, you can use jpackage to produce (platform specific) native executables for Java applications.
There are also 3rd-party tools that can generate executables, and third party installer generators that (in some cases) can install Java for the end user.
Note: if you take the approach of distributing your application as a self-contained JRE or native executable, the user no longer has the option of updating their Java to address security related issues. It becomes your problem / responsibility ... as the supplier of the software ... to make available in a timely fashion application updates that incorporate the new Java releases with important security patches.
If you use something like GraalVM to compile a native binary, then there is nothing more you should need for a simple application (meaning, nothing is tried to dynamically load classes at runtime with reflection)
Other than that, the Java JRE is required, and can be included as part of an application package; for example, IntelliJ or Eclipse IDE come with their own JRE.
Thanks everyone for your input.
After doing more research I found that by using a jdk greater than 8.?, it is possible to bundle everything an application needs in the deployment process.

Bundle GraalVM engine and graalpython with Java application

There is a way to run Python scripts that uses packages from Java using GraalVM and its Python module graalpython. Here is example https://github.com/paulvi/graalpython-java-template
I wonder if it is possible to bundle GraalVM engine and graalpython into my Java application and produce jar or native image (e.g. using native image compiler from GraalVM project ) ?
I think you can bundle whole GraalVM distribution with your application, like some other applications do with normal JDKs (e.g., I think IntelliJ bundles JDK with it). That would be the simplest option.
You need at least the GraalPython home directory, which contains Python standard library and other files necessary for GraalPython to run any meaningful program.
Moreover, if you want to run in JVM mode, then you need to run on GraalVM, other JDKs are not supported. In theory you could perhaps hack it somehow to run GraalPython on stock JDK with JVMCI, like it is possible with JavaScript [0], but it is going to be much more complicated with GraalPython.
In theory, you can bundle GraalPython home directory into your application by providing custom filesystem implementation [1].
[0] https://www.graalvm.org/reference-manual/js/RunOnJDK/
[1] https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/io/FileSystem.html

Packaging a particular version of java with my code

I've built a standalone Java Maven app. I need a particular version of java for running my code e.g. 1.8.0.155. My target environment has an older version. E.g. 1.8.0.45.
For various reasons I'm unable to get the target system to update their version of java.
How do I just bundle a version of the jdk along with my jar?
What you're looking for is how ot create a self-contained application, this link is how you do it without any third part assistance. Another option is Launch4j, a third party wrapper.

integrating org.apache.poi and the javax.xml.stream.* package (stax-api) in android - how to set the --core-library argument in Android Studio?

I'm using Android studio 1.5.1
I'd like to include the org.apache.poi-ooxml library in my android project. To include that library I needed to include some other library dependencies, among which the stax-api library.
The problem with stax api is that it has all the packages in javax.* which is a "core library". Java jdk has all these libraries included, so if I were to use it in Java SE, I wouldn't need that stax-api library. Android, on the other hand, has a "partial" stax-api library. For android I only need the javax.xml.stream.* package. That means that I need to extract the stax-api, remove everything except the javax.xml.stram package, and repackage it again.
So I guess it is safe to use this modified library in Android. But, it has the javax.* package, which, according to Android studio is a core library, so Android Studio (or whatever component in Android Studio) gives me a warning:
trouble processing "javax/xml/stream/EventFilter.class":
Ill-advised or mistaken usage of a core class (java.* or javax.*) when
not building a core library.
This is often due to inadvertently including a core library file in
your application's project, when using an IDE (such as Eclipse). If
you are sure you're not intentionally defining a core class, then this
is the most likely explanation of what's going on.
However, you might actually be trying to define a class in a core
namespace, the source of which you may have taken, for example, from a
non-Android virtual machine project. This will most assuredly not
work. At a minimum, it jeopardizes the compatibility of your app with
future versions of the platform. It is also often of questionable
legality.
If you really intend to build a core library -- which is only
appropriate as part of creating a full virtual machine distribution,
as opposed to compiling an application -- then use the
"--core-library" option to suppress this error message.
If you go ahead and use "--core-library" but are in fact building an
application, then be forewarned that your application will still fail
to build or run, at some point. Please be prepared for angry customers
who find, for example, that your application ceases to function once
they upgrade their operating system. You will be to blame for this
problem.
If you are legitimately using some code that happens to be in a core
package, then the easiest safe alternative you have is to repackage
that code. That is, move the classes in question into your own package
namespace. This means that they will never be in conflict with core
system classes. JarJar is a tool that may help you in this endeavor.
If you find that you cannot do this, then that is an indication that
the path you are on will ultimately lead to pain, suffering, grief,
and lamentation.
So, I'd like to use this --core-library option. But where to set it?
I already looked at Android Studio ignore --core-library flag which didn't help me. I think those answers are outdated, and that's why I'm asking a new question.
What I did try:
build.gradle:
dexOptions {
coreLibrary true;
}
build.gradle:
dexOptions {
preDexLibraries = false
}
project.tasks.withType(com.android.build.gradle.tasks.Dex) {
additionalParameters=['--core-library']
}
File --> Other Settings --> Default Settings --> Compilers --> Android Compilers
and check the 'Add --core-library flag'
None of these worked. Is there any way to set that option?
EDIT: Why do I need STAX:
I'm doing some stuff with Workbook, Sheet, Columns, Cells for .xlsx files.
When I include only poi-ooxml-3.14-beta1-20151223.jar I get an error in build time saying class file for org.apache.poi.ss.usermodel.Workbook not found.
Upon including poi-3.14-beta1-20151223.jar on runtime I get, among others, Could not find method org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook.isSetBookViews, referenced from method org.apache.poi.xssf.usermodel.XSSFWorkbook.
Upon including poi-ooxml-schemas-3.14-beta1-20151223.jar during runtime I get , among others, Failed resolving Lorg/openxmlformats/schemas/spreadsheetml/x2006/main/CTWorkbook; interface 59 'Lorg/apache/xmlbeans/XmlObject; and java.lang.VerifyError: org/apache/poi/xssf/usermodel/XSSFWorkbook
Upon including xmlbeans-2.6.0.jar during runtime I get, among others, Could not find method javax.xml.stream.events.Namespace.getPrefix, referenced from method org.apache.poi.openxml4j.opc.internal.marshallers.PackagePropertiesMarshaller.getQName and java.lang.NoClassDefFoundError: javax.xml.stream.XMLEventFactory at org.apache.poi.openxml4j.opc.internal.marshallers.PackagePropertiesMarshaller.<clinit>(PackagePropertiesMarshaller.java:41)
UPDATE
So, from http://poi.apache.org/faq.html#faq-N1017E
18. Why do I get a java.lang.NoClassDefFoundError: javax/xml/stream/XMLEventFactory.newFactory()
This error indicates
that the class XMLEventFactory does not provide functionality which
POI is depending upon. There can be a number of different reasons for
this:
Outdated xml-apis.jar, stax-apis.jar or xercesImpl.jar:
These libraries were required with Java 5 and lower, but are not actually required with spec-compliant Java 6 implementations, so try
removing those libraries from your classpath. If this is not possible,
try upgrading to a newer version of those jar files.
Running IBM Java 6 (potentially as part of WebSphere Application Server): IBM Java 6 does not provide all the interfaces required by
the XML standards, only IBM Java 7 seems to provide the correct
interfaces, so try upgrading your JDK.
Sun/Oracle Java 6 with outdated patchlevel: Some of the interfaces were only included/fixed in some of the patchlevels for Java 6. Try
running with the latest available patchlevel or even better use Java
7/8 where this functionality should be available in all cases.
So, if I read this correctly, in Android, I do need a "truncated" STAX api.
There are a number of problems when you try to use Apache POI and it's depending libraries in an Android Application. Among others there are duplicate classes in xmlbeans.jar, the "javax.*" packages are prohibited by the Android compiler and a few others.
There are currently two projects which try to fix those issues:
https://github.com/andruhon/android5xlsx
https://github.com/centic9/poi-on-android/ (which I maintain)
android5xlsx provides ready-made jar-files to include in your application, but currently uses a somewhat outdated version of POI. poi-on-android is based on POI 3.15-beta1 and can be recompiled for newer versions of POI fairly easily.
Both projects are for Android 5+ and come with sample code and should allow basic usage of Apache POI on Android.
Add implementation 'javax.xml.stream:stax-api:1.0' in you app build.gradle, as some core class missed

Where to check whether a package is shipped with the JRE for Java

I'm using javax.xml.soap package in my java desktop application and I would like to check whether that package (and more in general any package shipped with JDK) is available in JRE's on different platforms (win, mac, linux) for deployment.
The aim is to make sure that my application will run on target machines with JRE or check if full JDK is required. Also for linux I would like to make sure that the open-jdk jre 1.6 (not the oracle one) will be enough.
Thanks
If you wan't to find out if a class is included in the JRE you have, do the following:
Locate the rt.jar of your JRE, mine was at /usr/lib/jvm/jdk1.7.0_07/jre/lib/rt.jar
Open it with your favorite .zip viewer
Search for the wanted classes
You're done!
If you wan't to find out if the JRE you're running at contains your class, do the following:
Call Class.forName with the classname of the class you wan't to test
Put this in a try-catch-block
If you catch a ClassNotFoundException, its not there!
Note that this does not state if it is in the default library, just that is is on the classpath!
This effort on portability is very good!
I would suggest you requiring Java 7 because OpenJDK7 is the default implementation for it, so no more "oracle java is better than openjdk".
I think requiring Java 7 is better than requiring a specific Java implementation (Oracle) or "checking if it runs on openjdk 6".
Anyways I'd suggest david's points!
Ways to guess whether there's a package present in the JVM in runtime:
Check the JRE version system property (java.version)
Try to load the classes you're expecting in javax.xml.soap using reflection
In practice, I'd however rather demand certain JRE(s) to be used to run my application in my system requirements, rather than just trying to detect whether a package is available.

Categories