Showing posts with label tips. Show all posts
Showing posts with label tips. Show all posts

2010-03-11

Compiling Java applications to native Windows executables

Being a Java developer really sucks when it comes to making end-user desktop applications. You want these applications to be light, fast and easily redistributable. Packaging a bunch of jars along with startup script is the worst thing you can do. It may work quite well in various Linux distributions, where you can make a .deb or .rpm which automatically installs JRE, puts startup script to /usr/local/bin and creates a nice launcher with icon in the applications menu. In Mac OS you can use that outdated JRE that comes by default and then easily bundle all scripts and jars into an .app. But in Windows it does not work that way. You can use JSmooth to make .exe out of .jar and use NSIS to create a nice installer, but there still is a problem. User may not have a compatible JRE, or he/she may choose not to have one just because Java sucks for running on it's bloated memory hogging virtual machine. I have to agree here. As a user, I have no faith in desktop applications that are written in Java.

So what is the solution? Compile to native executable and forget JRE. It is possible, but it will not be a walk in the park. First, you will have to get familiar with GNU Compiler Collection and particularly with GCJ.

Let's compile a Hello World application like this one:

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello native world!");
    }
}
  1. Get the patched GCJ here: http://www.thisiscool.com/gcc_mingw.htm (120 MB)
  2. Extract it somewhere and add thisiscool-gcc/gcc-ejc/bin to your PATH
  3. Compile Hello.java as Hello.exe: gcj --main=Hello -o Hello Hello.java
  4. Enjoy your statically linked Hello.exe which prints Hello native world! and runs without JRE.
Wait. Hello.exe is 37MB? Holy crap! Well, it's a little overhead you have to pay for loosing the JRE, this .exe contains the whole garbage collection mechanism, etc. Also, you will be able to compile SWT GUI applications! It is possible to get smaller executables with MinGW tooling. Hello.java compiled with MinGW is about 3MB, but it has other issues, I couldn't manage to get the system output working. You may be more lucky though.

Anyway, when you compile native binaries, your Java code cannot be decompiled, so you have better protection than by using obfuscators. And the best thing is that end users won't complain that "it's crap because it's Java". They just wouldn't know.

