/**
* <copyright>
*
* Copyright (c) 2012 Springsite BV (The Netherlands) and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Martin Taal - Initial API and implementation
* </copyright>
*
* $Id: DaoRegistry.java,v 1.1 2011/09/24 04:00:25 mtaal Exp $
*/
package org.eclipse.emf.texo.server.store;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.texo.component.ComponentProvider;
import org.eclipse.emf.texo.component.TexoComponent;
import org.eclipse.emf.texo.converter.EMFModelConverter;
import org.eclipse.emf.texo.converter.ModelEMFConverter;
import org.eclipse.emf.texo.json.EMFJSONConverter;
import org.eclipse.emf.texo.provider.IdProvider;
import org.eclipse.emf.texo.store.EObjectStore;
import org.eclipse.emf.texo.store.ObjectStore;
/**
* An implementation of a persistence service which can be used as an OSGI service.
*
* This persistence service is capable of persisting EObjects by converting them to Texo model objects. The Texo pojos
* are standard JPA annotated java classes which can be persisted by the ORM.
*
* After updating/inserting the EObjects are updated with the values from the database/ORM layer. This is needed to pass
* the id back to the previous layer. Also other values may have been set in the object.
*
* You can set the entity manager provider to be used by this persistence service. If none is set then the one from the
* {@link EntityManagerProvider} is used.
*
* @see EMFJSONConverter
* @see JSONToConverter
* @see ObjectStore
* @see EntityManagerProvider
*
* @author <a href="mtaal@elver.org">Martin Taal</a>
* @version $Revision: 1.1 $
*/
public class EPersistenceService extends EObjectStore implements TexoComponent {
private EntityManagerFactory entityManagerFactory;
/**
* Performs several persistence actions, the insert and updates are done in the order in the toInsertUpdate list, the
* toDelete are done after the insert/updates.
*
* Note that in general it makes sense to first have the new objects in the toInsertUpdate and then the to-be-updated
* objects.
*
* NOTE: After the persist action the {@link EObject} instances in toInsertUpdate are updated with the data returned
* from the database. So id's for new objects and other computed information is set back in the passed EObjects.
*/
@Override
public void persist(List<EObject> toInsert, List<EObject> toUpdate, List<EObject> toDelete) {
final ObjectStore os = getObjectStore();
boolean err = true;
os.begin();
try {
final EMFModelConverter converter = ComponentProvider.getInstance().newInstance(EMFModelConverter.class);
converter.setUriResolver(os);
final List<Object> allObjects = new ArrayList<Object>();
int i = 0;
final Map<Object, InternalEObject> objectMapping = new HashMap<Object, InternalEObject>();
for (Object object : converter.convert(toInsert)) {
allObjects.add(object);
os.insert(object);
objectMapping.put(object, (InternalEObject) toInsert.get(i));
i++;
}
i = 0;
for (Object object : converter.convert(toUpdate)) {
allObjects.add(object);
os.update(object);
objectMapping.put(object, (InternalEObject) toUpdate.get(i));
i++;
}
i = 0;
for (Object delete : converter.convert(toDelete)) {
os.remove(delete);
removeFromCache(toUri(toDelete.get(i++)));
}
os.flush();
// and convert back
final ModelEMFConverter m2eConverter = createModelEMFConverter();
m2eConverter.setObjectMapping(objectMapping);
final List<EObject> result = m2eConverter.convert(allObjects);
// the result should have the exact same objects
for (EObject eObject : result) {
if (!toInsert.contains(eObject) && !toUpdate.contains(eObject)) {
throw new IllegalStateException("Invalid conversion"); //$NON-NLS-1$
}
addToCache(eObject);
}
err = false;
} finally {
if (err) {
os.rollback();
} else {
os.commit();
for (EObject delete : toDelete) {
deleted(delete);
}
}
os.close();
}
}
/**
* Query for a list of EObjects.
*/
@Override
public List<EObject> query(String qryStr, Map<String, Object> namedParameters, int firstResult, int maxResults) {
final ObjectStore os = getObjectStore();
boolean err = true;
os.begin();
try {
final List<?> objects = os.query(qryStr, namedParameters, firstResult, maxResults);
final ModelEMFConverter converter = createModelEMFConverter();
@SuppressWarnings("unchecked")
final List<EObject> result = converter.convert((List<Object>) objects);
err = false;
for (EObject resultObject : result) {
addToCache(resultObject);
}
return result;
} finally {
if (err) {
os.rollback();
} else {
os.commit();
}
os.close();
}
}
/**
* Execute a count query in the database.
*/
@Override
public long count(String qry, Map<String, Object> namedParameters) {
final ObjectStore os = getObjectStore();
boolean err = true;
os.begin();
try {
final long result = os.count(qry, namedParameters);
err = false;
return result;
} finally {
if (err) {
os.rollback();
} else {
os.commit();
}
os.close();
}
}
protected ObjectStore getObjectStore() {
final EntityManagerObjectStore emStore = ComponentProvider.getInstance()
.newInstance(EntityManagerObjectStore.class);
emStore.setEntityManager(getEntityManager());
emStore.setUri(getUri());
return emStore;
}
protected synchronized EntityManager getEntityManager() {
if (entityManagerFactory == null) {
return EntityManagerProvider.getInstance().getEntityManager();
}
return entityManagerFactory.createEntityManager();
}
/**
* Set the {@link EntityManagerFactory} to use for this persistence service. If this persistence service does not have
* an {@link EntityManagerFactory} then it is read from the {@link EntityManagerProvider}.
*
* @see EntityManagerProvider
*/
public void setEntityManagerFactory(EntityManagerFactory emf) {
entityManagerFactory = emf;
}
@Override
protected EObject loadEObject(EClass eClass, String idString) {
final ObjectStore os = getObjectStore();
boolean err = true;
os.begin();
try {
final Object id = IdProvider.getInstance().convertIdStringToId(eClass, idString);
final Object target = os.get(eClass, id);
if (target == null) {
return null;
}
final ModelEMFConverter converter = createModelEMFConverter();
final List<EObject> result = converter.convert(Collections.singletonList(target));
err = false;
return result.get(0);
} finally {
if (err) {
os.rollback();
} else {
os.commit();
}
os.close();
}
}
@Override
public void refresh(EObject eObject) {
final ObjectStore os = getObjectStore();
boolean err = true;
os.begin();
try {
final Object target = os.resolveFromEObject(eObject);
final Map<Object, InternalEObject> objectMapping = new HashMap<Object, InternalEObject>();
objectMapping.put(target, (InternalEObject) eObject);
final ModelEMFConverter converter = createModelEMFConverter();
converter.setObjectMapping(objectMapping);
final List<EObject> result = converter.convert(Collections.singletonList(target));
if (result.get(0) != eObject) {
throw new IllegalStateException("Object not refreshed, different object resolved back expected " + eObject //$NON-NLS-1$
+ " got " + result.get(0)); //$NON-NLS-1$
}
err = false;
} finally {
if (err) {
os.rollback();
} else {
os.commit();
}
os.close();
}
}
@Override
public List<EObject> getReferingObjects(EObject eTarget, int maxResult, boolean includeContainerReferences) {
final ObjectStore os = getObjectStore();
boolean err = true;
os.begin();
try {
final Object id = eTarget.eGet(IdProvider.getInstance().getIdEAttribute(eTarget.eClass()));
final Object target = os.get(eTarget.eClass(), id);
final List<?> objects = os.getReferingObjects(target, maxResult, includeContainerReferences);
final ModelEMFConverter converter = createModelEMFConverter();
@SuppressWarnings("unchecked")
final List<EObject> result = converter.convert((List<Object>) objects);
err = false;
return result;
} finally {
if (err) {
os.rollback();
} else {
os.commit();
}
os.close();
}
}
protected ModelEMFConverter createModelEMFConverter() {
final ModelEMFConverter converter = ComponentProvider.getInstance().newInstance(ModelEMFConverter.class);
converter.setObjectResolver(this);
converter.setMaxChildLevelsToConvert(1);
return converter;
}
}