Discovering the platform profile from Java
What's the simplest way to get CPU speed, amount of RAM, OS version, and other hardware details from the running JVM? I'm putting together a yet-to-be-announced tool that will include hardware specs in its reporting.
So far, I've been able to get the hardware profile on Mac OS X using
sysctl
and on Linux using
/proc/cpuinfo
and
/proc/meminfo
:
java.version: 1.5.0_13
java.vm.name: Java HotSpot(TM) Client VM
os.arch: i386
os.name: Mac OS X
os.version: 10.5.1
user.name: jessewilson
host.name: jessewilson-macbookpro-2.local
os.kernel.version: 9.1.0
host.model: MacBookPro1,1
host.cpus: 2
host.cpu.speeds: 2000000000
host.cpu.arch: i386
host.cpu.bits.physical: 32
host.cpu.names: Genuine Intel(R) CPU 1500 @ 2.00GHz
host.cpu.caches.l2: 2097152
host.memory.physical: 2147483648
This comes from a quick-n-dirty Java app,
HostInfo.java. Curious - anyone know of a simpler approach? Or a more reliable API? I'm not interested in JNI or nontrivial applications, since they complicate deployment.
Still to do - figure out what's necessary to discover this information on the Windows platform...
# posted by Jesse Wilson
on Monday, March 24, 2008
5 comments
post a comment
Coding in the small with Google Collections: ImmutableSet
Part 15 in a
Series.
The
Google Collections project has released an
impressive new collection of features.
The new release has prompted me to continue this series. My favourite feature of the new release is
ImmutableSet. It's a top-level implementation of
Set
that's full of features - this class alone justifies adding the entire
.jar
to your application's libraries folder...
For static constants
Before public static final Set<Integer> LUCKY_NUMBERS;
static {
Set<Integer> luckyNumbersMutable = new HashSet<Integer>();
luckyNumbersMutable.add(4);
luckyNumbersMutable.add(8);
luckyNumbersMutable.add(15);
luckyNumbersMutable.add(16);
luckyNumbersMutable.add(23);
luckyNumbersMutable.add(42);
LUCKY_NUMBERS = Collections.unmodifiableSet(luckyNumbersMutable);
}
After: public static final ImmutableSet<Integer> LUCKY_NUMBERS
= ImmutableSet.of(4, 8, 15, 16, 23, 42);
For defensive copies
Before: private final Set<Integer> luckyNumbers;
public Hatch(Set<Integer> luckyNumbers) {
this.luckyNumbers = Collections.unmodifiableSet(new HashSet<Integer>(luckyNumbers));
}
public Set<Integer> getLuckyNumbers() {
return luckyNumbers;
}
After: private final ImmutableSet<Integer> luckyNumbers;
public Foo(Set<Integer> luckyNumbers) {
this.luckyNumbers = ImmutableSet.copyOf(luckyNumbers);
}
public ImmutableSet<Integer> getLuckyNumbers() {
return luckyNumbers;
}
For more defensive copies
ImmutableSet.copyOf
has been heavily optimized when the argument is itself an ImmutableSet. It turns out that this method can
no-op if the argument is itself an
ImmutableSet
, since copying immutable objects is redundant. The more you use
ImmutableSet
, the cheaper it is to do defensive copies!
For predictable insertion order
ImmutableSet's elements iterate in the same order that they're added in. That means there's less
unpredictable behaviour in your application's business logic. There's no need to worry about tests that pass on one JVM and fail with another because of
HashSet
's unspecified iteration order.
ImmutableSet<Integer> numbers = ImmutableSet.of(8, 6, 7, 5, 3, 0, 9);
assertEquals("[8, 6, 7, 5, 3, 0, 9]", numbers.toString());
For self-documenting APIs
Before: /**
* Returns numbers most likely to be selected in upcoming lottery drawings.
*
* @return an immutable, non-empty set
*/
public Set<Integer> getLuckyNumbers();
After: /**
* Returns numbers most likely to be selected in upcoming lottery drawings.
*
* @return a non-empty set
*/
public ImmutableSet<Integer> getLuckyNumbers();
For less memory allocation
ImmutableSet allocates fewer objects and smaller objects than either
HashSet
or
LinkedHashSet
. This makes your program's heap smaller. There's also less work for your garbage collector.
For non-null data
ImmutableSet does not permit null elements. This is almost always what you want, and helps to detect bugs early:
Before: public Hatch(Set<Integer> numbers) {
for (Integer number : numbers) {
if (number == null) {
throw new NullPointerException();
}
}
this.numbers = Collections.unmodifiableSet(new LinkedHashSet<Integer>(numbers));
}
After: public Hatch(Set<Integer> numbers) {
this.numbers = ImmutableSet.copyOf(numbers);
}
ImmutableSet is my new default collection, replacing
ArrayList
. It's that good. And as a special treat, when I do need a List, Google Collections also includes
ImmutableList.
# posted by Jesse Wilson
on Friday, March 21, 2008
3 comments
post a comment
The 'anything goes' SecurityManager
As previously mentioned, my current 20% project involves some
RMI hackery. Today I ran into an unfortunate error message:
java.lang.ClassNotFoundException: com.publicobject.m2x.Measurer (no security manager: RMI class loader disabled)
at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:371)
at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:165)
at java.rmi.server.RMIClassLoader$2.loadClass(RMIClassLoader.java:620)
at java.rmi.server.RMIClassLoader.loadClass(RMIClassLoader.java:247)
at sun.rmi.server.MarshalInputStream.resolveClass(MarshalInputStream.java:197)
Apparently Java RMI won't let me download remote code without a security manager installed. The standard workaround for this problem is to create a
.policy
like so:
grant {
permission java.security.AllPermission;
};
. . . and then I need to reference the file when I launch the app:
java -cp . -Djava.security.Policy=m2x.policy com.publicobject.m2x.Main
I don't like this solution because it forces me to change how my app is launched, complicating deployment. It adds another file to manage. And the deployment work needs to be solved in Unixland, far from my comfort zone of Javaland.
It turns out I can do the same thing in Java code by installing a no-op security manager:
System.setSecurityManager(new SecurityManager() {
public void checkPermission(Permission permission) { }
public void checkPermission(Permission permission, Object context) { }
});
I like this better.
Java should be first on the Java Platform
When designing APIs for the Java platform, programmatic access must be a first-class citizen. APIs that require XML, configuration files, or System properties shouldn't be the only way to access functionality.
# posted by Jesse Wilson
on Thursday, March 20, 2008
1 comments
post a comment
Java RMI without a webserver
One of the four steps to setup
Java RMI is "Making classes network accessible." Since I'm new to Java RMI, I found this requirement surprising. We have a client and a server. Of the two of them, surely one of the two has a full set of classes. Why require a third server to host the classes?
I suppose they were thinking that somewhere near the RMI server would be a big expensive heavyweight J2EE container, and that thing can serve the classes. But even if I have the J2EE server setup, this is still annoying - I still need to configure the webserver, and then keep it's jars synchronized with the ones my RMI server is using.
Instead, I decided to do the Simplest Thing That Could Possibly Work. I wrote a tiny
HTTP Server (168 lines of code) and used it to publish all the classes in my local JVM. Now in my RMI code, I simply need this:
String currentHostname = "jessesmac.publicobject.com";
new RmiClassServer(currentHostname).run();
The RMI server serves classes to anyone who's interested. I don't need to tell it which classpath to use - it uses the exact same classes that the local classloader uses, via
Class.getResource
.
Sound useful for your RMI application? You'll need
RmiClassServer.java and
MiniHttpServer.java, both of which are available under your choice of
Mozilla 1.1 or
LGPL license.
A final word of caution - this server exposes everything on your application's classpath. Unless your classes themselves are public, please don't put this server (or your RMI server!) on your public website.
# posted by Jesse Wilson
on Tuesday, March 18, 2008
2 comments
post a comment
MiniHttpServer.java - an HTTP Server in 168 lines
For part of an project which I'll be announcing shortly, I needed an extremely lightweight HTTP server. Fortunately, HTTP is quite easy-to-implement. Tonight I hacked together
MiniHttpServer.java, a simple server with zero third-party dependencies.
I was able to support the core of HTTP in with just 168 lines by doing only the bare-minimum. Here's the server's core:
nextLine();
readUntil("GET\\s+");
String url = readUntil("\\s+HTTP/1.1");
do {
nextLine();
} while (readUntil("$").length() > 0);
InputStream responseData = handler.getResponse(url);
if (responseData != null) {
write("HTTP/1.1 200 OK\r\n\r\n");
int b;
while ((b = responseData.read()) != -1) {
connection.getOutputStream().write(b);
}
} else {
write("HTTP/1.1 404 Not Found\r\n\r\n");
write("404 Not Found: " + url);
}
connection.close();
If you need an embedded HTTP server, please help yourself to this code. It's fully open source, and available under your choice of
Mozilla 1.1 or
LGPL license.
# posted by Jesse Wilson
on Tuesday, March 18, 2008
2 comments
post a comment
Java Minutiae - Instantiating inner classes
Pop quiz - without reflection, access to private members, or changing the source, create an instance of
Inner
.
public final class Outer {
public static final Outer INSTANCE = new Outer();
private Outer() { }
public class Inner { }
}
Note that Inner is non-static, so each
Inner
has a reference to its containing
Outer
.
Show AnswerWell it turns out that you can 'dereference' a containing instance to instantiate an inner class. The syntax is awkward, but it works:
Inner inner = Outer.INSTANCE.new Inner();
I've found this syntax most useful for testing package-scoped inner classes.
# posted by Jesse Wilson
on Sunday, March 16, 2008
1 comments
post a comment
Java Minutiae - Map.remove()
Suppose you'd like to remove an entry from a Map, and perform some action only if the remove actually removed. Since
Map.remove()
returns the value associated with the removed key, we can do this:
if (map.remove(key) != null) {
deleteAssociatedFiles(key);
}
Unfortunately, if the map tolerates
null
values, this approach doesn't differentiate between removing 'key→null' and not removing. The standard workaround is to do two map lookups (which fails for
ConcurrentMaps):
if (map.containsKey(key)) {
map.remove(key);
deleteAssociatedFiles(key);
}
But there is an elegant solution. Although
Map.remove()
doesn't know 'null' from 'nothing', it turns out that
Set.remove()
makes the distinction. That method returns
true
only if the set changed. We simply operate on the map's keys, which will write-through:
if (map.keySet().remove(key)) {
deleteAssociatedFiles(key);
}
I learned this trick from Jared of the
Google Collections team.
# posted by Jesse Wilson
on Monday, March 10, 2008
2 comments
post a comment
Java Minutiae - I love ternary
I love the
? :
ternary operator. It makes my code feel tighter. Plus, I get to save code - fewer assignments, fewer return statements, and variable declarations are inline. In the code I was writing yesterday, a duplicated call to 'add()' made me itch for the ternary:
for (String key : keys) {
if (getCardinality(key) == 1) {
singleValuedKeys.add(key);
} else {
multiValuedKeys.add(key);
}
}
Unfortunately, with standard use of a ternary, the code gets bigger instead of smaller:
for (String key : keys) {
Set<String> setToAddTo = (getCardinality(key) == 1)
? singleValuedKeys
: multiValuedKeys;
setToAddTo.add(key);
}
Taking it one-step further, I inline the
setToAddTo
variable. This is where the code loses its familiar feel:
for (String key : keys) {
((getCardinality(key) == 1)
? singleValuedKeys
: multiValuedKeys).add(key);
}
It's tight, but somehow I've written Java code that doesn't have the Java feel. So I ended up dropping the ternary, and went with the familiar if/else structure. What's your preference?
# posted by Jesse Wilson
on Monday, March 10, 2008
8 comments
post a comment
Guice wins Jolt Award!
From the
Guice User's group,
Congratulations Bob, Kevin and the rest of the Guice team! Guice beat out rival Spring and several other worthy projects to win the 2008 Jolt Award for libraries and tools.
It was great to see the guys win - they deserve to be recognized for their hard work.
The award is also good news for Google's open source effort. It confirms Guice as a top-tier open source project, and encourages them to invest more in open source. Plus, the award should help to put some momentum into the development of Guice 2.0.
I'm looking forward to seeing Kevin & Bob's picture in an upcoming issue of Dr. Dobb's Journal. In the picture, they're holding the award: a giant can of Jolt encased in lucite. The award may also be recognized on one of the Google blogs.
# posted by Jesse Wilson
on Wednesday, March 05, 2008
1 comments
post a comment