I wish Sun (I just can't say Oracle when referring to Java, it makes me sick, sorry) could create an official AOT Java compiler so developers would not have to go through hellfire to make native executables.

2009-04-27

Symbolic links in Windows

Surprisingly, all the good Windows features are hidden, undocumented and hard to find. It took me nearly a decade to accidentally find out that Windows has symbolic links. They are called NTFS Junction Points. However their support is limited to directory links, and the usage is a bit weird.

Oh, and you have to install Windows Resource Kit to get the functionality. You can download it from any of these locations:


The command you want is linkd. Let's take it for a spin.



The sandbox contains a directory named original with text.txt inside.

To create a symbolic link named symlinked that points to original, the command is linkd symlinked original. In POSIX it would be ln -s original symlinked.



When calling dir, symlinked shows as "junction". The other behavior is like a plain folder. In explorer you cannot tell the difference between the two.



To delete the symlink use rmdir, because del will attempt to remove the files from original directory.

2009-01-06

Using Unicode in Java .property files

Using multi-byte characters in Java .property files? Forget the Sun's native2ascii application. Rather than doing the irritating conversions, create UTF-8 encoded .property files, edit them directly and use Utf8ResourceBundle to access them. The code:

package com.varaneckas.utils;

import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

/**
* UTF-8 friendly ResourceBundle support
*
* Utility that allows having multi-byte characters inside java .property files.
* It removes the need for Sun's native2ascii application, you can simply have
* UTF-8 encoded editable .property files.
*
* Use:
* ResourceBundle bundle = Utf8ResourceBundle.getBundle("bundle_name");
*
* @author Tomas Varaneckas <tomas.varaneckas@gmail.com>
*/
public abstract class Utf8ResourceBundle {

/**
* Gets the unicode friendly resource bundle
*
* @param baseName
* @see ResourceBundle#getBundle(String)
* @return Unicode friendly resource bundle
*/
public static final ResourceBundle getBundle(final String baseName) {
return createUtf8PropertyResourceBundle(
ResourceBundle.getBundle(baseName));
}

/**
* Creates unicode friendly {@link PropertyResourceBundle} if possible.
*
* @param bundle
* @return Unicode friendly property resource bundle
*/
private static ResourceBundle createUtf8PropertyResourceBundle(
final ResourceBundle bundle) {
if (!(bundle instanceof PropertyResourceBundle)) {
return bundle;
}
return new Utf8PropertyResourceBundle((PropertyResourceBundle) bundle);
}

/**
* Resource Bundle that does the hard work
*/
private static class Utf8PropertyResourceBundle extends ResourceBundle {

/**
* Bundle with unicode data
*/
private final PropertyResourceBundle bundle;

/**
* Initializing constructor
*
* @param bundle
*/
private Utf8PropertyResourceBundle(final PropertyResourceBundle bundle) {
this.bundle = bundle;
}

@Override
@SuppressWarnings("unchecked")
public Enumeration getKeys() {
return bundle.getKeys();
}

@Override
protected Object handleGetObject(final String key) {
final String value = bundle.getString(key);
if (value == null)
return null;
try {
return new String(value.getBytes("ISO-8859-1"), "UTF-8");
} catch (final UnsupportedEncodingException e) {
throw new RuntimeException("Encoding not supported", e);
}
}
}
}

2008-11-11

InputStreamChain

If you have several Java InputStreams that you want to queue up into a single InputStream object, you can use this:

package com.varaneckas;

import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;

/**
* {@link InputStream} implementation that allows chaining of various
* streams for seamless sequential reading
*
* @author Tomas Varaneckas <tomas.varaneckas@gmail.com>
*/
public class InputStreamChain extends InputStream {

/**
* Input stream chain
*/
private final LinkedList<InputStream> streams = new LinkedList<InputStream>();

/**
* Currently active stream
*/
private InputStream current;

/**
* Default constructor
*/
public InputStreamChain() {
//nothing to do
}

/**
* Constructor with an initial stream
*
* @param first Initial InputStream
*/
public InputStreamChain(final InputStream first) {
addInputStream(first);
}

/**
* Constructor with an array of initial streams
*
* @param streams Array of initial InputStreams
*/
public InputStreamChain(final InputStream[] streams) {
for (InputStream stream : streams) {
addInputStream(stream);
}
}

/**
* Vararg constructor
*
* @param streams initial input streams
*/
public InputStreamChain(final InputStream ... streams) {
for (InputStream stream : streams) {
addInputStream(stream);
}
}

/**
* Adds input stream to the end of chain
*
* @param stream InputStream to add to chain
* @return instance of self (for fluent calls)
*/
public InputStreamChain addInputStream(final InputStream stream) {
streams.addLast(stream);
if (current == null) {
current = streams.removeFirst();
}
return this;
}

@Override
public int read() throws IOException {
int bit = current.read();
if (bit == -1 && streams.size() > 0) {
try {
current.close();
} catch (final IOException e) {
//replace this with a call to logging facility
e.printStackTrace();
}
current = streams.removeFirst();
bit = read();
}
return bit;
}

@Override
public int available() throws IOException {
int available = current.available();
for (InputStream stream : streams) {
available += stream.available();
}
return available;
}

@Override
public void close() throws IOException {
current.close();
}

@Override
public boolean markSupported() {
return current.markSupported();
}

@Override
public synchronized void mark(int i) {
current.mark(i);
}

@Override
public synchronized void reset() throws IOException {
current.reset();
}

@Override
public long skip(long l) throws IOException {
return current.skip(l);
}

}


Example code:
InputStream chuck = new ByteArrayInputStream("Chuck ".getBytes());
InputStream norris = new ByteArrayInputStream("Norris".getBytes());
InputStream chuckNorris = new InputStreamChain()
.addInputStream(chuck)
.addInputStream(norris);
//will print "Chuck Norris"
System.out.println(new BufferedReader(
new InputStreamReader(chuckNorris)).readLine());


Have fun!

2008-11-06

Software design tips from the creator of C++ programming language

[1] Know what you are trying to achieve
[2] Keep in mind that software development is a human activity
[3] Proof by analogy is fraud
[4] Have specific and tangible aims
[5] Don’t try technological fixes for sociological problems
[6] Consider the longer term in design and in the treatment of people
[7] There is no lower limit to the size of programs for which it is sensible to design before starting to code
[8] Design processes to encourage feedback
[9] Don’t confuse activity for progress
[10] Don’t generalize beyond what is needed, what you have direct experience with, and what can be tested
[11] Represent concepts as classes
[12] There are properties of a system that should not be represented as a class
[13] Represent hierarchical relationships between concepts as class hierarchies
[14] Actively search for commonality in the concepts of the application and implementation and represent the resulting more general concepts as base classes
[15] Classifications in other domains are not necessarily useful classifications in an inheritance model for an application
[16] Design class hierarchies based on behaviour and invariants
[17] Consider use cases
[18] Consider using CRC cards
[19] Use existing systems as models, as inspiration, and as starting points
[20] Beware of viewgraph engineering
[21] Throw a prototype away before it becomes a burden
[22] Design for change, focusing on flexibility, extensibility, portability, and reuse
[23] Focus on component design
[24] Let each interface represent a concept at a single level of abstraction
[25] Design for stability in the face of change
[26] Make designs stable by making heavily used interfaces minimal, general, and abstract
[27] Keep it small. Don’t add features "just in case"
[28] Always consider alternative representations for a class. If no alternative representation is plausible, the class is probably not representing a clean concept
[29] Repeatedly review and refine both the design and the implementation
[30] Use the best tools available for testing and for analysing the problem, the design, and the implementation
[31] Experiment, analyse, and test as early as possible and as often as possible
[32] Don’t forget about efficiency
[33] Keep the level of formality appropriate to the scale of the project
[34] Make sure that someone is in charge of the overall design
[35] Document, market, and support reusable components
[36] Document aims and principles as well as details
[37] Provide tutorials for new developers as part of the documentation
[38] Reward and encourage reuse of designs, libraries, and classes

I found these great tips in a classic programming book: The C++ Programming Language Third Edition by Bjarne Stroustrup, the creator of C++. If you want to learn C++ or deepen your knowledge, this is The Book.

2008-09-18

Eclipse Template: Singleton Pattern

Are you writing your Java classes as Singletons quite often? Use this Eclipse template and make any class a singleton in two seconds:

Setup

Go to Window -> Preferences -> Java -> Editor -> Templates. Create New:



Code for copy paste:
private static final ${enclosing_type} instance = new ${enclosing_type}();
private ${enclosing_type}() {}
public static ${enclosing_type} getInstance() {
    return instance;
}


Action

Type "single" or "singleton", hit Content Assist shortcut key (ctrl+space by default), then enter:



And there you go - a singleton in two seconds (actual time may vary on your typing and CPU speed).



You may want to use a different Singleton implementation. Check out Java Singleton: The Proper Way for a good example.

2008-09-01

Add loggers to your Java code in seconds using Eclipse Templates

Custom Eclipse Templates can greatly increase your productivity by automating daily development. For instance, instead of creating Apache Commons Logging loggers by hand, you can do this:

Setup

Go to Window -> Preferences -> Java -> Editor -> Templates. Create New:



Action

Type "log", hit Content Assist shortcut key (ctrl+space by default), then enter:



Hit Ctrl+Shift+O to import Log and LogFactory:



Saves hell of a time in the long run.

2008-07-25

Slap your Java code hard with Maven and PMD

How good you think your code is? How can you be sure it's optimal, bug and bullet proof? Unit Tests? In case the coverage is good, they will tell if your code works, but will it tell if and where your code sucks in general? Let's get down to business.

As Maven is used de facto for Java builds, I assume you're using it. You may have heard of PMD, but have you tried it? If you have, did you know that it has a nice Maven Plugin? A quick way to integrate it:

Add the following to your pom.xml. Sadly, default check rulesets are too friendly, so you may want to try my configuration (even the "too hardcore" block):







org.apache.maven.plugins
maven-jxr-plugin


org.apache.maven.plugins
maven-pmd-plugin


rulesets/basic.xml
rulesets/braces.xml
rulesets/clone.xml
rulesets/codesize.xml
rulesets/coupling.xml
rulesets/favorites.xml
rulesets/finalizers.xml
rulesets/imports.xml
rulesets/junit.xml
rulesets/migrating_to_15.xml
rulesets/optimizations.xml
rulesets/typeresolution.xml
rulesets/unusedcode.xml
rulesets/strings.xml


true
true
utf-8
5
20
1.5








To generate a report, simply run:

mvn pmd:pmd

You may want to build Java cross reference for links to source code to work:

mvn jxr:jxr

Finally, open the report and see how naughty the code is:

target/site/pmd.html

Watch out for Cyclomatic Complexity!

2008-07-10

Oracle Exception Handling - Stack Trace


Oracle PL/SQL is definitely the worst programming language I've ever encountered. Some time ago I thought that PHP was the worst, but well, things change.

I've been searching for the source of a weird CLOB related bug in a big pile of PL/SQL sh.. mess for a couple of days till I got fed up and decided to find a way to get the stack trace or at least the last line of code where the error was triggered from. Would you believe that before Oracle 10g there was no normal way to get the trace? Here's some Daily WTF material from the official PL/SQL User's Guide and Reference.

----- WTF EXCERPT START -----

Using Locator Variables to Identify Exception Locations

Using one exception handler for a sequence of statements can mask the statement that caused an error:

BEGIN
SELECT ...
SELECT ...
EXCEPTION
WHEN NO_DATA_FOUND THEN ...
-- Which SELECT statement caused the error?
END;
Normally, this is not a problem. But, if the need arises, you can use a locator variable to track statement execution, as follows:
DECLARE
stmt INTEGER := 1; -- designates 1st SELECT statement
BEGIN
SELECT ...
stmt := 2; -- designates 2nd SELECT statement
SELECT ...
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO errors VALUES ('Error in statement ' || stmt);
END;
----- WTF EXCERPT END -----

Yes, they even have a name for this. Locator Variables. Damn. I can't decide whether to laugh or to cry...

On a good note, since Oracle 10g you can use DBMS_UTILITY.FORMAT_ERROR_BACKTRACE function to get a string representation of stack trace with procedure names and code line numbers. They still forgot to add this into the "Handling PL/SQL Errors" section of their manual...

So, here's how you get the stack trace:
declare
x number;
begin
x := 1 / 0;
dbms_output.put_line(x);
exception
when others then
dbms_output.put_line(SQLERRM);
dbms_output.put_line(dbms_utility.format_error_backtrace);
end;
Output:
ORA-01476: divisor is equal to zero
ORA-06512: at line 5

And it took them only 10 versions to implement.

2008-05-10

Getting Unicode output in Eclipse Console

Tired of seeing garbled Eclipse Console output? Here is a quick and dirty tutorial for getting Unicode output in Eclipse Console.

Fact: You will not get Unicode output in Eclipse Console while using System.out directly in Windows. See Eclipse BUG #13865.

1. add -Dfile.encoding=UTF-8 to your eclipse.ini

2. make sure your Eclipse Console font supports Unicode. You can try it out by typing unicode characters directly to console with keyboard. Console Font is set in Window -> Preferences -> General -> Appearance -> Colors and Fonts -> Debug -> Console Font

3. if you are NOT using Windows, set your system encoding to UTF-8. You should now see Unicode characters in Console after restarting Eclipse.

4. if you are using Windows or do not want to change your OS encoding, you will have to avoid using System.out stream directly. Instead, wrap it up with java.io.PrintStream:
PrintStream sysout = new PrintStream(System.out, true, "UTF-8");
sysout.println("\u2297\u0035\u039e\u322F\u5193");


5. if you are using Log4J with ConsoleAppender, make sure to set the encoding property to UTF-8. Example:
#TRACE appender
log4j.appender.stdout.trace=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.trace.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.trace.encoding=UTF-8
log4j.appender.stdout.trace.layout.ConversionPattern=%p [%c] - %m%n
log4j.appender.stdout.trace.Threshold=TRACE


Happy development!