Archive

Archive for the ‘java’ Category

Custom URL protocols and multiple classloaders

December 12th, 2009

In the introduction to Spring’s Resources, the following is mentioned in reference to the standard java.net.URL:

While it is possible to register new handlers for specialized URL prefixes (similar to existing handlers for prefixes such as http:), this is generally quite complicated, and the URL interface still lacks some desirable functionality, such as a method to check for the existence of the resource being pointed to.

Whilst I don’t disagree on the need for a simpler resource abstraction, I do think that the statement misses the key point that the URL protocol extension mechanism does not work well in multiple classloader environments (e.g. Webapps and OSGI bundles), hence I thought I would write this blog entry to explain:

  • The way custom URL protocol handlers are registered.
  • Why the extension mechanism does not work well with multiple classloaders.

Registering a custom URL protocol handler

To register a custom URL protocol handler the following needs to be done:

  1. Provide a concrete implementation for URLStreamHandler.
  2. Provide a concrete implementation for URLConnection.
  3. Name your URLStreamHandler class Handler and put it in a special package.

The following code illustrates a protocol called user, which will treat all file paths relative to the user’s home directory:

 
package sun.net.www.protocol.user;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
public class Handler extends URLStreamHandler {
  @Override
  protected URLConnection openConnection(URL url) throws IOException {
    return new UserURLConnection(url);
  }
  private static class UserURLConnection extends URLConnection {
    private String fileName;
    public UserURLConnection(URL url) {
      super(url);
      fileName = url.getPath();
    }
    @Override
    public void connect() throws IOException {
    }
    @Override
    public InputStream getInputStream() throws IOException {
      File absolutePath = new File(System.getProperty("user.home"), fileName);
      return new FileInputStream(absolutePath);
    }
  }
}

Note that the package is sun.net.www.protocol.user and the class is called Handler. The extension mechanism requires you to call your class Handler and put it in a subpackage that is your protocol name. The parent package can be arbitrary however by default sun.net.www.protocol will be searched. If you wish to use your own parent package you must also provide a system property called java.protocol.handler.pkgs which lists your package name (e.g. uk.co.cooljeff.protocol.user).

The following test case illustrates how the customer user protocol can be used:

 
public class URLTest {
  @Test
  public void testUserProtocol() throws Exception {
    URL url = new URL("user:.profile");
    InputStream ins = url.openStream();
    assertNotNull(ins);
    ins.close();
  }
}

This is all that needs to be done which I found pretty simple to do. The hardest bit was finding the documentation. Unfortunately the documentation for the extension mechanism is found on one of the java.net.URL constructors and not in the class level documentation for URL or the package documentation for java.net.

Multiple classloaders and custom URL protocol handlers

The custom user protocol described in the previous section works without any issue in an Eclipse project or in a vanilla standalone application. However if I were to supply my custom protocol in a web app deployed on tomcat, the following exception is likely to have been seen:

 
Caused by: java.net.MalformedURLException: unknown protocol: user
	at java.net.URL.(URL.java:574)
	at java.net.URL.(URL.java:464)
	at java.net.URL.(URL.java:413)
	at uk.co.cooljeff.protocol.user.URLTest.testUserProtocol(URLTest.java:12)
	. . . 5 more

