Skip to content

Commit

Permalink
- refactored uuid object
Browse files Browse the repository at this point in the history
- README contains api
  • Loading branch information
dcale committed Jan 31, 2016
1 parent c5cff6f commit b3ffe90
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 49 deletions.
94 changes: 91 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,96 @@
# Simple Object Storage

This is a Java library, that allows you to store/persist and retrieve objects.
This is a Java/Android library, that allows you to store/persist and retrieve objects.
The library's only dependency is gson, which is used for object serialization.
The core idea was to have a clean storage API that keeps things as simple as possible.

## API
The best documentation on how the lib should be used are its Unit Tests. The first thing you want to
do to persist an object is to implement the UuidObject interface of directly extend the AbstractUuidObject.
The reason you have to do this is because the library relies on UUID's for accessing specific objects:

```Java
public class TestModel extends AbstractUuidObject {
private final String name;
private final String description;

public TestModel(String name, String description) {
this.name = name;
this.description = description;
}
}
```

### Storing an Object
```Java
public final static File STORAGE_ROOT = new File(".");

// initialize the singleton
UuidObjectStorage.getInstance().init(STORAGE_ROOT);

// add a new TestModel
TestModel model = new TestModel("my name","my description");
UuidObjectStorage.getInstance().addEntry(model, new OnResultListener<TestModel>() {
@Override
public void onSuccess(TestModel result) {
// TestModel has been added successfully to the storage
}

@Override
public void onError(String message) {
// Oops something went wrong...
}
}, TestModel.class);

// after having added the model, it will be accessible in you app, but it has not been persisted yet.
// you need to commit in order to persist to disk.
UuidObjectStorage.getInstance().commit(new OnResultListener<String>() {
@Override
public void onSuccess(String result) {
// commit successful, everything was persisted
}

@Override
public void onError(String message) {
// Oops something went wrong...
}
});
```

### Retrieving an Object
```Java
UuidObjectStorage.getInstance().getEntries(new OnResultListener<Map<UUID, TestModel>>() {
@Override
public void onSuccess(Map<UUID, TestModel> result) {
// your entries have been retrieved
}

@Override
public void onError(String message) {
// Oops something went wrong...
}
}, TestModel.class);
```

### Working with Filters
```Java
UuidObjectStorage.getInstance().getEntriesAsList(new Filter<TestModel>() {
@Override
public boolean matches(TestModel object) {
return object.getName().equals("my name");
}
}, new OnResultListener<List<TestModel>>() {
@Override
public void onSuccess(List<TestModel> result) {
// this will return a list with all models with the name "my name"
}

@Override
public void onError(String message) {
// Oops something went wrong...
}
}, TestModel.class);
```



## FAQ
Expand All @@ -31,4 +117,6 @@ But it solves the same problem like an ORM (persisting Java Objects).

- Nothing is synchronous, I want my object now! What can I do?
Reading from disk is expensive and can encounter issues (like no permission to read or no file).
That's the reason why the library is completely asynchronous and works with callbacks.
That's the reason why the library is completely asynchronous and works with callbacks. If you really want
to wait for an object and make the code synchronous, you will need to work with CountDown latches. However I recommend
to keep things asynchronous.
6 changes: 3 additions & 3 deletions src/main/java/ch/papers/objectstorage/UuidObjectMapType.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import java.util.Map;
import java.util.UUID;

import ch.papers.objectstorage.models.UuidObject;
import ch.papers.objectstorage.models.AbstractUuidObject;


