Mutant World

Tuesday, August 04, 2009

Jetty Support for Cross-Domain XMLHttpRequests

Remember the same origin policy that restricts most of our JavaScript applications ?

Seems that we can finally get rid of it, thanks to a new W3C specification already implemented by Firefox 3.5 and, on server side, by the Jetty Servlet Container.

I blogged about all the details here.

Oh, if you're using Ubuntu Jaunty, you can install Firefox 3.5 via apt://firefox-3.5. It is named "Shiretoko" (its codename), but it's exactly Firefox 3.5.

Time to move on !

Labels: , , , ,

Thursday, August 14, 2008

Java's uncertain future

Java's future looks to me very uncertain in this period.

I started studying Java during 1999 summer, and working with it since then.

Many things happened since the release of JDK 5.

Many key people left Sun for other companies (and wow, the list of those names is truly impressive; among them Josh Bloch, Neal Gafter, Gilad Bracha, most of the Swing core team - Hans Muller, Scott Violet, Chet Haase, etc.)

Sun itself is not performing very well these days (profit plunged 73% in the last quarter).

Sun has open sourced Java.

Yet, there is no JDK 7 plan.
You heard that right, no official JSR has been opened yet, when we were used to have release of version N of the JDK and official JSR for version N+1 almost immediately opened.
But not this time, and noone seems able to predict neither when JDK 7 will be released, nor what it will contain.

There is OpenJDK.
Can anyone tell me the difference between JDK 7 and OpenJDK ?
And I am not meaning the obvious ones, but why two efforts, and how are they synchronizing ?
I never thought that open sourcing the JDK was such a great idea, from the point of view of developers, though it was probably such a good move for other fields that developers could be forgotten.

There is JDK 6 and JDK 6 update 10. Mmm. More confusion.

The closures will (most likely) not be part of JDK 7, but everyone talks about the "upcoming language changes in JDK 7" yet there is no official JSR, nor for JDK 7 nor for closures. Oops.

Java blogs are beginning to label Java as the next legacy language, but it surely will still live for many many years. I hear the same of COBOL.

It appears as if Sun released the command of the Java ship and let its best commanders flew away.
It would not be bad to see a real move from Sun about Java (because strong statements are just that, words), because hey, the ship seems DIW, dead in water.

It's 2008 summer, and I am studying Ruby.

But the worst indicator is that Hani and its Bileblog are quiet: he cannot desecrate the last moments of a dying era, can he ?

Labels:

Sunday, July 27, 2008

Static Fields in Enums

Enums in Java have a numeric, read-only, property called ordinal that is a strictly consecutive integer (starting from 0).

Sometimes, however, it is necessary to associate to an Enum another numeric property, let's call it code, that it may not be strictly consecutive and normally specifies something different than a sequence number. Furthermore, it may be necessary to be able to lookup the correct Enum from its code.

It seems totally trivial to write an Enum that has a static map from codes to Enum instances:

public enum Port
{
SSH(22), TELNET(23), HTTP(80), POP3(110), HTTPS(443);

// The static map from codes to Enum instances
private static final
Map<Integer, Port> ports = new HashMap<Integer, Port>();
private final int code;

private Port(int code)
{
this.code = code;
ports.put(code, this);
}

public int getCode()
{
return this.code;
}

// Lookup method that returns the Enum instance from the given code
public static Port from(int code)
{
return ports.get(code);
}
}

Note the method static from(int code) that returns an Enum instance from the given code.

Unfortunately, this will not compile. The compiler reports that it is illegal to access the static member ports from the constructor.

This makes sense when one imagines how an Enum is first translated into a class by the compiler. Roughly, there is a static initializer that creates the Ports instances, in this case SSH, TELNET, etc.; this static initializer is the first initializer run when the Ports class is referenced, and it is easy to see that when the static initializer runs, no other initializers have been run yet, and in particular the static Map ports has not been created yet.
See http://java.sun.com/docs/books/jls/third_edition/html/classes.html#301020 for further details.

Fortunately, there is an easy workaround: it's enough to use a different class to store the map from codes to Enum instances, and a private static inner class does the job:

public enum Port
{
SSH(22), TELNET(23), HTTP(80), POP3(110), HTTPS(443);

private final int code;

private Port(int code)
{
this.code = code;
Ports.ports.put(code, this);
}

public int getCode()
{
return this.code;
}

// Lookup method that returns the Enum instance from the given code
public static Port from(int code)
{
return Ports.ports.get(code);
}

private static class Ports
{
// The static map from codes to Enum instances
private static final
Map<Integer, Port> ports = new HashMap<Integer, Port>();
}
}