To understand why, take a look at the logic used to locate custom protocols (found in URL.getURLStreamHandler(String)):

 
static URLStreamHandler getURLStreamHandler(String protocol) {
. . .
    String clsName = packagePrefix + "." + protocol + ".Handler";
    Class cls = null;
    try {
      cls = Class.forName(clsName);
    } catch (ClassNotFoundException e) {
      ClassLoader cl = ClassLoader.getSystemClassLoader();
      if (cl != null) {
        cls = cl.loadClass(clsName);
      }
    }
    if (cls != null) {
      handler  = (URLStreamHandler)cls.newInstance();
    }
. . .

You will notice that Class.forName() is used. The issue here is that the classloader that will be used is the classloader of the calling class. The calling class in this instance is URL. Hence if URL is loaded in a parent classloader of where the custom protocol is, it won’t be found. This is why custom URL protocols have to be put on the web containers classpath rather than being bundled in the web app that uses it.

Conclusion

The URL protocol extension mechanism is fundamentally flawed when it comes to multi classloader environments such as OSGI and Webapp containers. The registration mechanism does not work because in such environments, the URL class itself is likely to be in a parent classloader of the custom protocol, resulting in the custom protocol not being visible to the registration logic. In addition there is no standardization for the default package structure for where additional protocols should be found. This leads to either a non portable solution across JVMs or the need to use system properties which are not that friendly in enterprise web app containers.

Resources

java

Garbage collection of the permanent generation (permgen)

November 1st, 2009

There is often confusion around what the permanent generation contains and given its name, whether or not it can be garbage collected. To cut a long story short, the permanent generation can be garbage collected and is where reflective class meta data, as well as string constants are stored.

This blog entry takes a practical approach to answer the following questions:

  • Can the permanent generation be garbage collected?
  • Does the value of -Xmx (the maximum heap size) include the permanent generation?

Can the permanent generation be garbage collected?

Yes it can. There is often the misconception that string constants cannot be garbage collected. However the only requirement that the JVM specification stipulates is that identity comparison works for constant string values. There is no requirement that the constant be the same object throughout the lifetime of the JVM. Hence if there are no references left to a string constant, there is no reason why it cannot be garbage collected.

To prove this take the following code:

 
public class PermGenDemo {
  public static void main(String[] args) {
    int i = 0;
    while (true) {
      ("string-" + ++i).intern();
    }
  }
}

If the above code is run using the following command:

 
$ java -verbose:gc -XX:PermSize=8m -XX:MaxPermSize=64m PermGenDemo

The following output will be seen (note output cut for brevity):

 
[Full GC [PSYoungGen: 32K->0K(28928K)] . . . [PSPermGen: 65535K->6461K(65536K)]]
[Full GC [PSYoungGen: 32K->0K(31168K)] . . . [PSPermGen: 65535K->6461K(65536K)]]

The above conclusively shows that the permanent generation is collected and when it requires collecting, triggers a full collection.

Does the value of -Xmx (the maximum heap size) include the permanent generation?

No it does not. The size of the permanent generation is controlled by the following JVM options:

* -XX:MaxPermSize controls the maximum permanent generation size.
* -XX:PermSize controls the initial permanent generation size.

The permanent generation is like any other generational compartment: it can grow to a maximum, technically can shrink and can also be garbage collected.

To demonstrate that the permanent generation is not included in the maximum heap settings, pmap can be used (e.g. by running pmap <pid> | tail -1).

The following table illustrates the output of pmap using different JVM heap and permanent generation settings:

JVM options pmap output
java -Xms256m -Xmx256m -XX:PermSize=64m -XX:MaxPermSize=64m 512204K
java -Xms512m -Xmx512m -XX:PermSize=64m -XX:MaxPermSize=64m 760556K
java -Xms512m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=128m 825188K

In the above -Xms=-Xmx and -XX:PermSize=-XX:MaxPermSize are set deliberately to stop the heap expanding and ensure constant results. The first value of 512204K gives us a base value which takes into account any overhead introduced by native libraries (including the jvm itself) being mapped into memory. The second value of 760556K is an exact increase of 256m, which is exactly how much the heap was increased by. The third value of 825188K is an exact increase of 64m, which is exactly how much the permanent generation was increased by.

The above results clearly show that the settings for permgen are unrelated to that of the heap.

Conclusion

  • The permanent generation can be garbage collected like other generations.
  • The permanent generation is additional memory to the java heap.
  • -XX:MaxPermSize controls the maximum memory used by the permanent generation.
  • -XX:PermSize controls the initial memory used by the permanent generation.

Resources

  1. Java Hotspot VM Options
  2. Presenting the Permanent Generation

java , ,

Handling native dependencies with Apache Ivy

August 1st, 2009

Being able to handle native dependencies with Ivy has cropped up a couple of times with no best practise solution being available. This blog entry discusses the various proposals that have been put forward in order to provide a solution that:

  1. Works with Ivy Ant tasks in order to help populate the java.library.path.
  2. Works with IvyDE in order to populate the Native Library Location of a classpath entry.
  3. Is able to deal with different platforms.
  4. Is suitable for building enterprise repositories in order to download by platform.

It is important to remember that the concept of a platform constitutes a permutation of various components not limited to Operating System and Endianess. A good example would be the C libraries available from the NAG (Numeric Algorithms Group) which have distributions that take into account the compiler version to. Occasionally you even see JARs being distributed by platform (e.g. IBM’s Java MQ Series Client), which although is arguably a bad practise, does happen and Ivy needs to be able to handle these edge cases. Having said this, in this blog entry I will only take into account Windows/Linux and 32-bit/64-bit combinations for brevity.

The following proposals are explored (from least to most favourite):

  • Using configurations to declare native artifacts.
  • Using the extra attribute to declare a JNI path.
  • Using types to declare native artifacts.
  • Using types and a platform attribute to declare native artifacts.

Using configurations to declare native artifacts

This solution would look as follows:

 
<ivy-module version="2.0">
  <info organisation="mit" module="kerberos" revision="1.7.0" />
  <configurations>
    <conf name="ia32.linux" description="32-bit linux native dependencies"/>
    <conf name="ia64.linux" description="64-bit linux native dependencies"/>
    <conf name="ia32.windows" description="32-bit windows native dependencies"/>
  </configurations>
  <publications>
    <artifact name="kerb5_lib" type="native" ext="so" conf="ia32.linux"/>
    <artifact name="kerb5_lib" type="native" ext="so" conf="ia64.linux"/>
    <artifact name="kerb5_lib" type="native" ext="dll" conf="ia32.windows"/>
  </publications>
</ivy-module>

Here we are using configurations to declare artifacts by platform. Something depending on this module would then explicitly depend on a specific platform through a configuration.

This solution has the following issues:

  1. Switching between platforms requires updates to Ivy files.
  2. Switching between platforms is not really possible for a transitive dependency.
  3. IvyDE does not support filtering by configuration (only by types).
  4. Repository structuring information is now in the dependency hierarchy.

Switching between platforms is a big issue here because we are abusing what configurations are designed for. A configuration is a way of using a module, not for describing what an artifact actually is. This is why you don’t see configurations labeled: jars, javadocs or source. Whilst I have to admit that I’ve not tried implementing this solution, I cannot see how it can work when resolving native dependencies transitively. Perhaps some conf mapping trickery could be used.

The owner of a 3rd party Ivy module (i.e. one found in some repository) does not know about the environment you are going to be working in. Hence if that module itself has native dependencies, the owner of the module would not be able to say which configuration to depend on when writing the ivy module, even though it clearly has a native dependency.

Even for the end user who does have a little more control over the configurations they directly pull in, you would not be able to switch between environments without updating the configurations you depend on. Being able to switch between environments is a common use case. Many people develop on Windows and deploy on Linux. The Ivy module should remain identical for both environments because in most use cases, the logical dependency stays the same. What changes is the physical artifact.

Finally, many shared libraries have the same file name for both 32-bit and 64-bit distributions. This means that you are going to have to use the configuration as a directory name to structure your repository, which is not ideal because repository structuring information is now directly in the dependency hierarchy that a user will use.

Using the extra attribute to declare a JNI path

This solution would look as follows:

 
<ivy-module version="2.0" xmlns:extra="http://ant.apache.org/ivy/extra">
  <info organisation="mit" module="kerberos" revision="1.7.0"
              extra:jni="native/lib" />
</ivy-module>

Here we are using the ability to add additional custom attributes to the info element in order to describe where the native libraries can then be found. An Ivy trigger would then need to be implemented by the Ant build infrastructure to detect module resolution in order to pick up the extra attribute and populate the java.library.path correctly.

This was proposed by Arthur Branham on a comment to his JIRA requesting Ivy to support native library path construction [IVY-600]. This is something that I’ve actually seen implemented as a quick solution to get over native library dependency issues when running integration tests as part of a build using Ant.

This solution has the following issues:

  1. Resolving for different platforms cannot be done using the same Ivy file.
  2. Resolving for a specific platform against a remote repository is not possible.
  3. IvyDE does not have support for extra attributes.

In order to support multiple platform resolution, you need to allow the attribute to have tokens that the resolver is capable of substituting. Even then, whilst this works for a local file system, it does not help when dealing with an external repository on the web because Ivy will need to download the artifacts into the cache for local use. With this solution there are no native artifacts, the repository structure is instead pushed into the ivy module file which ideally should remain in the ivy settings file.

Using types to declare native artifacts

This solution would look as follows:

 
<ivy-module version="2.0">
  <info organisation="mit" module="kerberos" revision="1.7.0" />
  <configurations>
    <conf name="runtime" description="Core runtime dependencies" />
  </configurations>
  <publications>
    <artifact name="kerb5_lib" type="ia32.linux" ext="so" conf="runtime" />
    <artifact name="kerb5_lib" type="ia64.linux" ext="so" conf="runtime" />
    <artifact name="kerb5_lib" type="ia32.windows" ext="dll" conf="runtime" />
  </publications>
</ivy-module>

Here we are using the type to provide the platform information. To switch between platforms, you simply need to filter by type when performing an Ivy Retrieve or Ivy Cache Path to match the platform you wish to resolve by.

This solution has the following clear advantages:

  1. The supported platforms are clearly stated in the Ivy module descriptor.
  2. Repository structuring has not leaked into the dependency information.
  3. Types fit in well with IvyDE which already uses types for javadocs and source.
  4. Types are already used by default to segregate artifacts in a cache.

This solution has the following issue:

  1. The type can no longer be used for other platform specific artifacts.

The concern I have with this solution is that we are not really using the type for its intended usage. This can result in blocking the use of other artifacts which are associated to the same platform but not associated to the java.library.path.

Imagine if you have jar file which is platform specific but still goes onto the classpath. As mentioned in the introduction, distributions of the IBM Java MQ Series Client have slightly different jars for each platform. For this use case you would still expect the type to be jar, since this is the type you will filter on when populating the classpath using the cachepath ant task. Similarly take a repository that has scripts or executables available for download by platform, you would expect the types to be scripts or exe respectively.

If we were to take a step back, forget what we are trying to solve and use the type classification for its intended usage, we probably would have named the type for native library dependencies to go on the java.libary.path as type=”library”.

Using types and a platform attribute to declare native artifacts

This solution would look as follows:

 
<ivy-module version="2.0">
  <info organisation="mit" module="kerberos" revision="1.7.0" />
  <configurations>
    <conf name="runtime" description="Core runtime dependencies" />
  </configurations>
  <publications>
    <artifact name="kerb5_lib" type="library" ext="so" platform="ia32.linux"
              conf="runtime" />
    <artifact name="kerb5_lib" type="library" ext="so" platform="ia64.linux"
              conf="runtime" />
    <artifact name="kerb5_lib" type="library" ext="dll" platform="ia32.windows"
              conf="runtime" />
  </publications>
</ivy-module>

This solution has the same benefits as using the type alone to define the platform information, however it does not have the same disadvantage of blocking other platform specific artifacts that are unrelated to the java.library.path from using the same type name. To integrate the above solution into Ivy the following would need to be done:

  1. IvyDE would need to support a Native Library Type (default to library).
  2. IvyDE would need to support a Platform.
  3. IvyDE would need to populate the Native Library Location of a classpath entry.
  4. Ivy would need to support platform as a filter option in retrieve and cachepath.
  5. Ivy would need to allow the user to set the platform easily in the Ivy settings.

When populating the Native Library Location IvyDE will need to create a directory tree to all of the artifacts and then remove all duplicate paths.

Conclusion

Handling native library dependencies is a gap in Ivy that will begin to impact enterprise users who have some native dependencies. Whilst types alone could be used to solve the problem, this potentially blocks using Ivy to resolve other platform specific dependencies that are not associated with the java.libary.path. The neatest solution would be to use type=”library” to group artifacts that are intended for the java.libary.path, along with a new attribute called platform. This solution will allow repositories to be structured well with platform specific information and also allow clients to resolve dependencies easily, regardless of the environment they happen to be currently working in.

Resources

  1. Official Apache Ivy website
  2. JNI and Endorsed directories ivy user mail thread
  3. Add ability to construct a native library path based on dependencies JIRA

java

The subtleties of overriding package private methods

May 3rd, 2009

The Java Language comes with several modifiers for controlling access to methods: public, private, protected and package private.

In general we assume the following rules govern these access modifiers:

  • A public method can be accessed by any other method.
  • A private method can only be accessed by the class that it is declared in.
  • A protected method can be accessed by any class in the same package or any subclass.
  • A package private method can be accessed by any class in the same package.

The above would be accepted as suitable answers at most interviews, however there are some subtleties seen in the behaviour of package private that cannot be explained using this simple definition alone.

Take the following piece of code that represents a Square:

 
package uk.co.cooljeff.access;
public class Square {
  private float length;
  public Square(float length) {
    this.length = length;
  }
  public float calculateArea() {
    return length * length;
  }
  String getColour() {
    return "Red";
  }
}

Take the following piece of code that represents a CustomSquare:

 
package uk.co.cooljeff.access;
import uk.co.cooljeff.access.Square;
public class CustomSquare extends Square {
  public CustomSquare() {
    super(5);
  }
  @Override
  String getColour() {
    return "Blue";
  }
}

From the simple definition of package private above, we would expect the following piece of code to print out Blue as the colour of CustomSquare:

 
public class Printer {
  public void print(Square square) {
    System.out.println("Square of type " + square.getClass()
                                   + " has colour " + square.getColour());
  }
  public static void main(String[] args) {
    Printer printer = new Printer();
    printer.print(new CustomSquare());
  }
}

For the majority of people who run the above code, indeed Blue is printed. However for one of my colleagues at work who tried to do something similar, Red was always observed.

To try to explain why Red is sometimes seen, we need to understand what the JVM is trying to do. If you decompile the Printer class you will see that the invokevirutal instruction is used to invoke the Square.getColour() method:

 
public void print(uk.co.cooljeff.access.Square);
  Code:
   25:	invokevirtual	#59; //Method uk/co/cooljeff/access/Square.getColour:()Ljava/lang/String;
   37:	return

For virtual methods, there is a lookup algorithm which is used to locate the exact method to invoke. Specifically the following is given for the invokevirtual instruction (paraphrasing):

Let C be the class of the target of the method invocation. The actual method to be invoked is selected by the following lookup procedure:

  • If C contains a declaration for an instance method M with the same name and descriptor as the resolved method, and the resolved method is accessible from C, then M is the method to be invoked, and the lookup procedure terminates.

Hence using this definition, I would expect that CustomSquare.getColour() would be considered since it matches the same name and descriptor as Square.getColour(). The question then becomes is this method accessible from Printer. To answer this we need to look at the Access Control (5.4.4) definition in the JVM Specification which states (paraphrasing):

A field or method R is accessible to a class or interface D if and only if any of the following conditions are true:

  • R is package private and is declared by a class in the same runtime package as D.

There is a subtlety here in that the phrase runtime package is used. At runtime a class is uniquely defined by its fully qualified name and its ClassLoader. The runtime package takes into account not only the compile time package but also the ClassLoader that loaded the class.

Taking the fact that the ClassLoader could have something to do with why Red is sometimes observed, lets redefine our Printer to load the CustomSquare in a different ClassLoader:

 
package uk.co.cooljeff.access;
import java.net.URL;
import java.net.URLClassLoader;
public class Printer {
  public void print(Square square) {
    System.out.println("Square of type " + square.getClass() + " has colour " + square.getColour());
  }
  public static void main(String[] args) throws Exception {
    // Path to a jar or classes containing CustomSquare.
    String customSquareURL = System.getProperty("customsquare.classpath");
    URL[] urls = new URL[] { new URL( customSquareURL ) };
    URLClassLoader loader = new URLClassLoader(urls);
    Class clazz = loader.loadClass("uk.co.cooljeff.access.CustomSquare");
    Printer printer = new Printer();
    printer.print((Square) clazz.newInstance());
  }
}

When CustomSquare is loaded by a different ClassLoader, the output is Red, which is what my colleague observed.

At this stage, although the behaviour is reproducible, it cannot be explained using the 2nd Edition of the JVM Specification alone. The specification clearly states in the definition of method resolution, that an IllegalAccessError should be thrown if the method is not accessible and the definition of accessibility clearly states that CustomSquare is not accessible. So why do we not get an IllegalAccessError in either Sun’s HotSpot JVM or IBM’s JVM?

The behaviour made sense to me because it provides a way to prevent hacks such as the one my colleague was attempting to do, however I could not prove it using the JVM Specification. It was time to call on the experts so I started a mailthread titled invokevirtual on package private override in different classloader on the hotspot-dev mailing list.

As it turns out there was an amendment made to the 2nd Edition of the JVM Specification relating to this behaviour which revises the definition of invokevirtual. Specifically it replaces the accessibility constraint in favour for an override constraint. Hence to explain the behaviour we don’t look at whether CustomSquare.getColour() is accessible, we need to determine if it overrides Square.getColour().

The answer to the override question is no, which explains why the behaviour is observed. However as pointed out on the HotSpot mail thread, I was not happy that the amendment to the JVM specification refered to a language definition (namely override). At the moment in order to explain the behaviour we need to use the revised definition of override in the Java Language Specification. This goes against the fundamental principle that the Java Virtual Machine Specification is decoupled from the Java Language Specification. This was acknowledged on the mailthread: Alex Buckley replied informing me that the 3rd edition of the JVM specification is independent of the Language specification. Specifically the 3rd edition (not publicly available yet) drops the chapter on the Java Programming Language Concepts entirely and gains a JVM specific definition of overrides.

So I’m happy now, I can explain the behaviour :)

