TimeUnit

How many times have you got a millisecond long timestamp and had to compare it to a duration e.g. 1000 * 60 * 60 * 24 * … ? I stumbled upon this more readable and less error prone way of representing, say, 5 hours, by using the java.util.concurrent.TimeUnit.


private static final long FIVE_HOURS = TimeUnit.MILLISECONDS.convert(5, TimeUnit.HOURS);
...
if (timestamp < System.currentTimeMillis() - FIVE_HOURS) {
    // do something.
}

The above will check if a timestamp is overdue for more than five hours. The variable twoDays will have the value 172800000. TimeUnit supports from nanoseconds, micro-, milli-, all the way up to days.

However, if the date/locale is important to you (e.g. daylight savings) then you should use the Calendar API/JodaTime rather than this "duration"-based TimeUnit.

maven compile jrxml to jasper

Unless your jasper reports change at runtime, .jrxml templates should be compiled at compile time into .jasper, and you will not need JDT at runtime, nor need to re-compile the reports each time it is run.

If you’re on maven, simply paste the usage guide into your pom and change your JasperCompileManager.compileReport(InputStream) into JRLoader.loadObject(InputStream).

Change SVN commit message

This day finally came when I copied/paste the wrong bug number into the SVN commit message. Usually errors in SVN commit messages can be ignored but this particular one may lead to much confusion later. Luckily there was a way to edit the commit message after it’s committed. As usual I paste the command here instead of just the reference link as I have already some posts that have dead reference links.


svn propset -r 12345 --revprop svn:log "#1234 description"

where 12345 is the revision number, and text in quotes is the corrected commit message.

I still prefer to be cautious to commit messages correctly, but humans are just humans…

Ref: http://subversion.apache.org/faq.html#change-log-msg

Netbeans Subversion 1.6 vs 1.7

I installed the latest and greatest TortoiseSVN on a new PC (which happen to be for SVN 1.7), and happily upgraded my working copy when prompted. Newer is better isn’t it? After all, I didn’t like the .svn folder everywhere, which 1.7 got rid of with centralized metadata storage.

To my horror later, Netbeans wouldn’t update my workspace anymore, since the current version has no way to support 1.7 yet, other than the command line client. Fine, I installed the 1.7 CLI over my 1.6 CLI, but the Subversion features in Netbeans became sluggish and often show incorrect change flags until I manually activated Show Changes each time.

Downgrading to 1.6 was not an easy feat, I installed TortoiseSVN 1.6.16, judging by it being the latest release bound to SVN 1.6. I was lucky my SVN server is local so re-checking out my workspace was not that tough (I know some places which will take hours, and I haven’t found a “downgrade working copy” method that didn’t require a checkout).

Then Netbeans complained the working copy isn’t compatible anymore with my SVN 1.7 CLI. I cleared the SVN path setting, but couldn’t find any option to force it to revert to using the built-in bindings. Reinstalling the plugin did not help either. A half hour later I resorted to a brute force search on “subversion” in the netbeans folder and my home folder and I finally found this file:


C:\Users\%USERNAME%\.netbeans\7.1\config\Preferences\org\netbeans\modules\subversion.properties

where the option “forcedCommandline” is set to true. Changing it to false and restarting my IDE got me out of the situation and ended my fight with SVN 1.7. I still like the idea of the new working copy, so hopefully a new NB SVN plugin will be released soon.

Microsoft Outlook Sync Issues taking up folder size of Server Data

My mailbox gets full frequently despite constant archiving. I check the folder size using my mailbox properties to help me clear the problem areas since it shows the distribution of the data amongst the server folders. Most folders get cleared out, but one area that starts to build up over time in my Server Data’s folder list is the “Sync Issues\Conflicts”, which I could not clear.

Today I finally found the folder in “Go > Folder List > (left navigation panel)”, and managed to clear it out. To go back to the original folders, click “Go > Mail”.

Saving tabs of multiple windows in Chrome

Chrome restores all tabs when it is closed and reopened. This has been very useful for me but I got greedy. I now have multiple windows, with each window on a topic I’m search on. E.g. a window with tabs on different hotels and another window with tabs on day trips.

No perfection, but I found that Ctrl-Shift-D will bookmark all tabs into a bookmark folder, and right-clicking on a bookmark folder allows me to open all bookmarks in a bookmark folder to a new window.

Good enough for me.

Eclipse Launcher stays at splash screen for few minutes

Oddly this only happens once after the computer is restarted each time. Subsequently the loading would be much quicker.

Using the profiler the following stack trace is obtained:


