Sunday, 19 June 2016

Printing Checkboxes in Tables - Grossly Inefficient

Printing in Java has always seemed like a bit of a black art to me. With anything complicated, you need to manually determine where each bit of text should be placed on the page, how much space it takes up, and where/how to manage page breaks.

So I was thrilled when I found Java's JTable.print(..) method (http://docs.oracle.com/javase/7/docs/api/javax/swing/JTable.html#print%28%29) I thought it would make printing much easier. This method is really a great tool.

Then I decided to print a list of a few items. Take my JTable, print it, it renders just like it does on the screen and no need to do extra work. Piece of cake!

Or so I thought.

Expand that table to a list of a few hundred, or a few thousand items. Suddenly you're waiting half an hour to print a single page. What went wrong? I use a PDF printer for debugging because there's no sense killing trees, and the files were in the tens to hundreds of megabytes range....for text?

To be fair, and this may make a difference (I didn't check), I'm using the Nimbus look and feel. A little bit of debugging, commenting out the checkboxes from the table, and the printout was now the in the hundreds of kilobytes range, which was what I expected, and I was able to work around the problem.

Since I needed the printout to look exactly like the screen, I "solved" the problem by editing my custom renderer to return a checkbox if displaying for the screen, and a label that looks exactly like the checkbox if the table.isPaintingForPrint() method returned true.

if( table.isPaintingForPrint() )
{
    return printLabel;
} else
{
    return guiBox;
}

Saturday, 8 August 2015

Install MySQL

I also find myself needing to install MySQL 5.6.25 as well for my classes. Step by step how to install...

1. Visit mysql's website and obtain a copy of mysql-5.6.25-winx64.zip (standalone zip file, NOT the installer).

2. Extract it to the desired drive. In my case this is drive G. Rename to mysql.
3. Create an option file with the following contents and save it to G:/mysql/my.ini
[mysqld]

# basedir to installation path
basedir=G:/mysql

# location of data directory
datadir=G:/mydb/data

4. Ensure both the basedir and the datadir exist, creating them if necessary.
5. Copy the contents of directory G:/mysql/data/ to G:/mydb/data/. This gets you an empty database. (if you don't follow this step you will get an error [ERROR] Fatal error: Can't open and lock privilege tables: Table 'mysql.user' doesn't exist)

6. Start mysql
cd /d G:
mysql\bin\mysqld --console


Output should end with:
2015-06-13 16:56:04 1388 [Note] mysql\bin\mysqld: ready for connections.
Version: '5.6.25'  socket: ''  port: 3306  MySQL Community Server (GPL)


7. Open a new command prompt and login to the database
G:\>mysql\bin\mysql --user=root
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
+--------------------+
2 rows in set (0.00 sec)

If you see database "mysql" all is well.

Now you can do whatever you need to with the new database, or create another database/schema if you wish.

JAI Tutorials

Found links to some JAI examples since the top links on Oracle's site return 404 not found errors on the actual tutorials. Turns out that the tutorials/demos were migrated over to java.net under jai-demos and jaistuff projects.

Links are:
https://java.net/projects/jai-demos
https://java.net/projects/jaistuff

You can browse the code through these projects or download the source through SVN.

The source compiles through ant (there is a readme with instructions on how to compile the examples) or you can pull it into your favorite IDE, add the JAI libraries to the classpath, and run from there.

More useful links to JAI related code are here: http://www.silverbaytech.com/2014/05/16/java-advanced-imaging-downloads/

Sunday, 17 May 2015

Setting up Java Advanced Imaging (JAI)

Java Advanced Imaging (henceforth referred to as just JAI) is a relatively old (hasn't been updated since 2006) package used for advanced image manipulation. Working with images has been built into Java Swing, but the functions provided aren't...everything...that you might need to do.

According to the readme provided with version 1.1.3, JAI does the following:
Java Advanced Imaging extends the imaging functionality provided in the Java 2D API by providing a more flexible and scalable architecture targeted for complex, high performance imaging requirements.

I find myself taking a class where JAI is a required library, and that means I need to install it on my computer.

First off, the download location:
http://www.oracle.com/technetwork/java/current-142188.html

I have a Windows 7 64-bit computer, so this could get a bit interesting. Looks like there are instructions for setting it up on 64-bit Solaris, so hopefully there won't be too many issues.

I decided to download this file: jai-1_1_3-lib-windows-i586.exe.

Step 1: Run the installer.
  • It's one of those old-style installers built using InstallShield.
  • Use the default installation location of: C:\Program Files (x86)\Sun Microsystems\Java Advanced Imaging 1.1.3\ 
  • And do a "complete" install.

That produces a directory with the following files:
JAR files:
    jai_codec.jar
    jai_core.jar
    mlibwrapper_jai.jar

DLL files:
    mlib_jai.dll
    mlib_jai_mmx.dll
    mlib_jai_util.dll


Step 2: Test the install by getting a "Hello World" program working.
Let's fire up Eclipse (Luna, x64) and see what can be done....

Eclipse is setup to use its own built in compiler at a compliance level of 1.7.
I have set Eclipse up with the JRE built into my installed JDK, so the JRE that we're going to use for the first test is an x64 JDK 1.7.0_51.

I found an example test application at this URL: http://jai-api.blogspot.ca/ (JAISampleProgram) which looks like it's reasonably short.

Copy the code into Eclipse and add all three JAR files from the JAI install location in step 1 to the classpath. When I save the code it now compiles.

Change the location of the image to load to a file that actually exists. I'm using a random jpeg.

Click Run (or Debug) and wow, it works!

That's a 10% scale in both X and Y dimensions of my source image. Note that since nobody bothered to code the X button to actually do anything you'll have to kill the app through Eclipse or the command line.

When I ran the application, I got the following error:

Error: Could not load mediaLib accelerator wrapper classes. Continuing in pure Java mode.
Occurs in: com.sun.media.jai.mlib.MediaLibAccessor
com.sun.media.jai.mlib.MediaLibLoadException


Sounds like native acceleration isn't working. I don't really care at this point if it works or not, so let's just get rid of that warning....

static
{
    System.setProperty("com.sun.media.jai.disableMediaLib", "true");
}


There are other ways to get rid of it too, as described on this post: 
https://www.java.net/node/666373

And there we have it. Apparently JAI does indeed run in an x64 bit environment. Can't say the same for JMF, which is another one of my required libraries, so this will be getting demoted to x86 when I start doing actual development.


Wednesday, 21 August 2013

Automatically compile different languages in GWT

How to integrate internationalization and localization into a GWT application? Assuming you're familiar with GWT internationalization, you probably answered "just put a language resource file into the appropriate source path, make sure your UI references these keys appropriately, and that you're using the Constants and Messages interfaces for everything dynamic". Fine.

Let's say you've done all that. Your application is fully internationalized. Now you want to localize it to three different languages, and I don't care what those languages are. You don't want to compile for all of those languages because that becomes a lot of permutations very quickly.

My default GWT compile is six different permutations per language. Three languages are 18 permutations, or 24 if you compile a "default" permutation. It takes me 10 minutes on my old computer to do just a six permutation build. I don't want a 40 minute compile, especially if I know ahead of time that whoever uses this application is going to want French only.

I'm also using ant as my build tool.

So I decided to take advantage of a little bit of automation.

Step 1: Create a new module file for each language.
This module file inherits the old module file and customizes the language only. Filename is App_2.gwt.xml.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.4.0//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.4.0/distro-source/core/src/gwt-module.dtd">
<module rename-to='app'>
    <inherits name="com.app.App" />

    <!-- Language specific compilation -->
    <extend-property name="locale" values="fr_CA" />
    <set-property-fallback name="locale" value="fr_CA" />
   
</module>


Step 2: Modify the ant script to build using this language file.
<java failonerror="true" fork="true" classname="com.google.gwt.dev.Compiler">
    <classpath>
        <path refid="project.class.path" />
    </classpath>
    <arg line="-war" />
    <arg value="war" />
    <arg value="com.app.App_2" />
</java>
I just changed the name of the GWT module that's being built, the rest of it's the same.

Step 3: Modify the ant script to copy the correct module over before the GWT compile even happens.

<copy todir="src/com/app" file="lang/App_2.gwt.xml" overwrite="true" />

All done. Now I can add new languages and all I need to maintain is a module file specifying which languages to include in a particular compilation. (And of course the language files themselves.)

Saturday, 6 July 2013

Linux and Java report filesystem space differently

I ran into something interesting this last week. Linux's ext2 filesystem and Java have a different opinion of what free space means, to the tune of 5% difference.

Let's take a look at how each application defines free space. Linux provides a df command that can be used to check free space:

root@system:/$ df Filesystem 1k-blocks Used Available Use% Mounted on /dev/hda2 7834788 2111688 5325092 28% /dev/hda1
 
Filesystem: The name of the partition.
1k-blocks: The total size of the partition, in blocks of 1024 B.
Used : The number of blocks that are used.
Available: The number of blocks that are available for use.
Use %: Equal to [ Used / ( Available + Used ) ].
Mounted on: The logical name of the partition.

Note a couple things here:
First:
Used + Available != Total available.
2,111,688+5,325,092 = 7,436,780

Total - (Used + Available)
7,834,788 - 7,436,780 = 398,008 blocks unaccounted for.

A little bit of research turned up that by default, Linux reserves 5% of the available space (in this case, 400MB) to help ensure the system remains defragmented. The space is hidden under the root user's account, so that even if the filesystem fills up completely, the root user will still be able to login.

Java, on the other hand, can see this 5% hidden space, and it includes it in its free space calculations. Java would calculate the available space as (2111688 + 398008 blocks ) = 2,509,696 blocks free. Java thinks there is 32% free space when there is in reality only 28% usable space.

I used the File.getFreeSpace() and File.getTotalSpace() methods from the Java 6 API to get the disk free values.

If you run a Java application as the root user, the extra hidden space never gets used. df only reports used space of up to 100% used. If the hidden space had been used, the use % column would increase to a maximum of 105% when the entire disk was actually full.

You can use tune2fs to configure the amount of space the ext2 filesystem is allowed to reserve. The -r option will configure the number of reserved blocks.

The lesson learned? Java isn't quite as smart as it pretends to be, and "free" space does not necessarily mean both free and usable.

Monday, 1 July 2013

Hello World!

Hello World! Just created my first blog post and looking forward to adding more.

What is this blog about?

Obvious in Hindsight is about using the past to guide our future decisions. We all make mistakes and we all learn from them. The trick is to never make the mistake again. If you've ever heard the saying "Fool me once, shame on you; fool me twice, shame on me", this blog is the place to be.

Here I will be recording the mistakes I make, things I learned from those mistakes, and general thoughts on things that could be done better. The content will be geared toward software development in a variety of languages. I'm currently working with Java at work and at home, so that's what a lot of the early posts will be about. I'm certain that some other topics will definitely work their way into the discussion.