I’d like to thank the following people who helped me understand the behaviour discussed in this blog entry: Karen Kinnear (Sun Microsystems), David Holmes (Sun Microsystems) and Alex Buckley (Sun Microsystems).

Resources:

java

Detecting all running JVMs

April 5th, 2009

Several well known JVM tools appear to be able to magically detect the Java processes running on a system. Good examples of this are: jps and Visual VM. As of Java 6 it is even possible to find out yourself which Java processes are running on the local machine that you have access to using the Dynamic Attach API. These APIs can be found in the tools.jar (JAVA_HOME/lib/tools.jar).

The following code illustrates how the Dynamic Attach API can be used to list all of the local virtual machine identifiers (which for the HotSpot VM map onto the JVM PID):

 
package uk.co.cooljeff.dynamicattach;
import java.util.List;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
public class JVMFinder {
  public static void main(String[] args) {
    List<VirtualMachineDescriptor> vmDescriptors = VirtualMachine.list();
    for (VirtualMachineDescriptor vmDescriptor : vmDescriptors) {
      System.out.println("Name: " + vmDescriptor.displayName()
                                                    + " PID: " + vmDescriptor.id());
    }
  }
}

The above gives the following output on my machine (cut out a few for brevity):

 
Name: uk.co.cooljeff.dynamicattach.JVMFinder PID: 21116

