public class Storage

  1. Object
  2. Storage

Abstracts the underlying application specific storage system, unlike the com.codename1.io.FileSystemStorage this class is a higher level abstraction. The Storage class is designed to be very portable and as such it has no support for staple file system capabilities such as hierarchies.

Check out a more thorough discussion of this API here.

The sample code below shows a simple storage browser tool in action:

public void showForm() {
    Toolbar.setGlobalToolbar(true);
    Form hi = new Form("Storage", new BoxLayout(BoxLayout.Y_AXIS));
    hi.getToolbar().addCommandToRightBar("+", null, (e) -> {
        TextField tf = new TextField("", "File Name", 20, TextField.ANY);
        TextArea body = new TextArea(5, 20);
        body.setHint("File Body");
        Command ok = new Command("OK");
        Command cancel = new Command("Cancel");
        Command result = Dialog.show("File Name", BorderLayout.north(tf).add(BorderLayout.CENTER, body), ok, cancel);
        if(ok == result) {
            try(OutputStream os = Storage.getInstance().createOutputStream(tf.getText())) {
                os.write(body.getText().getBytes("UTF-8"));
                createFileEntry(hi, tf.getText());
                hi.getContentPane().animateLayout(250);
            } catch(IOException err) {
                Log.e(err);
            }
        }
    });

    for(String file : Storage.getInstance().listEntries()) {
        createFileEntry(hi, file);
    }
    hi.show();
}

private void createFileEntry(Form hi, String file) {
   Label fileField = new Label(file);
   Button delete = new Button();
   Button view = new Button();
   FontImage.setMaterialIcon(delete, FontImage.MATERIAL_DELETE);
   FontImage.setMaterialIcon(view, FontImage.MATERIAL_OPEN_IN_NEW);
   Container content = BorderLayout.center(fileField);
   int size = Storage.getInstance().entrySize(file);
   content.add(BorderLayout.EAST, BoxLayout.encloseX(new Label(size + "bytes"), delete, view));
   delete.addActionListener((e) -> {
       Storage.getInstance().deleteStorageFile(file);
       content.setY(hi.getWidth());
       hi.getContentPane().animateUnlayoutAndWait(150, 255);
       hi.removeComponent(content);
       hi.getContentPane().animateLayout(150);
   });
   view.addActionListener((e) -> {
       try(InputStream is = Storage.getInstance().createInputStream(file)) {
           String s = Util.readToString(is, "UTF-8");
           Dialog.show(file, s, "OK", null);
       } catch(IOException err) {
           Log.e(err);
       }
   });
   hi.add(content);
}

Constructors

public Storage()

Methods

public static boolean isInitialized()Returns true if the storage is initialized
public static Storage getInstance()Returns the storage instance or null if the storage wasn’t initialized using a call to init(String) first.
public static void setStorageInstance(Storage s)Allows installing a custom storage instance to provide functionality such as seamless encryption
public void setHardCacheSize(int size)Indicates the caching size, storage can be pretty slow
public void clearCache()Storage is cached for faster access, however this might cause a problem with refreshing objects since they are not cloned.
public void flushStorageCache()Flush the storage cache allowing implementations that cache storage objects to store
public void deleteStorageFile(String name)Deletes the given file name from the storage
public void clearStorage()Deletes all the files in the application storage
public OutputStream createOutputStream(String name) throws IOExceptionCreates an output stream to the storage with the given name
public InputStream createInputStream(String name) throws IOExceptionCreates an input stream to the given storage source file
public boolean exists(String name)Returns true if the given storage file exists
public String[] listEntries()Lists the names of the storage files
public int entrySize(String name)Returns the size in bytes of the given entry
public boolean writeObject(String name, Object o)Writes the given object to storage assuming it is an externalizable type or one of the supported types.
public boolean writeObject(String name, Object o, boolean includeLogging)Writes the given object to storage assuming it is an externalizable type or one of the supported types.
protected OutputStream createOutputStreamForWrite(String name) throws IOExceptionCreates the stream that writeObject writes a whole value into.
public Object readObject(String name)Reads the object from the storage, returns null if the object isn’t there
public Object readObject(String name, boolean includeLogging)Reads the object from the storage, returns null if the object isn’t there
public boolean isNormalizeNames()Indicates whether characters that are typically illegal in filesystems should be sanitized and replaced with underscore
public void setNormalizeNames(boolean normalizeNames)Indicates whether characters that are typically illegal in filesystems should be sanitized and replaced with underscore

