Category Archives: Java

CORS Filter with improved performance

CORS FilterThe new 2.5 release of the CORS Filter for handling cross-domain requests offers improved performance. This benefits Java web servers that handle lots of traffic, particularly situations when a significant proportion of that is invalid or unauthorised CORS requests.

The improvement is achieved by using static (cached) exceptions within the filter. Here is an an informative discussion with metrics about Java exception handling and how it can be sped up.

The 2.5 release also fixes a NPE bug affecting Origin validation during configuration.

CORS Filter with automatic reconfiguration

CORS FilterVersion 2.4 of the Java CORS Filter for handling cross-domain requests has added support for automatic reconfiguration. You can change your CORS policy at runtime without having to reload your web service or application. Kudos to Alexey Zvolinsky for contributing this cool new feature.

Automatic reconfiguration is provided by a special variant of the CORS Filter. Stick the following declaration into your web.xml file to use it:

<filter>
	<filter-name>CORS</filter-name>
	<filter-class>com.thetransactioncompany.cors.autoreconf.AutoReconfigurableCORSFilter</filter-class>
</filter>

This filter variant must be configured with an external Java properties file. The filter init-param style configuration will not work here as the web.xml file may not be modified at runtime.

The configuration file will be polled for changes every 20 seconds. If a change is detected the filter will automatically reload itself with the new configuration. If the new configuration is invalid an error message will be printed to the server log and the filter will continue operating with its previous intact settings.

Check out the CORS Filter docs for the complete instructions on setting up automatic reconfiguration.

Finding the most efficient Java ObjectOutput method for strings

Coding distributed services and apps often calls for marshalling Java objects into a binary form that can be streamed over the network. Infinispan, for example, requires objects to be serialised so they can be multicast to the nodes of the data grid.

The standard Java serialisation implementation packs a lot of object data in order to be able to automatically reproduce an object upon deserialisation. Devising your custom serialiser can save a lot of bytes, as the following snippet demonstrates:

// Serialise a date object
Date now = new Date();

// As object
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutput oout = new ObjectOutputStream(bout);
oout.writeObject(now);
oout.flush();
System.out.println("Date writeObject length: " + bout.toByteArray().length);

// As long representation
bout = new ByteArrayOutputStream();
oout = new ObjectOutputStream(bout);
oout.writeLong(now.getTime());
oout.flush();
System.out.println("Date writeLong length: " + bout.toByteArray().length);

Running the above code produces the following result:

Date writeObject length: 46
Date writeLong length: 14

Amazing, converting the Date object to its long representation results in a three-fold saving. For every 1 million transmitted Date objects that means a difference of 32 Mbytes.

The conclusion is clear: custom serialisers make sense. They can reduce network traffic and speed up the overall responsiveness of your distributed service or app.

Developers are typically given the standard DataOutput interface to implement their custom serialisers. This is true for Infinispan, JBoss Marshalling, and probably other frameworks too. Use of the DataOutput interface is straightforward – you just have to pick the correct method for the data type that you wish to marshal. For serialising strings, however, there are three methods provided:

  • DataOutput.writeUTF(String)
  • DataOutput.writeBytes(String)
  • DataOutput.writeChars(String)

Let’s find out which one is the most efficient:

String s = "The quick brown fox jumps over the lazy dog";

ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutput oout = new ObjectOutputStream(bout);
oout.writeUTF(s);
oout.flush();
System.out.println("writeUTF length: " + bout.toByteArray().length);

bout = new ByteArrayOutputStream();
oout = new ObjectOutputStream(bout);
oout.writeBytes(s);
oout.flush();
System.out.println("writeBytes length: " + bout.toByteArray().length);

bout = new ByteArrayOutputStream();
oout = new ObjectOutputStream(bout);
oout.writeChars(s);
oout.flush();
System.out.println("writeChars length: " + bout.toByteArray().length);

bout = new ByteArrayOutputStream();
oout = new ObjectOutputStream(bout);
oout.writeObject(s);
oout.flush();
System.out.println("writeObject length: " + bout.toByteArray().length);

Running the above produces the following:

writeUTF length: 51
writeBytes length: 49
writeChars length: 92
writeObject length: 50

