January 27, 2011

Caching in Java

This is a very simple lightweight java caching class which I wrote a while ago. I originally wrote it to check whether a program had already been run with a particular set of conditions. The code isn't designed to be thread-safe and the it isn't particularly elegant since it was only required for one-off use. First, the class itself:

package util;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
*
* @author Mike Downey
*/
public class PersistentCache {

   private String cacheFile;
   private Map<Object,Object> dataCache;

   public PersistentCache(String cacheFile) {
       this.cacheFile = cacheFile;
       File cf = new File(cacheFile);
       if(cf.exists())
           try {
           dataCache = loadCache();
           return;
       } catch (IOException ex) {
           // if exception, start again with empty cache.
       }

       dataCache = new HashMap<Object,Object>();
   }

   public boolean contains(Object o){
       return dataCache.containsKey(o);
   }

   public Object get(Object key){
       return dataCache.get(key);
   }

   public void put(Object key, Object value){
       dataCache.put(key, value);
   }

   public Map<Object,Object> loadCache() throws IOException {
       BufferedInputStream fstream = new BufferedInputStream(
                       new FileInputStream(cacheFile));
       XMLDecoder instream = new XMLDecoder(fstream);
       Map<Object,Object> cached = (Map<Object,Object>) instream.readObject();
       instream.close();
       fstream.close();

       return cached;
   }

   public void writeCache() throws IOException {
       BufferedOutputStream fstream = new BufferedOutputStream(
                       new FileOutputStream(cacheFile));
       XMLEncoder ostream = new XMLEncoder(fstream);
       ostream.writeObject(dataCache);
       ostream.flush();
       ostream.close();
       fstream.close();
   }

}

Since the program runs then terminates, the cache had to be made persistent so I designed it to serialize the data. Of course this means any classes you need to store in the cache need to be serializable.

To use the class create an instance, passing the filename which is to be used for the cache:

PersistentCache pc = new PersistentCache(cacheFile);

The cache was intended to hold the input parameters and also the output values, so the data is stored as a map:

pc.put(parameterObject, returnValueObject);
pc.writeCache();

The cache does not automatically serialize itself back to disk whenever an object is added. This could easily be changed by putting a call to writeCache() in the put() method. The put() method will then need to either throw the IOException or handle it itself.

Check whether an object is in the cache using:

if(pc.contains(parameterObject)){
}

Retrieving objects is handled using:

returnValueObject = pc.get(parameterObject);

If caching requirements are very simple then it might not be worth using a heavyweight solution. The class isn't 'production ready' and I'm only using while running tests on some data.


January 18, 2011

Some OpenOffice notes

Adding images to slide shows usually adds linked images. To convert to embedded, select Edit -> Links and select 'Break Links'. Alternatively add images using 'Insert' -> Picture -> From File, and make sure 'Link' isn't selected.

If you don't follow the above procedure, the images will only be stored as 'links' to the files so you won't be able to copy the presentation onto a memory stick or another computer without copying all the image files too.


ImageJ Classloader Problems

Last week I wrote a stand-alone program which used the ImageJ libraries to do some image analysis. The program used a JavaBean to store its configuration data so I used the XMLEncoder and XMLDecoder classes to load and save the data. Everything worked ok as the original standalone app but when I tried to adapt it into an ImageJ plugin, everything started to go wrong.

Instead of loading the xml file and returning the bean, I was getting a null object. A similar problem occurred if I tried to create a new configuration and save it - I got an 'empty' xml file with no data in it.

Attempting to save the data gave the following error:

java.lang.ClassNotFoundException: test.BeanForTesting
Continuing ...
java.lang.Exception: XMLEncoder: discarding statement XMLEncoder.writeObject(BeanForTesting);
Continuing ...

Loading data gave a similar error:

SEVERE: null
java.lang.ArrayIndexOutOfBoundsException: 0
       at com.sun.beans.ObjectHandler.dequeueResult(ObjectHandler.java:139)
       at java.beans.XMLDecoder.readObject(XMLDecoder.java:201)

A bit of 'googling' found the answer here. Including the following line before I call my load and save methods does the trick:

Thread.currentThread().setContextClassLoader(getClass().getClassLoader());

So it looks like the ClassLoader used within ImageJ causes problems with the XMLEncoder/Decoder classes. The problem occurs whether the classes are all in the default package or not. The solution is a bit ungainly but provided it makes my program run correctly, it looks like it is needed at the moment.



January 14, 2010

Forging Java AWT Events

I am testing the user interface to a program which I have written, and I need to click on a few things to set things up before running the program.

