package org.eclipse.emf.texo.store; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.texo.model.ModelObject; import org.eclipse.emf.texo.model.ModelResolver; import org.eclipse.emf.texo.provider.IdProvider; import org.eclipse.emf.texo.utils.ModelUtils; import org.eclipse.emf.texo.utils.ModelUtils.TypeIdTuple; /** * An object store which keeps all the data in memory, only supports simple querying. * * @author <a href="mtaal@elver.org">Martin Taal</a> */ public class MemoryObjectStore extends ObjectStore { private static final String FROM = "from"; //$NON-NLS-1$ private static final int FROM_LENGTH = FROM.length(); private final Map<EClass, List<Object>> data = new HashMap<EClass, List<Object>>(); protected Map<EClass, List<Object>> getData() { return data; } public void addData(Collection<Object> objects) { for (Object object : objects) { @SuppressWarnings("unchecked") final ModelObject<Object> modelObject = (ModelObject<Object>) ModelResolver.getInstance().getModelObject(object); final EClass eClass = modelObject.eClass(); List<Object> dataList = data.get(resolveEClass(eClass)); if (dataList == null) { dataList = new ArrayList<Object>(); data.put(eClass, dataList); } dataList.add(object); } } @Override public Object get(EClass eClass, Object id) { final List<Object> dataList = data.get(resolveEClass(eClass)); if (dataList != null) { for (Object o : dataList) { final Object objectId = IdProvider.getInstance().getId(o); if (objectId != null && objectId.equals(id)) { return o; } } } return null; } @Override public long countNamedQuery(String name, Map<String, Object> namedParameters) { throw new UnsupportedOperationException(); } /* * (non-Javadoc) * * @see org.eclipse.emf.texo.server.store.ObjectStore#get(java.lang.Class, java.lang.Object) */ @SuppressWarnings("unchecked") @Override public <T extends Object> T get(Class<T> clz, Object id) { for (List<Object> dataList : data.values()) { for (Object o : dataList) { final Object objectId = IdProvider.getInstance().getId(o); if (clz.isAssignableFrom(o.getClass()) && objectId != null && objectId.equals(id)) { return (T) o; } } } return null; } @Override public <T extends Object> T update(T object) { return object; } @Override public <T extends Object> void remove(T object) { if (object == null) { return; } final ModelObject<?> modelObject = ModelResolver.getInstance().getModelObject(object); final List<Object> dataList = data.get(resolveEClass(modelObject.eClass())); boolean removed = false; if (dataList != null) { removed = dataList.remove(object); } if (!removed) { return; } // remove all contained children for (EReference eref : modelObject.eClass().getEAllReferences()) { if (!eref.isContainment()) { continue; } if (eref.isMany()) { final Collection<?> collection = (Collection<?>) modelObject.eGet(eref); for (Object o : collection) { remove(o); } } else { remove(modelObject.eGet(eref)); } } } protected EClass resolveEClass(EClass eClass) { if (data.containsKey(eClass)) { return eClass; } for (EClass key : data.keySet()) { if (key.getName().equals(eClass.getName()) && key.getEPackage().getNsURI().equals(eClass.getEPackage().getNsURI())) { return key; } } return eClass; } @Override public <T extends Object> void refresh(T object) { // don't do anything } @Override public <T extends Object> void insert(T object) { final ModelObject<?> modelObject = ModelResolver.getInstance().getModelObject(object); List<Object> dataList = data.get(resolveEClass(modelObject.eClass())); if (dataList == null) { dataList = new ArrayList<Object>(); data.put(modelObject.eClass(), dataList); } if (dataList.contains(object)) { // already inserted go away return; } // set the id setIdAttributeOnInsert(modelObject); // add it dataList.add(object); // insert all contained children for (EReference eref : modelObject.eClass().getEAllReferences()) { if (!eref.isContainment()) { continue; } if (eref.isMany()) { final Collection<?> collection = (Collection<?>) modelObject.eGet(eref); for (Object o : collection) { insert(o); } } else { insert(modelObject.eGet(eref)); } } } protected void setIdAttributeOnInsert(ModelObject<?> modelObject) { final EAttribute idEAttribute = IdProvider.getInstance().getIdEAttribute(modelObject.eClass()); if (modelObject.eGet(idEAttribute) == null) { // always wait a few milliseconds to make sure id is unique, is not good for production code // but production code should not use the MemoryObjectStore or its derivatives try { Thread.sleep(2); } catch (Exception ignore) { } if (idEAttribute.getEAttributeType().getInstanceClass() == String.class) { modelObject.eSet(idEAttribute, "" + System.currentTimeMillis()); //$NON-NLS-1$ } else if (Long.class.isAssignableFrom(idEAttribute.getEAttributeType().getInstanceClass())) { modelObject.eSet(idEAttribute, System.currentTimeMillis()); } else if (long.class.isAssignableFrom(idEAttribute.getEAttributeType().getInstanceClass())) { modelObject.eSet(idEAttribute, System.currentTimeMillis()); } else if (Integer.class.isAssignableFrom(idEAttribute.getEAttributeType().getInstanceClass())) { modelObject.eSet(idEAttribute, new Integer((int) System.currentTimeMillis())); } else if (Integer.class.isAssignableFrom(idEAttribute.getEAttributeType().getInstanceClass())) { modelObject.eSet(idEAttribute, new Integer((int) System.currentTimeMillis())); } } } @Override public List<?> query(String qryStr, Map<String, Object> namedParameters, int firstResult, int maxResults) { final int index = qryStr.toLowerCase().indexOf(FROM); if (index != -1) { String eClassName = qryStr.substring(index + FROM_LENGTH).trim(); if (eClassName.indexOf(" ") != -1) { //$NON-NLS-1$ eClassName = eClassName.substring(0, eClassName.indexOf(" ")); //$NON-NLS-1$ } final EClass eClass = ModelUtils.getEClassFromQualifiedName(eClassName); if (eClass == null) { return Collections.emptyList(); } return query(eClass, firstResult, maxResults); } return Collections.emptyList(); } @Override public List<?> namedQuery(String name, Map<String, Object> namedParameters, int firstResult, int maxResults) { throw new UnsupportedOperationException(); } @Override public long count(String qryStr, Map<String, Object> namedParameters) { final List<?> list = query(qryStr, namedParameters, 0, -1); return list.size(); } /* * (non-Javadoc) * * @see org.eclipse.emf.texo.store.ObjectStore#query(org.eclipse.emf.ecore.EClass) */ @Override public List<?> query(EClass eClass, int firstResult, int maxResults) { List<?> result = data.get(resolveEClass(eClass)); if (result == null) { return Collections.emptyList(); } int from = 0; if (firstResult > -1) { from = firstResult; } int to = result.size(); if (maxResults > -1) { to = from + maxResults; } if (from >= result.size()) { from = result.size(); if (from == 0) { return Collections.emptyList(); } } if (to > result.size()) { to = result.size(); } return result.subList(from, to); } @Override public Object getDelegate() { return data; } /* * (non-Javadoc) * * @see org.eclipse.emf.texo.server.store.ObjectStore#getReferingObjects(java.lang.Object, int, boolean) */ @Override public List<Object> getReferingObjects(Object target, int maxResult, boolean includeContainmentReferences) { return null; } @Override public EObject getEObject(URI objectUri) { EObject eObject = super.getEObject(objectUri); if (eObject == null) { final TypeIdTuple tuple = ModelUtils.getTypeAndIdFromUri(isUseWebServiceUriFormat(), objectUri); eObject = (EObject) get(tuple.getEClass(), tuple.getId()); if (eObject == null) { eObject = EcoreUtil.create(tuple.getEClass()); eObject.eSet(IdProvider.getInstance().getIdEAttribute(tuple.getEClass()), tuple.getId()); } } return eObject; } }