You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2013/12/09 15:04:20 UTC
git commit: [OLINGO-32] Performance improvement in DataStore
Updated Branches:
refs/heads/master 388d2279c -> 8f4604f91
[OLINGO-32] Performance improvement in DataStore
Project: http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/commit/8f4604f9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/tree/8f4604f9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/diff/8f4604f9
Branch: refs/heads/master
Commit: 8f4604f911611f41e53ac91ea47203d00c9b6150
Parents: 388d227
Author: Michael Bolz <mi...@sap.com>
Authored: Mon Dec 9 15:01:25 2013 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Mon Dec 9 15:04:07 2013 +0100
----------------------------------------------------------------------
.../odata2/core/annotation/data/DataStore.java | 156 +++++++++++++------
.../core/annotation/util/ClassHelper.java | 30 ++++
2 files changed, 138 insertions(+), 48 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/8f4604f9/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/DataStore.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/DataStore.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/DataStore.java
index 696ab9a..515b916 100644
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/DataStore.java
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/DataStore.java
@@ -26,10 +26,13 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
import org.apache.olingo.odata2.api.exception.ODataApplicationException;
import org.apache.olingo.odata2.core.annotation.util.AnnotationHelper;
+import org.apache.olingo.odata2.core.annotation.util.ClassHelper;
import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
/**
@@ -38,8 +41,9 @@ import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
public class DataStore<T> {
private static final AnnotationHelper ANNOTATION_HELPER = new AnnotationHelper();
- private final List<T> dataStore;
+ private final Map<KeyElement, T> dataStore;
private final Class<T> dataTypeClass;
+ private final KeyAccess keyAccess;
private int idCounter = 1;
@@ -67,13 +71,19 @@ public class DataStore<T> {
return (DataStore<T>) InMemoryDataStore.getInstance(clazz, !keepExisting);
}
- private DataStore(List<T> wrapStore, Class<T> clz) {
- dataStore = Collections.synchronizedList(wrapStore);
+ private DataStore(Map<KeyElement, T> wrapStore, Class<T> clz) {
+ dataStore = Collections.synchronizedMap(wrapStore);
dataTypeClass = clz;
+ try {
+ keyAccess = new KeyAccess(clz);
+ } catch (DataStoreException ex) {
+ // FIXME: replace exception with correct error handling
+ throw new RuntimeException("");
+ }
}
private DataStore(Class<T> clz) {
- this(new ArrayList<T>(), clz);
+ this(new HashMap<KeyElement, T>(), clz);
}
public Class<T> getDataTypeClass() {
@@ -95,89 +105,139 @@ public class DataStore<T> {
}
public T read(T obj) {
- List<Object> objKeys = getKeys(obj);
- for (T stored : dataStore) {
- if (objKeys.equals(getKeys(stored))) {
- return stored;
- }
- }
- return null;
+ KeyElement objKeys = getKeys(obj);
+ return dataStore.get(objKeys);
}
public Collection<T> read() {
- return Collections.unmodifiableCollection(dataStore);
+ return Collections.unmodifiableCollection(dataStore.values());
}
public T create(T object) throws DataStoreException {
synchronized (dataStore) {
- if (read(object) != null || getKeys(object).contains(null)) {
+ KeyElement keyElement = getKeys(object);
+ if (dataStore.get(keyElement) != null || !keyElement.allKeysSet()) {
createKeys(object);
return this.create(object);
}
- dataStore.add(object);
+ dataStore.put(keyElement, object);
}
return object;
}
public T update(T object) {
synchronized (dataStore) {
- T stored = read(object);
- dataStore.remove(stored);
- dataStore.add(object);
+ KeyElement keyElement = getKeys(object);
+ dataStore.remove(keyElement);
+ dataStore.put(keyElement, object);
}
return object;
}
public T delete(T object) {
synchronized (dataStore) {
- T stored = read(object);
- if (stored != null) {
- dataStore.remove(stored);
- }
- return stored;
+ KeyElement keyElement = getKeys(object);
+ return dataStore.remove(keyElement);
}
}
- private List<Object> getKeys(T object) {
- Map<String, Object> keys = ANNOTATION_HELPER.getValueForAnnotatedFields(object, EdmKey.class);
+ private class KeyElement {
+ private final List<Object> keyValues;
+ private int cachedHashCode;
- // XXX: list should be in a defined order -> better to create an 'Key' object which is comparable
- List<Object> keyList = new ArrayList<Object>(keys.values());
- return keyList;
- }
+ public KeyElement(int size) {
+ keyValues = new ArrayList<Object>(size);
+ }
- private T createKeys(T object) throws DataStoreException {
- List<Field> fields = ANNOTATION_HELPER.getAnnotatedFields(object, EdmKey.class);
- if (fields.isEmpty()) {
- throw new DataStoreException("No EdmKey annotated fields found for class " + object.getClass());
+ public KeyElement() {
+ this(2);
}
- Map<String, Object> fieldName2KeyValue = new HashMap<String, Object>();
- for (Field field : fields) {
- Object key = createKey(field);
- fieldName2KeyValue.put(ANNOTATION_HELPER.getCanonicalName(field), key);
+ private void addValue(Object keyValue) {
+ keyValues.add(keyValue);
+ cachedHashCode = keyValues.hashCode();
+ }
+
+ boolean allKeysSet() {
+ return !keyValues.contains(null);
}
- ANNOTATION_HELPER.setValuesToAnnotatedFields(object, EdmKey.class, fieldName2KeyValue);
+ @Override
+ public int hashCode() {
+ return cachedHashCode;
+ }
- return object;
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final KeyElement other = (KeyElement) obj;
+ if (this.keyValues != other.keyValues && (this.keyValues == null || !this.keyValues.equals(other.keyValues))) {
+ return false;
+ }
+ return true;
+ }
}
+
+ private class KeyAccess {
+ List<Field> keyFields;
+
+ KeyAccess(Class<?> clazz) throws DataStoreException {
+ keyFields = ANNOTATION_HELPER.getAnnotatedFields(clazz, EdmKey.class);
+ if (keyFields.isEmpty()) {
+ throw new DataStoreException("No EdmKey annotated fields found for class " + clazz);
+ }
+ }
+
+ KeyElement getKeyValues(T object) {
+ KeyElement keyElement = new KeyElement(keyFields.size());
+ for (Field field : keyFields) {
+ Object keyValue = ClassHelper.getFieldValue(object, field);
+ keyElement.addValue(keyValue);
+ }
- private Object createKey(Field field) {
- Class<?> type = field.getType();
+ return keyElement;
+ }
+
+ T createKeys(T object) throws DataStoreException {
+ for (Field field : keyFields) {
+ Object key = createKey(field);
+ ClassHelper.setFieldValue(object, field, key);
+ }
- if (type == String.class) {
- return String.valueOf(idCounter++);
- } else if (type == Integer.class || type == int.class) {
- return Integer.valueOf(idCounter++);
- } else if (type == Long.class || type == long.class) {
- return Long.valueOf(idCounter++);
+ return object;
}
+
+ private Object createKey(Field field) {
+ Class<?> type = field.getType();
+
+ if (type == String.class) {
+ return String.valueOf(idCounter++);
+ } else if (type == Integer.class || type == int.class) {
+ return Integer.valueOf(idCounter++);
+ } else if (type == Long.class || type == long.class) {
+ return Long.valueOf(idCounter++);
+ }
- throw new UnsupportedOperationException("Automated key generation for type '" + type
- + "' is not supported (caused on field '" + field + "').");
+ throw new UnsupportedOperationException("Automated key generation for type '" + type
+ + "' is not supported (caused on field '" + field + "').");
+ }
+ }
+
+ private KeyElement getKeys(T object) {
+ return keyAccess.getKeyValues(object);
+ }
+
+ private T createKeys(T object) throws DataStoreException {
+ return keyAccess.createKeys(object);
}
+
+
public static class DataStoreException extends ODataApplicationException {
private static final long serialVersionUID = 42L;
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/8f4604f9/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/ClassHelper.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/ClassHelper.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/ClassHelper.java
index 5e9fcdb..75585d1 100644
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/ClassHelper.java
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/ClassHelper.java
@@ -21,9 +21,11 @@ package org.apache.olingo.odata2.core.annotation.util;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
+import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
+import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
/**
*
@@ -90,6 +92,34 @@ public class ClassHelper {
return annotatedClasses;
}
+
+ public static Object getFieldValue(Object instance, Field field) {
+ try {
+ boolean access = field.isAccessible();
+ field.setAccessible(true);
+ Object value = field.get(instance);
+ field.setAccessible(access);
+ return value;
+ } catch (IllegalArgumentException ex) { // should never happen
+ throw new ODataRuntimeException(ex);
+ } catch (IllegalAccessException ex) { // should never happen
+ throw new ODataRuntimeException(ex);
+ }
+ }
+
+ public static void setFieldValue(Object instance, Field field, Object value) {
+ try {
+ boolean access = field.isAccessible();
+ field.setAccessible(true);
+ field.set(instance, value);
+ field.setAccessible(access);
+ } catch (IllegalArgumentException ex) { // should never happen
+ throw new ODataRuntimeException(ex);
+ } catch (IllegalAccessException ex) { // should never happen
+ throw new ODataRuntimeException(ex);
+ }
+ }
+
private static File[] listSubFolder(File folder) {
File[] subfolders = folder.listFiles(FOLDER_FILTER);