Labels: ,

Thursday, July 26, 2007

Upgrading to SSL an existing socket connection

SSL support is in the JDK since 1.4 (and even before as a separate jar), so it is fairly common knowledge how to create and use SSLSocket and SSLServerSocket.

What is less known, or it was to me at least, is that it is possible to create a plain socket, connect to a server, exchange some message, then upgrade the existing socket connection to SSL, exchange some private message with confidentiality (for example a password that would have traveled in clear text), then downgrade back to the plain the socket connection; all this without closing the original socket nor creating a new one on a different port.

Let's see how.

The server


The server class creates a plain ServerSocket, and calls accept() on it; when a client connects, accept() returns a socket that is normally handed to a different thread (details omitted):

Socket socket = serverSocket.accept();
threadPool.execute(new Handler(socket));

class Handler implements Runnable
{
private final Socket socket;
Handler(Socket socket) { this.socket = socket; }
public void run()
{
Socket currentSocket = this.socket;
while (isConnectionOpen(currentSocket))
{
String message = readMessage(currentSocket);
if (upgradeToSSL(message))
{
SSLSocketFactory sslSocketFactory =
(SSLSocketFactory)SSLSocketFactory.getDefault();
SSLSocket sslSocket =
(SSLSocket)sslSocketFactory.
createSocket(currentSocket,
currentSocket.getInetAddress().getHostAddress(),
currentSocket.getPort(),
false);
sslSocket.setUseClientMode(false);
sslSocket.startHandshake();
currentSocket = sslSocket;
}
else if (downgradeFromSSL(message))
{
currentSocket.close();
currentSocket = this.socket;
}
else
{
handleNormalMessage(currenSocket, message);
}
}
}
}

When upgrading, the server wraps the current (plain) socket using SSLSocketFactory.createSocket(socket, address, port, autoClose), then configures the SSLSocket to be a non-client one (for the purposes of the SSL handshake), then starts the SSL handshake to secure the connection.

When downgrading, the current (ssl) socket is just closed and, thanks to the autoClose argument set to false (which will not close the underlying plain socket), the original plain socket is still operative.

In order for this mechanism to work, you have to configure the SSL details as usual for a server. This means having created a private/public key pair in a keystore (and optionally having signed the public key with a CA root) and having set the relevant SSL system properties (or having done the equivalent using the SSL APIs).

The client


The client connects to the server using a plain Socket, then upgrades the socket connection (details omitted):

// Connects to server
this.socket = new Socket(serverAddress, serverPort);
...
Socket currentSocket = this.socket;
while (moreMessagesToSend)
{
if (upgradeToSSL)
{
SSLSocketFactory sslSocketFactory =
(SSLSocketFactory)SSLSocketFactory.getDefault();
SSLSocket sslSocket =
(SSLSocket)sslSocketFactory.
createSocket(currentSocket,
currentSocket.getInetAddress().getHostAddress(),
currentSocket.getPort(),
false);
sslSocket.setUseClientMode(true);
sslSocket.startHandshake();
currentSocket = sslSocket;
}
else if (downgradeFromSSL)
{
currentSocket.close();
currentSocket = this.socket;
}

sendMessage(currentSocket);
readReply(currentSocket);
}

Upgrading and downgrading the socket connection in the client works like in the server code, the only difference being that the SSLSocket is configured to be a client one (for the purposes of the SSL handshake). The autoClose argument prevents the original plain socket to be closed when the SSL socket is closed.