Inherited methods

Constructor details

Storage

public Storage()

Method details

isInitialized

public static boolean isInitialized()
Returns true if the storage is initialized

Returns

true if the storage is initialized

getInstance

public static Storage getInstance()
Returns the storage instance or null if the storage wasn’t initialized using a call to init(String) first.

Returns

storage instance

setStorageInstance

public static void setStorageInstance(Storage s)
Allows installing a custom storage instance to provide functionality such as seamless encryption

Parameters

s Storage
the storage instance

setHardCacheSize

public void setHardCacheSize(int size)
Indicates the caching size, storage can be pretty slow

Parameters

size int
size in elements (not kb!)

clearCache

public void clearCache()
Storage is cached for faster access, however this might cause a problem with refreshing objects since they are not cloned. Clearing the cache allows to actually reload from the storage file.

flushStorageCache

public void flushStorageCache()
Flush the storage cache allowing implementations that cache storage objects to store

deleteStorageFile

public void deleteStorageFile(String name)
Deletes the given file name from the storage

Parameters

name String
the name of the storage file

clearStorage

public void clearStorage()
Deletes all the files in the application storage

createOutputStream

public OutputStream createOutputStream(String name) throws IOException
Creates an output stream to the storage with the given name

Parameters

name String
the storage file name

Returns

an output stream of limited capacity

createInputStream

public InputStream createInputStream(String name) throws IOException
Creates an input stream to the given storage source file

Parameters

name String
the name of the source file

Returns

the input stream

exists

public boolean exists(String name)
Returns true if the given storage file exists

Parameters

name String
the storage file name

Returns

true if it exists

listEntries

public String[] listEntries()
Lists the names of the storage files

Returns

the names of all the storage files

entrySize

public int entrySize(String name)
Returns the size in bytes of the given entry

Parameters

name String
the name of the entry

Returns

the size in bytes

writeObject

public boolean writeObject(String name, Object o)

Writes the given object to storage assuming it is an externalizable type or one of the supported types.

The sample below demonstrates the usage and registration of the com.codename1.io.Externalizable interface:

// File: Main.java
public class Main {
  public void init(Object o) {
    theme = UIManager.initFirstTheme("/theme");

    // IMPORTANT: Notice we don't use MyClass.class.getName()! This won't work due to obfuscation!
    Util.register("MyClass", MyClass.class);
  }

  public void start() {
    //...
  }

  public void stop() {
    //...
  }

  public void destroy() {
    //...
  }
}
// File: MyClass.java
public class MyClass implements Externalizable {
  // allows us to manipulate the version, in this case we are demonstrating a data change between the initial release
  // and the current state of object data
  private static final int VERSION = 2;

  private String name;
  private Map data;

  // this field was added after version 1
  private Date startedAt;

  public int getVersion() {
    return VERSION;
  }

  public void externalize(DataOutputStream out) throws IOException {
    Util.writeUTF(name, out);
    Util.writeObject(data, out);
    if(startedAt != null) {
        out.writeBoolean(true);
        out.writeLong(startedAt.getTime());
    } else {
        out.writeBoolean(false);
    }
  }
  public void internalize(int version, DataInputStream in) throws IOException {
    name = Util.readUTF(in);
    data = (Map)Util.readObject(in);
    if(version > 1) {
        boolean hasDate = in.readBoolean();
        if(hasDate) {
            startedAt = new Date(in.readLong());
        }
    }
  }
  public String getObjectId() {
    // IMPORTANT: Notice we don't use getClass().getName()! This won't work due to obfuscation!
    return "MyClass";
  }
}
// File: ReadAndWrite.java
// will read the file or return null if failed
MyClass object = (MyClass)Storage.getInstance().readObject("NameOfFile");

