How to create a *standalone* linux executable from java code - java

I know that java intent is for gui and multi platform, but the problem I'm facing it how to release a java application into a linux servers, which I don't have control on, i.e. I dont know what java vm is installed if at all.
So, how do i compile this into a true standalone linux exe, do not assume any pre installed package on the target linux.
public class MyTest {
public static void main(String[] args) {
System.out.println("You passed in: " + args[0]);
}
}

You need to specify as a requirement an installed JRE.
Otherwise you would need to deliver a JRE yourself as part of the deliverable application

The GNU COmpiler for Java does exactly this. Keep in mind that it will work properly only for small programs, either way you'll need a JVM.
There's also Avian, which has another approach and allows to deploy a lightweight JVM with jour application, but it still hasn't all the features of a full JRE.

Creating one binary from java may not be that good. You may consider tools like http://launch4j.sourceforge.net/ for creating a full installation along with appropriate jre.

Related

Replace a class within the Java class library with a custom version

The class BasicLabelUI in javax/swing/plaf/basic is affected by a confirmed bug.
In my application I need functionality provided by the fixed version (filed for v9).
Due to both legal and technical reasons, I'm still bound to the affected JDK version.
My approach was to create a package javax/swing/plaf/basic inside my project, containing the fixed version.
How can I force my project to favor my included version of the class over the defective class in the installed JDK?
This has to be somewhat portable as the fixed class also has to be working on customer side and the defective class in the JDK installation has to be disregarded. Therefore, I dont want to modify the JDK, but rather bypass this particular class.
As mentioned by the other answers, you could in theory of course unzip your JVM's rt.jar file and replace the file with a compatible bugfixed version.
Any classes of the Java Class library such as those of Swing are loaded by the bootstrap class loader which looks up its classes from this rt.jar. You can generally not prepend classes to this classpath without adding them to this file. There is a (non-standard) VM option
-Xbootclasspath/jarWithPatchedClass.jar:path
where you would prepend a jar file that includes the patched version, but this does not necessarily work on any Java virtual machine. Also, it is illegal to deploy an application that changes this hehavior! As it is stated in the official documentation:
Do not deploy applications that use this option to override a class in
rt.jar because this violates the Java Runtime Environment binary code
license.
If you however appended a class to the bootstrap class loader (what is possible without using non-standard APIs by using the instrumentation API), the runtime would still load the original class as the bootstrap class loader in this case searches the rt.jar first. It is therefore impossible to "shadow" the broken class without modifying this file.
Finally, it is always illegal to distribute a VM with a patched file, i.e. putting it into a production system for a customer. The license agreement states clearly that you need to
[...] distribute the [Java runtime] complete and unmodified and only bundled as part of your applets and applications
Changing the VM that you distribute is therefore not recommended as you might face legal consequences when this is ever uncovered.
Of course, you can in theory build your own version of the OpenJDK but you could not call the binary Java anymore when you distribute it and I assume that your customer would not allow for this by what you suggest in your answer. By experience, many secure environments compute hashes of binaries before execution what would prohibit both approaches of tweaking the executing VM.
The easiest solution for you would probably be the creation of a Java agent that you you add to your VM process on startup. In the end, this is very similar to adding a library as a class path dependency:
java -javaagent:bugFixAgent.jar -jar myApp.jar
A Java agent is capable of replacing a class's binary representation when the application is started and can therefore change the implementation of the buggy method.
In your case, an agent would look something like the following where you need to include the patched class file as a ressource:
public static class BugFixAgent {
public static void premain(String args, Instrumentation inst) {
inst.addClassFileTransformer(new ClassFileTransformer() {
#Override
public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) {
if (className.equals("javax/swing/plaf/basic/BasicLabelUI")) {
return patchedClassFile; // as found in the repository
// Consider removing the transformer for future class loading
} else {
return null; // skips instrumentation for other classes
}
}
});
}
}
The javadoc java.lang.instrumentation package offers a detail description of how to build and implement a Java agent. Using this approach, you can use the fixed version of the class in question without breaking the license agreement.
From experience, Java agents are a great way for fixing temporary bugs in third party libraries and in the Java Class Library without needing to deploy changes in your code or even being required to deploy a new version for a customer. As a matter of fact, this is a typical use case for using a Java agent.
How can I force my project to favor my included version of the class over the defective class in the installed JDK?
Simple answer - you can't. At least, not while strictly obeying the constraint that you should use the affected Java version.
Assuming that you can identify an appropriate version in the OpenJDK source repos, it would be possible to build your own flavor of the Java libraries with a bug patched. However, that won't be real Java. Certainly, it won't qualify as "the affected Java version" that you are constrained to use. (And besides, you are committing yourself to an endless cycle of reapplying your patch to each new patch release of the current version of Java ...)
It is also possible in theory to put a modified version of some Java standard library class into a JAR and prepend it to the JVM's bootstrap classpath using the -Xbootclasspath command line option. But that is tantamount to changing "the affected Java version" too.
Doing it by using a Java agent to use a patched version of the class is breaking the rules too. And it is more complicated. (If you are going to break your rules, do it the easy way ...)
If you and your customers do decide that tweaking the JVM is an acceptable solution, then doing it via the bootstrap classpath is probably the simplest and cleanest approach. And it is DEFINITELY legal1.
However, I'd recommend that you find a workaround for the bug until a version of Java 9 with your fix is released.
1 - Actually, even the build-from-modified-source approach is legal, because the Oracle Binary license does not apply to that. The Binary license is about distributing a modified version of an Oracle binary. The other possible issue is that you may be violating the terms for using the Java trademark(s) if you distribute a version that is incompatible with "true" Java, and call your distro "Java". The solution to that is ... don't call it "Java"!
However, don't just follow my advice. Ask a lawyer. Better yet, don't do it at all. It is unnecessarily complicated.