In order for this mechanism to work, you have once again to configure the SSL details as usual for a client. This means having setup properly a trust store (and optionally having imported into it the server certificate if it's not signed by a CA root) and having set the relevant SSL system properties (or having done the equivalent using the SSL APIs).

If you're writing custom network protocols that require confidentiality, the above may come handy. Enjoy !

Labels: , ,

Monday, January 01, 2007

UTF-8 handling for ResourceBundle and Properties

Every new version of the JDK comes with small improvements, often unnoticed, that however correct long-standing bugs or request for enhancements.

One such improvements is - finally! - the ability for java.util.Properties to handle non ISO-8859-1 properties files.
At first seems like a very small improvement, but anyone that worked on localizing an application (for example translating messages into a country specific language) knows that encoding problems are just painful, and that is far too easy to waste days trying to get them right.

JDK 5 added a new API, namely Properties.loadFromXML(InputStream), that allowed to specify properties using an XML syntax, and hence to specify the encoding of the XML file in the XML declaration (the first line of an XML file):

<?xml version="1.0" encoding="UTF-8" ?>
<properties>
<entry key="hello.world">Καλημέρα κόσμε</entry>
</properties>

JDK 6 went further, adding Properties.load(Reader): in case the encoding is known a priori by the program, it is possible to create a Reader that uses the specific encoding to read the properties file.

However, in JDK 5, java.util.ResourceBundle was only able to read properties files that were encoded in ISO-8859-1, and this forced the translators to put horrible unicode escapes instead of real text. Following the above example, in JDK 5 you have to write the properties file containing translations like this:

hello.world=\u039A\u03B1\u03BB\u03B7\u03BC\u03AD\u03C1\u03B1 \u03BA\u03CC\u03C3\u03BC\u03B5

Pretty ugly, especially when you think that the API to read properties file in XML format is already present in JDK 5, only that ResourceBundle has not been updated to use it.

Fortunately, with JDK 6 it is possible to solve this problem, although requires a bit of coding (see below).

In JDK 6 ResourceBundle has been extended to give the user more control on how to load resources, by subclassing ResourceBundle.Control, and passing an instance of the ResourceBundle.Control subclass like this:

ResourceBundle bundle = ResourceBundle.getBundle("messages", new MyControl());

where MyControl is the ResourceBundle.Control subclass.
The class ResourceBundle.Control allows to tune:
  • the kind of resource to load (a Java class, a properties file, a properties file in XML format, or any other format you decide)

  • the policy of expiration of the resource, thus allowing reload the resource upon some condition

  • the ResourceBundle subclass to instantiate, normally depending on the kind of resource

Here's the JDK 6 class that allows to load XML properties files as resource bundles.

/**
* JDK 6's {@link ResourceBundle.Control} subclass that allows
* loading of bundles in XML format.
* The bundles are searched first as Java classes, then as
* properties files (these two methods are the standard
* search mechanism of ResourceBundle), then as XML properties
* files.
* The filename extension of the XML properties files is assumed
* to be *.properties.xml
*/
public class ExtendedControl extends ResourceBundle.Control
{
private static final String FORMAT_XML_SUFFIX = "properties.xml";
private static final String FORMAT_XML = "java." + FORMAT_XML_SUFFIX;
private static final List<String> FORMATS;
static
{
List<String> formats = new ArrayList<String>(FORMAT_DEFAULT);
formats.add(FORMAT_XML);
FORMATS = Collections.unmodifiableList(formats);
}

@Override
public List<String> getFormats(String baseName)
{
return FORMATS;
}

@Override
public ResourceBundle newBundle(String baseName, Locale locale,
String format, ClassLoader loader,
boolean reload)
throws IllegalAccessException, InstantiationException, IOException
{
if (!FORMAT_XML.equals(format))
return super.newBundle(baseName, locale, format, loader, reload);

String bundleName = toBundleName(baseName, locale);
String resourceName = toResourceName(bundleName, FORMAT_XML_SUFFIX);
final URL resourceURL = loader.getResource(resourceName);
if (resourceURL == null) return null;

InputStream stream = getResourceInputStream(resourceURL, reload);

try
{
PropertyXMLResourceBundle result = new PropertyXMLResourceBundle();
result.load(stream);
return result;
}
finally
{
stream.close();
}
}

private InputStream getResourceInputStream(final URL resourceURL,
boolean reload)
throws IOException
{
if (!reload) return resourceURL.openStream();

try
{
// This permission has already been checked by
// ClassLoader.getResource(String), which will return null
// in case the code has not enough privileges.
return AccessController.doPrivileged(
new PrivilegedExceptionAction<InputStream>()
{
public InputStream run() throws IOException
{
URLConnection connection = resourceURL.openConnection();
connection.setUseCaches(false);
return connection.getInputStream();
}
});
}
catch (PrivilegedActionException x)
{
throw (IOException)x.getCause();
}
}

/**
* ResourceBundle that loads definitions from an XML properties file.
*/
public static class PropertyXMLResourceBundle extends ResourceBundle
{
private final Properties properties = new Properties();

public void load(InputStream stream) throws IOException
{
properties.loadFromXML(stream);
}

protected Object handleGetObject(String key)
{
return properties.getProperty(key);
}

public Enumeration<String> getKeys()
{
final Enumeration<Object> keys = properties.keys();
return new Enumeration<String>()
{
public boolean hasMoreElements()
{
return keys.hasMoreElements();
}

public String nextElement()
{
return (String)keys.nextElement();
}
};
}
}
}

Labels: ,