package org.eclipse.emf.texo.store; import java.util.List; import java.util.Map; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.texo.model.ModelConstants; import org.eclipse.emf.texo.provider.IdProvider; import org.eclipse.emf.texo.resolver.DefaultObjectResolver; import org.eclipse.emf.texo.utils.ModelUtils; /** * Defines the interface for an object store. An object store can: * <ul> * <li>create a unique uri for an object</li> * <li>retrieve objects using an uri</li> * <li>query for an object using a string query</li> * <li>update, delete and insert objects</li> * </ul> * * An object store corresponds roughly to the concept of an EMF {@link Resource} or JPA EntityManager. * * Compared to the EMF Resource, the main difference is that an object store does not support the concept of containment * and is mostly a wrapper around specific implementations such as a JPA entity manager. * * The object store api is not targeted as a full replacement or wrapper over an underlying technology such as an * EntityManager. The main purpose of the api is to support webservice and crud operations. * * An object store is uniquely identified by an {@link URI}. * * A main capability of an object store is to create a uniquely identifying string for an object, the uri. * * Creating an object store should be a light weight operation comparable to creating an EntityManager in JPA. * * @author <a href="mtaal@elver.org">Martin Taal</a> */ public abstract class ObjectStore extends DefaultObjectResolver { /** * Update an existing object in the object store. The signature of the method corresponds to the merge operation of * the EntityManager.merge operation. * * @param object * the object to update or merge with the object store * @return the object stored in the object store. */ public abstract <T extends Object> T update(T object); /** * Delete an existing object from the object store. * * @param object */ public abstract <T extends Object> void remove(T object); /** * Insert an existing object in the object store. * * @param object */ public abstract <T extends Object> void insert(T object); /** * Refresh an existing object from the object store. * * @param object */ public abstract <T extends Object> void refresh(T object); /** * Query for a set of objects from the object store. * * @param qry * a query string which can be handled by the native implementation * @param namedParameters * a set of parameters used in the query * @param firstResult * the row number of the first row to return, pass -1 to not have a first row. * @param maxResults * the number of rows to return * @return the objects part of the query */ public abstract List<?> query(String qryStr, Map<String, Object> namedParameters, int firstResult, int maxResults); /** * Query for a set of objects from the object store using a predefined named query. * * @param name * the name of the named query * @param namedParameters * a set of parameters used in the query * @param firstResult * the row number of the first row to return, pass -1 to not have a first row. * @param maxResults * the number of rows to return * @return the objects part of the query */ public abstract List<?> namedQuery(String name, Map<String, Object> namedParameters, int firstResult, int maxResults); /** * Query for a specific type * * @param eClass * the type to query * @param firstResult * the row number of the first row to return, pass -1 to not have a first row. * @param maxResults * the number of rows to return * @return the objects part of the query */ public abstract List<?> query(EClass eClass, int firstResult, int maxResults); /** * Count a set of objects in the object store. * * @param qry * a query string which can be handled by the native implementation * @param namedParameters * a set of parameters used in the query * @return the objects part of the query */ public abstract long count(String qry, Map<String, Object> namedParameters); /** * Count a set of objects in the object store. * * @param name * the named query for counting * @param namedParameters * a set of parameters used in the query * @return the objects part of the query */ public abstract long countNamedQuery(String name, Map<String, Object> namedParameters); /** * Method to indicate that a transaction is to be started by the underlying implementation. */ public void begin() { } /** * Method to indicate that a transaction can be committed by the underlying implementation. */ public void commit() { } /** * Method to indicate that a transaction can be rolled back by the underlying implementation. */ public void rollback() { } /** * Method to indicate that the underlying implementation can be closed. */ public void close() { } /** * @return the underlying technical component taking care of actually storing and retrieving information. This can for * example be the EntityManager which is used to access the database. Note that null is returned if there is * no delegate. */ public abstract Object getDelegate(); /** * Flush any changes to the underlying store. */ public void flush() { } /** * Return the instance of the specified class which has the id. */ public abstract <T extends Object> T get(Class<T> clz, Object id); /** * Checks if an object is new for the datastore or exists. An existing object can be detached, this method will return * false for detached non-new objects. * * @param o * the object to check * @return true if the object is new, false otherwise * @see IdProvider#getId(Object) */ public boolean isNew(Object o) { return null == IdProvider.getInstance().getId(o); } /** * Can be used to check if an object is referenced from other objects. This is usefull when trying/planning to delete * an object. * * @param target * the object to check if it is referenced * @return true if the target is refered to from other objects, false otherwise */ public <T extends Object> boolean isReferenced(T target, boolean includeContainmentReferences) { final List<Object> referees = getReferingObjects(target, 1, includeContainmentReferences); return !referees.isEmpty(); } /** * Returns all objects which refer to the passed in target object. Calls {@link #getReferingObjects(Object, int)} with * -1 as the second parameter. * * @param target * the target object for which the referees need to be retrieved * @param includeContainmentReferences * also return refering objects which reference the target through an EReference with containment==true * @return the referencing objects */ public <T extends Object> List<Object> getReferingObjects(T target, boolean includeContainmentReferences) { return getReferingObjects(target, -1, includeContainmentReferences); } /** * Returns all objects which refer to the passed in target object, will stop querying if maxResult has been reached. * * @param target * the target object for which the referees need to be retrieved * @param maxResult * the maximum number of results to return * @param includeContainmentReferences * also return refering objects which reference the target through an EReference with containment==true * @return the referencing objects */ public abstract <T extends Object> List<Object> getReferingObjects(T target, int maxResult, boolean includeContainmentReferences); protected String getJavaPropertyName(EStructuralFeature eFeature) { final String propertyName = ModelUtils.getEAnnotation(eFeature, ModelConstants.JAVAMEMBER_ANNOTATION_KEY); if (propertyName == null) { return eFeature.getName(); } return propertyName; } /** * Return the (JPA) entity name for the {@link EClass}. The entity name can be used to create queries. * * @param eClass * the {@link EClass} for which to get the entity name * @return the entity name for the {@link EClass} */ public String getEntityName(EClass eClass) { return eClass.getName(); } }