The writeUTF and writeBytes methods output similar byte lengths. Surprisingly so does writeObject. This could be due to Java treating strings in writeObject in a optimised way. writeChars however produces a byte output that is almost twice as long.

The conclusion is that for strings you could use any of the available methods, but stay clear of writeChars.

Happy coding! πŸ™‚

CORS Filter 1.7 with more configuration options

CORS FilterThe Java servet filter for enabling CORS (cross-domain) web applications received a major upgrade today.

Up until now in order to change the out-of-the-box CORS configuration you had to add filter init-params in the web.xml descriptor of your application. A number of developers asked for alternative configuration means, such as specifying a properties file for the configuration. This is now supported.

The CORS Filter will now apply the following precedence when resolving the configuration:

  1. Checks for an environment variable “cors.configurationFile” pointing to a properties file with the CORS configuration.
  2. Checks for a servlet filter init-param “cors.configurationFile” pointing to a properties file with the CORS configuration.
  3. Checks for CORS params in filter init section, applies the default values if not found.

Another important configuration change is the ability to specify a general “allow-any-request-header” policy by setting the cors.supportedHeaders to an asterisk.

Handling of same-domain requests that carry a redundant Origin header (set by some Javascript frameworks) is fixed too.

Thanks to David Bellem, Stijn Cremers and Casey Lucas for initiating this new release of the CORS Filter. Also thanks to Anne van Kesteren for answering my CORS-related query on the W3C list.

CORS Filter 1.6 supports any URI scheme

CORS FilterThe Java CORS Filter for adding Cross-Origin Resource Sharing to existing web apps received an important update to permit any URI scheme, not just the ubiquitous http:// and https:// as originally supported. This change is in line with RFC 6454 which defines the concept of web origins.

This means that now you can also service CORS requests for “custom” schemes as app://, fb:// , etc.

The new CORS Filter release should reach Maven Central later today. You can also get it from the CORS Filter Git repo at Bitbucket.

Cheers to EdraΓ­ Brosa for initiating this important change!

 

All JSON-RPC 2.0 libraries are now in Maven Central

masthead-jsonrpc2baseThe migration from Ant to Maven is now complete and all Java libraries for handling JSON-RPC 2.0 messages are now published in Maven Central.

You can find them under the com.thetransactioncompany.com groupId:

The useful JSON-RPC 2.0 Shell tool, available for purchase, has also been completely mavenised. It has found a lot of use in Android development recently and there have been plans to add HTTP basic authentication support to it (via a prompt).

JSON-RPC 2.0 libraries and tools switch to Maven

masthead-jsonrpc2baseThe Java libraries and tools for JSON-RPC 2.0 message serving and processing now use Apache Maven to build.

Migrating the previous Apache Ant scripts took about a day a to complete and was not without hassles, notable the ZIP package distribution and the automatic versioning of JavaDocs. We’ll now be able to gain from Maven’s automatic dependency resolution and I have gained enough knowledge to begin considering myself a Maven power user πŸ™‚

The following related JSON-RPC 2.0 projects also got a Maven make-over:

Publishing to Maven Central is on the to-do list complete now πŸ™‚

The JSON-RPC 2.0 Client can now handle GZIP and DEFLATE compression

Does your JSON-RPC server return large amounts of data? If so applying HTTP response compression can greatly reduce network traffic and response time, occasionally by a whole magnitude if your JSON structures contain long repeating keys or values.

Today we released a new version of the JSON-RPC 2.0 Client library for Java that adds support for GZIP and DEFLATE compression. These two algorithms are commonly implemented by web servers such as Apache HTTPD and Apache Tomcat.

To enable HTTP response compression in your Java client app:

URL serverURL = new URL("http://example.com/jsonrpc2/");

JSONRPC2Session mySession = new JSONRPC2Session(serverURL);

mySession.getOptions().enableCompression(true);

The JSON-RPC client will then set the Accept-Encoding request header to signal that it can process compressed responses. Note that many web servers don’t have HTTP compression enabled by default so this setting will simply be ignored by them.

To enable compression in Apache Tomcat you need to configure the HTTP connector by setting compression to “on”.

The JSON-RPC client will then automatically decompress the HTTP responses before processing the JSON payload.

The new version of the JSON-RPC client library also improves HTTP cookie support. It has dropped the primitive internal cookie store in favour of the standard java.net.CookieManager so now cookie expiration and replacement are also handled.