I decided to see if I could 'fake' the AWT events, in order to force the program to think I had clicked on the various parts of the user interface. I couldn't find any information on the Internet on how to do this, so I had a mess around and this seems to work:

  1. Setting Checkboxes: If there is no action listener attached to the boxes, then it is a straightforward job of calling the .setState(boolean) method of the Checkbox.
  2. Selecting a field in a 'Choice' object: There was an event listener attched to the object, so this was a two-step process. First, select the relevent item:
    choiceObject.select("Text of Selection");

    Next, create a suitable ItemEvent object and pass it to the itemStateChanged method:

    ItemEvent e = new ItemEvent(choiceObject, ItemEvent.ITEM_STATE_CHANGED, choiceObject,ItemEvent.DESELECTED);
    itemStateChanged(e);

    I couldn't find a way of 'throwing' an event but this method worked and seemed to properly simulate choosing from the choice box.

  3. Activating the 'GO' button on the form was a simple job of calling the 'actionPerformed' method again, but passing an 'ActionEvent' this time:
    actionPerformed(new ActionEvent(theButton, ActionEvent.ACTION_PERFORMED,"");

January 08, 2010

File Renaming

I keep forgetting how to rename multiple files according to a pattern. The Unix/Linux rename command allows rename old new file-list, eg.

rename txt csv mydata*.txt

to rename all eg. mydata01.txt to .csv files. The body of the filename can also be changed. eg:

rename data measurements mydata*.txt

October 06, 2009

Batch File Stuff

To convert multiple images from one format to another, the ImageMagick program doesn’t accept wildcards.

Put this in a batch file eg. doconv.bat

FOR /f “delims=” %? IN (‘DIR/b *.%1’) DO convert %n?.1 %n?.%2

and call it using

doconv png eps

to convert from png to eps.


October 01, 2009

Java Regular Expressions

This is another of those things which have been added to Java since I first learnt it. I've been using regular expressions in Perl for years. I've been using things like String.matches() and similar in Java for a while but I hadn't delved into more advanced/useful regex functions.

One of the most useful things in Perl regex is using brackets to do capturing. It's a bit more long winded in Java but not too bad. For example to match (a,b) in a string and pick out the a and b values, I used:

Pattern RANGEPATTERN= Pattern.compile("\\((\\d*),(\\d*)\\)");
Matcher m = RANGEPATTERN.matcher(nextLine);
if(m.matches()){
startRange = Integer.parseInt(m.group(1));
endRange = Integer.parseInt(m.group(2));
}


February 04, 2009

I think I need a new Java book

When I learned Java, it was from a book designed for Java 1.3 which the University recommended to me. I didn't know that Java 1.4 has already been released. A few weeks after I bought the book, an updated version for Java 1.4 came out.

As a result, most of my Java programming is based on older language structures. I use the latest javadocs for the current classes available in 1.6, but there have been a few changes to the language which I was unaware of.

The first one I came across was generics. This seems to be a useful way of dealing with collections which can contain any type of Object. By declaring what type the collection can contain, the compiler can make sure you don't try to a square peg into a round list or vice versa.

I only found out about the second new feature earlier this morning. I have been programming in Perl for a few years and I'm used to using the foreach loop to iterate through arrays. I didn't know that Java had had a similar version since 1.5:

for(int i : myIntArray){
doSomething(i);
}

I'll need to have a look to see what other new useful features are out there which I haven't discovered yet.


October 08, 2008

Relearning Java

It's been a few years since I did any serious Java programming. The last time I seriously used it was 2004 when I did my Computer Science MSc project. Although I could remember the basics I made some silly mistakes, mainly maths related errors caused by mixing floats and ints. I've been doing most of my recent programming in Perl which only has one type of numerical variable.

I've been reading a textbook - Digital Image Processing: An Algorithmic Introduction using Java and working through some of the exercises and examples. My supervisor lent me the book to read. I'll be needing to do some java based image processing so it should come in handy.


June 2021

Mo Tu We Th Fr Sa Su
May |  Today  |
   1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30            

Search this blog

Tags

Galleries

Most recent comments

  • The class wasn't supposed to be thread–safe because I wrote it for a single stand–alone application … by on this entry
  • Be careful with HashMap, it isn't thread–safe so you can get unexpected results when accessing your … by Mathew Mannion on this entry
  • I realise that I shouldn't do things this way but it was only a quick shortcut to save me from click… by on this entry
  • If you use Swing rather than just plain AWT*, then you can use Fest . There are a few other tools in… by Chris May on this entry
  • If you already know the core language, and you just need to get up to speed on the 1.5 language chan… by Chris May on this entry

Blog archive

Loading…
RSS2.0 Atom
Not signed in
Sign in

Powered by BlogBuilder
© MMXXI