I’m about to spoil the fun now for those of you who were hoping to see some wacky OS dependent mechanism or hidden RMI registry for finding this information. The solution is quite simple, the JVM dumps a file containing performance data to a standard location which it uses to work out what JVMs are running on a host.

Specifically the performance data is for jvmstat, however it is this file that forms the basis of the Dynamic Attach implementation that HotSpot uses.

The following piece of code replicates what the LocalVmManager (part of jvmstat) does to locate running Java processes:

 
package uk.co.cooljeff.dynamicattach;
import java.io.File;
import java.io.FilenameFilter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import sun.jvmstat.perfdata.monitor.protocol.local.PerfDataFile;
public class JVMDataLocation {
  public static void main(String[] args) throws Exception {
    final Pattern filePattern = Pattern.compile(PerfDataFile.userDirNamePattern);
    final Matcher fileMatcher = filePattern.matcher("");
    FilenameFilter fileFilter = new FilenameFilter() {
      public boolean accept(File dir, String name) {
        fileMatcher.reset(name);
        return fileMatcher.matches();
      }
    };
    File[] files = new File(PerfDataFile.getTempDirectory()).listFiles(fileFilter);
    for (File file : files) {
      System.out.println("PerfDataDir: " + file);
    }
  }
}

Which gives the following on my machine:

 
PerfDataDir: /tmp/hsperfdata_root
PerfDataDir: /tmp/hsperfdata_tomcat55
PerfDataDir: /tmp/hsperfdata_jeffsinc

