Latest News
I have just finished Joshua Bloch's Effective Java Programming Language Guide and I can confidently say it is brilliant. This book will not introduce Java to the uninitiated, but it does illuminate the dusty and frankly perverse corners of a very powerful language. Although it is a dense read, it is a resource I will be returning to again and again.
With his many citings of the official Java spec, Bloch's authority is quickly established. Anyone that explains the uses and abuses of such common, but mysterious object properties as serialVersionUID and hashCode already has won me over.
Bloch's real gift is in making these opaque features understandable and putting them in to a context an average programmer is likely to understand. For instance, all Java objects have a clone() method that's meant to quickly and effeciently create new copies of an instantiated object. However, correctly implementing a clone() method is far trickier than it looks. And the same goes for the Serializable interface.
In many ways, Bloch complements the Gang of Four's Design Patterns. He extends the higher order approach to object-oriented programming into the Java context and provides concrete advice (e.g. favor object composition to inheritence, limit your APIs expose to the minimum, use the Singleton pattern for effeciency and comparison correctness, etc.).
What this book isn't is a how-to guide to anything. This is programming practices book and it rates as highly as any I've read.
Following on the earlier post I made about programming hex maps for games, I have taken a stab at a Java program that generates different sized maps. You can download the zip file here. If you've got a recent version of the JRE (1.5), this should work for you out of the box by double clicking on it. Otherwise, you can run it by unpacking the archive and typing "java -jar HexMap.jar".
This toy just generates hex maps according to adjustable parameters. Hit the "Repaint" button to see the glory.
In a future post, I'll be explaining the math and heuristics I used. I'll also make the source code available then. However, there are better implementations I have in mind for this. Eventually, I should be able to emit an actual game that uses this work. No time, no time. Sigh.
From a truly ill-considered Ask Slashdot question came this pearl of wisdom. A former (award winning!) Java hacker confesses his adulterous thoughts for Our Favorite Language. I'd like to pick up on a few of his points and perhaps add a bit of my own.
- Unicode: it's a sore spot of Perl, but seems to be hunky-dory for java. I lay the blame for Perl's developmental problems here on DWIM. As Perl coders, we've come to expect Perl to handle simple (and not so simple) string manipulation without that much handholding from us. I suspect that this bit of Sloth is biting the 'porters. Certainly, the unicode issue is preventing Perl from being a first class XML processing language (no XS cheating here).
- Perl's threading system is still developing, but java's model seems to be working fine. Of course, Perl's forking model is probably better and easier to use than java's (cross-platform forking is difficult to guarentee). I say tit-for-tat on threading/forking here.
- Dedicated IDEs are bullshit. There, I said it. Coders shouldn't handle their code with the tongs of an IDE, like some poor MS Word shlub. If the java folks have more IDEs than Perl People, good on 'em.
- ALL PRAISE CPAN! Perl was years ahead of MOST other languages here and continues to put java to shame. CPAN is not only an FTP archive, it's damn protocol to download and install libraries! In your face, JAR!
- Elegance is something for which python and java are praised and for which Perl is found wanting. Clearly, I don't get the 'elegance' argument and I never have. If 'elegance' means fewer characters typed during coding, Perl wins for most applications. Consider perl one-liners, the inclusion of perl hashes, regexes, etc. Perl delivers the promises of 'less typing'. Is elegence the lack of 'weird characters?' It may be, but Perl's syntax acts like a road sign to tell the maintain what's going on. Sigils (those funny characters preceding variable names) are not a misfeature -- they are essential to maintaining a Perl program. You always know what to expect from a variable with a sigil. Without them, the reader (and coder!) needs to find the original declaration of the variable to figure out what it is. I hate that. Is elegance the object model of a language? Python and Perl's object model isn't terribly different. Shocked? Don't be. The difference between python and Perl objects is that python has a object type, where perl blesses variable data. Java and Perl object models are very different. Java's single inherentence (which is a Good Thing) and object data protection (which is a Useless Thing) definitely come from the C++ crowd.
- You always get the source code with every Perl script and library. This makes it simpler to debug programs in Perl because you can always step through almost all of the code, including the libraries.
- Readability. Perhaps this is meant to go under 'elegance,' but I think this is a different issue. All languages can be obfuscated. It's not the language designer's perview to make you code clearly. Any claim a language makes to being inherently cleaner to code in (I'm looking at you, Java and python) is naive. I don't expect a java programmer to maintain a Perl program, just as I don't expect a Perl programmer to maintain a java program. In fact, that's why I'm not an editor for a Japanese magazine -- I have no facility for the language. Does that mean Japanese is inferior to English?
The more I use Java, the more I realize what "ivory tower development" means. And I don't like one bit, sir.
Java doesn't support printf. The C function
printf is something nearly
100% of all programmers worldwide know how to use because it's how you make
words appear on a screen or in a file. More importantly, it's the function
you use to format text. That is, it allows you to control how
many decimal places appear for floating point numbers, whether leading zeros
appear in front of numbers, whether to show numbers as hexadecimal, octal or
decimal, and a whole lot more. It's used in that most famous
of introductory programs, hello.c:
#includevoid main (char **argv, int argc) { printf("Hello, world!n"); }
It's so basic a function that you can forget how darn useful it is. But, Java doesn't have it. What Java has a method, which is part of those kinds of classes that concern themselves with streams, which is a highly generic way of thinking about files and consoles and network sockets and your mom.
Ok, let's leave your mom out of this (for now).
That Java method is named println. It doesn't
know how to format your output (to make your decimal numbers all pretty or to
add fancy columns to your output), but it does know how to put the
platform-appropriate newline character on the end of your string! So,
you've got that going for you!
Now, the designers of Java aren't stupid (more on this later). There are
problems that programs using printf encounter. For instance,
internationalizing the output of programs with printf can be
difficult. Sometimes. In badly designed large programs, which few programmers
ever have to deal with.
More damningly, printf is ideologically impure. It's a
function and Java's all about the Objects, baby. Sure, they could
have made a static method of the String (or OutputStream or whatever) class
called printf, but that might cause
someone a little grief sometime somehow. Better to cheese off every programmer
coming to the language. Yup. Great thinking there.
Another noticable absentee from Java fopen. The C function
fopen is known by 99% of all
programmers worldwide and nearly all popular programming languages have
something like open (Perl has 3 closely related file open functions but you
probably only ever need open).
As programming interfaces go,
fopen is pretty nasty. You need to pass it a filename (and
all operating systems name files differently). You need pass it a mode (are
you reading from, writing to, appending to the file or all of the above?).
And what do you get back from fopen? A file handle? A file
descriptor? A lottary number? Who knows? However, it's a big puddle of
programming poo that 99% of us have learned to deal with.
Instead, java has many circumlocutions to address files and even more to get data into and out of them. Working with files is task performed in 98% of all programs ever written. And Java makes getting to these files weird, frightening and confusing. You need a File object, which is then passed to a Output/Input Stream object, which in turn is passed to a Buffered Stream object. Nice and Object Oriented. And a complete pain in the genitals.
So, let's recap. Java, which was loosed upon the world in the nineties purposefully ignored very popular input/output conventions so that 100% of the programmers who learned any other language (most have syntaxes derived from C) would be utterly baffled by the most common of all programming tasks.
Are there times where all this OO sugar pays off? Sure. And Java is very helpful in these cases. Could Java have provided a nice compatibility layer for the oceans of existing C-based programmers? Sure, it could have. Easily, in fact. But the Java language designers thought they knew more about the how to tackle the jobs that Java programmers would face than the programmers themselves.
In classical literture, this type of overweaning pride is called hubris. In my native country Massholia, we just call that "being a f*cktard."
A project for work required me to program in that most rigid and litigious
of languages, Java. I used Apache
Axis to make SOAP calls over SSL, thus making the project buzzword
compliant. This post is about how, with the help of John Cho at VMware, I
was able to coax Java in talking with SSL hosts whose X509 certificates have
no recognized identity by the client. Typically, this means the hosts are
self-signed and are not know to trusted root certificate servers. Without
this hack, Java will refuse to use the SSL connection until the user imported
the client certificate from the self-signed server, using the
keytool utility from the JRE.
NOTE: Disabling authenticating of SSL certs is not compatible with security-sensative projects. Please understand that by using this hack, you are reducing the effectiveness of SSL security (although the actual network traffic through the SSL tunnel is still encrypted). The decision to use this hack is typical of the design choices made on the security-versus-convenience axis.
Although this code is specific to Axis, the careful reader may find this code applicable to their next Java project.
Apache Axis 1.4 (and earlier) uses the standard java.net.ssl package that is distributed with Sun's JDK 1.5 (it's in older JDKs too). The Axis class that creates the SSL socket factory that contacts the class that actually does the cert authenication is:
org.apache.axis.components.net.JSSESocketFactory.java
What we need to do create a special X509TrustManager that accepts all certs and install it as part of the SSL Factory. There's a lot of abstraction and action at a distance code here, so let's start with how to implement an all-trusting X509Certificate class.
class TrustyTrustManager implements javax.net.ssl.X509TrustManager {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] c,
String authType) throws CertificateException {
// do nothing, accept by default
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] c,
String authType) throws CertificateException {
// do nothing, accept by default
}
}
Recall that X509TrustManager is just an abstract class. It requires three
methods to be implemented. Fortunately, these methods are easy to deal with,
if you don't care about authenication. The first,
getAcceptedIssuers(), is supposed to return an array of certs
for trusted authority servers. Since we aren't going to consult any, we
can return null there. The last two methods throw an exception if the
described certificate cannot be authenticated by building a "trust path" from
the root authorities to the given one. Since not throwing an exception means
that the trust path was succesfully constructed, we do absolutely nothing in
these methods. If only all code were so easy to write!
The only catch here is that we do need to import
java.security.cert.CertificateException to handle the exceptions
that we'll never throw, otherwise we get a compiler error. Thanks for the
extra hoop, Java.
I added this class as an inner, private class to the JSSESocketFactory.java file, but you may want to isolate this code into its own file for use in other projects.
Now we need to install this X509Certificate class. This can be done by
change the code in initFactory() to something like the following:
protected void initFactory() throws IOException {
// Inspired by John Cho
try {
javax.net.ssl.TrustManager[] trusty =
new javax.net.ssl.TrustManager[] {
new TrustyTrustManager()
};
javax.net.ssl.SSLContext sc =
javax.net.ssl.SSLContext.getInstance("SSL");
sc.init(null, trusty, new java.security.SecureRandom());
sslFactory = (SSLSocketFactory) sc.getSocketFactory();
} catch (Exception e) {
throw(new IOException("SSLFactory: " + e.getMessage()));
}
}
Let me step through the code backwards, since it will help to know where
we're going with this method. The whole point of initFactory()
is to initialize the protected class member sslFactory with a
valid object. SSLSocketFactory objects are returned by
javax.net.ssl.SSLContext objects, which the documentation describes like this:
«Instances of this class represent a secure socket protocol implementation which acts as a factory for secure socket factories. This class is initialized with an optional set of key and trust managers and source of secure random bytes.»
I emphasized "trust manager" here, since that's what we implemented with the TrustyTrustManager class. Now, we just need to create an SSLContext object for the SSL protocol (not sure why there are other options here), and shove in our TrustManager.
Well, not quite. It turns out that SSLContext expects to get an array of TrustManagers.
init(KeyManager[] km, TrustManager[] tm, SecureRandom random)
We don't need KeyManagers at all and the random seed can be generated from
a method in java.security. What we do need is an array of
TrustManagers with one TrustyTrustManager object in it. Once this is
assembled, init() can be called correctly and the
SSLSocketFactory obtained.
There you are! It's as simple as rocket science, but not as hard as brain surgery.
Some advanced Java coders will probably decry this code as
cheating. It's not very OO to manhandle an existing class like this. Surely,
there must be a way to subclass JSSESocketFactory and override the behavior of
initFactory() more cleanly. The answer is "yes," but that means finding all
those places that instantiate JSSESocketFactory objects and subclassing
those classes. And, of course, you can see how this subclassing will
quickly ripple through the entire object heirarchy of Axis to destroy all
my free time. In Perl, I might have simply poked through the package namespace
at some point to overwrite initFactory(). I'm not aware how to
do that in Java effectively, but I welcome your suggestions.
UPDATE: For additional information on doing this with Apache's XML-RPC lib for Java, check this out. I think this technique may work with axis too, since it is built of the standard Sun SSL stuff. But, I haven't tried.
Programmers love to argue about which programming languages are better than others. If you listen carefully, you'll notice that there's a hierarchy to the debate. Java programmers laugh at C++. C++ coders deride C monkeys. Everyone laughs at shell hackers. No one can understand assembly programmers and those that "think in LISP" occupy a sublime and knowing orbit above all rest (so they think).
But I'm a Perl hacker first and foremost. Despite some of the more vocal members of the community, Perl is a humble language (with, as its critics will quickly add, much to be humble about). In recent years, I've forced myself out of this comfort zone into the wider world of programming. Like all generalist, I try to pick the right tool for the task. For instance, PHP is a best tool I've found for general web applications, which is why this site uses it. For quick and dirty Windows games, Python (with its pygame library bindings to SDL) stands alone. For repetative system admin tasks, shell scripts and cron combine like Voltron to create superlative software robots. The thing is, most programming languages are pretty similar. They have data types, loops and conditional branching. That's really the bare minimum you need to get things done. Where languages differ is in the services they offer the programmer.
I've heard that you love someone not for his winning attributes, but for his faults. However, I've found that there are definitely some faults that are harder to love than others. This missive is about those faults in Java that keep our relationship forever at the stage of the first date. If Java is your "Main Mama", you may want to stop reading this now.
For my work, I need to hack up a bit of Java that speaks XML-RPC. Now, you may recall that I'm no stranger to working with this protocol. I've written XML-RPC clients and servers in Python, Perl, PHP, ASP and even (God help me) C. But I missed out on Java until now.
No problem, I thought. I'll just look through my book at the chapter Simon St. Laurent wrote about using the helma XML-RPC library for Java. Simon did the lion's share of the book and did the most thorough job of any of us on the project, so I took a look. Funny thing: that library has morphed into the Apache XML-RPC library. Ok, fine. How different could it be? I mean, it was working fine before. How many changes were needed? Perl's Frontier::RPC library has hardly changed in six years (and we use it heavily at Leostream).
As it turns out, the one thing Java does well is faciliate abstractions. With the newest version of the library, you can tweak all kinds of parameters, swap out XML parsers, add additional data types (which defeats the whole effing point of XML-RPC), create new class factories -- the list goes on! In fact, there's a whole class just for configuring the XML-RPC client! Excessive you say? Just wait.
The one thing you can't do with this library is start using it quickly. The main culprit? Missing dependencies. When I tried to run a simple XML-RPC client, it complained about not knowning how to encode the XML-RPC timestamp thingie. Oy. But wait! Weren't JAR files supposed to solve this issue? Wrong again, Fatty!
Ok, so I needed to install subversion just to get the bleeding-edge version of the missing ws-common library. That's not so bad, right? Wrong. I also needed to get a nightly snapshot of the TRUNK code of the main library because the "release" version could not handle structures correctly (the unknown "string" problem). Fine. That happens. It's open source so you've got to expect the release management to get a little "cowboy" sometimes.
At length, my "hello, world" XML-RPC program got up and running. After several phone calls gloating about this teapot triumph, I proceeded on to handling more realistic and complicated data structures. I had my test server return a structure to my Java client that had a value that was an array. In perl, the structure looks something like this:
{ "foo" => "bar",
"boz" => [ "boom", "doom", "soon" ],
}
Here's a quick test: how many dictionary classes does Java have? I'm talking about generic collection types that hold key-value pairs. 1? 3? 10? Wrong! It's a trick question. In Java, new Map classes spontaneously generate all the time.
I bring this up because in order to traverse this data structure, I need to know the how to type the objects correctly. Now, in simple programs where you control the data, that's easy. When you have to deal with arbitrary data coming in from an unknown source, Java whips out the hate on you.
Because Java sucks is very advanced, I have to iterate
through methods to transverse this structure. Something like the following:
Map my_struct = get_the_struct();
Iterator it = struct.keySet().iterator();
while (it.hasNext()) {
Object this_key = my_struct.next();
Object raw_object = result.get(this_key);
// here comes the good part
Class c = raw_object.getClass();
if (c.isArray()) {
// fetching this object was so nice, I do it twice!
Object [] this_value = (Object []) result.get(this_key);
System.out.print(this_key + " => ");
int i;
for (i=0; i < this_value.length; i++ ) {
System.out.print(this_value[i] + ", ");
}
System.out.println();
} else {
// simple data type
System.out.println(this_key + " => " + raw_object);
}
}
It took me about 3 hours to puzzle out this code. It would have been swell for the docs to have an example of handling complex data like arrays and hashes, but then I would have missed out on my afternoon of personal discovery and emotional growth.
After many fruitless web, book, and source code searches, I managed to hack this code to handle my "weird" data. It's crappy, but it works.
The truly loathesome part is the way I had to work with hash values that are arrays. For reasons that aren't clear, I couldn't just use the value returned from a Map if it is an array of Objects. That would be too easy. I had to properly cast the data because Java is a bucket full of venomous hate. Of course, I need to check if the object is, in fact, an array and then fetch the object again for the cast!
Allow me to paint with a very broad brush for a moment. The stunt programming exhibited in the code above is exactly the kind of stupidity that prevents Java folks from learning about what's going on in the rest of the computer universe. Strict data typing is 100%, no-foolin' legalese.
All modern scripting languages handle this kind of "collection of random data types" better than Java. VBScript is only slightly less lawyerly about it, but it too sucks hard on big, stiff data structures (VBScript has two assignment operators: one for objects, one for everything else. Thanks for nothing, Microsoft).
It's enough to really bring me down, man.
What the hell is wrong with these language designers? Can they please stop worrying about continuations, anonymous classes, multiple inheritance, abstract interfaces, factory classes and orthogonality long enough to make a language that's useful for the kind of problems I have to deal with? I live in world of strings. If your language makes dealing with strings hard for me, I will hate you with my fists.
Can I get a "hell ya!"?
Jesus H. Christ.
About this blog
The taskboy blog is a exploration of computer technology by Joe Johnston. Topics of posts include practical examples Perl, PHP, Python and Java as well as book reviews, industry insights and miscellaneous good stuff.
Current Status
Watching _Brass Latern_. Ah IF, your coyness is your charm.
Posted: Sun Sep 05 16:02:15 +0000 2010
Latest Feedbag
- Do It Anyway
- Reader recommendation: Atlas, Schmatlas
- Scientists Cut Greenland Ice Loss Estimate By Half
- (Video) George Parker: Agencies Need To Buy Themselves Back
- Android Is As Open As The Clenched Fist Id Like To Punch The Carriers With
- Eden Ventures Joins The Super Angels Gang, Five Investments Down
- Human Translation Startup myGengo Raises Seed Round From International Investors
- Another Instant Music Video
- DARPA Wants Extreme Wireless Interference Buster
- Film Industry Hires Cyber Hitmen To Take Down Pirates
Generated: 04:52 on 09/Sep/2010
Recent posts
- Very quick git primer for basic functionality
- Tips for spammers: don't insult me
- CakePHP vs. Symfony: a quick note
- Creating events for Yahoo and Google calendars
- SANs on a budget: iSCSI under Ubuntu
- iPad, iTouch and Kindle: Which is the better mousetrap?
- Rise of the Ad-Hocracy, Part II
- Rise of the Ad-Hocracy, Part I
- Small Hiatus