Opera finally with CORS support

Opera was the last major browser to add support for handling cross-origin requests in its 12th version. The CORS protocol was devised several years ago by a W3C working group to allow for clean making of cross-domain XHR, without JSONp hacks. CORS was initially adopted by Firefox and Chrome, and was subsequently joined by the other major players, such as Microsoft’s Internet Explorer.

Today more than 85% of the browsers on the web support CORS and an increasing number of developers are starting to use the protocol, judging by downloads of our CORS Filter package which allows CORS support to be easily retrofitted to any Java web app or service. When the new Opera 12 appeared the CORS Filter was successfully tested under it.

Thanks to Joost Cassee the CORS filter is now also available on Maven.

Access filters for JSON-RPC 2.0 services

Services on the web often have to be controlled for who and how accesses them. If they deal with sensitive data, such as usernames and passwords, you may want to ensure that all requests come in over encrypted HTTPS. If you’re running a private service, you may want to ensure that only selected internet hosts can make use of it. Or you may want to limit access to portions of the web API, such as administration, to selected users and clients.

For this purpose I created an Access Filter package for JSON-RPC 2.0 services. Today I released it to the public in its stable 1.1 version under a generous Apache 2.0 licence. I wanted filtering to be fast and robust, so the package was designed to be as simple and efficient as possible. It also nicely complements the proven Java libraries JSON-RPC 2.0 Base and JSON-RPC 2.0 Server.

The package defines four basic filters:

  • HostFilter Access filter ensuring JSON-RPC 2.0 requests originate from selected host names / IP addresses.
  • HTTPSFilter Access filter ensuring requests are passed over HTTPS.
  • X509ClientCertFilter Access filter ensuring HTTPS requests carry an X.509 client certificate with optional specified principal (subject DN).
  • APIKeyFilter Access filter ensuring clients present an API key for protected JSON-RPC 2.0 request methods.

There is a ready CompositeFitler which combines these four basic filters into a chain. You can then plug this filter chain into your JSON-RPC 2.0 service and call it prior to passing the incoming requests to the actual execution logic.

The CompositeFilter can be configured with a simple properties text file. The properties format is detailed in the JavaDocs for the CompositeFilterConfiguration class.

access.https.require=true
access.https.requireClientCert=true
access.https.clientCertPrincipal=cn=John Doe,ou=people,cd=company,dc=org
 
access.hosts.allow=*
 
access.apiKeys.require=true
access.apiKeys.exemptedMethods=ws.getName ws.getVersion ws.getTime
access.apiKeys.map.f70defbe-b881-41f8-8138-bea52b6e1b9c=sso.login sso.logout sso.getSession
access.apiKeys.map.08d1e641-b1c1-4d88-8796-e47c06430efb=sso.proxiedLogin sso.proxiedLogout sso.getSession
access.apiKeys.map.d881afe0-4d7d-4520-9fda-bffffc3022ba=sso.userCount sso.sessionCount sso.listUsers

Alternatively, you may devise your own custom filter chain, based on the AccessFilterChain class.

How do you use the CompositeFitler?

// Parse config from properties, create composite filter
java.util.Properties props = ...
CompositeFilter filter = new CompositeFilter();
filter.init(new CompositeFilterConfiguration(props)); 

// Invoke the filter for each incoming JSON-RPC 2.0 request

// Parse JSON-RPC 2.0 request
JSONRPC2Request request = JSONRPC2Request.parse(...);

// Set the message context, i.e. client host IP, etc.
MessageContext mctx = new MessageContext(...);

// Call the filter
AccessFilterResult result = filter.filter(request, mctx);

if (result.accessAllowed()) {
    // Continue with request processing...

}
else {
    // Return specified access denied JSON-RPC 2.0 error
    // to the calling client
    JSONRPC2Error error = result.getAccessDeniedError().toJSONRPC2Error();
}

The Access Filter package is available at Bitbucket: https://bitbucket.org/vdzhuvinov/access-filter/

We plan to integrate into the upcoming new releases of the Json2Ldap, NimbusSSO and AuthService web services from NimbusDS software.

If you have comments of feedback to share, get in touch or leave a ticket at the Bitbucket repo.