/**
Expand All @@ -14,9 +14,9 @@
* [email protected]
*/
public class UuidObjectMapType implements ParameterizedType {
private Class<? extends UuidObject> wrapped;
private Class<? extends AbstractUuidObject> wrapped;

public UuidObjectMapType(Class<? extends UuidObject> wrapper) {
public UuidObjectMapType(Class<? extends AbstractUuidObject> wrapper) {
this.wrapped = wrapper;
}

Expand Down
46 changes: 23 additions & 23 deletions src/main/java/ch/papers/objectstorage/UuidObjectStorage.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import ch.papers.objectstorage.filters.UuidFilter;
import ch.papers.objectstorage.listeners.OnResultListener;
import ch.papers.objectstorage.listeners.OnStorageChangeListener;
import ch.papers.objectstorage.models.UuidObject;
import ch.papers.objectstorage.models.AbstractUuidObject;

public class UuidObjectStorage {

Expand All @@ -43,14 +43,14 @@ private UuidObjectStorage() {

private File rootPath;

private final Map<Class<? extends UuidObject>, Map<UUID, ? extends UuidObject>> uuidObjectCache = new LinkedHashMap<Class<? extends UuidObject>, Map<UUID, ? extends UuidObject>>();
private final Map<Class<? extends UuidObject>, List<OnStorageChangeListener>> listeners = new HashMap<Class<? extends UuidObject>, List<OnStorageChangeListener>>();
private final Map<Class<? extends AbstractUuidObject>, Map<UUID, ? extends AbstractUuidObject>> uuidObjectCache = new LinkedHashMap<Class<? extends AbstractUuidObject>, Map<UUID, ? extends AbstractUuidObject>>();
private final Map<Class<? extends AbstractUuidObject>, List<OnStorageChangeListener>> listeners = new HashMap<Class<? extends AbstractUuidObject>, List<OnStorageChangeListener>>();

public synchronized void init(File rootPath) {
this.rootPath = rootPath;
}

public <T extends UuidObject> void addEntries(final Map<UUID, T> entries, final OnResultListener<Map<UUID, T>> resultCallback, final Class<T> clazz) {
public <T extends AbstractUuidObject> void addEntries(final Map<UUID, T> entries, final OnResultListener<Map<UUID, T>> resultCallback, final Class<T> clazz) {
new Thread(new Runnable() {
@Override
public void run() {
Expand All @@ -65,7 +65,7 @@ public void run() {
}).start();
}

public <T extends UuidObject> void addEntriesAsList(final List<T> entries, final OnResultListener<List<T>> resultCallback, final Class<T> clazz) {
public <T extends AbstractUuidObject> void addEntriesAsList(final List<T> entries, final OnResultListener<List<T>> resultCallback, final Class<T> clazz) {
final Map<UUID, T> entriesToAdd = new HashMap<UUID, T>();
for (T entry:entries) {
entriesToAdd.put(entry.getUuid(),entry);
Expand All @@ -84,7 +84,7 @@ public void onError(String message) {
},clazz);
}

public <T extends UuidObject> void addEntry(final T entry, final OnResultListener<T> resultCallback, final Class<T> clazz) {
public <T extends AbstractUuidObject> void addEntry(final T entry, final OnResultListener<T> resultCallback, final Class<T> clazz) {
final Map<UUID, T> entriesToAdd = new HashMap<UUID, T>();
entriesToAdd.put(entry.getUuid(),entry);
this.addEntries(entriesToAdd, new OnResultListener<Map<UUID,T>>() {
Expand All @@ -100,7 +100,7 @@ public void onError(String message) {
},clazz);
}

public <T extends UuidObject> void deleteEntry(final T entry, final OnResultListener<T> resultCallback, final Class<T> clazz) {
public <T extends AbstractUuidObject> void deleteEntry(final T entry, final OnResultListener<T> resultCallback, final Class<T> clazz) {
this.deleteEntries(new UuidFilter(entry.getUuid()), new OnResultListener<Map<UUID, T>>() {
@Override
public void onSuccess(Map<UUID, T> result) {
Expand All @@ -114,7 +114,7 @@ public void onError(String message) {
},clazz);
}

public <T extends UuidObject> void deleteEntries(final Filter<T> filter, final OnResultListener<Map<UUID, T>> resultCallback, final Class<T> clazz) {
public <T extends AbstractUuidObject> void deleteEntries(final Filter<T> filter, final OnResultListener<Map<UUID, T>> resultCallback, final Class<T> clazz) {
this.getEntries(filter, new OnResultListener<Map<UUID, T>>() {
@Override
public void onSuccess(Map<UUID, T> result) {
Expand All @@ -132,7 +132,7 @@ public void onError(String message) {
}, clazz);
}

public <T extends UuidObject> void getEntries(final Filter<T> filter, final OnResultListener<Map<UUID, T>> resultCallback, final Class<T> clazz) {
public <T extends AbstractUuidObject> void getEntries(final Filter<T> filter, final OnResultListener<Map<UUID, T>> resultCallback, final Class<T> clazz) {
new Thread(new Runnable() {
@Override
public void run() {
Expand All @@ -151,11 +151,11 @@ public void run() {
}).start();
}

public <T extends UuidObject> void getEntries(final OnResultListener<Map<UUID, T>> resultCallback, final Class<T> clazz) {
public <T extends AbstractUuidObject> void getEntries(final OnResultListener<Map<UUID, T>> resultCallback, final Class<T> clazz) {
this.getEntries(new MatchAllFilter(), resultCallback, clazz);
}

public <T extends UuidObject> void getEntriesAsList(final Filter<T> filter, final OnResultListener<List<T>> resultCallback, final Class<T> clazz) {
public <T extends AbstractUuidObject> void getEntriesAsList(final Filter<T> filter, final OnResultListener<List<T>> resultCallback, final Class<T> clazz) {
this.getEntries(filter, new OnResultListener<Map<UUID, T>>() {
@Override
public void onSuccess(Map<UUID, T> result) {
Expand All @@ -169,11 +169,11 @@ public void onError(String message) {
}, clazz);
}

public <T extends UuidObject> void getEntriesAsList(final OnResultListener<List<T>> resultCallback, final Class<T> clazz) {
public <T extends AbstractUuidObject> void getEntriesAsList(final OnResultListener<List<T>> resultCallback, final Class<T> clazz) {
this.getEntriesAsList(new MatchAllFilter(), resultCallback, clazz);
}

public <T extends UuidObject> void getFirstMatchEntry(final Filter<T> filter, final OnResultListener<T> resultCallback, final Class<T> clazz) {
public <T extends AbstractUuidObject> void getFirstMatchEntry(final Filter<T> filter, final OnResultListener<T> resultCallback, final Class<T> clazz) {
this.getEntries(filter, new OnResultListener<Map<UUID, T>>() {
@Override
public void onSuccess(Map<UUID, T> result) {
Expand All @@ -191,27 +191,27 @@ public void onError(String message) {
},clazz);
}

public <T extends UuidObject> void getEntry(final UUID uuid, final OnResultListener<T> resultCallback, final Class<T> clazz) {
public <T extends AbstractUuidObject> void getEntry(final UUID uuid, final OnResultListener<T> resultCallback, final Class<T> clazz) {
this.getFirstMatchEntry(new UuidFilter(uuid),resultCallback,clazz);
}

public <T extends UuidObject> void registerOnChangeListener(OnStorageChangeListener onStorageChangeListener, final Class<T> clazz) {
public <T extends AbstractUuidObject> void registerOnChangeListener(OnStorageChangeListener onStorageChangeListener, final Class<T> clazz) {
final List<OnStorageChangeListener> listeners = this.getOrCreateListenerList(clazz);
listeners.add(onStorageChangeListener);
}

public <T extends UuidObject> void unRegisterOnChangeListener(OnStorageChangeListener onStorageChangeListener, final Class<T> clazz) {
public <T extends AbstractUuidObject> void unRegisterOnChangeListener(OnStorageChangeListener onStorageChangeListener, final Class<T> clazz) {
final List<OnStorageChangeListener> listeners = this.getOrCreateListenerList(clazz);
listeners.remove(onStorageChangeListener);
}

public void commit(final OnResultListener<String> resultCallback) {
for (Class<? extends UuidObject> keyClazz : this.uuidObjectCache.keySet()) {
for (Class<? extends AbstractUuidObject> keyClazz : this.uuidObjectCache.keySet()) {
this.commit(resultCallback, keyClazz);
}
}

public void commit(final OnResultListener<String> resultCallback, final Class<? extends UuidObject> clazz) {
public void commit(final OnResultListener<String> resultCallback, final Class<? extends AbstractUuidObject> clazz) {
new Thread(new Runnable() {
@Override
public void run() {
Expand All @@ -225,14 +225,14 @@ public void run() {
}).start();
}

private <T extends UuidObject> void notifyListeners(final Class<T> clazz) {
private <T extends AbstractUuidObject> void notifyListeners(final Class<T> clazz) {
final List<OnStorageChangeListener> listeners = this.getOrCreateListenerList(clazz);
for (OnStorageChangeListener listener : listeners) {
listener.onChange();
}
}

private <T extends UuidObject> List<OnStorageChangeListener> getOrCreateListenerList(final Class<T> clazz) {
private <T extends AbstractUuidObject> List<OnStorageChangeListener> getOrCreateListenerList(final Class<T> clazz) {
List<OnStorageChangeListener> listeners = this.listeners.get(clazz);
if (listeners == null) {
listeners = new ArrayList<OnStorageChangeListener>();
Expand All @@ -241,7 +241,7 @@ private <T extends UuidObject> List<OnStorageChangeListener> getOrCreateListener
return listeners;
}

private synchronized <T extends UuidObject> Map<UUID, T> getOrCreateClassCache(final Class<T> clazz) throws IOException {
private synchronized <T extends AbstractUuidObject> Map<UUID, T> getOrCreateClassCache(final Class<T> clazz) throws IOException {
try {
if (!this.uuidObjectCache.containsKey(clazz)) {
this.<T>loadEntries(clazz);
Expand All @@ -260,15 +260,15 @@ private synchronized <T extends UuidObject> Map<UUID, T> getOrCreateClassCache(f
return entries;
}

private synchronized void persistEntries(Class<? extends UuidObject> clazz) throws IOException {
private synchronized void persistEntries(Class<? extends AbstractUuidObject> clazz) throws IOException {
final File objectStorageFile = new File(this.rootPath, clazz.getSimpleName() + ".json");
final FileOutputStream fileOutputStream = new FileOutputStream(objectStorageFile);
OutputStreamWriter fileOutputStreamWriter = new OutputStreamWriter(fileOutputStream);
Constants.GSON.toJson(this.uuidObjectCache.get(clazz), fileOutputStreamWriter);
fileOutputStreamWriter.close();
}

private synchronized <T extends UuidObject> void loadEntries(Class<T> clazz) throws IOException {
private synchronized <T extends AbstractUuidObject> void loadEntries(Class<T> clazz) throws IOException {
this.uuidObjectCache.remove(clazz);
final File objectStorageFile = new File(this.rootPath, clazz.getSimpleName() + ".json");
final FileInputStream fileInputStream = new FileInputStream(objectStorageFile);
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/ch/papers/objectstorage/filters/Filter.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package ch.papers.objectstorage.filters;

import ch.papers.objectstorage.models.UuidObject;
import ch.papers.objectstorage.models.AbstractUuidObject;

/**
* Created by Alessandro De Carli (@a_d_c_) on 23/11/15.
* Papers.ch
* [email protected]
*/
public interface Filter<T extends UuidObject> {
public interface Filter<T extends AbstractUuidObject> {
public boolean matches(T object);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package ch.papers.objectstorage.filters;

import ch.papers.objectstorage.models.UuidObject;
import ch.papers.objectstorage.models.AbstractUuidObject;

/**
* Created by Alessandro De Carli (@a_d_c_) on 23/01/16.
Expand All @@ -9,7 +9,7 @@
*/
public class MatchAllFilter implements Filter {
@Override
public boolean matches(UuidObject object) {
public boolean matches(AbstractUuidObject object) {
return true;
}
}
4 changes: 2 additions & 2 deletions src/main/java/ch/papers/objectstorage/filters/UuidFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import java.util.UUID;

import ch.papers.objectstorage.models.UuidObject;
import ch.papers.objectstorage.models.AbstractUuidObject;

/**
* Created by Alessandro De Carli (@a_d_c_) on 23/01/16.
Expand All @@ -18,7 +18,7 @@ public UuidFilter(UUID matchingUUID) {
}

@Override
public boolean matches(UuidObject object) {
public boolean matches(AbstractUuidObject object) {
return object.getUuid().equals(this.matchingUUID);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ch.papers.objectstorage.models;

import java.util.UUID;


/**
* Created by Alessandro De Carli (@a_d_c_) on 21/11/15.
* Papers.ch
* [email protected]
*/
public abstract class AbstractUuidObject implements UuidObject{
protected UUID uuid = UUID.randomUUID();

public UUID getUuid() {
return uuid;
}
}
Loading

0 comments on commit b3ffe90

Please sign in to comment.