javax.comm.CommPortIdentifier.getPortIdentifiers() empty on device running Debian 6

I'm afraid this might not strictly be a programming question, but more something I need cleared up to continue my programming.
I am simply trying to write a program to do serial communication, specifically using the javax.comm API and I have succeeded on Win7, but when I run any such program on my device, I get no output. The device is running Debian 6, and it has JDK1.8.0 installed.
In order to run my programs on Win7, I needed to get the API and place the three magic files comm.jar, win32comm.dll and javax.comm.properties in specific folders, but I don't know how to do this on my device.
Does anyone know if I can just put these three files in some arbitrary folders and reference them with a path environment variable?
The code I am trying to run is simply:
package test;
import java.util.Enumeration;
import javax.comm.*;
public class Test {
public static void main(String[] args) {
Enumeration e = CommPortIdentifier.getPortIdentifiers();
while (e.hasMoreElements()) {
CommPortIdentifier com = (CommPortIdentifier) e.nextElement();
System.out.println(com.getName());
}
}
According to http://reprap.org/wiki/JavaComm#Installation_on_Linux you need a number of files:
commapi/jar/comm.jar
commapi/lib/libLinuxSerialParallel.so
commapi/lib/libLinuxSerialParallel_g.so
commapi/docs/javax.comm.properties
"Put the jar file somewhere in your class path (e.g. somewhere like usr/java/j2sdk/jre/lib/ext), the .so files in java's load-library path (on my system that's in /usr/java/j2sdk/jre/lib/i386), and javax.comm.properties "somewhere that java can find it" - on my system, that seems to mean creating a symbolic link to it from the directory in which you're running the project, but there must be an easier way."
You might want to find the source used to build the libraries in case the binaries do not work on your system and compile them yourself.
Clues as to how to do this yourself:
http://www.phidgets.com/phorum/viewtopic.php?f=39&t=3750
https://github.com/rxtx/rxtx.git

Multiple main-methods for testing purposes in Netbeans 7.4 (project from Netbeans 7.2.1)

I recently switched from my older Netbeans version 7.2.1 to 7.4. I am working on a bigger project which uses only one main-entry point of course. However, for testing purposes I am using a second class which also contains a main-method. In my older Netbeans version I was able to Shift+F6 (Run File) and it did what it says: It runs the file because if has a valid main-method. With the never version of the IDE the program keeps telling me, that there is no main-method. This main-method is anything but special and the autocheck does not warn me either (Why wouldn't it? It is totally valid and worked in version 7.2.1).
Here is my testing class definition for the sake of completeness:
package Tests;
// various imports from surrounding project or external packages
public class TEST001 {
// variables and methods for further testing
public static void main(String[] args) throws IOException{
// [...]
}
}
Now, are there incompabilities between projects of Netbeans 7.2.1 to these of version 7.4 which might have caused this?
Or do I have to check a special option somewhere to allow the handling of multiple main-entry points? Which seems unlikely because running a file instead of the project seems to be permanent feature with its own user controls.
Or is this simply a bug?
Thank you for your suggestions.

Problem with jdk and eclipse

Let me start by saying I've been doing professional development work in C++ for about 15 years, and I've done a very small amount of Java on Linux systems. However, I seem to be doing something incorrectly with my Java installation on eclipse.
I have eclipse installed on a Windows 7 machine in C:\tools\eclipse\helios.
I have the Java jdk installed in C:\tools\Java\jdk1.6.0.
The Java jre is installed in C:\tools\Java\jre1.6.0.
In eclipse, I create a java project, and point the project at the jdk folder listed above. In other words, I have the jdk listed as one of the installed JREs and it is the selected JRE.
BTW: I also have Google's android tools and the MotoDev envioronment installed in eclipse, and I can write and build android java code in those projects. Of course, they don't use the jdk.
So, I'm relatively new to Java and I want to start simple, so I created the basic HelloWorld project. I have the following simple code:
package app;
import system; // System not recognized here!!!
public class Application
{
public static void main(String[] args)
{
system.out.println("Hello World!"); // System not recognized here, obviously!
}
}
Anyone have any idea what I'm doing wrong here? There doesn't seem to be anywhere to point to the jdk/lib directory. The jdk looks in jdk1.6.0/jre/lib, which I'm pretty sure isn't going to help me.
Thanks.
System class is present in java.lang package. It's imported by default. So no need to import it like you did. Please bear in mind that it's Java's convention to have class names begin with uppercase characters. Hence System class is with upper case S
Documentation for packages and classes in JDK is available at http://download.oracle.com/javase/6/docs/api/. It's a good idea to refer to this often especially when beginning with Java programming
Maybe you need a capital 'S' for System? And you shouldn't need to import 'System'. It is imported automatically.
It is System and not system. And No need to import it explicitly.

#Override for interface methods causes JSP compilation to fail

For some reason, putting #Override on methods overriding interface methods causes JSP compilation to fail in weblogic. Everything is definitely running off of JDK 1.6.0_14, but this Java 5'ism still persists.
Oddly, JSP compilation occasionally fails with a stacktrace pointing at code not necessarily obviously used by the JSP itself.
What's going on here?
The #Override is supposed to only be retained in source so shouldn't come up in byte code. There might an angle you can play in ensuring those classes are complied separately from the JSPs and simply available in the classpath -- rather than the source path.
If that's already the case then it might be a different issue than what is immediately showing.
Used to be the JSP complier was a separate library shipped with the server and not tied to the vm the server is running in. WLS used to use Javelin. Seems like they switched that in 10 to use the Java Compiler API. So it should work fine as long as you have Sun vm Java 1.6. But if there's 'javelin' anything in your stacktrace, definitely check that angle.
I've seen this a lot myself. In Java 6, it is (supposedly) permissible to use #Override on interface implementation methods. In Java 5, this is an error. However in my Java 6 code, sometimes #Override is accepted on interface implementation methods, and sometimes it is not.
To make things weirder, some IDEs (e.g. NetBeans) are fine with it, while IntelliJ IDEA is sometimes ok and sometimes not. I have found, however, that compiling the code in either IDE will ignore the alleged errors being reported by the IDE.
In other words, is the problem manifesting in your IDE? If so, compile the code directly (use the command-line if necessary) and see what happens. The IDE may be reporting spurious errors.
A possible workaround might be to precompile JSP using appc. This could at least allow to circumvent the issue.
Regarding the "real" question, my understanding is that you did upgrade domains, so maybe have a look at the following resources:
Web Applications, JSPs, and Servlets
Backwards Compatibility Flags
Procedure for Upgrading a WebLogic Domain
Select Upgrade Options (related to domain upgrade)
Backward Compatibility Flags
JSPCompilerBackwardsCompatible - Specifies whether to allow JSPs that do not comply with the JSP 2.0 specification
This is a wild guess but maybe some backward compatibility flag is activated and WebLogic keeps using the "old" approach.
I agree with your instinct and the other answers that WLS is using Java 5 somehere. The items below seem like useful tidbits from Oracle/WebLogic resources. I don't have a WebLogic Server 10.3 installation to confirm these:
Weblogic Server 10.3
According to this, at least Weblogic Server 10.3 is required to use Java 6, but I can't see anything the confirms this as authoritative info:
http://forums.oracle.com/forums/thread.jspa?threadID=884263
Re: WebLogic 10.0 supports Java 6?
Posted: Apr 9, 2009 12:26 PM in response to: user8324142
Hi,
Weblogic 10 will not support JDK6.
Please upgrade to Weblogic 10.3 to work with JDK 6.
Checking the Java version
http://download.oracle.com/docs/cd/E12840_01/common/docs103/install/postins.html#wp1090736
Determining Which JDK Version You Are Using
You can determine which version of the JDK you are using by issuing a command, as follows:
Open a command prompt window and go to the appropriate directory:
BEA_HOME\WL_HOME\server\bin (Windows)
BEA_HOME/WL_HOME/server/bin (UNIX)
In both pathnames, BEA_HOME represents the directory in which you have installed your software and WL_HOME represents the wlserver_< version >.
Make sure that your environment is set up properly by entering the following command at the prompt:
setWLSenv.cmd (Windows)
setWLSenv.sh (UNIX)
Enter the following command at the prompt:
java -version
Configuring Java version:
http://download.oracle.com/docs/cd/E12840_01/wls/docs103/perform/WLSTuning.html
Setting Java Parameters for Starting WebLogic Server
... Java parameters must be specified whenever you start WebLogic Server. ... Oracle recommends that you incorporate the command into a [startup] script ...
If you used the Configuration Wizard to create your domain, the WebLogic startup scripts are located in the domain-name directory where you specified your domain. By default, this directory is BEA_HOME\user_projects\domain\domain-name, where BEA_HOME is the directory that contains the product installation, and domain-name is the name of the domain directory defined by the selected configuration template. ...
Change the value of the variable JAVA_HOME to the location of your JDK. For example:
set JAVA_HOME=C:\bea\jdk150_03
...
In my mind, #Override makes sense on methods that are overriding methods, not implementing methods.
So if you have an interface:
public interface MyInterface {
public void doSomething();
}
A class that implements that interface is below (MyClassA):
public MyClassA implements MyInterface {
public void doSomething() {
System.out.println("This is from MyClassA");
}
}
Then, the below class extends MyClassA and overrides doSomething, and so then I'd add the #Override annotation.
public MyClassB extends MyClassA implements MyInterface {
#Override
public void doSomething() {
System.out.println("This is from MyClassB");
}
}
I wouldn't do the below (whether or not it is permissable) in any case, since it breaks the idea about overriding something - you're implementing, not overriding the interface:
public MyClassA implements MyInterface {
#Override
public void doSomething() {
System.out.println("This is from MyClassA");
}
}

Categories