If you take a look at one of these directories you will find 1 file per Java process running by the specific user. The name of the file is the local virtual machine identifier (lvmid) which for HotSpot will correspond to the process id. If you run strings on the file you will see all of the properties relating to that JVM instance.

It is as simple as that, on Linux the JVM simply looks for all files that match: /tmp/hsperfdata_*/*.

Resources:

java , ,

Building the OpenJDK on Ubuntu 8.10

January 3rd, 2009

When I asked a colleague at work what I should do during my vacation, he said build the OpenJDK… so I did!

In hindsight, it would have been easier to have built IcedTea (RedHat’s OpenJDK hybrid) rather than Sun’s raw OpenJDK. However since I spent quite a bit of time setting up the environment I was determined to get it to build.

At a high level I did the following:

  • Downloaded the source (~ 85Mb): http://download.java.net/openjdk/jdk7/.
  • Downloaded the binary plugins (the bits of the OpenJDK that are yet to be open sourced).
  • Downloaded the dependencies.
  • Modified some environment variables.
  • Checked the environment is ok via the sanity script.
  • Made 1 change to the source code.
  • Made 1 change to the make compiler flags.
  • Ran the build.

The README file did not cover all of the dependencies needed to build the OpenJDK on Ubuntu, here is what worked for me:

  • sudo apt-get install build-essential
  • sudo apt-get install gawk
  • sudo apt-get install m4
  • sudo apt-get install libasound2-dev
  • sudo apt-get install libcupsys2-dev
  • sudo apt-get install sun-java6-jdk
  • sudo apt-get install x11proto-print-dev
  • sudo apt-get install libxp-dev
  • sudo apt-get install libfreetype6-dev
  • sudo apt-get install libxt-dev
  • sudo apt-get install libxtst-dev

The OpenJDK comes with a script (jdk/make/jdk_generic_profile.sh) to help set up your environment. The main updates I needed to make were:

  • The bootjdk variable which holds the folder name of your Java 6 install.
  • The jdk_instances variable which holds the parent directory of your bootjdk.
  • The binplugs variable which holds the location of the non open source bits of the OpenJDK.
  • Ensure ANT_HOME was exported.
  • Ensusre ANT_HOME/bin was on the PATH.

You can see my full environment here: jdk_generic_profile.

The environment was then verified using the sanity make target:

 
$ . jdk/make/jdk_generic_profile.sh
$ make sanity

Once this passed I tried building but got a couple of errors.

The first error was:

 
/openjdk/hotspot/src/share/vm/libadt/port.hpp:
In function 'void bcopy(const void*, void*, size_t)':
/openjdk/hotspot/src/share/vm/libadt/port.hpp:40:
error: 'void bcopy(const void*, void*, size_t)' redeclared inline
without 'gnu_inline' attribute
/usr/include/bits/string3.h:90:
error: 'void bcopy(const void*, void*, size_t)' previously defined here
make[6]: *** [incls/_precompiled.incl.gch] Error 1

I understand what the error means but I could not work out why the error occurs because after looking through /usr/include/string.h, the include of /usr/include/bits/string3.h is only done if the user specifies _FORTIFY_SOURCE which as far as I can tell is not done in the OpenJDK. My workaround is quite simple, I commented out the redeclaration of inline void bcopy(const void*, void*, size_t) since it appears to already be inlined somehow.

The second error was:

 
/openjdk/hotspot/src/share/vm/runtime/arguments.cpp:
In static member function 'static void Arguments::set_aggressive_opts_flags()':
/openjdk/hotspot/src/share/vm/runtime/arguments.cpp:1359:
error: format '%d' expects type 'int', but argument 3 has type 'intx'

This occurs because of a flag that treats WARNINGS as ERRORS. The correct approach would have been to go and fix the warnings, instead I disabled the flag WARNINGS_ARE_ERRORS = -Werror which can be found in hotspot/make/linux/makefiles/gcc.make.

After making these changes I was able to run the build (just typed make) and saw the following output in the end:

 
Control linux amd64 1.7.0-internal build_product_image build finished:
Control linux amd64 1.7.0-internal all_product_build build finished:
Control linux amd64 1.7.0-internal all build finished:

I had a working JDK which could be found in build/linux-amd64/j2sdk-image/bin.

 
$ ./java -version
openjdk version "1.7.0-internal"
OpenJDK Runtime Environment (build 1.7.0-internal-jeffsinc_2009_01_03_10_52-b00)
OpenJDK 64-Bit Server VM (build 14.0-b09, mixed mode)

java ,

APT v AspectJ

January 2nd, 2009

APT has interested me for quite some time because after reading various blog entries and articles, it was unclear to me where APT fits in relation to other tools that provide functionality triggered by annotations. Specifically I’ve been interested in any overlap between APT and AspectJ.

Both AspectJ and APT provide the following common functionality:

  • Ability to intercept annotations.
  • Ability to declare custom compiler errors and warnings based off annotation matching.

I attempted to implement an architecture enforcement requirement using both tools. The requirement was simple: a compile error should occur when an attempt is made to access a class annotated with @RestrictedResource unless the caller is annotated with @SuppressRestrictions.

This was relatively simple with AspectJ, the following Aspect provides the enforcement:

 
public aspect RestrictedResourceEnforcer {
    private pointcut accessToRestrictedResource() :
        call(* (@RestrictedResource *).*(..))
                || call((@RestrictedResource *).new(..));
    private pointcut withinUnrestrictedCode() :
        @withincode(SuppressRestrictions) || @within(SuppressRestrictions);
    declare error : accessToRestrictedResource() && !withinUnrestrictedCode():
        "Attempt to access a restricted resource.";
}

The following test demonstrated the compiler error as well as the lack of compiler error should @SuppressRestrictions be used:

 
public class RestrictedResourceEnforcerTest {
    public void testAccessToRestrictedResource() {
        // Compile error: attempt to access restricted resource.
        RestrictedClass restrictedClass = new RestrictedClass();
        // Compile error: attempt to access restricted resource.
        restrictedClass.method1();
    }
    @SuppressRestrictions
    public void testAccessToSuppressedRestrictionResource() {
        RestrictedClass restrictedClass = new RestrictedClass();
        restrictedClass.method1();
    }
    @RestrictedResource
    private static class RestrictedClass {
        public void method1() {
        }
    }
}

Immediately I realised that it is not possible to implement this kind of architecture enforcement using APT without annotating the calling class (i.e RestrictedResourceEnforcerTest). Without marking the calling class, I’m not going to get a process() callback from APT.

This attempt has shown me that APT is only of real use for processing that is completely contained within the annotated class.

I still wanted try APT in direct comparison with AspectJ so I tried enforcing immutability on any class with an @Immutable annotation. I gave up pretty quickly using APT for this because although it is technically possible, it requires a lot of work with ASM to generate the correct source to enforce immutability (i.e. return unmodifiable collections on getters, throw an exception with setters). AspectJ provides a much more maintainable solution without ever having to go near something like ASM.

So I’m left wondering if APT has any value to your regular Java developer (rather than toolkit developer), I don’t think it has. APT’s use-case looks purely in the space of creating extensions to the regular Java compiler to generate bye products directly related to the class with the annotation.

As a general rule I’d break down APT and AspectJ usage as follows:

  • Use AspectJ if you need to add a functional requirement to existing entities. Examples include: monitoring, architecture enforcement, transactional functionality.
  • Use APT if you need to generate bye products for framework integration. Examples include: schema generation, source code generation tools (e.g. JAXB, JAXWS)

APT is not designed to be updating code to meet a functional requirement, AspectJ is. Instead APT provides a compiler extension that allows you to generate bye products driven by meta data on a class.

java , ,