ZiltiTech

Desktop and server programming with the JVM

Howto: Doing some storage in JavaFX

, ,

Today I'll show you an example of how you can use the storage API efficiently. For my social-networking-app Lopia I wrote some wrapper code around the JavaFX Storage API. I won't write about the Storage API itself, because there's a detailed description using examples in the JavaFX API.

I'm not an expert in code design or design patterns at all, but nonetheless I want to share my work with the hope that people which are new to JavaFX will find it helpful and that I'll get some feedback when I've designed it badly.

So why do I use the JavaFX Storage API? For me it's pretty clear: For signed applications it provides a huge lot of storage (as far as I remember over 80 MiB), it provides still some storage for unsigned ones, and it's platform independent, which means it will work without changes on a TV or a mobile. The second reason is that the files get removed, too, if the user decides to uninstall the application. This can be a problem in some situations. But I'll give my users the possibility to save their settings "in the cloud" anyway.

For my storage implementation, I used key/value pairs which get stored in one file per class. The files are by "convention" named as "package.class.param1.param2" (add more params if you like to).
I then made three .fx-Files, two of them simply holding data:

  • Store.fx which manages the storage itself trought the storage API
  • Setting.fx a class which simply holds a key/value-pair
  • SettingsContainer.fx a class which holds all Setting-classes of one class and provides functions (well, as of now, only one) to access (and later maybe write) the settings stored inside and direct access to the Setting-classes.


Well, let's start with the simplest part: The Setting.fx:
public class Setting {
    public var key:String;
    public var value:String;
}

I think that's pretty obvious. Now we have the SettingsContainer.fx which manages the setting-classes:
public class SettingsContainer {
    public var settings:Setting[];
    public function getSettingValue(key:String):String {
        var value:String;
        for(setting in settings) {
            if(setting.key == key) {
                value = setting.value;
            }
        }
        return value;
    }
}

Now, as we have the data-holding classes, we get to the Store.fx which is - surprise! - not a class but simply a script file, because it doesn't make sense to have multiple instances of it:
public function store(component:String, settings:SettingsContainer):Void {
    var store = Storage {
        source: "{component}"
    }
    var writer = new BufferedWriter(new OutputStreamWriter(store.resource.openOutputStream(true)));
    for(setting in settings.settings) {
        writer.write("{setting.key}~{setting.value}");
        writer.newLine();
    }
    writer.close();
}
public function load(component:String):SettingsContainer {
    var store = Storage {
        source: "{component}"
    }
    var reader = new BufferedReader(new InputStreamReader(store.resource.openInputStream()));
    var line:String;
    var ret = SettingsContainer{};
    while((line = reader.readLine()) != null) {
        var lineSplit = line.split("~");
        insert Setting {
            key: lineSplit[0]
            value: lineSplit[1]
        } into ret.settings;
    }
    return ret;
}

As you can read out of the code, the "library" unfortunately isn't capable of being used in the JavaFX Mobile runtime, because it uses the String.split() method. I have to figure out how to replace this functionality (with the substring method if it's available, or by writing the key and value on different lines), but as of now it's ok. There aren't any JavaFX-capable phones, anyway.

"Proof of concept" Series: Drag and DropLopia opensourced under the GPL

Comments

Anonymous Monday, May 24, 2010 1:12:23 PM

Jasper Potts writes: JavaFX already has a Properties object for storing key/value pairs. It has methods to load/save to stream so can be combined with Storage object to save key/value pairs on all platforms with same code. Here is the code that works for me, hope its helpful :-) /** * Load the data in named data store {@code dataSourceName} into the given * properties object {@code props}. * * @param dataSourceName The name of the data source to read from * @param props The properties object to populate */ override function loadProperties(dataSourceName:String, props:Properties):Void { def storage:Storage = Storage{ source: dataSourceName}; if (storage.resource.length > 0 and storage.resource.readable) { def streamIn = storage.resource.openInputStream(); props.load(streamIn); streamIn.close(); } } /** * Save the data in the given properties object {@code props} into the named * data store {@code dataSourceName}. * * @param dataSourceName The name of the data source to write to * @param props The properties object containing the data to write */ override function saveProperties(dataSourceName:String, props:Properties):Void { def storage:Storage = Storage{ source: dataSourceName}; def streamOut = storage.resource.openOutputStream(true); props.store(streamOut); streamOut.flush(); streamOut.close(); }

Anonymous Wednesday, May 26, 2010 4:05:47 PM

Anonymous writes: Daniel, you might like to take a look at the XStore class in the JFXtras project and see if any of that is relevant. There is a demo application as well. Allows for lots of functionality over application persistent data stores to make life lots easier.

Anonymous Wednesday, May 26, 2010 6:59:27 PM

Ranbir Mazumdar writes: Daniel, Here is a JavaFX 1.3 mobile safe split method. I have used this successfully in my FX mobile application. All you need to do is create a utility java class and use this instead of the regular String split(): Here is the code: // A Java ME safe String.split() implementation for the JavaFX Mobile target public class SafeSplitter { public static String[] split(String original,String separator) { ArrayList nodes = new ArrayList(); // Parse nodes into ArrayList int index = original.indexOf(separator); while(index >= 0) { nodes.add( original.substring(0, index) ); original = original.substring(index+separator.length()); index = original.indexOf(separator); } // Get the last node nodes.add( original ); // Create split string array String[] result = new String[ nodes.size() ]; if( nodes.size() > 0 ) { for(int loop = 0; loop

Anonymous Wednesday, May 26, 2010 7:01:07 PM

Ranbir Mazumdar writes: Rest of the code // Create split string array String[] result = new String[ nodes.size() ]; if( nodes.size() > 0 ) { for(int loop = 0; loop

Anonymous Wednesday, June 2, 2010 3:48:58 AM

Ranbir Mazumdar writes: Here is a link to the code on my blog. Copy paste did not work out as expected for me above. http://ivoice.blogspot.com/2010/06/stringsplit-implementation-for-javafx.html

How to use Quote function:

  1. Select some text
  2. Click on the Quote link

Write a comment

Comment
(BBcode and HTML is turned off for anonymous user comments.)

If you can't read the words, press the small reload icon.


Smilies