// write the object back to storage
Storage.getInstance().writeObject("NameOfFile", object);

Parameters

name String
store name
o Object
object to store

Returns

true for success, false for failure

writeObject

public boolean writeObject(String name, Object o, boolean includeLogging)

Writes the given object to storage assuming it is an externalizable type or one of the supported types.

The sample below demonstrates the usage and registration of the com.codename1.io.Externalizable interface:

// File: Main.java
public class Main {
  public void init(Object o) {
    theme = UIManager.initFirstTheme("/theme");

    // IMPORTANT: Notice we don't use MyClass.class.getName()! This won't work due to obfuscation!
    Util.register("MyClass", MyClass.class);
  }

  public void start() {
    //...
  }

  public void stop() {
    //...
  }

  public void destroy() {
    //...
  }
}
// File: MyClass.java
public class MyClass implements Externalizable {
  // allows us to manipulate the version, in this case we are demonstrating a data change between the initial release
  // and the current state of object data
  private static final int VERSION = 2;

  private String name;
  private Map data;

  // this field was added after version 1
  private Date startedAt;

  public int getVersion() {
    return VERSION;
  }

  public void externalize(DataOutputStream out) throws IOException {
    Util.writeUTF(name, out);
    Util.writeObject(data, out);
    if(startedAt != null) {
        out.writeBoolean(true);
        out.writeLong(startedAt.getTime());
    } else {
        out.writeBoolean(false);
    }
  }
  public void internalize(int version, DataInputStream in) throws IOException {
    name = Util.readUTF(in);
    data = (Map)Util.readObject(in);
    if(version > 1) {
        boolean hasDate = in.readBoolean();
        if(hasDate) {
            startedAt = new Date(in.readLong());
        }
    }
  }
  public String getObjectId() {
    // IMPORTANT: Notice we don't use getClass().getName()! This won't work due to obfuscation!
    return "MyClass";
  }
}
// File: ReadAndWrite.java
// will read the file or return null if failed
MyClass object = (MyClass)Storage.getInstance().readObject("NameOfFile");

// write the object back to storage
Storage.getInstance().writeObject("NameOfFile", object);

Parameters

name String
store name
o Object
object to store
includeLogging boolean
During app initialization, the logging on error might impact the apps stability

Returns

true for success, false for failure

createOutputStreamForWrite

protected OutputStream createOutputStreamForWrite(String name) throws IOException

Creates the stream that writeObject writes a whole value into.

This is deliberately not createOutputStream. That one is the public streaming API, where a caller may hold the stream open and read back what it has flushed – the log writer keeps one for the life of the application – so it goes on writing into the entry. A whole value has no such expectation, and so can be given what streaming cannot: it is assembled away from the entry and put in place as one step, where the platform is able to, so the entry is never seen half written and a write that fails leaves what was stored alone.

A Storage installed through setStorageInstance to wrap the bytes – the seamless encryption that extension point exists for – has always had writeObject go through its own createOutputStream, and still does: bypassing it would write those bytes past the encryption while reads went on expecting it. Such a subclass can override this method to take the stronger guarantee as well, wrapping what the superclass returns.

Parameters

name String
the storage file name, already normalized

Returns

the stream to write the value into

readObject

public Object readObject(String name)

Reads the object from the storage, returns null if the object isn’t there

The sample below demonstrates the usage and registration of the com.codename1.io.Externalizable interface:

// File: Main.java
public class Main {
  public void init(Object o) {
    theme = UIManager.initFirstTheme("/theme");

    // IMPORTANT: Notice we don't use MyClass.class.getName()! This won't work due to obfuscation!
    Util.register("MyClass", MyClass.class);
  }

  public void start() {
    //...
  }

