GCJ, the GNU compiler with java extensions, does a great job at compiling Java into bytecode, but still has some bugs in its libraries when dealing with Swing components. Installing Sun’s Java packages on Debian thus is occasionally necessary, and has historically been a chore. I won’t list the process here to even show my distaste for it - it just wasn’t very fun.
Things are much easier now, though. Just make sure a non-free package repository is listed in your sources.list, and things become magic:
sudo echo "deb http://ftp.us.debian.org/debian/ lenny non-free" >> /etc/apt/sources.list
(Note that if you aren’t using lenny, you should change that. Also, feel free to choose a different mirror.)
Now update your package repository:
sudo apt-get update
And finally install whichever Sun Java packages you want!
sudo apt-get install sun-java6-jdk sun-java6-jre sun-java6-plugin
Cheers to Matthias Klose (Ubuntu), Juergen Kreileder (Blackdown), Barry Hawkins, Jeroen van Wolffelaar, and the other folks behind debian-java for adding these packages to Debian’s repositories. It is another push that greatly enhances the usability of the project for both developers and users alike.
I ran across a problem where I had incoming socket streams taking a really long time (25-65 seconds) to read from. I knew the data was leaving the client application, and the incoming connection socket handling code was running correctly, so the only thing holding up my server handling the data was the speed at which that data was being read from the socket. Additionally, this was all running on a local loopback so network latency wasn’t the issue.
The solution was simple: while I was manually flushing the socket OutputStream on the client side, I had forgotten to close the socket explicitly (which forcefully flushes the socket’s streams before closing). Once this modification was made to the client, the data appeared instantaneously on the server.
So when doing I/O, don’t forget! Flush and close your streams and sockets!
The attendance database project I’ve recently written about requires the use of iButtons for verifying the physical presence of members at meetings. Having never worked with either the hardware other than as a user of it nor the software SDK in any capacity, it was a learning experience. One thing I quickly ran across when developing the software to locate a plugged-in adapter and read the iButton’s ID was the incredible amount of time it took to enumerate through the available ports just to find a connected adapter. The SDK provided examples on how to go about locating connected adapters, but to improve the speed at which it runs we can take advantage of what we know about the system and exploiting the code’s error conditions.
During installation of the 1-Wire drivers needed to communicate with iButton adapters, you have the option of selecting a default port to which the adapter will be connected. This information is stored as a property the SDK knows how to locate. The first step to increasing the speed of locating an adapter is to use this information - simply check the default port before searching all other ports on the machine. Odds are higher that the adapter is located on that port than any other port on the system, and by placing it as the first check before serially searching all other ports you increase your chances of getting on the first attempt.
The second enhancement requires a bit of background information. The example provided in the SDK shows you how to search all possible adapter types, then all possible ports for that adapter, and print them out. To be useful we would want instead of printing out the adapter and port names to attempt retrieving the device connected there. This would logically be done using the static getAdapter(String adapterName, String portName) method of the DSPortAdapter class. However, the time this method takes to return whether the adapter exists could be measured in seconds. To make this faster using our understanding of the system, we could skip over adapters we know we won’t be using (network adapters, parallel adapters, serial adapters, etc) and avoid scanning for them over all ports entirely. Reducing the size of the problem reduces the time it takes to come to a solution.
That is not all we can do, however. For some reason, if you try to retrieve an adapter using the getAdapter method and attempt to tell if it is successful by comparing the return object against null, it takes a long time. In comparison, the method throws an exception if it cannot locate the adapter much more quickly. Using this last bit of information, by putting a continue statement in your exception catching code you can just skip the attempt to open the obviously unavailable reader and enjoy a nice speed boost.
Here is some example code illustrating what I’ve talked about, excluding rolling over adapters we don’t care about. The speed of this is much faster than my first attempt, from taking around five minutes to locate an adapter to around 30 seconds. Base of code taken from the examples provided in the 1-Wire Java API. Sorry about the indenting, I gave up trying to figure out how to adjust the tabstop!
/**
* Locate a reader to communicate with.
*
* @return boolean - true if adapter was found, false otherwise.
*/
public boolean locateAdapter( ) {
boolean found = false;
while( !found ) {
try {
DSPortAdapter adapter = OneWireAccessProvider.getDefaultAdapter();
System.out.println(”Adapter ” + adapter.getAdapterName() +
” found on port ” + adapter.getPortName());
this.adapter = adapter;
this.port = adapter.getPortName();
found = true;
} catch(Exception e) {
System.out.println(”Adapter not found on default port, trying all ” +
“available to the system…”);
}
if( !found ) {
DSPortAdapter adapter;
String port;
// get the adapters
for (Enumeration adapter_enum = (Enumeration) OneWireAccessProvider.enumerateAllAdapters();
adapter_enum.hasMoreElements(); )
{
adapter = ( DSPortAdapter ) adapter_enum.nextElement();
System.out.println(”Trying adapter ” + adapter.getAdapterName() );
// get the ports
for (Enumeration port_enum = adapter.getPortNames();
port_enum.hasMoreElements(); )
{
port = ( String ) port_enum.nextElement();
System.out.println(”trying port ” + port );
try {
OneWireAccessProvider.getAdapter(adapter.getAdapterName(), port);
this.adapter = adapter;
this.port = port;
found = true;
} catch( OneWireException owe ) {
// Just continue…
continue;
}
}
if( found ) {
break;
}
}
}
if( found ) {
System.out.println(”Adapter found! Using ” + this.adapter.getAdapterName() +
” on port ” + this.port );
} else {
// Wait 5 seconds before trying again
try {
Thread.sleep( 5000 );
} catch (InterruptedException ie ) {}
}
}
return found;
}
I’ve inherited a decently complex graphical interface to add functionality to, all written in Java. The previous developer who originally designed the interface (and who is also no longer with the company) used NetBeans to accelerate the process. While not bad in itself, the results are horrifying.
I now have a couple hundred lines of variables named along the lines of “jPanel18″ and “jTextField3.” There are three separate layouts being used across the many panels. Not a comment is to be seen, except for what was provided by NetBeans’ auto-generated comments, which have nothing to do with the code and everything to do with “this is auto generated, don’t edit.” To make things worse, the form file that accompanies the source for NetBeans is almost two years out of date, and a lot of functionality and structure changes have occurred since then leaving me to do all the editing by hand.
Tips I suggest for those thrown into situations like this:
- Put a TitledBorder around each panel with the panel’s name. Now that you know which panel goes where, write it down.
- Seriously, draw a picture. When working with generically named components, you’ll appreciate having a ‘map’ of where everything is going.
- Refactor. If you can rename the components without breaking things, give them useful names (Eclipse makes this easy). If nothing else, move the components into groups of functionality or physical geometry in your initialization method.
- Read up on the layouts being used. If you know how to work with the layouts within a panel, you’ll spend more time coding and less time making a single modification, rebuilding, and running your application to see how the change affected things.
- Learn from this painful experience, and don’t do this in code you write in the future.
May you be blessed with patience. You’ll need it.