main [RUNNABLE, IN_NATIVE] CPU time: 0:00
java.io.WinNTFileSystem.list(File)
java.io.File.list()
sun.security.provider.SeedGenerator$1.run()
java.security.AccessController.$$YJP$$doPrivileged(PrivilegedAction)
java.security.AccessController.doPrivileged(PrivilegedAction)
sun.security.provider.SeedGenerator.getSystemEntropy()
sun.security.provider.SecureRandom.engineNextBytes(byte[])
java.security.SecureRandom.nextBytes(byte[])
java.security.SecureRandom.next(int)
java.util.Random.nextLong()
java.io.File.generateFile(String, String, File)
java.io.File.createTempFile(String, String, File)
org.eclipse.core.runtime.adaptor.LocationManager.canWrite(File)
org.eclipse.core.runtime.adaptor.LocationManager.computeDefaultConfigurationLocation()
org.eclipse.core.runtime.adaptor.LocationManager.initializeLocations()
org.eclipse.core.runtime.adaptor.EclipseStarter.startup(String[], Runnable)
org.eclipse.core.runtime.adaptor.EclipseStarter.run(String[], Runnable)
sun.reflect.NativeMethodAccessorImpl.invoke0(Method, Object, Object[])
sun.reflect.NativeMethodAccessorImpl.invoke(Object, Object[])
sun.reflect.DelegatingMethodAccessorImpl.invoke(Object, Object[])
java.lang.reflect.Method.invoke(Object, Object[])
org.eclipse.equinox.launcher.Main.invokeFramework(String[], URL[])
org.eclipse.equinox.launcher.Main.basicRun(String[])
org.eclipse.equinox.launcher.Main.run(String[])
org.eclipse.equinox.launcher.Main.main(String[])

The main thread is stuck in a native File.list() method. From the SeedGenerator source code, there is only one location where it calls the File.list() method, and it happens to match the stack trace — inside an anonymous inner class. From there we can see that it is trying to list the temp folder (system property java.io.tmpdir). On Windows, this is the “%USERPROFILE%\Local Settings\Temp” folder.

When I do a directory listing on the folder, I get more than 100,000 temp files. Removing them solves the problem.

From the stack trace Eclipse startup was trying to test whether a folder is writable, by creating a temporary file, which uses a random number generator to generate the filename, in turn using the list of filenames from the TEMP folder as part of the seed. Essentially this problem would surface if you have a TEMP folder with many many files (regardless of size) and perform any of the following:

  • use File.list() on the folder (or any folder with many many files)
  • generate a random number
  • Create a temporary file
  • Starting up Eclipse runtime…

Does Windows cache the directory listing so that it’s faster next time?

When they say HashMap is not thread-safe, it means it is not.

We had this deadlock-like behavior where the UI froze sometimes when performing a particular action. But when run with our profiler, it did not report a deadlock when it froze.

After hours of tracing, the cause was identified as an infinite loop on the HashMap.get() method, running in the AWT Event Dispatch thread. The HashMap is the constraints object in a javax.swing.SpringLayout. Why would that happen???

More tracing revealed that there were multiple threads trying to add components to this container, triggering SpringLayout to add new constraints to its map. With reasonable luck the map hits its threshold and tries to resize itself. If you understand hashing you know that this is when it picks a new table size and re-hashes all the objects into its new buckets. When two of this happen at the same time the linked list screws up, and with more luck a later element in the link list points to the next element which is earlier in the same list. The worse part is this is a hidden problem, it doesn’t “surface” until you try to get() an object that’s even later than the later element, that’s when it iterates the bucket past the later element, back to the earlier element, and repeats.

The typical solution to swap the HashMap for a Hashtable is not available here, because the map exists in the core JDK. So it’s a good time to re-iterate to the team the significance of “single threaded model” of AWT/Swing. To be explicit, this issue was resolved by queuing the adding of components to the container on the Event Dispatch thread. Of course a more direct approach would be to synchronize the points where the components were added, but you shouldn’t be doing such things outside the AWT Event Dispatch thread anyway.

When I googled about the HashMap.get() infinite loop I realize it occurs in other areas as well, e.g. a Servlet’s session may be represented as a HashMap. Concurrent put()s and then a get() can cause the same problem.

abc.getXyz()

Why is it not good to keep using “abc.getXyz()” in the same method?

1. This is especially important if you are expecting the same value to be returned for each call. A 2nd call can potentially give you a different result from the first, therefore caching it in a local variable is a good idea.

2. The call may be expensive. Each call may be going through a web service to query a database for the return value. If you save it in a local variable it will only be done once. Even if you “know” that it doesn’t now, you should expect polymorphism.