# Class Storage

java.lang.Object
com.codename1.io.Storage

public class Storage extends Object

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);
    }

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `Storage()`

- ## Method Summary

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

  ### Methods inherited from class Object

  `clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## 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`: the storage instance

  - ### setHardCacheSize

    public void setHardCacheSize(int size)

    Indicates the caching size, storage can be pretty slow

    ###### Parameters

    - `size`: 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`: 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`: the storage file name

    ###### Returns

    an output stream of limited capacity

    Throws:
      `IOException`

  - ### createInputStream

    public InputStream createInputStream(String name) throws IOException

    Creates an input stream to the given storage source file

    ###### Parameters

    - `name`: the name of the source file

    ###### Returns

    the input stream

    Throws:
      `IOException`

  - ### exists

    public boolean exists(String name)

    Returns true if the given storage file exists

    ###### Parameters

    - `name`: 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`: 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`: store name

    - `o`: 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`: store name

    - `o`: object to store

    - `includeLogging`: 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`: the storage file name, already normalized

    ###### Returns

    the stream to write the value into

    Throws:
      `IOException`

  - ### 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`: 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`: name of the store

    - `includeLogging`: 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`: the normalizeNames to set