blob: 1ad7e46f08f0e7e78bb4cf0ea019b55247967745 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* dclarke/tware - initial
* tware
******************************************************************************/
package org.eclipse.persistence.jpa.rs;
import static org.eclipse.persistence.jaxb.JAXBContext.MEDIA_TYPE;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.spi.PersistenceUnitInfo;
import javax.ws.rs.core.MediaType;
import org.eclipse.persistence.jaxb.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.dynamic.DynamicEntity;
import org.eclipse.persistence.dynamic.DynamicType;
import org.eclipse.persistence.internal.helper.ConversionManager;
import org.eclipse.persistence.internal.jpa.EJBQueryImpl;
import org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl;
import org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor;
import org.eclipse.persistence.internal.jpa.deployment.SEPersistenceUnitInfo;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
import org.eclipse.persistence.jpa.Archive;
import org.eclipse.persistence.jpa.JpaHelper;
import org.eclipse.persistence.jpa.PersistenceProvider;
import org.eclipse.persistence.jpa.dynamic.JPADynamicHelper;
import org.eclipse.persistence.jpa.rs.util.CustomSerializationMetadataSource;
import org.eclipse.persistence.jpa.rs.util.DynamicXMLMetadataSource;
import org.eclipse.persistence.jpa.rs.util.InMemoryArchive;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.server.Server;
import org.eclipse.persistence.sessions.server.ServerSession;
import org.eclipse.persistence.jpa.rs.util.ChangeListener;
import org.eclipse.persistence.jpa.rs.qcn.JPARSChangeNotificationListener;
import org.eclipse.persistence.jpa.rs.PersistenceFactory;
/**
* A wrapper around the JPA and JAXB artifacts used to persist an application
*
* @author douglas.clarke, tom.ware
*/
public class PersistenceContext {
private static final String PACKAGE_ROOT = "jpars.app.";
private static final String MODEL_PACKAGE = ".model";
private String name = null;
private EntityManagerFactory emf;
private JAXBContext context = null;
public PersistenceContext(Archive archive, Map<String, Object> properties, ClassLoader classLoader){
super();
List<SEPersistenceUnitInfo> persistenceUnits = PersistenceUnitProcessor.getPersistenceUnits(archive, classLoader);
SEPersistenceUnitInfo persistenceUnitInfo = persistenceUnits.get(0);
this.name = persistenceUnitInfo.getPersistenceUnitName();
if (!persistenceUnitInfo.getProperties().containsKey(PersistenceUnitProperties.JDBC_DRIVER) && !properties.containsKey(PersistenceUnitProperties.JDBC_DRIVER)) {
properties.put(PersistenceUnitProperties.NON_JTA_DATASOURCE, "jdbc/jpa-rs");
}
EntityManagerFactoryImpl emf = createDynamicEMF(persistenceUnitInfo, properties);
this.emf = emf;
try{
JAXBContext jaxbContext = createJAXBContext(persistenceUnitInfo.getPersistenceUnitName(), emf.getServerSession());
this.context = jaxbContext;
} catch (Exception e){
e.printStackTrace();
emf.close();
throw new RuntimeException("JAXB Creation Exception", e);
}
}
protected EntityManagerFactoryImpl createDynamicEMF(PersistenceUnitInfo info, Map<String, ?> properties){
PersistenceProvider provider = new PersistenceProvider();
EntityManagerFactory emf = provider.createContainerEntityManagerFactory(info, properties);
PersistenceContext.subscribeToEventNotification(emf);
return (EntityManagerFactoryImpl)emf;
}
/**
* @param session
* @return
*/
protected JAXBContext createJAXBContext(String persistenceUnitName, Server session) throws JAXBException, IOException {
JAXBContext jaxbContext = (JAXBContext) session.getProperty(JAXBContext.class.getName());
if (jaxbContext != null) {
return jaxbContext;
}
String oxmLocation = (String) emf.getProperties().get("eclipselink.jpa-rs.oxm");
String packageName = PACKAGE_ROOT + persistenceUnitName + MODEL_PACKAGE;
Map<String, Object> properties = new HashMap<String, Object>(1);
Object metadataLocation = null;
if (oxmLocation != null){
metadataLocation = new InMemoryArchive((new URL(oxmLocation)).openStream());
} else {
metadataLocation = new DynamicXMLMetadataSource(persistenceUnitName, session, packageName);
}
List<Object> metadataLocations = new ArrayList<Object>();
metadataLocations.add(metadataLocation);
metadataLocations.add(new CustomSerializationMetadataSource(persistenceUnitName, session, packageName));
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, metadataLocations);
ClassLoader cl = session.getPlatform().getConversionManager().getLoader();
jaxbContext = DynamicJAXBContextFactory.createContextFromOXM(cl, properties);
session.setProperty(JAXBContext.class.getName(), jaxbContext);
return jaxbContext;
}
public String getName() {
return name;
}
public EntityManagerFactory getEmf() {
return emf;
}
public JAXBContext getJAXBContext() {
return context;
}
public void create(String tenantId, DynamicEntity entity) {
EntityManager em = getEmf().createEntityManager();
try {
em.getTransaction().begin();
em.persist(entity);
em.getTransaction().commit();
} finally {
em.close();
}
}
public DynamicEntity merge(String type, String tenantId, DynamicEntity entity) {
EntityManager em = getEmf().createEntityManager();
DynamicEntity mergedEntity = null;
try {
em.getTransaction().begin();
if (isList(type)){
mergedEntity = newEntity(type);
List<Object> returnValues = new ArrayList<Object>();
mergedEntity.set("serializedData", returnValues);
@SuppressWarnings("unchecked")
List<Object> values = (List<Object>)entity.get("serializedData");
for (Object value: values){
Object merged = em.merge(value);
returnValues.add(merged);
}
} else {
mergedEntity = em.merge(entity);
}
em.getTransaction().commit();
return mergedEntity;
} finally {
em.close();
}
}
public boolean isList(String type){
Server session = JpaHelper.getServerSession(getEmf());
ClassDescriptor descriptor = session.getDescriptorForAlias(type);
if (descriptor == null && getDescriptor(type) != null){
return true;
}
return false;
}
/**
* TODO
*/
public DynamicEntity newEntity(String type) {
return newEntity(null, type);
}
public DynamicEntity newEntity(String tenantId, String type) {
JPADynamicHelper helper = new JPADynamicHelper(getEmf());
DynamicEntity entity = null;
try{
entity = helper.newDynamicEntity(type);
} catch (IllegalArgumentException e){
ClassDescriptor descriptor = getDescriptor(type);
if (descriptor != null){
DynamicType jaxbType = (DynamicType) descriptor.getProperty(DynamicType.DESCRIPTOR_PROPERTY);
if (jaxbType != null){
return jaxbType.newDynamicEntity();
}
}
throw e;
}
return entity;
}
/**
* TODO
*/
public void save(String tenantId, DynamicEntity entity) {
EntityManager em = getEmf().createEntityManager();
try {
em.getTransaction().begin();
em.merge(entity);
em.getTransaction().commit();
} finally {
em.close();
}
}
/**
* TODO
*/
public void delete(String tenantId, String type, Object id) {
EntityManager em = getEmf().createEntityManager();
try {
em.getTransaction().begin();
DynamicEntity entity = (DynamicEntity)em.find(getClass(type), id);
em.remove(entity);
em.getTransaction().commit();
} finally {
em.close();
}
}
/**
* Stop the current application instance
*/
protected void stop() {
emf.close();
this.emf = null;
this.context = null;
}
public DynamicEntity find(String entityName, Object id) {
return find(null, entityName, id);
}
public DynamicEntity find(String tenantId, String entityName, Object id) {
EntityManager em = getEmf().createEntityManager();
try {
return (DynamicEntity) em.find(getClass(entityName), id);
} finally {
em.close();
}
}
public String toString() {
return "Application(" + getName() + ")::" + System.identityHashCode(this);
}
public ClassDescriptor getDescriptor(String entityName){
Server session = JpaHelper.getServerSession(getEmf());
ClassDescriptor descriptor = session.getDescriptorForAlias(entityName);
if (descriptor == null){
for (Object ajaxBSession:((JAXBContext)getJAXBContext()).getXMLContext().getSessions() ){
descriptor = ((Session)ajaxBSession).getClassDescriptorForAlias(entityName);
if (descriptor != null){
break;
}
}
}
return descriptor;
}
public Class<?> getClass(String entityName) {
return getDescriptor(entityName).getJavaClass();
}
public Object query(String name, Map<?, ?> parameters) {
return query(name, parameters, false);
}
@SuppressWarnings("rawtypes")
public Object query(String name, Map<?, ?> parameters, boolean returnSingleResult) {
EntityManager em = getEmf().createEntityManager();
try{
Query query = em.createNamedQuery(name);
DatabaseQuery dbQuery = ((EJBQueryImpl<?>)query).getDatabaseQuery();
if (parameters != null){
Iterator i=parameters.keySet().iterator();
while (i.hasNext()){
String key = (String)i.next();
Class parameterClass = null;
int index = dbQuery.getArguments().indexOf(key);
if (index >= 0){
parameterClass = dbQuery.getArgumentTypes().get(index);
}
Object parameter = parameters.get(key);
if (parameterClass != null){
parameter = ConversionManager.getDefaultManager().convertObject(parameter, parameterClass);
}
query.setParameter(key, parameter);
}
}
if (returnSingleResult){
return query.getSingleResult();
} else {
return query.getResultList();
}
} catch (Exception e){
e.printStackTrace();
} finally {
em.close();
}
return null;
}
public DynamicEntity unmarshalEntity(String entityName, String tenantId, String acceptedMedia, InputStream in) throws JAXBException {
Unmarshaller unmarshaller = getJAXBContext().createUnmarshaller();
if (acceptedMedia == null || acceptedMedia.indexOf(MediaType.APPLICATION_JSON) < 0) {
unmarshaller.setProperty(MEDIA_TYPE, MediaType.APPLICATION_JSON);
// TODO - handle type
} else {
unmarshaller.setProperty(MEDIA_TYPE, MediaType.APPLICATION_XML);
}
JAXBElement<?> element = unmarshaller.unmarshal(new StreamSource(in), getClass(entityName));
return (DynamicEntity) element.getValue();
}
protected EntityManager createEntityManager(String tenantId) {
return getEmf().createEntityManager();
}
/**
* TODO
*/
public void addListener(ChangeListener listener) {
JPARSChangeNotificationListener changeListener = (JPARSChangeNotificationListener) JpaHelper.getDatabaseSession(getEmf()).getProperty(PersistenceFactory.CHANGE_NOTIFICATION_LISTENER);
if (changeListener == null) {
throw new RuntimeException("Change Listener not registered properly");
}
changeListener.addChangeListener(listener);
}
/**
* TODO
*/
public void remove(ChangeListener listener) {
JPARSChangeNotificationListener changeListener = (JPARSChangeNotificationListener) JpaHelper.getDatabaseSession(getEmf()).getProperty(PersistenceFactory.CHANGE_NOTIFICATION_LISTENER);
if (changeListener != null) {
changeListener.removeChangeListener(listener);
}
}
public static JPARSChangeNotificationListener subscribeToEventNotification(EntityManagerFactory emf) {
ServerSession session = (ServerSession) JpaHelper.getServerSession(emf);
Iterator<ClassDescriptor> i = session.getDescriptors().values().iterator();
JPARSChangeNotificationListener listener = new JPARSChangeNotificationListener();
session.setDatabaseEventListener(listener);
while (i.hasNext()) {
ClassDescriptor descriptor = i.next();
listener.initialize(descriptor, session);
}
listener.register(session);
session.setProperty(PersistenceFactory.CHANGE_NOTIFICATION_LISTENER, listener);
return listener;
}
}