  public void stop() {
    //...
  }

  public void destroy() {
    //...
  }
}
// File: MyClass.java
public class MyClass implements Externalizable {
  // allows us to manipulate the version, in this case we are demonstrating a data change between the initial release
  // and the current state of object data
  private static final int VERSION = 2;

  private String name;
  private Map data;

  // this field was added after version 1
  private Date startedAt;

  public int getVersion() {
    return VERSION;
  }

  public void externalize(DataOutputStream out) throws IOException {
    Util.writeUTF(name, out);
    Util.writeObject(data, out);
    if(startedAt != null) {
        out.writeBoolean(true);
        out.writeLong(startedAt.getTime());
    } else {
        out.writeBoolean(false);
    }
  }
  public void internalize(int version, DataInputStream in) throws IOException {
    name = Util.readUTF(in);
    data = (Map)Util.readObject(in);
    if(version > 1) {
        boolean hasDate = in.readBoolean();
        if(hasDate) {
            startedAt = new Date(in.readLong());
        }
    }
  }
  public String getObjectId() {
    // IMPORTANT: Notice we don't use getClass().getName()! This won't work due to obfuscation!
    return "MyClass";
  }
}
// File: ReadAndWrite.java
// will read the file or return null if failed
MyClass object = (MyClass)Storage.getInstance().readObject("NameOfFile");

// write the object back to storage
Storage.getInstance().writeObject("NameOfFile", object);

Parameters

name String
name of the store

Returns

object stored under that name

readObject

public Object readObject(String name, boolean includeLogging)

Reads the object from the storage, returns null if the object isn’t there

The sample below demonstrates the usage and registration of the com.codename1.io.Externalizable interface:

// File: Main.java
public class Main {
  public void init(Object o) {
    theme = UIManager.initFirstTheme("/theme");

    // IMPORTANT: Notice we don't use MyClass.class.getName()! This won't work due to obfuscation!
    Util.register("MyClass", MyClass.class);
  }

  public void start() {
    //...
  }

  public void stop() {
    //...
  }

  public void destroy() {
    //...
  }
}
// File: MyClass.java
public class MyClass implements Externalizable {
  // allows us to manipulate the version, in this case we are demonstrating a data change between the initial release
  // and the current state of object data
  private static final int VERSION = 2;

  private String name;
  private Map data;

  // this field was added after version 1
  private Date startedAt;

  public int getVersion() {
    return VERSION;
  }

  public void externalize(DataOutputStream out) throws IOException {
    Util.writeUTF(name, out);
    Util.writeObject(data, out);
    if(startedAt != null) {
        out.writeBoolean(true);
        out.writeLong(startedAt.getTime());
    } else {
        out.writeBoolean(false);
    }
  }
  public void internalize(int version, DataInputStream in) throws IOException {
    name = Util.readUTF(in);
    data = (Map)Util.readObject(in);
    if(version > 1) {
        boolean hasDate = in.readBoolean();
        if(hasDate) {
            startedAt = new Date(in.readLong());
        }
    }
  }
  public String getObjectId() {
    // IMPORTANT: Notice we don't use getClass().getName()! This won't work due to obfuscation!
    return "MyClass";
  }
}
// File: ReadAndWrite.java
// will read the file or return null if failed
MyClass object = (MyClass)Storage.getInstance().readObject("NameOfFile");

// write the object back to storage
Storage.getInstance().writeObject("NameOfFile", object);

Parameters

name String
name of the store
includeLogging boolean
During app initialization, the logging on error might impact the apps stability

Returns

object stored under that name

isNormalizeNames

public boolean isNormalizeNames()
Indicates whether characters that are typically illegal in filesystems should be sanitized and replaced with underscore

Returns

the normalizeNames

setNormalizeNames

public void setNormalizeNames(boolean normalizeNames)
Indicates whether characters that are typically illegal in filesystems should be sanitized and replaced with underscore

Parameters

normalizeNames boolean
the normalizeNames to set