diff options
Diffstat (limited to 'hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo')
105 files changed, 21567 insertions, 0 deletions
diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/EMFInterceptor.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/EMFInterceptor.java new file mode 100755 index 000000000..0a523afd9 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/EMFInterceptor.java @@ -0,0 +1,213 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EMFInterceptor.java,v 1.15 2010/02/04 10:53:08 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.emf.common.notify.Adapter; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.teneo.extension.ExtensionInitializable; +import org.eclipse.emf.teneo.extension.ExtensionManager; +import org.eclipse.emf.teneo.extension.ExtensionManagerAware; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierCacheHandler; +import org.eclipse.emf.teneo.mapping.elist.PersistableDelegateList; +import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy; +import org.eclipse.emf.teneo.type.PersistentStoreAdapter; +import org.eclipse.emf.teneo.util.FieldUtil; +import org.hibernate.EmptyInterceptor; +import org.hibernate.Transaction; +import org.hibernate.collection.AbstractPersistentCollection; + +/** + * Intercepts the getEntityName call to return the EClass name as the entity name. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.15 $ + */ + +public class EMFInterceptor extends EmptyInterceptor implements ExtensionPoint, ExtensionManagerAware, + ExtensionInitializable { + + // is kept to do dereferencing of collections, see the description in the deReferenceCollections + // method + // clear all session instances in the persistentcollection to solve + // this issue which still occured with Teneo in hibernate 3.2.5 + // http://forum.hibernate.org/viewtopic.php?t=934961&highlight=two+representations+same+collection + // http://opensource.atlassian.com/projects/hibernate/browse/HHH-511 + // this issue occured when doing the following using a resource: + // create a new object with a isMany feature, save the resource, + // delete the just saved object, save the resource + // undo the delete (possible in the editor) and then + // save the resource a 'Found two representations of same collection:' + // exception occurs + private static ThreadLocal<List<AbstractPersistentCollection>> persistentCollections = new ThreadLocal<List<AbstractPersistentCollection>>(); + private static ThreadLocal<List<EObject>> deletedEObjects = new ThreadLocal<List<EObject>>(); + + // note is also used for non-deleted objects in HbResource + public static void registerCollectionsForDereferencing(EObject eObject) { + for (EReference eReference : eObject.eClass().getEAllReferences()) { + if (eReference.isMany()) { + final Object refValue = eObject.eGet(eReference); + if (refValue instanceof PersistableDelegateList<?>) { + final Object delegate = ((PersistableDelegateList<?>) refValue).getDelegate(); + if (delegate instanceof AbstractPersistentCollection) { + if (persistentCollections.get() == null) { + persistentCollections.set(new ArrayList<AbstractPersistentCollection>()); + } + final List<AbstractPersistentCollection> list = persistentCollections.get(); + list.add((AbstractPersistentCollection) delegate); + } + } + } + } + if (deletedEObjects.get() == null) { + deletedEObjects.set(new ArrayList<EObject>()); + } + deletedEObjects.get().add(eObject); + } + + // is used to unset a session in a collection. Note that it would be better to use the + // AbstractPersistentCollection.unsetSession/getSession method but these give me a + // java.lang.AccessError + private static final Field sessionField = FieldUtil.getField(AbstractPersistentCollection.class, "session"); + + /** + * Generated Serial Version ID + */ + private static final long serialVersionUID = 1680117509182298808L; + + /** The qualify property used to compute the eclassname */ + private EntityNameStrategy qualifyStrategy; + + private ExtensionManager extensionManager; + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.emf.teneo.extension.ExtensionManagerAware#setExtensionManager(org.eclipse.emf.teneo.extension. + * ExtensionManager) + */ + public void setExtensionManager(ExtensionManager extensionManager) { + this.extensionManager = extensionManager; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.extension.ExtensionInitializable#initializeExtension() + */ + public void initializeExtension() { + qualifyStrategy = extensionManager.getExtension(EntityNameStrategy.class); + } + + /** + * Is overridden to return the eclass uri as the entity name. + * + * @see org.hibernate.EmptyInterceptor#getEntityName(java.lang.Object) + */ + @Override + public String getEntityName(Object object) { + if (object instanceof EObject) { + // TODO handle featuremap + EObject eobj = (EObject) object; + return qualifyStrategy.toEntityName(eobj.eClass()); + } + + return super.getEntityName(object); + } + + @Override + @SuppressWarnings("rawtypes") + public void postFlush(Iterator entities) { + // TODO: consider to move this to after commit + final List<AbstractPersistentCollection> list = persistentCollections.get(); + if (list == null) { + return; + } + try { + for (AbstractPersistentCollection apc : list) { + try { + sessionField.set(apc, null); + } catch (Exception e) { + throw new HbStoreException(e); + } + } + } finally { + persistentCollections.set(null); + } + } + + @Override + public void afterTransactionCompletion(Transaction tx) { + if (tx.wasCommitted()) { + if (deletedEObjects.get() != null) { + try { + for (EObject eObject : deletedEObjects.get()) { + // remove the PersistentStoreAdapter + PersistentStoreAdapter toRemoveAdapter = null; + for (Adapter adapter : eObject.eAdapters()) { + if (adapter instanceof PersistentStoreAdapter) { + toRemoveAdapter = (PersistentStoreAdapter) adapter; + } + } + if (toRemoveAdapter != null) { + eObject.eAdapters().remove(toRemoveAdapter); + } + IdentifierCacheHandler.getInstance().setVersion(eObject, null); + IdentifierCacheHandler.getInstance().setID(eObject, null); + + } + } finally { + deletedEObjects.set(null); + } + } + } + super.afterTransactionCompletion(tx); + } + + /** + * Returns true if the eobject belongs to the newEObject set of a hibernateResource, in all other cases returns + * null. + */ + // Disabled this method because an object can be new to a resource but already + // exist in the database. + // See bugzilla 280355 and the related testcase + // @Override + // public Boolean isTransient(Object entity) { + // if (!(entity instanceof EObject)) { + // return null; + // } + // + // final EObject eObject = (EObject) entity; + // final Resource res = eObject.eResource(); + // if (res == null || !(res instanceof StoreResource)) { + // return null; + // } + // + // final StoreResource storeResource = (StoreResource) res; + // if (storeResource.getNewEObjectSet().contains(entity)) { + // return true; + // } + // // in all other cases let hibernate do it + // return null; + // } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/EPackageConstructor.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/EPackageConstructor.java new file mode 100755 index 000000000..518c6083e --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/EPackageConstructor.java @@ -0,0 +1,230 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EPackageConstructor.java,v 1.5 2010/02/06 18:25:50 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl; + +/** + * Reads epackages from different formats and makes them available to other beans. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EPackageConstructor { + + // The logger + private static final Log log = LogFactory.getLog(EPackageConstructor.class); + + // The ecore context in which this app runs + // private EcoreContext ecoreContext; + + // The arraylist of epackages, is build in the getEPackages call + private List<EPackage> ePackages = null; + + // The classnames of EcoreModelClasses + private List<String> ecoreModelClasses = new ArrayList<String>(); + + // The array of model class names + private List<String> ecoreModelFiles = new ArrayList<String>(); + + private boolean initialized = false; + + /** + * The list of files with ecore or xsd models. + */ + public void setModelFiles(List<String> ecoreModelFiles) { + this.ecoreModelFiles = ecoreModelFiles; + } + + /** + * Set the list of EcoreModelPackages which are to be read. + */ + public void setModelClasses(List<String> ecoreModelClasses) { + this.ecoreModelClasses = ecoreModelClasses; + } + + /** + * This method will read the models from the modelFiles and the EcoreModelPackages. The EPackages are initialized + * and registered in the EPackage registry. + * + * @return the EPackages which are read from the modelFiles or are defined in EcoreModelPackages. + */ + public List<EPackage> getEPackages() { + if (ePackages == null) { + initialize(); + } + return ePackages; + } + + /** Initialize it all */ + private void initialize() { + if (initialized) { + return; + } + // build the list of EPackages + log.debug("Reading EPackages"); + final ArrayList<EPackage> ePacks = new ArrayList<EPackage>(); + ePacks.addAll(buildFromModelClasses()); + ePacks.addAll(buildFromModelFiles()); + + for (EPackage epackage : ePacks) { + log.info("Registered EPackage: " + epackage.getNsURI()); + } + + // also add subpackages + for (EPackage ePackage : new ArrayList<EPackage>(ePacks)) { + addSubPackages(ePacks, ePackage); + } + + ePackages = ePacks; + initialized = true; + } + + private void addSubPackages(List<EPackage> list, EPackage ePackage) { + for (EPackage subPackage : ePackage.getESubpackages()) { + if (!list.contains(subPackage)) { + list.add(subPackage); + addSubPackages(list, subPackage); + } + } + } + + /** + * Build a list of EPackages from the passed EcoreModelClasses. + */ + private List<EPackage> buildFromModelClasses() { + final ArrayList<EPackage> result = new ArrayList<EPackage>(); + for (String ecoreModelPackageClassName : ecoreModelClasses) { + try { + final Class<?> cls = this.getClass().getClassLoader().loadClass(ecoreModelPackageClassName); + final EPackage emp; + // handle the case that this is an EPackage interface + if (cls.isInterface()) { + final Field f = cls.getField("eINSTANCE"); + // purposely passing null because it must be static + emp = (EPackage) f.get(null); + } else { + final Method m = cls.getMethod("init"); + // purposely passing null because it must be static + emp = (EPackage) m.invoke(null); + } + + // initialise the emp, will also read the epackage + result.add(emp); + } catch (Exception e) { + throw new IllegalStateException( + "Excption while trying to retrieve EcoreModelPackage instance from class: " + + ecoreModelPackageClassName, e); + } + } + return result; + } + + /** + * Builds a list of epackages from the modelfiles, pre-normalized for duplicates and not registered. + */ + private List<EPackage> buildFromModelFiles() { + // separate the files in xsd and ecore files and treat each of them separately + final ArrayList<String> ecoreFiles = new ArrayList<String>(); + final ArrayList<String> xsdFiles = new ArrayList<String>(); + for (String modelFile : ecoreModelFiles) { + if (modelFile.endsWith(".xsd")) { + xsdFiles.add(modelFile.trim()); + } else { + if (!modelFile.trim().endsWith(".ecore")) { + log.warn("Filename " + modelFile + " passed as modelFile but it does not end on either " + + "xsd or ecore, processing it anyway."); + } + ecoreFiles.add(modelFile.trim()); + } + } + + // now get the ecores and xsd's parse them separately + final ArrayList<EPackage> result = new ArrayList<EPackage>(); + result.addAll(readFromEcore(ecoreFiles)); + // result.addAll(readFromXmlSchema(xsdFiles)); + + return result; + } + + // /** + // * Builds and registers EPackages from an XML Schema. + // * + // * @param file + // * The XML Schema file. + // */ + // private List<EPackage> readFromXmlSchema(List<String> xsdFiles) { + // final ArrayList<EPackage> result = new ArrayList<EPackage>(); + // for (String xsdFile : xsdFiles) { + // log.debug("Building ECore model from XML Schema \"" + xsdFile + "\"."); + // try { + // // final String path = ecoreContext.getQualifiedPath(xsdFile); + // final java.net.URI netURI = this.getClass().getResource(xsdFile).toURI(); + // final URI uri = URI.createURI(netURI.toString()); + // + // // Note: we use an inline SerializableXSDEcoreBuilder to avoid a dependency on + // // XSDEcoreBuilder during + // // classloading. + // for (Object obj : new XSDEcoreBuilder().generate(uri)) { + // final EPackage ePackage = (EPackage) obj; + // result.add(ePackage); + // } + // } catch (Exception e) { + // throw new StateException("Could not build ECore model from XML Schema, from file " + xsdFile, e); + // } + // } + // return result; + // } + + /** + * Reads the epackages present in the passed ecore files. Note this method does not register the epackages. It does + * not check for duplicates either. + */ + private List<EPackage> readFromEcore(List<String> ecoreFiles) { + final ResourceSet resourceSet = new ResourceSetImpl(); + resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new EcoreResourceFactoryImpl()); + final ArrayList<EPackage> epackages = new ArrayList<EPackage>(); + for (String ecoreFile : ecoreFiles) { + log.debug("Reading ecore file: " + ecoreFile); + // final String path = ecoreContext.getQualifiedPath(ecoreFile); + // log.debug("Using qualified path: " + path); + try { + final java.net.URI netURI = this.getClass().getResource(ecoreFile).toURI(); + final Resource res = resourceSet.getResource(URI.createURI(netURI.toString()), true); + for (Object obj : res.getContents()) { + if (obj instanceof EPackage) { + epackages.add((EPackage) obj); + } + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + return epackages; + } +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbBaseSessionDataStore.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbBaseSessionDataStore.java new file mode 100755 index 000000000..954d0a7ef --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbBaseSessionDataStore.java @@ -0,0 +1,216 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HbBaseSessionDataStore.java,v 1.11 2010/11/11 10:28:18 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import java.io.Serializable; +import java.sql.Connection; +import java.util.Map; +import java.util.Set; + +import javax.naming.NamingException; +import javax.naming.Reference; + +import org.hibernate.HibernateException; +import org.hibernate.Interceptor; +import org.hibernate.SessionFactory; +import org.hibernate.StatelessSession; +import org.hibernate.classic.Session; +import org.hibernate.engine.FilterDefinition; +import org.hibernate.metadata.ClassMetadata; +import org.hibernate.metadata.CollectionMetadata; +import org.hibernate.stat.Statistics; + +/** + * Holds the sessionfactory related methods, makes the HbSessionDataStore better + * readable. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.11 $ + */ +public abstract class HbBaseSessionDataStore extends HbDataStore implements + SessionFactory { + + private static final long serialVersionUID = 1L; + + /** The persistency manager factory */ + private SessionFactory sessionFactory; + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbDataStore#close() + */ + @Override + public void close() { + if (isInitialized()) { + closeSessionFactory(); + // this will call the close method again but because the + // datastore + // is not initialized anymore it won't get here + HbHelper.INSTANCE.deRegisterDataStore(this); + } + } + + /** + * @return the sessionFactory + */ + @Override + public SessionFactory getSessionFactory() { + if (!isInitialized()) { + initialize(); + } + return sessionFactory; + } + + // close session factory if set + protected void closeSessionFactory() { + if (sessionFactory != null && !sessionFactory.isClosed()) { + sessionFactory.close(); + sessionFactory = null; + // do set initialized false after closing it + setInitialized(false); + } + } + + /** + * @param sessionFactory + * the sessionFactory to set + */ + public void setSessionFactory(SessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + } + + @SuppressWarnings({ "rawtypes", "deprecation" }) + public void evict(Class persistentClass, Serializable id) + throws HibernateException { + getSessionFactory().evict(persistentClass, id); + } + + @SuppressWarnings({ "rawtypes", "deprecation" }) + public void evict(Class persistentClass) throws HibernateException { + getSessionFactory().evict(persistentClass); + } + + @SuppressWarnings({ "deprecation" }) + public void evictCollection(String roleName, Serializable id) + throws HibernateException { + getSessionFactory().evictCollection(roleName, id); + } + + @SuppressWarnings({ "deprecation" }) + public void evictCollection(String roleName) throws HibernateException { + getSessionFactory().evictCollection(roleName); + } + + @SuppressWarnings({ "deprecation" }) + public void evictEntity(String entityName, Serializable id) + throws HibernateException { + getSessionFactory().evictEntity(entityName, id); + } + + @SuppressWarnings({ "deprecation" }) + public void evictEntity(String entityName) throws HibernateException { + getSessionFactory().evictEntity(entityName); + } + + @SuppressWarnings({ "deprecation" }) + public void evictQueries() throws HibernateException { + getSessionFactory().evictQueries(); + } + + @SuppressWarnings({ "deprecation" }) + public void evictQueries(String cacheRegion) throws HibernateException { + getSessionFactory().evictQueries(cacheRegion); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public Map getAllClassMetadata() throws HibernateException { + return getSessionFactory().getAllClassMetadata(); + } + + @SuppressWarnings({ "rawtypes" }) + public Map getAllCollectionMetadata() throws HibernateException { + return getSessionFactory().getAllCollectionMetadata(); + } + + @SuppressWarnings({ "rawtypes" }) + public ClassMetadata getClassMetadata(Class persistentClass) + throws HibernateException { + return getSessionFactory().getClassMetadata(persistentClass); + } + + public ClassMetadata getClassMetadata(String entityName) + throws HibernateException { + return getSessionFactory().getClassMetadata(entityName); + } + + public CollectionMetadata getCollectionMetadata(String roleName) + throws HibernateException { + return getSessionFactory().getCollectionMetadata(roleName); + } + + public Session getCurrentSession() throws HibernateException { + return getSessionFactory().getCurrentSession(); + } + + @SuppressWarnings("rawtypes") + public Set getDefinedFilterNames() { + return getSessionFactory().getDefinedFilterNames(); + } + + public FilterDefinition getFilterDefinition(String filterName) + throws HibernateException { + return getSessionFactory().getFilterDefinition(filterName); + } + + public Reference getReference() throws NamingException { + return getSessionFactory().getReference(); + } + + public Statistics getStatistics() { + return getSessionFactory().getStatistics(); + } + + public boolean isClosed() { + return getSessionFactory().isClosed(); + } + + public Session openSession() throws HibernateException { + return getSessionFactory().openSession(); + } + + public Session openSession(Connection connection, Interceptor interceptor) { + return getSessionFactory().openSession(connection, interceptor); + } + + public Session openSession(Connection connection) { + return getSessionFactory().openSession(connection); + } + + public Session openSession(Interceptor interceptor) + throws HibernateException { + return getSessionFactory().openSession(interceptor); + } + + public StatelessSession openStatelessSession() { + return getSessionFactory().openStatelessSession(); + } + + public StatelessSession openStatelessSession(Connection connection) { + return getSessionFactory().openStatelessSession(connection); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbConstants.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbConstants.java new file mode 100755 index 000000000..5ed22761e --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbConstants.java @@ -0,0 +1,78 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HbConstants.java,v 1.9 2010/04/02 15:24:12 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import org.eclipse.emf.teneo.PersistenceOptions; + +/** + * AnnotationUtil used in the runtime layer as well as the hibernate mapping step. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.9 $ + */ +public class HbConstants { + /** + * Column names used to store the econtainer class + * + * @deprecated use {@link PersistenceOptions#ECONTAINER_CLASS_COLUMN} + */ + public final static String COLUMN_ECONTAINER_CLASS = "econtainer_class"; + + /** Property Name of the econtainer property */ + public final static String PROPERTY_ECONTAINER = "e_container"; + + /** + * Column names used to store the econtainer hibernate id. + * + * @deprecated use {@link PersistenceOptions#ECONTAINER_COLUMN} + */ + public final static String COLUMN_ECONTAINER = "e_container"; + + /** + * Column names used to store the econtainer feature name. + * + * @deprecated use {@link PersistenceOptions#ECONTAINER_FEATURE_NAME_COLUMN} + */ + public final static String COLUMN_ECONTAINER_FEATURE_NAME = "e_container_feature_name"; + + /** Property Name of the econtainer feature id property */ + public final static String PROPERTY_ECONTAINER_FEATURE_ID = "e_container_featureid"; + + /** Property Name of the econtainer feature name property */ + public final static String PROPERTY_ECONTAINER_FEATURE_NAME = "e_container_featurename"; + + /** Column names used to store the econtainer feature id */ + public final static String COLUMN_ECONTAINER_FEATUREID = "e_container_featureid"; + + /** The filename of a hibernate file */ + public final static String HBM_FILE_NAME = "hibernate.hbm.xml"; + + /** The file extension used for ehb files */ + public final static String EHB_FILE_EXTENSION = "ehb"; + + /** The ex/import format from and to xml */ + public final static int EXCHANGE_FORMAT_XML = 0; + + /** The ex/import format from and to xmi */ + public final static int EXCHANGE_FORMAT_XMI = 1; + + public final static String EAV_TABLE_PREFIX_PARAMETER_REGEX = "\\{tableprefix\\}"; + + public final static String EAV_COLLECTIONLAZY_REGEX = "\\{collectionLazySetting\\}"; + + public final static String SYNTHETIC_PROPERTY_INDICATOR = "synthetic-property"; +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbContext.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbContext.java new file mode 100755 index 000000000..5d5d7974a --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbContext.java @@ -0,0 +1,188 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HbContext.java,v 1.9 2008/02/28 07:08:24 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.teneo.extension.ExtensionManager; +import org.eclipse.emf.teneo.extension.ExtensionManagerAware; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.mapping.econtainer.EContainerAccessor; +import org.eclipse.emf.teneo.hibernate.mapping.econtainer.EContainerFeatureIDAccessor; +import org.eclipse.emf.teneo.hibernate.mapping.elist.FeatureMapEntryTuplizer; +import org.eclipse.emf.teneo.hibernate.mapping.property.EAttributePropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.property.EListPropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.property.EReferencePropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.property.FeatureMapEntryFeatureURIPropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.property.FeatureMapEntryPropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.property.FeatureMapPropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.property.VersionPropertyHandler; +import org.eclipse.emf.teneo.hibernate.tuplizer.EMFComponentTuplizer; +import org.eclipse.emf.teneo.hibernate.tuplizer.EMFTuplizer; +import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy; +import org.hibernate.Interceptor; +import org.hibernate.cfg.Configuration; +import org.hibernate.property.PropertyAccessor; + +/** + * The HbContext contains factory methods or configuration methods for different objects or other + * parameters used by the Hibernate EMF layer. This class can be overridden to instantiate your own + * tuplizers, accessors etc. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.9 $ + */ +public class HbContext implements ExtensionPoint, ExtensionManagerAware { + + private ExtensionManager extensionManager; + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#getEMFTuplizerClass(org.hibernate.cfg.Configuration) + */ + public Class<?> getEMFTuplizerClass(Configuration hbConfiguration) { + return EMFTuplizer.class; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#getEMFComponentTuplizerClass(org.hibernate.cfg.Configuration) + */ + public Class<?> getEMFComponentTuplizerClass(Configuration hbConfiguration) { + return EMFComponentTuplizer.class; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#getFeatureMapEntryTuplizer(org.hibernate.cfg.Configuration) + */ + public Class<?> getFeatureMapEntryTuplizer(Configuration hbConfiguration) { + return FeatureMapEntryTuplizer.class; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#createInterceptor(org.hibernate.cfg.Configuration) + */ + public Interceptor createInterceptor(Configuration hbConfiguration, EntityNameStrategy ens) { + return extensionManager.getExtension(EMFInterceptor.class); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#createFeatureMapEntryFeatureURIAccessor() + */ + public PropertyAccessor createFeatureMapEntryFeatureURIAccessor() { + return extensionManager.getExtension(FeatureMapEntryFeatureURIPropertyHandler.class); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#createFeatureMapEntryAccessor(org.eclipse.emf.ecore.EStructuralFeature) + */ + public PropertyAccessor createFeatureMapEntryAccessor(EStructuralFeature feature) { + final FeatureMapEntryPropertyHandler handler = + extensionManager.getExtension(FeatureMapEntryPropertyHandler.class); + handler.initialize(feature); + return handler; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#createVersionAccessor() + */ + public PropertyAccessor createVersionAccessor() { + return extensionManager.getExtension(VersionPropertyHandler.class); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#createEContainerAccessor() + */ + public PropertyAccessor createEContainerAccessor() { + return extensionManager.getExtension(EContainerAccessor.class); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#createEContainerFeatureIDAccessor() + */ + public PropertyAccessor createEContainerFeatureIDAccessor() { + return extensionManager.getExtension(EContainerFeatureIDAccessor.class); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#createFeatureMapPropertyAccessor(org.eclipse.emf.ecore.EStructuralFeature) + */ + public PropertyAccessor createFeatureMapPropertyAccessor(EStructuralFeature eFeature) { + final FeatureMapPropertyHandler fmh = extensionManager.getExtension(FeatureMapPropertyHandler.class); + fmh.initialize(eFeature); + return fmh; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#createEListAccessor(org.eclipse.emf.ecore.EStructuralFeature) + */ + public PropertyAccessor createEListAccessor(EStructuralFeature eFeature, boolean extraLazy, boolean newEMapMapping) { + final EListPropertyHandler handler = extensionManager.getExtension(EListPropertyHandler.class); + handler.initialize(eFeature, extraLazy, newEMapMapping); + return handler; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#createEReferenceAccessor(org.eclipse.emf.ecore.EReference) + */ + public PropertyAccessor createEReferenceAccessor(EReference eReference) { + final EReferencePropertyHandler handler = extensionManager.getExtension(EReferencePropertyHandler.class); + handler.initialize(eReference); + return handler; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#createEAttributeAccessor(org.eclipse.emf.ecore.EAttribute) + */ + public PropertyAccessor createEAttributeAccessor(EAttribute eAttribute) { + return new EAttributePropertyHandler(eAttribute); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.extension.ExtensionManagerAware#setExtensionManager(org.eclipse.emf.teneo.extension.ExtensionManager) + */ + public void setExtensionManager(ExtensionManager extensionManager) { + this.extensionManager = extensionManager; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbDataStore.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbDataStore.java new file mode 100755 index 000000000..5ea9709d7 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbDataStore.java @@ -0,0 +1,1866 @@ +/** + * <copyright> Copyright (c) 2005, 2006, 2007, 2008 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 </copyright> $Id: + * HbDataStore.java,v 1.21 2007/04/17 15:49:44 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.EcorePackage; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.FeatureMap.Entry; +import org.eclipse.emf.ecore.xmi.XMLResource; +import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; +import org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl; +import org.eclipse.emf.ecore.xml.type.XMLTypePackage; +import org.eclipse.emf.teneo.Constants; +import org.eclipse.emf.teneo.DataStore; +import org.eclipse.emf.teneo.ERuntime; +import org.eclipse.emf.teneo.PackageRegistryProvider; +import org.eclipse.emf.teneo.PersistenceOptions; +import org.eclipse.emf.teneo.PersistenceOptions.EContainerFeaturePersistenceStrategy; +import org.eclipse.emf.teneo.TeneoException; +import org.eclipse.emf.teneo.annotations.mapper.PersistenceMappingBuilder; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel; +import org.eclipse.emf.teneo.classloader.StoreClassLoadException; +import org.eclipse.emf.teneo.ecore.EModelResolver; +import org.eclipse.emf.teneo.extension.ExtensionManager; +import org.eclipse.emf.teneo.extension.ExtensionManagerFactory; +import org.eclipse.emf.teneo.hibernate.hbmodel.HbAnnotatedEReference; +import org.eclipse.emf.teneo.hibernate.mapper.HbMapperConstants; +import org.eclipse.emf.teneo.hibernate.mapper.HibernateMappingGenerator; +import org.eclipse.emf.teneo.hibernate.mapper.MappingUtil; +import org.eclipse.emf.teneo.hibernate.mapping.econtainer.EContainerAccessor; +import org.eclipse.emf.teneo.hibernate.mapping.econtainer.EContainerFeatureIDAccessor; +import org.eclipse.emf.teneo.hibernate.mapping.econtainer.EContainerFeatureIDUserType; +import org.eclipse.emf.teneo.hibernate.mapping.econtainer.EContainerUserType; +import org.eclipse.emf.teneo.hibernate.mapping.econtainer.NewEContainerFeatureIDPropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.elist.HibernateFeatureMapEntry; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierCacheHandler; +import org.eclipse.emf.teneo.hibernate.mapping.property.SyntheticPropertyHandler; +import org.eclipse.emf.teneo.hibernate.resource.HibernateResource; +import org.eclipse.emf.teneo.hibernate.resource.HibernateResourceFactory; +import org.eclipse.emf.teneo.hibernate.resource.HibernateXMLResourceFactory; +import org.eclipse.emf.teneo.hibernate.tuplizer.EMFEntityNameResolver; +import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.EntityMode; +import org.hibernate.EntityNameResolver; +import org.hibernate.FetchMode; +import org.hibernate.Interceptor; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.cache.HashtableCacheProvider; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.cfg.Mappings; +import org.hibernate.engine.CascadeStyle; +import org.hibernate.mapping.Collection; +import org.hibernate.mapping.Column; +import org.hibernate.mapping.Component; +import org.hibernate.mapping.IndexedCollection; +import org.hibernate.mapping.Join; +import org.hibernate.mapping.ManyToOne; +import org.hibernate.mapping.MetaAttribute; +import org.hibernate.mapping.OneToMany; +import org.hibernate.mapping.OneToOne; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; +import org.hibernate.mapping.SimpleValue; +import org.hibernate.mapping.Table; +import org.hibernate.mapping.Value; + +/** + * Common base class for the standard hb datastore and the entity manager + * oriented datastore. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.75 $ + */ +public abstract class HbDataStore implements DataStore { + + /** The logger */ + private static Log log = LogFactory.getLog(HbDataStore.class); + + /** Initialize EMF */ + static { + initializeTypes(); + } + + /** Initializes emf types with jpox */ + private static synchronized void initializeTypes() { + log.debug("Initializing protocol/extension for hibernate"); + Resource.Factory.Registry.INSTANCE.getProtocolToFactoryMap().put( + "hibernate", new HibernateResourceFactory()); + Resource.Factory.Registry.INSTANCE.getProtocolToFactoryMap().put("ehb", + new HibernateResourceFactory()); + Resource.Factory.Registry.INSTANCE.getProtocolToFactoryMap().put( + "hbxml", new HibernateXMLResourceFactory()); + Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put( + "hibernate", new HibernateResourceFactory()); + Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put( + "ehb", new HibernateResourceFactory()); + Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put( + "hbxml", new HibernateXMLResourceFactory()); + } + + /** HashMap with referers */ + private HashMap<String, java.util.List<ReferenceTo>> referers; + + /** The array with entities (eclasses) which are not contained */ + private String[] topEntities; + + /** The list of contained eclasses */ + private List<EClass> containedEClasses; + + /** The name under which it is registered */ + private String name; + + /** The list of epackages stored in the datastore */ + private EPackage[] ePackages; + + private EPackageConstructor ePackageConstructor = null; + + /** Update the schema option */ + // private boolean updateSchema = true; + /** The hb context */ + private HbContext hbContext = null; + + /** The pannotated model, is set in the mapEPackages method */ + private PAnnotatedModel paModel = null; + + /** The properties used to create the hibernate configuration object */ + private PersistenceOptions persistenceOptions; + + /** The properties */ + private Properties properties = new Properties(); + + /** The interceptor */ + private Interceptor interceptor; + + /** + * The used mapping if not passed through a hbm file, can be retrieved for + * debugging purposes + */ + private String mappingXML = null; + + /** The extensionManager */ + private ExtensionManager extensionManager; + + /** the entitynamestrategy is read from the extensionManager */ + private EntityNameStrategy entityNameStrategy; + + private EMFEntityNameResolver entityNameResolver; + + private Map<EClass, EStructuralFeature> idFeatureByEClass = null; + + private EPackage.Registry packageRegistry = null; + + private boolean resetConfigurationOnInitialization = true; + + public EPackage.Registry getPackageRegistry() { + if (packageRegistry == null) { + return PackageRegistryProvider.getInstance().getPackageRegistry(); + } + return packageRegistry; + } + + public void setPackageRegistry(EPackage.Registry packageRegistry) { + this.packageRegistry = packageRegistry; + } + + /** + * @return the dsName + */ + public String getName() { + return name; + } + + /** + * @return the epackages + */ + public EPackage[] getEPackages() { + if (ePackages == null && ePackageConstructor != null) { + final java.util.List<EPackage> ePacks = ePackageConstructor + .getEPackages(); + final EPackage[] ePacksArray = new EPackage[ePacks.size()]; + int i = 0; + for (EPackage ePack : ePacks) { + ePacksArray[i++] = ePack; + } + setEPackages(ePacksArray); + } + + return ePackages; + } + + private List<EClass> computeContainedEClasses() { + final List<EClass> result = new ArrayList<EClass>(); + for (EPackage ePackage : getEPackages()) { + for (EClassifier eClassifier : ePackage.getEClassifiers()) { + if (eClassifier instanceof EClass) { + final EClass eClass = (EClass) eClassifier; + for (EReference eReference : eClass.getEAllReferences()) { + if (eReference.isContainment()) { + if (eReference.getEReferenceType() != EcorePackage.eINSTANCE + .getEObject()) { + result.add(eReference.getEReferenceType()); + } + } + } + } + } + } + for (EPackage ePackage : getEPackages()) { + for (EClassifier eClassifier : ePackage.getEClassifiers()) { + if (eClassifier instanceof EClass) { + final EClass eClass = (EClass) eClassifier; + if (!result.contains(eClass) + && isSuperContained(eClass, result)) { + result.add(eClass); + } + } + } + } + return result; + } + + private boolean isSuperContained(EClass eClass, List<EClass> containedEClass) { + for (EClass eSuperClass : eClass.getESuperTypes()) { + if (containedEClass.contains(eSuperClass)) { + return true; + } + if (isSuperContained(eSuperClass, containedEClass)) { + return true; + } + } + return false; + } + + /** + * @param epackages + * the epackages to set + */ + public void setEPackages(EPackage[] epackages) { + // automatically add EPackage + final List<EPackage> epacks = new ArrayList<EPackage>(); + for (EPackage epack : epackages) { + resolveSubPackages(epack, epacks); + } + + this.ePackages = epacks.toArray(new EPackage[epacks.size()]); + } + + private void resolveSubPackages(EPackage epack, List<EPackage> epacks) { + if (!epacks.contains(epack)) { + epacks.add(epack); + } + + for (EPackage subEPackage : epack.getESubpackages()) { + resolveSubPackages(subEPackage, epacks); + } + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + HbHelper.INSTANCE.register(this); + } + + /** + * The entities (eclasses) which are not contained in another eclass. + * + * @return the topEntities + */ + public String[] getTopEntities() { + return topEntities; + } + + /** Initialize the subclass */ + public abstract void initialize(); + + /** Initializes this Data Store */ + protected void initializeDataStore() { + // buildmappings has to be done before setting the tuplizers because + // buildMappings will ensure that the element + // is set in the List properties. + buildMappings(); + + setInterceptor(); + + log.debug("Determine referers for each class"); + + referers = computeReferers(); + + topEntities = computeTopEntities(); + + containedEClasses = computeContainedEClasses(); + + // now add the econtainer mappings to the contained types, only for + // unidirectional container relations + addContainerMappings(); + // and add inverse relations for extra lazy + addExtraLazyInverseProperties(); + + setTuplizer(); + + // set the event listeners + setEventListeners(); + + if (getPersistenceOptions().isUpdateSchema()) { + log.warn("The teneo update schema option is not used anymore for hibernate, use the hibernate option: hibernate.hbm2ddl.auto"); + } + + log.debug("Registering datastore with persistent classes"); + HbHelper.INSTANCE.registerDataStoreByPC(this); + } + + /** Build the mappings in the configuration */ + protected abstract void buildMappings(); + + /** + * Closes the data store and its underlying session or entity manager + * factory. Calls {@link HbHelper#deRegisterDataStore(String)} to deregister + * the data store so that it can not be used anymore. + */ + public abstract void close(); + + /** Return the hibernate configuration */ + public abstract Configuration getHibernateConfiguration(); + + /** + * Gets the persistence options. The persistence options is a type + * representation of the persistence options. If not set through the + * setPersistenceProperties method then a properties file is searched If + * found it is used to set the persistence options. + * <p> + * If no properties have been set explicitly, the method will attempt to + * load them from the file "/elver-persistence.properties" at the root of + * the classpath. (A mechanism similar to "hibernate.properties".) + * + * @throws HbMapperException + * if an error occured reading the properties file. + * @return the persistence options as a Properties instance. + */ + public PersistenceOptions getPersistenceOptions() { + if (persistenceOptions == null) { + final Properties props = new Properties(); + final InputStream in = this.getClass().getResourceAsStream( + PersistenceOptions.DEFAULT_CLASSPATH_FILENAME); + if (in != null) { + try { + props.load(in); + } catch (IOException e) { + throw new HbMapperException(e); + } finally { + try { + in.close(); + } catch (IOException e) { + throw new HbMapperException(e); + } + } + } + persistenceOptions = getExtensionManager().getExtension( + PersistenceOptions.class, new Object[] { props }); + } + return persistenceOptions; + } + + /** + * Sets the persistence options. + * + * @deprecated use setProperties + */ + @Deprecated + public void setPersistenceProperties(Properties persistenceOptions) { + this.persistenceOptions = getExtensionManager().getExtension( + PersistenceOptions.class, new Object[] { persistenceOptions }); + } + + /** + * @deprecated use getDatastoreProperties + */ + @Deprecated + public Properties getHibernateProperties() { + return properties; + } + + /** + * @deprecated use getDatastoreProperties + */ + @Deprecated + public Properties getPersistenceProperties() { + return persistenceOptions.getProperties(); + } + + /** + * @deprecated use setDatastoreProperties + */ + @Deprecated + public void setHibernateProperties(Properties hibernateProperties) { + this.properties = hibernateProperties; + } + + /** + * Sets both the persistence as well as the hibernate properties + * + * @deprecated use {@link #setDataStoreProperties(Properties)} + */ + public void setProperties(Properties props) { + setDataStoreProperties(props); + } + + public void setDataStoreProperties(Properties props) { + this.persistenceOptions = getExtensionManager().getExtension( + PersistenceOptions.class, new Object[] { props }); + this.properties = props; + } + + protected void setDefaultProperties(Properties properties) { + if (properties.getProperty("hibernate.cache.provider_class") == null) { + log.warn("No hibernate cache provider set, using " + + HashtableCacheProvider.class.getName()); + log.warn("For production use please set the ehcache (or other) provider explicitly and configure it"); + properties.setProperty("hibernate.cache.provider_class", + HashtableCacheProvider.class.getName()); + } + final String hbmUpdate = properties + .getProperty(Environment.HBM2DDL_AUTO); + if (hbmUpdate == null) { + log.info("Hibernate property: " + Environment.HBM2DDL_AUTO + + " not set, setting to update"); + properties.setProperty(Environment.HBM2DDL_AUTO, "update"); + } + log.debug("Setting properties in Hibernate Configuration:"); + logProperties(properties); + } + + /** + * Note: was previously called getProperties! Returns the combined hibernate + * and persistence properties + */ + public Properties getDataStoreProperties() { + final Properties props = new Properties(); + props.putAll(properties); + props.putAll(getPersistenceOptions().getProperties()); + return props; + } + + /** Get the session factory */ + public abstract SessionFactory getSessionFactory(); + + /** Return a new session wrapper */ + public abstract SessionWrapper createSessionWrapper(); + + /** Is the store initialized */ + private boolean initialized = false; + + /** + * @return the hbContext + */ + public HbContext getHbContext() { + if (hbContext == null) { + hbContext = getExtensionManager().getExtension(HbContext.class); + } + return hbContext; + } + + /** + * @param hbContext + * the hbContext to set + */ + public void setHbContext(HbContext hbContext) { + hbContext.setExtensionManager(getExtensionManager()); + this.hbContext = hbContext; + } + + /** Return the Classmappings as an iterator */ + public abstract Iterator<?> getClassMappings(); + + /** + * Returns an array of EObjects and FeatureMapEntries which refer to a + * certain EObject, note if the array is of length zero then no refering + * EObjects where found. The passed Session is used to create a query. The + * transaction handling should be done by the caller. + */ + public Object[] getCrossReferencers(Session session, Object referedTo) { + final ArrayList<Object> result = getCrossReferencers( + new HbSessionWrapper(this, session), referedTo, false); + + return result.toArray(new Object[result.size()]); + } + + /** + * Returns an array of EObjects and FeatureMapEntries which refer to a + * certain EObject, note if the array is of length zero then no refering + * EObjects where found. The passed Session is used to create a query. The + * transaction handling should be done by the caller. + */ + public Object[] getCrossReferencers(SessionWrapper sessionWrapper, + Object referedTo) { + final ArrayList<Object> result = getCrossReferencers(sessionWrapper, + referedTo, false); + return result.toArray(new Object[result.size()]); + } + + /** + * Returns an array of EObjects which refer to a certain EObject, note if + * the array is of length zero then no refering EObjects where found. The + * passed Session is used to create a query. The transaction handling should + * be done by the caller. onlyContainers means to only check containment + * relations. + */ + private ArrayList<Object> getCrossReferencers( + SessionWrapper sessionWrapper, Object referedTo, + boolean onlyContainers) { + assert (referedTo != null); + + String targetEntityName = null; + if (referedTo instanceof EObject) { + final EObject eReferedTo = (EObject) referedTo; + targetEntityName = getEntityNameStrategy().toEntityName( + eReferedTo.eClass()); + } else if (referedTo instanceof HibernateFeatureMapEntry) { + final HibernateFeatureMapEntry fme = (HibernateFeatureMapEntry) referedTo; + targetEntityName = fme.getEntityName(); + } else { + throw new IllegalArgumentException("Non eobject not yet supported " + + referedTo.getClass().getName()); + } + + final java.util.List<ReferenceTo> refersList = referers + .get(targetEntityName); + if (refersList == null || refersList.size() == 0) { + return new ArrayList<Object>(); + } + final ArrayList<Object> result = new ArrayList<Object>(); + for (int i = 0; i < refersList.size(); i++) { + final ReferenceTo refersTo = refersList.get(i); + + // if we only check containment relations then skip this + if (onlyContainers && !refersTo.isContainer()) { + continue; + } + + final java.util.List<?> list = sessionWrapper.executeQuery( + refersTo.getQueryStr(), "to", referedTo); + for (Object obj : list) { + if (obj instanceof HibernateFeatureMapEntry) { + // search then again with the + final ArrayList<Object> fms = getCrossReferencers( + sessionWrapper, obj, false); + if (fms.size() == 0) { + new AssertionError( + "The featuremap for featuremap entry " + + obj.getClass().getName() + + " can not be found"); + } + obj = fms.get(0); + } + + // AssertUtil.assertTrue("Getting refersto of " + + // referedTo.getClass().getName() + + // ", however one of the refersto is not an eobject but a " + + // obj.getClass().getName(), + // obj instanceof EObject); + + if (!result.contains(obj)) { + result.add(obj); + } + } + } + + return result; + } + + /** Compute the top eclasses */ + protected String[] computeTopEntities() { + final ArrayList<String> result = new ArrayList<String>(); + for (Iterator<?> pcs = getClassMappings(); pcs.hasNext();) { + final PersistentClass pc = (PersistentClass) pcs.next(); + + final EClass eclass; + if (pc.getEntityName() != null) { + eclass = getEntityNameStrategy().toEClass(pc.getEntityName()); + } else { + eclass = EModelResolver.instance().getEClass( + pc.getMappedClass()); + } + + if (eclass == null + && !pc.getEntityName().equals( + Constants.EAV_EOBJECT_ENTITY_NAME)) { + continue; + } + + java.util.List<ReferenceTo> refs = referers.get(getMappedName(pc)); + boolean topEntity = true; + if (refs != null) { + for (ReferenceTo referenceTo : refs) { + ReferenceTo rt = referenceTo; + if (rt.isContainer) { + topEntity = false; + break; + } + } + } + try { + // see bugzilla 220106 + if (topEntity && (pc.isAbstract() == null || !pc.isAbstract())) { + result.add(getMappedName(pc)); + } + } catch (Exception e) { + e.printStackTrace(System.err); + throw new TeneoException(e.getMessage(), e); + } + } + return result.toArray(new String[result.size()]); + } + + protected boolean isClassOrSuperClassEAVMapped(PersistentClass pc) { + if (pc == null) { + return false; + } + // don't do the EAV mapped ones + if (pc.getEntityName().equals(Constants.EAV_EOBJECT_ENTITY_NAME)) { + return true; + } + return isClassOrSuperClassEAVMapped(pc.getSuperclass()); + } + + /** + * Extra lazy mapping for lists needs a real property for the list index and + * a real inverse for the other side as well. + * + * This method iterates over all associations and adds an inverse for the + * list and set mappings. + */ + protected void addExtraLazyInverseProperties() { + final Map<String, PersistentClass> persistentClasses = new HashMap<String, PersistentClass>(); + for (Iterator<?> pcs = getClassMappings(); pcs.hasNext();) { + final PersistentClass pc = (PersistentClass) pcs.next(); + if (isClassOrSuperClassEAVMapped(pc)) { + continue; + } + persistentClasses.put(pc.getEntityName(), pc); + } + for (Iterator<?> pcs = getClassMappings(); pcs.hasNext();) { + final PersistentClass pc = (PersistentClass) pcs.next(); + + // copy to prevent concurrent modification + final Iterator<?> propIt = pc.getPropertyIterator(); + final List<Property> props = new ArrayList<Property>(); + while (propIt.hasNext()) { + final Property prop = (Property) propIt.next(); + props.add(prop); + } + + for (Property prop : props) { + EClass eClass = null; + if (pc.getMetaAttribute(HbMapperConstants.FEATUREMAP_META) == null) { + if (pc.getEntityName() != null) { + eClass = getEntityNameStrategy().toEClass( + pc.getEntityName()); + } else { + eClass = EModelResolver.instance().getEClass( + pc.getMappedClass()); + } + } + + final EStructuralFeature ef = eClass == null ? null : StoreUtil + .getEStructuralFeature(eClass, prop.getName()); + if (ef != null && ef instanceof EReference + && prop.getValue() instanceof Collection) { + final Collection collection = (Collection) prop.getValue(); + final EReference eReference = (EReference) ef; + + // only work for extra lazy + if (!collection.isExtraLazy()) { + continue; + } + + final Value elementValue = collection.getElement(); + final PersistentClass elementPC; + if (elementValue instanceof OneToMany) { + final OneToMany oneToMany = (OneToMany) elementValue; + elementPC = oneToMany.getAssociatedClass(); + } else if (elementValue instanceof ManyToOne) { + final ManyToOne mto = (ManyToOne) elementValue; + elementPC = persistentClasses.get(mto + .getReferencedEntityName()); + } else { + continue; + } + + if (isClassOrSuperClassEAVMapped(elementPC)) { + continue; + } + + collection.setInverse(true); + + // and add an eopposite + if (eReference.getEOpposite() == null) { + + final Table collectionTable = collection + .getCollectionTable(); + + if (isClassOrSuperClassEAVMapped(elementPC)) { + continue; + } + + final Property inverseRefProperty = new Property(); + inverseRefProperty.setName(StoreUtil + .getExtraLazyInversePropertyName(ef)); + final Map<Object, Object> metas = new HashMap<Object, Object>(); + final MetaAttribute metaAttribute = new MetaAttribute( + HbConstants.SYNTHETIC_PROPERTY_INDICATOR); + metaAttribute.addValue("true"); + metas.put(HbConstants.SYNTHETIC_PROPERTY_INDICATOR, + metaAttribute); + inverseRefProperty.setMetaAttributes(metas); + inverseRefProperty.setNodeName(inverseRefProperty + .getName()); + inverseRefProperty + .setPropertyAccessorName(SyntheticPropertyHandler.class + .getName()); + inverseRefProperty.setLazy(false); + + final ManyToOne mto = new ManyToOne(getMappings(), + collectionTable); + mto.setReferencedEntityName(pc.getEntityName()); + mto.setLazy(false); + mto.setFetchMode(FetchMode.SELECT); + + inverseRefProperty.setValue(mto); + final Iterator<?> it = collection.getKey() + .getColumnIterator(); + while (it.hasNext()) { + final Column originalColumn = (Column) it.next(); + // final Column newColumn = new + // Column(originalColumn.getName()); + mto.addColumn(originalColumn); + } + mto.createForeignKey(); + + // now determine if a join should be created + if (collectionTable.getName().equalsIgnoreCase( + elementPC.getTable().getName())) { + elementPC.addProperty(inverseRefProperty); + } else { + // create a join + final Join join = new Join(); + join.setPersistentClass(elementPC); + join.setTable(collectionTable); + join.addProperty(inverseRefProperty); + + final ManyToOne keyValue = new ManyToOne( + getMappings(), collectionTable); + join.setKey(keyValue); + @SuppressWarnings("unchecked") + final Iterator<Column> keyColumns = collection + .getElement().getColumnIterator(); + while (keyColumns.hasNext()) { + keyValue.addColumn(keyColumns.next()); + } + keyValue.setReferencedEntityName(elementPC + .getEntityName()); + keyValue.setTable(collectionTable); + keyValue.createForeignKey(); + + elementPC.addJoin(join); + } + } + + // add an opposite index + if (collection.isIndexed() && !collection.isMap()) { + + Table collectionTable = collection.getCollectionTable(); + + IndexedCollection indexedCollection = (IndexedCollection) collection; + + final Column column = (Column) indexedCollection + .getIndex().getColumnIterator().next(); + + final Property indexProperty = new Property(); + indexProperty.setName(StoreUtil + .getExtraLazyInverseIndexPropertyName(ef)); + final Map<Object, Object> metas = new HashMap<Object, Object>(); + final MetaAttribute metaAttribute = new MetaAttribute( + HbConstants.SYNTHETIC_PROPERTY_INDICATOR); + metaAttribute.addValue("true"); + metas.put(HbConstants.SYNTHETIC_PROPERTY_INDICATOR, + metaAttribute); + indexProperty.setMetaAttributes(metas); + indexProperty.setNodeName(indexProperty.getName()); + indexProperty + .setPropertyAccessorName(SyntheticPropertyHandler.class + .getName()); + // always make this nullable, nullability is controlled + // by the main property + indexProperty.setOptional(true); + + Join join = null; + @SuppressWarnings("unchecked") + final Iterator<Join> it = (Iterator<Join>) elementPC + .getJoinIterator(); + while (it.hasNext()) { + final Join foundJoin = it.next(); + if (foundJoin + .getTable() + .getName() + .equalsIgnoreCase(collectionTable.getName())) { + join = foundJoin; + collectionTable = join.getTable(); + break; + } + } + + final SimpleValue sv = new SimpleValue(getMappings(), + indexedCollection.getIndex().getTable()); + sv.setTypeName("integer"); + // final Column svColumn = new Column(column.getName()); + sv.addColumn(column); // checkColumnExists(collectionTable, + // svColumn)); + indexProperty.setValue(sv); + if (join != null) { + join.addProperty(indexProperty); + } else { + elementPC.addProperty(indexProperty); + } + } + } + } + } + + } + + /** Adds a econtainer mapping to the class mapping */ + protected void addContainerMappings() { + if (getPersistenceOptions().isDisableEContainerMapping()) { + log.debug("EContainer mapping disabled."); + return; + } + for (Iterator<?> pcs = getClassMappings(); pcs.hasNext();) { + final PersistentClass pc = (PersistentClass) pcs.next(); + + // if a featuremap then just return + if (HbUtil.getEClassNameFromFeatureMapMeta(pc) != null) { + continue; + } + + // check if container is required is done in the + // addContainerMapping call + addContainerMapping(pc); + } + } + + /** Sets the tuplizer */ + protected void setTuplizer() { + for (Iterator<?> pcs = getClassMappings(); pcs.hasNext();) { + final PersistentClass pc = (PersistentClass) pcs.next(); + if (pc.getMetaAttribute(HbMapperConstants.FEATUREMAP_META) != null) { // featuremap + // entry + pc.addTuplizer( + EntityMode.MAP, + getHbContext().getFeatureMapEntryTuplizer( + getHibernateConfiguration()).getName()); + } else if (pc.getMetaAttribute(HbMapperConstants.ECLASS_NAME_META) != null) { + // only the pc's with this meta should get a tuplizer + + pc.addTuplizer(EntityMode.MAP, getHbContext() + .getEMFTuplizerClass(getHibernateConfiguration()) + .getName()); + pc.addTuplizer(EntityMode.POJO, getHbContext() + .getEMFTuplizerClass(getHibernateConfiguration()) + .getName()); + } else if (pc.getMetaAttribute(HbMapperConstants.ECLASS_NAME_META) == null) { + // don't change these pc's any further, these are not eclasses + continue; + } + + // also set the tuplizer for the components, and register for the + // component + + // Build a list of all properties. + java.util.List<Property> properties = new ArrayList<Property>(); + final Property identifierProperty = pc.getIdentifierProperty(); + if (identifierProperty != null) { + properties.add(identifierProperty); + } + for (Iterator<?> it = pc.getPropertyIterator(); it.hasNext();) { + properties.add((Property) it.next()); + } + + // Now set component tuplizers where necessary. + for (Object name2 : properties) { + Property prop = (Property) name2; + if (prop.getName().compareTo("_identifierMapper") == 0) { + continue; // ignore this one + } + final Value value = prop.getValue(); + if (value instanceof Component) { + setComponentTuplizer((Component) value, + getHibernateConfiguration()); + } else if (value instanceof Collection + && ((Collection) value).getElement() instanceof Component) { + setComponentTuplizer( + (Component) ((Collection) value).getElement(), + getHibernateConfiguration()); + } + } + } + } + + /** Set the event listener, can be overridden, in this impl. it does nothing */ + protected void setEventListeners() { + } + + /** + * Sets the emf component tuplizer (if it is an eclass) or the hibernate + * component tuplizer + */ + protected void setComponentTuplizer(Component component, Configuration cfg) { + // check if the eclass exists + // todo: change recognizing a component to using metadata! + EClass eClass = ERuntime.INSTANCE.getEClass(component + .getComponentClass()); + if (eClass == null) { + eClass = getEntityNameStrategy().toEClass( + component.getComponentClassName()); + } + if (eClass != null) { + log.debug("Found " + eClass.getName() + " as a component"); + } else { + eClass = HbUtil.getEClassFromMeta(component); + if (eClass == null) { + return; + } + } + + // is a valid eclass + component.addTuplizer(EntityMode.MAP, getHbContext() + .getEMFComponentTuplizerClass(cfg).getName()); + component.addTuplizer(EntityMode.POJO, getHbContext() + .getEMFComponentTuplizerClass(cfg).getName()); + HbHelper.INSTANCE.registerDataStoreByComponent(this, component); + } + + /** Returns true if the pc is contained */ + private boolean isContained(PersistentClass pc) { + final EClass eclass; + if (pc.getEntityName() != null) { + eclass = getEntityNameStrategy().toEClass(pc.getEntityName()); + } else { + eclass = EModelResolver.instance().getEClass(pc.getMappedClass()); + } + + if (eclass == null + && !pc.getEntityName() + .equals(Constants.EAV_EOBJECT_ENTITY_NAME)) { + return false; + } + + if (pc.getEntityName() != null + && pc.getEntityName().equals(Constants.EAV_EOBJECT_ENTITY_NAME)) { + return true; + } + + return containedEClasses.contains(eclass); + } + + /** Sets initialized */ + protected void setInitialized(boolean initialized) { + this.initialized = initialized; + } + + /** + * Gets the initialized state. + */ + public boolean isInitialized() { + return initialized; + } + + /** Sets the interceptor */ + protected abstract void setInterceptor(); + + /** Generate a hibernate mapping xml string from a set of epackages */ + protected String mapEPackages() { + log.debug("Generating mapping file from in-mem ecore"); + // DCB: Use Hibernate-specific annotation processing mechanism. This + // allows use of + // Hibernate-specific annotations. + final PersistenceOptions po = getPersistenceOptions(); + setPaModel(getExtensionManager().getExtension( + PersistenceMappingBuilder.class).buildMapping(getEPackages(), + po, getExtensionManager())); + final HibernateMappingGenerator hmg = getExtensionManager() + .getExtension(HibernateMappingGenerator.class); + hmg.setPersistenceOptions(po); + final String hbm = hmg.generateToString(getPaModel()); + + log.debug("Computing id types of mapped EClasses"); + idFeatureByEClass = new HashMap<EClass, EStructuralFeature>(); + computeIdTypesByEClass(idFeatureByEClass); + + return hbm; + } + + /** + * @return the type of the id of the passed EClass + */ + public EClassifier getIdType(EClass eClass) { + final EStructuralFeature feature = getIdFeature(eClass); + if (feature == null) { + return XMLTypePackage.eINSTANCE.getLong(); + } + return feature.getEType(); + } + + /** + * Return the ID value of an eObject. + * + * @param eObject + * the object for which to return the id + * @return the id, can be null when the object is new. + */ + public Object getId(EObject eObject) { + final EStructuralFeature feature = getIdFeature(eObject.eClass()); + if (feature == null) { + return IdentifierCacheHandler.getInstance().getID(eObject); + } + return eObject.eGet(feature); + } + + /** + * The {@link EStructuralFeature} representing the id of the passed EClass. + * + * @param eClass + * the id class to check + * @return the EStructuralFeature + */ + public EStructuralFeature getIdFeature(EClass eClass) { + return idFeatureByEClass.get(eClass); + } + + protected void computeIdTypesByEClass(Map<EClass, EStructuralFeature> result) { + for (PAnnotatedEPackage aPackage : getPaModel().getPaEPackages()) { + for (PAnnotatedEClass aClass : aPackage.getPaEClasses()) { + for (PAnnotatedEStructuralFeature aFeature : aClass + .getPaEStructuralFeatures()) { + if (aFeature instanceof PAnnotatedEAttribute) { + final PAnnotatedEAttribute aAttribute = (PAnnotatedEAttribute) aFeature; + if (aAttribute.getId() != null) { + result.put(aClass.getModelEClass(), + aAttribute.getModelEStructuralFeature()); + break; + } + } + if (aFeature instanceof HbAnnotatedEReference) { + final HbAnnotatedEReference aReference = (HbAnnotatedEReference) aFeature; + if (aReference.getEmbeddedId() != null) { + result.put(aClass.getModelEClass(), + aReference.getModelEStructuralFeature()); + break; + } + } + } + } + } + } + + /** Recursively check the container prop in the super hierarchy */ + private boolean hasEContainerProp(PersistentClass pc) { + final Iterator<?> it = pc.getPropertyIterator(); + while (it.hasNext()) { + final Property prop = (Property) it.next(); + if (prop.getName().equals(HbConstants.PROPERTY_ECONTAINER)) { + return true; + } + } + if (pc.getSuperclass() == null) { + return false; + } + return hasEContainerProp(pc.getSuperclass()); + } + + /** Updates the database schema */ + // this method is removed because it is just as easy to use the hibernate + // option + // hibernate.hbm2ddl.auto directly + // protected void updateDatabaseSchema() { + // if (getPersistenceOptions().isUpdateSchema()) { + // log.debug("Database schema not updated, option " + + // PersistenceOptions.UPDATE_SCHEMA + + // " has been set to false"); + // return; + // } + // log.debug("Starting update of schema"); + // new SchemaUpdate(getHibernateConfiguration()).execute(false, true); + // log.debug(">>> Update of schema finished"); + // } + /** + * Adds a econtainer mapping to the class mapping, is only called for + * eclasses which do not have am explicit feature which points to the + * container + */ + protected void addContainerMapping(PersistentClass pc) { + + // always first check if the super class should have a container mapping + if (pc.getSuperclass() != null) { + addContainerMapping(pc.getSuperclass()); + } + + // always add for the eav object + // todo: externalize + if (pc.getEntityName().equals(Constants.EAV_EOBJECT_ENTITY_NAME) + && !hasEContainerProp(pc)) { + addContainerMappingToPC(pc); + return; + } + + if (!isContained(pc)) { + return; + } + if (hasEContainerProp(pc)) { + return; + } + + log.debug("Adding container mapping for " + getMappedName(pc)); + // check if there are not alreadyecontai ner features for the eclass + + final EClass eclass; + if (pc.getEntityName() != null) { + eclass = getEntityNameStrategy().toEClass(pc.getEntityName()); + } else { + eclass = EModelResolver.instance().getEClass(pc.getMappedClass()); + } + + // DCB: Provide a way to avoid container mappings for a particular + // class. You'd do this if, for example, + // you never load the contained objects except through the containers... + // or, you don't fit the use case + // for which this was put together (i.e., the generated model editing + // code tries to eagerly resolve the + // container) + if (eclass == null + || eclass + .getEAnnotation("http://facet.elver.org/SkipContainerMappings") != null) { + return; // featuremap + } + + for (EReference eref : eclass.getEAllReferences()) { + if (eref.isContainer()) { + log.debug("There are container ereferences present, assuming that no separate econtainer columns are required."); + return; + } + } + addContainerMappingToPC(pc); + } + + protected void addContainerMappingToPC(PersistentClass pc) { + log.debug("Adding eContainer and econtainerfeatureid properties to " + + pc.getClassName()); + final EContainerFeaturePersistenceStrategy featurePersistenceStrategy = getPersistenceOptions() + .getEContainerFeaturePersistenceStrategy(); + + final Property eContainer = new Property(); + eContainer.setName(HbConstants.PROPERTY_ECONTAINER); + eContainer.setMetaAttributes(new HashMap<Object, Object>()); + eContainer.setNodeName(eContainer.getName()); + eContainer.setPropertyAccessorName(EContainerAccessor.class.getName()); + + final SimpleValue sv = new SimpleValue(getMappings(), pc.getTable()); + sv.setTypeName(EContainerUserType.class.getName()); + + final Column eccColumn = new Column(getPersistenceOptions() + .getSQLColumnNamePrefix() + + getPersistenceOptions().getEContainerClassColumn()); + sv.addColumn(checkColumnExists(pc.getTable(), eccColumn)); + + final Column ecColumn = new Column(getPersistenceOptions() + .getSQLColumnNamePrefix() + + getPersistenceOptions().getEContainerColumn()); + sv.addColumn(checkColumnExists(pc.getTable(), ecColumn)); + + eContainer.setValue(sv); + pc.addProperty(eContainer); + + if (featurePersistenceStrategy + .equals(EContainerFeaturePersistenceStrategy.FEATUREID) + || featurePersistenceStrategy + .equals(EContainerFeaturePersistenceStrategy.BOTH)) { + final Property ecFID = new Property(); + ecFID.setName(HbConstants.PROPERTY_ECONTAINER_FEATURE_ID); + ecFID.setMetaAttributes(new HashMap<Object, Object>()); + ecFID.setNodeName(ecFID.getName()); + ecFID.setPropertyAccessorName(EContainerFeatureIDAccessor.class + .getName()); + final SimpleValue svfid = new SimpleValue(getMappings(), + pc.getTable()); + svfid.setTypeName("integer"); + + final Column ecfColumn = new Column(getPersistenceOptions() + .getSQLColumnNamePrefix() + + HbConstants.COLUMN_ECONTAINER_FEATUREID); + svfid.addColumn(checkColumnExists(pc.getTable(), ecfColumn)); + + ecFID.setValue(svfid); + pc.addProperty(ecFID); + } + if (featurePersistenceStrategy + .equals(EContainerFeaturePersistenceStrategy.FEATURENAME) + || featurePersistenceStrategy + .equals(EContainerFeaturePersistenceStrategy.BOTH)) { + final Property ecFID = new Property(); + ecFID.setName(HbConstants.PROPERTY_ECONTAINER_FEATURE_NAME); + ecFID.setMetaAttributes(new HashMap<Object, Object>()); + ecFID.setNodeName(ecFID.getName()); + ecFID.setPropertyAccessorName(NewEContainerFeatureIDPropertyHandler.class + .getName()); + final SimpleValue svfid = new SimpleValue(getMappings(), + pc.getTable()); + svfid.setTypeName(EContainerFeatureIDUserType.class.getName()); + + final Column ecfColumn = new Column(getPersistenceOptions() + .getSQLColumnNamePrefix() + + getPersistenceOptions().getEContainerFeatureNameColumn()); + + ecfColumn.setLength(getEContainerFeatureNameColumnLength()); + + svfid.addColumn(checkColumnExists(pc.getTable(), ecfColumn)); + + ecFID.setValue(svfid); + pc.addProperty(ecFID); + } + } + + // returns the length for string columns used for mapping econtainers + protected int getEContainerFeatureNameColumnLength() { + return 255; + } + + /** Checks if a certain column already exists in a class */ + private Column checkColumnExists(Table table, Column searchCol) { + for (int i = 0; i < table.getColumnSpan(); i++) { + final Column column = table.getColumn(i); + if (stripQuotes(column.getName()).equalsIgnoreCase( + searchCol.getName())) { + return column; + } + } + table.addColumn(searchCol); + return searchCol; + } + + private String stripQuotes(String name) { + if (name == null) { + return ""; + } + return name.replaceAll("`", "").replaceAll("\"", ""); + } + + /** + * Checks if the passed object is by any change a contained object and if so + * returns true + */ + public boolean isContainedObject(Object obj) { + // TODO also check containment for superclasses + throw new UnsupportedOperationException("Operation is not supported"); + + // final ArrayList theReferers = (ArrayList) + // referers.get(obj.getClass().getName()); + // if (theReferers == null || theReferers.size() == 0) + // return false; + // for (int i = 0; i < theReferers.size(); i++) { + // final ReferenceTo refTo = (ReferenceTo) theReferers.get(i); + // if (refTo.isContainer()) + // return true; + // } + // return false; + } + + /** + * Import the complete content from an inputstream into the EMF Data Store. + * The ExportTarget is the constant defined in the EMFDataStore interface. + */ + public void importDataStore(InputStream is, int importFormat) { + final Resource importResource; + if (importFormat == HbConstants.EXCHANGE_FORMAT_XML) { + importResource = new XMLResourceImpl(); + } else { + importResource = new XMIResourceImpl(); + } + + final HibernateResource hibResource = new HibernateResource( + URI.createFileURI("." + name)); + + try { + importResource.load(is, Collections.EMPTY_MAP); + hibResource.getContents().addAll(importResource.getContents()); + hibResource.save(Collections.EMPTY_MAP); + } catch (IOException e) { + throw new HbMapperException("Exception when importing " + name, e); + } + } + + /** + * Export the complete content of the EMF Data Store to an outputstream, the + * exportFormat is a HbConstants.EXCHANGE_FORMAT_XML or + * HbConstants.EXCHANGE_FORMAT_XMI, the encoding can be null and is used to + * set XMLResource.OPTION_ENCODING. + */ + public void exportDataStore(OutputStream os, int exportFormat, + String encoding) { + final HibernateResource hibResource = new HibernateResource( + URI.createFileURI("teneo." + name)); + hibResource.load(Collections.EMPTY_MAP); + + try { + final Resource exportResource; + if (exportFormat == HbConstants.EXCHANGE_FORMAT_XML) { + exportResource = new XMLResourceImpl(); + } else { + exportResource = new XMIResourceImpl(); + } + + exportResource.getContents().addAll(hibResource.getContents()); + + final HashMap<String, String> options = new HashMap<String, String>(); + if (encoding != null) { + options.put(XMLResource.OPTION_ENCODING, encoding); + } + + exportResource.save(os, options); + + hibResource.unload(); + } catch (IOException e) { + throw new HbMapperException("Exception when exporting " + name, e); + } + } + + /** + * Computes the referers, handles the lazy for containment + */ + protected HashMap<String, java.util.List<ReferenceTo>> computeReferers() { + final HashMap<String, java.util.List<ReferenceTo>> result = new HashMap<String, java.util.List<ReferenceTo>>(); + + final Iterator<?> it = getClassMappings(); + final ArrayList<String> fmes = new ArrayList<String>(); + while (it.hasNext()) { + final PersistentClass pc = (PersistentClass) it.next(); + + // keep track which are the feature map entries + if (pc.getMetaAttribute(HbMapperConstants.FEATUREMAP_META) != null) { + fmes.add(getMappedName(pc)); + } + + // everyone should have a list otherwise the copying of referers to + // super types to + // this type does not work + if (result.get(getMappedName(pc)) == null) { + result.put(getMappedName(pc), new ArrayList<ReferenceTo>()); + } + + final Iterator<?> propIt = pc.getPropertyIterator(); + while (propIt.hasNext()) { + // handle few cases + // OneToOne or ManyToOne, referenced class can be obtained from + // Value and then getReferencedEntityName + // List: in this case search for a structural feature and get + // the EType from it + // if no structural feature then use the type name and hope for + // the best. + + final Property prop = (Property) propIt.next(); + EClass eClass = null; + if (pc.getMetaAttribute(HbMapperConstants.FEATUREMAP_META) == null) { + if (pc.getEntityName() != null) { + eClass = getEntityNameStrategy().toEClass( + pc.getEntityName()); + } else { + eClass = EModelResolver.instance().getEClass( + pc.getMappedClass()); + } + } + + final EStructuralFeature ef = eClass == null ? null : StoreUtil + .getEStructuralFeature(eClass, prop.getName()); + try { + String toEntity = ""; + boolean isContainer = false; + boolean isMany = false; + + if (prop.getValue() instanceof ManyToOne) { + final ManyToOne mto = (ManyToOne) prop.getValue(); + toEntity = mto.getReferencedEntityName(); + if (ef != null) { + isContainer = ef instanceof EReference + && ((EReference) ef).isContainment(); + } else { + isContainer = prop.getCascadeStyle() + .hasOrphanDelete() + || prop.getCascade().compareTo("all") == 0; // ugly + // but + } + // this was + // the only + // way to + // get all + // there! + } else if (prop.getValue() instanceof OneToOne) { + final OneToOne oto = (OneToOne) prop.getValue(); + toEntity = oto.getReferencedEntityName(); + if (ef != null) { + isContainer = ef instanceof EReference + && ((EReference) ef).isContainment(); + } else { + isContainer = prop.getCascadeStyle() + .hasOrphanDelete() + || prop.getCascadeStyle() == CascadeStyle.ALL; + } + } else if (prop.getValue() instanceof Collection) { + isMany = true; + if (ef == null) { // TODO can this happen? + isContainer = prop.getCascadeStyle() + .hasOrphanDelete() + || prop.getCascadeStyle() == CascadeStyle.ALL; + if (((Collection) prop.getValue()).getElement() instanceof OneToMany) { + final Collection coll = (Collection) prop + .getValue(); + toEntity = ((OneToMany) coll.getElement()) + .getReferencedEntityName(); + } else if (((Collection) prop.getValue()) + .getElement() instanceof ManyToOne) { + final Collection coll = (Collection) prop + .getValue(); + toEntity = ((ManyToOne) coll.getElement()) + .getReferencedEntityName(); + } else { + continue; + // throw new HbMapperException("Type " + // + ((Collection) + // prop.getValue()).getElement().getClass().getName() + // + " not supported, property " + + // prop.getName()); + } + } else { + // in case of featuremap set containment always on + // true because only the featuremap entries + // themselves know if they are containment + if (ef instanceof EAttribute + && ((EAttribute) ef).getEType() + .getInstanceClass() == Entry.class) { + isContainer = true; + // composite-elements are not supported. + if (!(((Collection) prop.getValue()) + .getElement() instanceof OneToMany)) { + continue; + } + final OneToMany otm = (OneToMany) ((Collection) prop + .getValue()).getElement(); + toEntity = otm.getReferencedEntityName(); + } else if (ef instanceof EReference) { + final EReference er = (EReference) ef; + isContainer = er.isContainment(); // prop.getCascadeStyle(). + // hasOrphanDelete() + // || + // prop.getCascadeStyle() + // == + // CascadeStyle.ALL; + toEntity = getEntityNameStrategy() + .toEntityName( + ((EReference) ef) + .getEReferenceType()); + } else if (ef instanceof EAttribute + && ef.getEType() instanceof EClass) { // TODO + // can + // this + // ever + // happen? + isContainer = true; // prop.getCascadeStyle().hasOrphanDelete() + // || prop.getCascadeStyle() + // == CascadeStyle.ALL; + toEntity = getEntityNameStrategy() + .toEntityName((EClass) ef.getEType()); + } + // filter out non eobjects + else { + continue; + } + } + } else { + continue; + } + + java.util.List<ReferenceTo> list = result.get(toEntity); + if (list == null) { + list = new ArrayList<ReferenceTo>(); + result.put(toEntity, list); + } + + list.add(new ReferenceTo(getMappedName(pc), prop, + isContainer, isMany, toEntity)); + } catch (StoreClassLoadException e) { + throw new HbMapperException( + "Class not found using property: " + prop.getName() + + " of " + prop, e); + } + } + } + + // at the end for each class all the refersto of superclasses and + // interfaces are added also + final ArrayList<EClass> classDone = new ArrayList<EClass>(); + for (String em : result.keySet()) { + // only do this if not a fme + if (!fmes.contains(em)) { + setRefersToOfSupers(em, result, classDone); + } + } + return result; + } + + /** Returns either the entityname or the classname, which ever is filled */ + private String getMappedName(PersistentClass pc) { + if (pc.getEntityName() != null) { + return pc.getEntityName(); + } + return pc.getClassName(); + } + + /** + * Add the refersto for each superclass/interface to the subclass refersto + * list. As a convenience returns the set list + */ + private java.util.List<ReferenceTo> setRefersToOfSupers(String eClassUri, + HashMap<String, java.util.List<ReferenceTo>> refersTo, + ArrayList<EClass> classDone) { + final EntityNameStrategy ens = getEntityNameStrategy(); + EClass eclass; + // eclass = null when the refered to eclass is not mapped + // because it is is embeddable + eclass = ens.toEClass(eClassUri); + if (eclass == null) { + return new ArrayList<ReferenceTo>(); + } + + if (classDone.contains(eclass)) { + return refersTo.get(eClassUri); + } + + final java.util.List<ReferenceTo> thisList = refersTo.get(ens + .toEntityName(eclass)); + if (thisList == null) { + return new ArrayList<ReferenceTo>(); + } + for (EClass class1 : eclass.getESuperTypes()) { + String eclassUri = ens.toEntityName(class1); + addUnique(thisList, + setRefersToOfSupers(eclassUri, refersTo, classDone)); + } + classDone.add(eclass); + return thisList; + } + + /** Adds list 2 to list 1 without duplicates */ + private void addUnique(java.util.List<ReferenceTo> l1, + java.util.List<ReferenceTo> l2) { + if (l2 == null) { + return; // this is a valid situation so do nothing + } + + final Iterator<ReferenceTo> it = l2.iterator(); + while (it.hasNext()) { + final ReferenceTo obj = it.next(); + if (!l1.contains(obj)) { + l1.add(obj); + } + } + } + + /** Dump properties in the log */ + protected void logProperties(Properties props) { + final Iterator<?> it = props.keySet().iterator(); + while (it.hasNext()) { + final String key = (String) it.next(); + log.info(key + ": " + props.get(key)); + } + } + + /** Contains the reference to a class which refers to another reference */ + public static class ReferenceTo { + + /** Is contained */ + private final boolean isContainer; + + /** The query used to find the occurence */ + private final String qryStr; + + /** Constructor */ + public ReferenceTo(String fromEntity, Property prop, + boolean isContainer, boolean isMany, String toEntity) { + this.isContainer = isContainer; + if (isMany) { + qryStr = "SELECT ref FROM " + + fromEntity + + " as ref, " + + toEntity + + " as refTo WHERE refTo = :to and refTo in elements(ref." + + prop.getName() + ")"; + } else { + qryStr = "SELECT ref FROM " + fromEntity + + " as ref WHERE :to = ref." + prop.getName(); + } + } + + /** + * @return Returns the isContainer. + */ + public boolean isContainer() { + return isContainer; + } + + /** Returns the query string used used */ + public String getQueryStr() { + return qryStr; + } + } + + /** + * Return the list of mapping files. If the mapping file path property of + * persistenceoptions was set then this is returned, otherwise the classpath + * is searched for the mapping file. + */ + protected String[] getMappingFileList() { + if (getPersistenceOptions().getMappingFilePath() != null) { + log.debug("Using specified list of mapping files " + + getPersistenceOptions().getMappingFilePath()); + return getPersistenceOptions().getMappingFilePath().split(","); + } else if (getPersistenceOptions().isUseMappingFile()) { + // register otherwise the getFileList will not work + EModelResolver.instance().register(getEPackages()); + + log.debug("Searching hbm files in class paths of epackages"); + return StoreUtil.getFileList(HbConstants.HBM_FILE_NAME, null); + } else { + throw new HbStoreException( + "This method may only be called if either the useMappingFile property or the MappingFilePath property has been set"); + } + } + + /** + * @return the mappingXML + */ + public String getMappingXML() { + return mappingXML; + } + + /** + * @param mappingXML + * the mappingXML to set + */ + public void setMappingXML(String mappingXML) { + this.mappingXML = mappingXML; + } + + /** + * @return the interceptor + */ + public Interceptor getInterceptor() { + return interceptor; + } + + /** + * @return the EntityNameResolver + * @see org.hibernate.EntityNameResolver + */ + public EntityNameResolver getEntityNameResolver() { + if (entityNameResolver == null) { + entityNameResolver = getExtensionManager().getExtension( + EMFEntityNameResolver.class); + entityNameResolver.setQualifyStrategy(getEntityNameStrategy()); + } + return entityNameResolver; + } + + /** Returns the persistent class for a certain EObject */ + public PersistentClass getPersistentClass(String entityName) { + final Iterator<?> it = getClassMappings(); + while (it.hasNext()) { + final PersistentClass pc = (PersistentClass) it.next(); + if (pc.getEntityName() != null + && pc.getEntityName().equals(entityName)) { + return pc; + } + } + return null; + } + + /** + * @param interceptor + * the interceptor to set + */ + public void setInterceptor(Interceptor interceptor) { + this.interceptor = interceptor; + } + + /** + * @return the paModel + */ + public PAnnotatedModel getPaModel() { + if (paModel == null) { + // happens in case a hbm file is used + // just create the pamodel with the default values + paModel = getExtensionManager().getExtension( + PersistenceMappingBuilder.class).buildMapping( + getEPackages(), getPersistenceOptions(), + getExtensionManager()); + } + return paModel; + } + + /** + * @return the referers + */ + public HashMap<String, java.util.List<ReferenceTo>> getReferers() { + return referers; + } + + /** + * If the extensionManager is not yet set then the DefaultExtensionManager + * is used. + * + * @return the extensionManager + */ + public ExtensionManager getExtensionManager() { + if (extensionManager == null) { + setExtensionManager(ExtensionManagerFactory.getInstance().create()); + } + return extensionManager; + } + + /** + * @param extensionManager + * the extensionManager to set + */ + public void setExtensionManager(ExtensionManager extensionManager) { + this.extensionManager = extensionManager; + MappingUtil.registerHbExtensions(extensionManager); + } + + /** + * @return the entityNameStrategy + */ + public EntityNameStrategy getEntityNameStrategy() { + if (entityNameStrategy == null) { + entityNameStrategy = getExtensionManager().getExtension( + EntityNameStrategy.class); + entityNameStrategy.setPaModel(getPaModel()); + } + return entityNameStrategy; + } + + /** + * @param paModel + * the paModel to set + */ + public void setPaModel(PAnnotatedModel paModel) { + this.paModel = paModel; + } + + /** + * Facilitates setting ePackages through Spring + */ + public void setEPackageClasses(java.util.List<String> ePackageClasses) { + if (ePackageConstructor == null) { + ePackageConstructor = new EPackageConstructor(); + } + ePackageConstructor.setModelClasses(ePackageClasses); + } + + public void setEPackageFiles(java.util.List<String> ePackageFiles) { + if (ePackageConstructor == null) { + ePackageConstructor = new EPackageConstructor(); + } + ePackageConstructor.setModelFiles(ePackageFiles); + } + + protected String processEAVMapping(InputStream inputStream) { + try { + final InputStreamReader reader = new InputStreamReader(inputStream, + "UTF-8"); + final char[] chars = new char[500]; + int readNum = 0; + final StringBuilder sb = new StringBuilder(); + while ((readNum = reader.read(chars, 0, 500)) > 0) { + sb.append(chars, 0, readNum); + } + String eav = sb.toString(); + eav = eav.replaceAll(HbConstants.EAV_TABLE_PREFIX_PARAMETER_REGEX, + getPersistenceOptions().getSQLTableNamePrefix()); + + final boolean extraLazy = getPersistenceOptions() + .isFetchAssociationExtraLazy(); + eav = eav.replaceAll(HbConstants.EAV_COLLECTIONLAZY_REGEX, + (extraLazy ? "extra" : "false")); + + return eav; + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + protected Mappings getMappings() { + return getHibernateConfiguration().createMappings(); + } + + /** + * If set to true (the default) then when initialize is called the + * configuration object is set to null and then recreated. + * + * @return if the configuration object is reset when initializing + */ + public boolean isResetConfigurationOnInitialization() { + return resetConfigurationOnInitialization; + } + + /** + * @see #isResetConfigurationOnInitialization() + * @param resetConfigurationOnInitialization + */ + public void setResetConfigurationOnInitialization( + boolean resetConfigurationOnInitialization) { + this.resetConfigurationOnInitialization = resetConfigurationOnInitialization; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbDataStoreFactory.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbDataStoreFactory.java new file mode 100755 index 000000000..51c120270 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbDataStoreFactory.java @@ -0,0 +1,33 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HbDataStoreFactory.java,v 1.4 2008/02/28 07:08:24 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +/** + * Defines the factory interface for creating Hibernate Configuration. By + * specifying their own configuration factory the client application can add + * their own properties and control the creation of session factories. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.4 $ + */ +public interface HbDataStoreFactory { + /** + * The method which gets called to create a EMFDataStore. The default + * factory creates a standard EMFDataStore + */ + public HbDataStore createHbDataStore(); +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbEntityDataStore.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbEntityDataStore.java new file mode 100755 index 000000000..ec6d3c53c --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbEntityDataStore.java @@ -0,0 +1,737 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HbEntityDataStore.java,v 1.37 2011/07/05 05:09:41 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringBufferInputStream; +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import javax.persistence.Cache; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; +import javax.persistence.FlushModeType; +import javax.persistence.LockModeType; +import javax.persistence.Parameter; +import javax.persistence.PersistenceUnitUtil; +import javax.persistence.Query; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.metamodel.Metamodel; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.teneo.PackageRegistryProvider; +import org.eclipse.emf.teneo.annotations.mapper.PersistenceFileProvider; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage; +import org.eclipse.emf.teneo.hibernate.mapper.MappingUtil; +import org.eclipse.emf.teneo.hibernate.mapping.EMFInitializeCollectionEventListener; +import org.eclipse.emf.teneo.hibernate.mapping.eav.EAVGenericIDUserType; +import org.hibernate.Interceptor; +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; +import org.hibernate.ejb.Ejb3Configuration; +import org.hibernate.ejb.EntityManagerFactoryImpl; +import org.hibernate.ejb.QueryImpl; +import org.hibernate.engine.query.NamedParameterDescriptor; +import org.hibernate.event.InitializeCollectionEventListener; +import org.hibernate.impl.AbstractQueryImpl; +import org.hibernate.type.EntityType; +import org.hibernate.type.Type; + +/** + * Adds Hibernate Entitymanager behavior to the hbDataStore. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.37 $ + */ +@SuppressWarnings("deprecation") +public class HbEntityDataStore extends HbDataStore implements + EntityManagerFactory { + + /** The logger */ + private static Log log = LogFactory.getLog(HbEntityDataStore.class); + + /** The persistency manager factory */ + private EntityManagerFactory entityManagerFactory; + + /** The used Hibernate configuration */ + private Ejb3Configuration ejb3Configuration; + + private Field queryParametersField; + + /** Initializes this Data Store */ + @Override + public void initialize() { + if (ejb3Configuration != null && isResetConfigurationOnInitialization()) { + ejb3Configuration = null; + } + + MappingUtil.registerHbExtensions(getExtensionManager()); + + try { + PackageRegistryProvider.getInstance().setThreadPackageRegistry( + getPackageRegistry()); + + log.debug("Initializing EJB3 Hb Entity DataStore"); + // check a few things + if (getEPackages() == null) { + throw new HbMapperException("EPackages are not set"); + // if (getName() == null) + // throw new HbStoreException("Name is not set"); + } + + // reset interceptor + setInterceptor(null); + + mapModel(); + + setPropertiesInConfiguration(); + + initializeDataStore(); + + // wait for the session factory until the database is (re)created + if (entityManagerFactory != null && entityManagerFactory.isOpen()) { + entityManagerFactory.close(); + } + entityManagerFactory = buildEntityManagerFactory(); + + // register ourselves + HbHelper.INSTANCE.register(this); + + setInitialized(true); + } finally { + PackageRegistryProvider.getInstance() + .setThreadPackageRegistry(null); + } + } + + /** Build the mappings in the configuration */ + @Override + protected void buildMappings() { + getConfiguration().buildMappings(); + } + + /** Set the event listener, can be overridden, in this impl. it does nothing */ + @Override + protected void setEventListeners() { + final EMFInitializeCollectionEventListener eventListener = getExtensionManager() + .getExtension(EMFInitializeCollectionEventListener.class); + getConfiguration() + .getEventListeners() + .setInitializeCollectionEventListeners( + new InitializeCollectionEventListener[] { eventListener }); + } + + /** Sets the interceptor */ + @Override + protected void setInterceptor() { + if (getInterceptor() != null) { + return; + } + final Interceptor interceptor = getHbContext().createInterceptor( + getHibernateConfiguration(), getEntityNameStrategy()); + getConfiguration().setInterceptor(interceptor); + setInterceptor(interceptor); + } + + /** Returns a new ejb3 configuration object */ + protected Ejb3Configuration createConfiguration() { + return new Ejb3Configuration(); + } + + /** Sets the properties in the Hibernate Configuration. */ + protected void setPropertiesInConfiguration() { + Properties properties = getDataStoreProperties(); + if (properties != null) { + setDefaultProperties(properties); + // set this as this gives errors in the hibernate entity manager + // see this bugzilla: + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=330855 + // Using HbEntityDataStore causes org.hibernate.MappingException: + // Unknown entity:... + if (!properties.containsKey("hibernate.ejb.metamodel.generation")) { + properties.setProperty("hibernate.ejb.metamodel.generation", + "disabled"); + } + getConfiguration().addProperties(properties); + } + } + + /** + * Maps an ecore model of one ore more epackages into a hibernate xml String + * which is added to the passed configuration + */ + protected void mapModel() { + if (getPersistenceOptions().isUseMappingFile() + || getPersistenceOptions().getMappingFilePath() != null) { + log.debug("Searching hbm files in class paths of epackages"); + final String[] fileList = getMappingFileList(); + for (String element : fileList) { + log.debug("Adding file " + element + + " to Hibernate Configuration"); + final PersistenceFileProvider pfp = getExtensionManager() + .getExtension(PersistenceFileProvider.class); + final InputStream is = pfp.getFileContent(this.getClass(), + element); + if (is == null) { + throw new HbStoreException("Path to mapping file: " + + element + " does not exist!"); + } + getConfiguration().addInputStream(is); + } + } else { + setMappingXML(mapEPackages()); + + boolean hasEAVMapping = false; + for (PAnnotatedEPackage aPackage : getPaModel().getPaEPackages()) { + for (PAnnotatedEClass aClass : aPackage.getPaEClasses()) { + if (aClass.getEavMapping() != null) { + hasEAVMapping = true; + break; + } + } + } + if (hasEAVMapping) { + try { + if (getPersistenceOptions().getEAVMappingFile() != null) { + final PersistenceFileProvider pfp = getExtensionManager() + .getExtension(PersistenceFileProvider.class); + final InputStream is = pfp.getFileContent(this + .getClass(), getPersistenceOptions() + .getEAVMappingFile()); + getConfiguration().addInputStream(processEAV(is)); + is.close(); + } else { + final PersistenceFileProvider pfp = getExtensionManager() + .getExtension(PersistenceFileProvider.class); + final InputStream is = pfp.getFileContent( + EAVGenericIDUserType.class, "eav.hbm.xml"); + getConfiguration().addInputStream(processEAV(is)); + is.close(); + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + // TODO replace this + final StringBufferInputStream is = new StringBufferInputStream( + getMappingXML()); + getConfiguration().addInputStream(is); + } + } + + protected InputStream processEAV(InputStream is) { + return new StringBufferInputStream(processEAVMapping(is)); + } + + /** Build the session factory */ + protected EntityManagerFactory buildEntityManagerFactory() { + final EntityManagerFactory emf = getConfiguration() + .buildEntityManagerFactory(); + return new WrappedEntityManagerFactory(emf); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbDataStore#close() + */ + @Override + public void close() { + if (isInitialized()) { + if (getEntityManagerFactory().isOpen()) { + getEntityManagerFactory().close(); + } + entityManagerFactory = null; + setInitialized(false); + // this will call the close method again but because the + // datastore + // is not initialized anymore it won't get here + HbHelper.INSTANCE.deRegisterDataStore(this); + } + ejb3Configuration = null; + } + + /** + * Note: returns an instance of the {@link WrappedEntityManagerFactory} + * class. + */ + public EntityManagerFactory getEntityManagerFactory() { + if (!isInitialized()) { + initialize(); + } + assert (entityManagerFactory != null); + return entityManagerFactory; + } + + /** Return a new session wrapper */ + @Override + public SessionWrapper createSessionWrapper() { + return new HbEntityManagerWrapper(this); + } + + /** + * @return the ejbConfiguration + */ + public Ejb3Configuration getConfiguration() { + if (ejb3Configuration == null) { + ejb3Configuration = createConfiguration(); + } + return ejb3Configuration; + } + + public void setConfiguration(Ejb3Configuration configuration) { + ejb3Configuration = configuration; + } + + /** + * @return the hbConfiguration + */ + @Override + public Configuration getHibernateConfiguration() { + return getConfiguration().getHibernateConfiguration(); + } + + /** Return the Classmappings as an iterator */ + @Override + public Iterator<?> getClassMappings() { + return getConfiguration().getClassMappings(); + } + + /** Is added for interface compliance with HbDataStore, should not be used */ + @Override + public SessionFactory getSessionFactory() { + final EntityManagerFactoryImpl entityManagerFactoryImpl; + if (getEntityManagerFactory() instanceof WrappedEntityManagerFactory) { + entityManagerFactoryImpl = (EntityManagerFactoryImpl) ((WrappedEntityManagerFactory) getEntityManagerFactory()) + .getDelegate(); + } else { + entityManagerFactoryImpl = (EntityManagerFactoryImpl) getEntityManagerFactory(); + } + return entityManagerFactoryImpl.getSessionFactory(); + } + + /** + * Note: returns the {@link WrappedEntityManager} class. + */ + public EntityManager createEntityManager() { + return getEntityManagerFactory().createEntityManager(); + } + + /** + * Note: returns the {@link WrappedEntityManager} class. + */ + @SuppressWarnings("rawtypes") + public EntityManager createEntityManager(Map arg0) { + return getEntityManagerFactory().createEntityManager(arg0); + } + + public boolean isOpen() { + return getEntityManagerFactory().isOpen(); + } + + public Cache getCache() { + return getEntityManagerFactory().getCache(); + } + + public CriteriaBuilder getCriteriaBuilder() { + return getEntityManagerFactory().getCriteriaBuilder(); + } + + public Metamodel getMetamodel() { + return getEntityManagerFactory().getMetamodel(); + } + + public PersistenceUnitUtil getPersistenceUnitUtil() { + return getEntityManagerFactory().getPersistenceUnitUtil(); + } + + public Map<String, Object> getProperties() { + return getEntityManagerFactory().getProperties(); + } + + /** + * The HbEntityDataStore uses a wrapped entity manager factory and wrapped + * entity manager to work around an issue that the Hibernate entity manager/ + * query implementation does not resolve query parameters of the EntityType + * correctly. It determines a wrong type. See the statement about this in + * the javadoc of the Hibernate {@link EntityType#getReturnedClass()} + * method. + * + * To get to the original Hibernate entity manager use the + * {@link WrappedEntityManagerFactory#getDelegate()} method. + * + * @author mtaal + */ + public class WrappedEntityManagerFactory implements EntityManagerFactory { + private EntityManagerFactory delegate; + + public WrappedEntityManagerFactory(EntityManagerFactory emf) { + delegate = emf; + } + + public EntityManagerFactory getDelegate() { + return delegate; + } + + public void setDelegate(EntityManagerFactory delegate) { + this.delegate = delegate; + } + + public void close() { + delegate.close(); + } + + public EntityManager createEntityManager() { + EntityManager em = delegate.createEntityManager(); + return new WrappedEntityManager(em); + } + + public EntityManager createEntityManager( + @SuppressWarnings("rawtypes") Map map) { + EntityManager em = delegate.createEntityManager(map); + return new WrappedEntityManager(em); + } + + public Cache getCache() { + return delegate.getCache(); + } + + public CriteriaBuilder getCriteriaBuilder() { + return delegate.getCriteriaBuilder(); + } + + public Metamodel getMetamodel() { + return delegate.getMetamodel(); + } + + public PersistenceUnitUtil getPersistenceUnitUtil() { + return delegate.getPersistenceUnitUtil(); + } + + public Map<String, Object> getProperties() { + return delegate.getProperties(); + } + + public boolean isOpen() { + return delegate.isOpen(); + } + } + + /** + * See {@link WrappedEntityManagerFactory} for a description why this class + * is needed. + * + * To get to the original Hibernate entity manager use the + * {@link WrappedEntityManager#getDelegateEntityManager()} method. + * + * @author mtaal + * + */ + public class WrappedEntityManager implements EntityManager { + private EntityManager delegateEntityManager; + + public WrappedEntityManager(EntityManager em) { + delegateEntityManager = em; + } + + public void clear() { + delegateEntityManager.clear(); + } + + public void close() { + delegateEntityManager.close(); + } + + public boolean contains(Object arg0) { + return delegateEntityManager.contains(arg0); + } + + @SuppressWarnings("unchecked") + public <T> TypedQuery<T> createNamedQuery(String arg0, Class<T> arg1) { + return (TypedQuery<T>) HbEntityDataStore.this + .repairParameterJavaType((QueryImpl<?>) delegateEntityManager + .createNamedQuery(arg0, arg1)); + } + + public Query createNamedQuery(String arg0) { + return (Query) HbEntityDataStore.this + .repairParameterJavaType((QueryImpl<?>) delegateEntityManager + .createNamedQuery(arg0)); + } + + public Query createNativeQuery(String arg0, + @SuppressWarnings("rawtypes") Class arg1) { + return (Query) HbEntityDataStore.this + .repairParameterJavaType((QueryImpl<?>) delegateEntityManager + .createNativeQuery(arg0, arg1)); + } + + public Query createNativeQuery(String arg0, String arg1) { + return (Query) HbEntityDataStore.this + .repairParameterJavaType((QueryImpl<?>) delegateEntityManager + .createNativeQuery(arg0, arg1)); + } + + public Query createNativeQuery(String arg0) { + return (Query) HbEntityDataStore.this + .repairParameterJavaType((QueryImpl<?>) delegateEntityManager + .createNativeQuery(arg0)); + } + + @SuppressWarnings("unchecked") + public <T> TypedQuery<T> createQuery(CriteriaQuery<T> arg0) { + return (TypedQuery<T>) HbEntityDataStore.this + .repairParameterJavaType((QueryImpl<?>) delegateEntityManager + .createQuery(arg0)); + } + + @SuppressWarnings("unchecked") + public <T> TypedQuery<T> createQuery(String arg0, Class<T> arg1) { + return (TypedQuery<T>) HbEntityDataStore.this + .repairParameterJavaType((QueryImpl<?>) delegateEntityManager + .createQuery(arg0, arg1)); + } + + public Query createQuery(String arg0) { + return (Query) HbEntityDataStore.this + .repairParameterJavaType((QueryImpl<?>) delegateEntityManager + .createQuery(arg0)); + } + + public void detach(Object arg0) { + delegateEntityManager.detach(arg0); + } + + public <T> T find(Class<T> arg0, Object arg1, LockModeType arg2, + Map<String, Object> arg3) { + return delegateEntityManager.find(arg0, arg1, arg2, arg3); + } + + public <T> T find(Class<T> arg0, Object arg1, LockModeType arg2) { + return delegateEntityManager.find(arg0, arg1, arg2); + } + + public <T> T find(Class<T> arg0, Object arg1, Map<String, Object> arg2) { + return delegateEntityManager.find(arg0, arg1, arg2); + } + + public <T> T find(Class<T> arg0, Object arg1) { + return delegateEntityManager.find(arg0, arg1); + } + + public void flush() { + delegateEntityManager.flush(); + } + + public CriteriaBuilder getCriteriaBuilder() { + return delegateEntityManager.getCriteriaBuilder(); + } + + public Object getDelegate() { + return delegateEntityManager.getDelegate(); + } + + public EntityManagerFactory getEntityManagerFactory() { + return delegateEntityManager.getEntityManagerFactory(); + } + + public FlushModeType getFlushMode() { + return delegateEntityManager.getFlushMode(); + } + + public LockModeType getLockMode(Object arg0) { + return delegateEntityManager.getLockMode(arg0); + } + + public Metamodel getMetamodel() { + return delegateEntityManager.getMetamodel(); + } + + public Map<String, Object> getProperties() { + return delegateEntityManager.getProperties(); + } + + public <T> T getReference(Class<T> arg0, Object arg1) { + return delegateEntityManager.getReference(arg0, arg1); + } + + public EntityTransaction getTransaction() { + return delegateEntityManager.getTransaction(); + } + + public boolean isOpen() { + return delegateEntityManager.isOpen(); + } + + public void joinTransaction() { + delegateEntityManager.joinTransaction(); + } + + public void lock(Object arg0, LockModeType arg1, + Map<String, Object> arg2) { + delegateEntityManager.lock(arg0, arg1, arg2); + } + + public void lock(Object arg0, LockModeType arg1) { + delegateEntityManager.lock(arg0, arg1); + } + + public <T> T merge(T arg0) { + return delegateEntityManager.merge(arg0); + } + + public void persist(Object arg0) { + delegateEntityManager.persist(arg0); + } + + public void refresh(Object arg0, LockModeType arg1, + Map<String, Object> arg2) { + delegateEntityManager.refresh(arg0, arg1, arg2); + } + + public void refresh(Object arg0, LockModeType arg1) { + delegateEntityManager.refresh(arg0, arg1); + } + + public void refresh(Object arg0, Map<String, Object> arg1) { + delegateEntityManager.refresh(arg0, arg1); + } + + public void refresh(Object arg0) { + delegateEntityManager.refresh(arg0); + } + + public void remove(Object arg0) { + delegateEntityManager.remove(arg0); + } + + public void setFlushMode(FlushModeType arg0) { + delegateEntityManager.setFlushMode(arg0); + } + + public void setProperty(String arg0, Object arg1) { + delegateEntityManager.setProperty(arg0, arg1); + } + + public <T> T unwrap(Class<T> arg0) { + return delegateEntityManager.unwrap(arg0); + } + + public EntityManager getDelegateEntityManager() { + return delegateEntityManager; + } + + public void setDelegateEntityManager(EntityManager delegateEntityManager) { + this.delegateEntityManager = delegateEntityManager; + } + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected QueryImpl<?> repairParameterJavaType(QueryImpl<?> query) { + try { + final Set<Parameter<?>> repairedParameters = new HashSet<Parameter<?>>(); + final Object parametersObject = getQueryParametersField() + .get(query); + final AbstractQueryImpl queryImpl = AbstractQueryImpl.class + .cast(query.getHibernateQuery()); + for (Parameter<?> parameter : (Collection<Parameter>) parametersObject) { + if (Map.class == parameter.getParameterType()) { + final Type type; + if (parameter.getName() != null) { + // repair these ones + final NamedParameterDescriptor descriptor = queryImpl + .getParameterMetadata() + .getNamedParameterDescriptor( + parameter.getName()); + type = descriptor.getExpectedType(); + } else { + type = queryImpl.getParameterMetadata() + .getOrdinalParameterExpectedType( + parameter.getPosition()); + } + if (type instanceof EntityType) { + final Parameter<?> param = new ParameterImpl( + parameter.getName(), parameter.getPosition(), + Object.class); + repairedParameters.add(param); + // final EntityType entityType = (EntityType) type; + // final String entityName = entityType + // .getAssociatedEntityName(); + // final EClass eClass = HbEntityDataStore.this + // .getEntityNameStrategy().toEClass(entityName); + + } else { + repairedParameters.add(parameter); + } + } else { + repairedParameters.add(parameter); + } + } + getQueryParametersField().set(query, repairedParameters); + return query; + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + protected Field getQueryParametersField() throws Exception { + if (queryParametersField != null) { + return queryParametersField; + } + Field field = QueryImpl.class.getDeclaredField("parameters"); + field.setAccessible(true); + return field; + } + + @SuppressWarnings("rawtypes") + private static class ParameterImpl implements Parameter { + private String name; + private Integer position; + private Class<?> javaClass; + + ParameterImpl(String name, Integer position, Class<?> clz) { + this.name = name; + this.position = position; + this.javaClass = clz; + } + + public Class<?> getParameterType() { + return javaClass; + } + + public String getName() { + return name; + } + + public Integer getPosition() { + return position; + } + } + +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbEntityManagerWrapper.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbEntityManagerWrapper.java new file mode 100755 index 000000000..382402816 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbEntityManagerWrapper.java @@ -0,0 +1,272 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * Benjamin Cabe + * </copyright> + * + * $Id: HbEntityManagerWrapper.java,v 1.16 2010/11/12 13:35:37 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; +import javax.persistence.FlushModeType; +import javax.persistence.Query; + +import org.eclipse.emf.teneo.annotations.pannotation.InheritanceType; +import org.hibernate.Session; +import org.hibernate.engine.ForeignKeys; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.mapping.JoinedSubclass; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.SingleTableSubclass; +import org.hibernate.mapping.UnionSubclass; + +/** + * Wraps a hibernate entity manager. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.16 $ + */ +public class HbEntityManagerWrapper implements SessionWrapper { + + /** The hibernate session */ + private EntityManager entityManager = null; + + /** The datastore which created me */ + private final HbEntityDataStore hbEntityDataStore; + + /** The current transaction */ + private EntityTransaction entityTransaction = null; + + private FlushModeType flushMode = null; + + /** Constructor */ + public HbEntityManagerWrapper(HbEntityDataStore hbEntityDataStore) { + this.hbEntityDataStore = hbEntityDataStore; + } + + /** Set the session in the constructor */ + public HbEntityManagerWrapper(HbEntityDataStore hbEntityDataStore, + EntityManager entityManager) { + this.hbEntityDataStore = hbEntityDataStore; + this.entityManager = entityManager; + } + + /** + * Return the session or entityManager, return is an object to support both + * session as well as entitymanager. + */ + public Object getClassicSession() { + if (entityManager == null) { + entityManager = hbEntityDataStore.getEntityManagerFactory() + .createEntityManager(); + } + return entityManager; + } + + /** + * Return the session or entityManager, return is an object to support both + * session as well as entitymanager. + */ + public Object getSession() { + if (entityManager == null) { + entityManager = hbEntityDataStore.getEntityManagerFactory() + .createEntityManager(); + } + return entityManager; + } + + /** Convenience which casts */ + public EntityManager getEntityManager() { + return (EntityManager) getSession(); + } + + /** Begin a transaction */ + public void beginTransaction() { + assert (entityTransaction == null); + entityTransaction = getEntityManager().getTransaction(); + entityTransaction.begin(); + } + + /** Commit a transaction */ + public void commitTransaction() { + if (entityTransaction == null) { + throw new IllegalStateException( + "EntityTransaction is null, call begin before commit!"); + } + entityTransaction.commit(); + entityTransaction = null; + } + + /** Rollback transaction */ + public void rollbackTransaction() { + if (entityTransaction == null) { + throw new IllegalStateException( + "EntityTransaction is null, call begin before commit!"); + } + entityTransaction.rollback(); + entityTransaction = null; + } + + /** Return an object using the entityname and a serializable id */ + public Object get(String entityName, Serializable id) { + return ((Session) getEntityManager().getDelegate()).get(entityName, id); + } + + /** Query */ + public List<?> executeQuery(String qry) { + final Query query = getEntityManager().createQuery(qry); + return query.getResultList(); + } + + /** Query */ + public List<?> executeQuery(String qry, boolean cacheable) { + final Query query = getEntityManager().createQuery(qry); + // todo: cacheable in ejb3? + // query.setCacheable(cacheable); + return query.getResultList(); + } + + /** Query */ + public List<?> executeQuery(String qry, String entityParameter, + Object entity) { + final Query query = getEntityManager().createQuery(qry); + query.setParameter(entityParameter, entity); + return query.getResultList(); + } + + /** Query */ + public List<?> executeQuery(String qry, List<Object> parameters) { + final Query query = getEntityManager().createQuery(qry); + int pos = 1; + for (Object obj : parameters) { + query.setParameter(pos++, obj); + } + return query.getResultList(); + } + + /** Query with named parameters */ + public List<?> executeQuery(String qry, Map<String, Object> namedParameters) { + final Query query = getEntityManager().createQuery(qry); + for (Map.Entry<String, Object> entry : namedParameters.entrySet()) { + query.setParameter(entry.getKey(), entry.getValue()); + } + return query.getResultList(); + } + + /** Does this impl. wrap an entitymanager */ + public boolean isEJB3EntityManager() { + return true; + } + + public void restorePreviousFlushMode() { + if (flushMode != null) { + getEntityManager().setFlushMode(flushMode); + flushMode = null; + } + } + + /** Set the flushmode */ + public void setFlushModeManual() { + flushMode = getEntityManager().getFlushMode(); + getEntityManager().setFlushMode(FlushModeType.COMMIT); + } + + /** Close the underlying session */ + public void close() { + getEntityManager().close(); + } + + /** Save or update the pass object */ + public void saveOrUpdate(Object obj) { + final Session session = (Session) getEntityManager().getDelegate(); + final String entityName = hbEntityDataStore.getInterceptor() + .getEntityName(obj); + if (((SessionImplementor) session).getPersistenceContext().isEntryFor( + obj)) { + getEntityManager().persist(obj); + } else if (ForeignKeys.isNotTransient(entityName, obj, false, + (SessionImplementor) session) + || !ForeignKeys.isTransient(entityName, obj, false, + (SessionImplementor) session)) { + // this is a trick because ejb3 does not support saveOrUpdate (why + // did they not add + // this behavior!) + session.saveOrUpdate(obj); + } else { + getEntityManager().persist(obj); + } + } + + /** Delete the object */ + public void delete(Object obj) { + getEntityManager().remove(obj); + } + + /** Flush the session */ + public void flush() { + getEntityManager().flush(); + } + + /** Is transaction active */ + public boolean isTransactionActive() { + return entityTransaction != null && entityTransaction.isActive(); + } + + /** Refresh the object */ + public void refresh(Object obj) { + getEntityManager().refresh(obj); + } + + /** Check if a certain class is mapped using a certain inheritance strategy */ + public boolean isInheritanceStrategy(Class<?> cls, InheritanceType strategy) { + final String name = cls.getName(); + final String realName = name.substring(name.lastIndexOf('.') + 1, + name.length() - 4); + final PersistentClass cmd = hbEntityDataStore.getConfiguration() + .getClassMapping(realName); + if (strategy.equals(InheritanceType.SINGLE_TABLE)) { + return cmd instanceof SingleTableSubclass; + } + if (strategy.equals(InheritanceType.JOINED)) { + return cmd instanceof JoinedSubclass; + } + if (strategy.equals(InheritanceType.TABLE_PER_CLASS)) { + return cmd instanceof UnionSubclass; + } + throw new HbStoreException("Strategy: " + strategy.toString() + + " not supported "); + } + + /** Clear the session */ + public void clear() { + getEntityManager().clear(); + } + + /** Merge with the datastore */ + public Object merge(Object obj) { + return getEntityManager().merge(obj); + } + + public void persist(Object obj) { + getEntityManager().persist(obj); + } + + public Session getHibernateSession() { + return (Session) getEntityManager().getDelegate(); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbHelper.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbHelper.java new file mode 100755 index 000000000..5b7119ef7 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbHelper.java @@ -0,0 +1,211 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HbHelper.java,v 1.19 2010/04/02 22:28:53 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.teneo.PersistenceOptions; +import org.eclipse.emf.teneo.annotations.mapper.PersistenceMappingBuilder; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel; +import org.eclipse.emf.teneo.extension.ExtensionManager; +import org.eclipse.emf.teneo.extension.ExtensionManagerFactory; +import org.eclipse.emf.teneo.hibernate.mapper.HibernateMappingGenerator; +import org.eclipse.emf.teneo.hibernate.mapper.MappingUtil; +import org.hibernate.mapping.Component; +import org.hibernate.mapping.PersistentClass; + +/** + * Is the main entry point for 'outside' users to create, register and retrieve EMF Data stores. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.19 $ + */ +public class HbHelper { + /** The logger */ + private static Log log = LogFactory.getLog(HbHelper.class); + + /** The singleton instance of this class */ + public static final HbHelper INSTANCE = new HbHelper(); + + /** The list of EMF Datastores mapped by name */ + private final Hashtable<String, HbDataStore> emfDataStores = new Hashtable<String, HbDataStore>(); + + /** The list of emf datastores mapped by hibernate persistent class */ + private final Hashtable<Object, HbDataStore> dataStoreByPersistentClass = new Hashtable<Object, HbDataStore>(); + + /** The registered emf data store factory */ + private static HbDataStoreFactory emfDataStoreFactory = new HbDataStoreFactory() { + public HbDataStore createHbDataStore() { + return new HbSessionDataStore(); + } + }; + + /** + * @param emfDataStoreFactory + * the emfDataStoreFactory to set + */ + public static void setHbDataStoreFactory(HbDataStoreFactory hbDataStoreFactory) { + HbHelper.emfDataStoreFactory = hbDataStoreFactory; + } + + /** Put a datastore in the dataStoreByPersistentClass */ + void registerDataStoreByPC(HbDataStore ds) { + for (Iterator<?> it = ds.getClassMappings(); it.hasNext();) { + final PersistentClass pc = (PersistentClass) it.next(); + if (dataStoreByPersistentClass.get(pc) != null) { + throw new HbMapperException("There is already a datastore registered for this pc: " + + pc.getEntityName() + (dataStoreByPersistentClass.get(pc)).getName() + "/" + ds.getName()); + } + log.debug("Datastore: " + ds.getName() + " registered for pc: " + pc.getEntityName()); + dataStoreByPersistentClass.put(pc, ds); + } + } + + /** Register the datastore also for the components */ + void registerDataStoreByComponent(HbDataStore ds, Component component) { + log.debug("Datastore: " + ds.getName() + " registered for component: " + component.getComponentClassName()); + dataStoreByPersistentClass.put(component, ds); + } + + /** Return the datastore on the basis of the pc */ + public HbDataStore getDataStore(PersistentClass pc) { + final HbDataStore ds = dataStoreByPersistentClass.get(pc); + if (ds == null) { + throw new HbMapperException("No datastore for pc " + pc.getEntityName()); + } + return ds; + } + + /** Return the datastore on the basis of the component */ + public HbDataStore getDataStore(Component component) { + final HbDataStore ds = dataStoreByPersistentClass.get(component); + if (ds == null) { + throw new HbMapperException("No datastore for pc " + component.getComponentClassName()); + } + return ds; + } + + /** Clears the list of session factories */ + public synchronized void closeAll() { + final List<HbDataStore> dataStores = new ArrayList<HbDataStore>(emfDataStores.values()); + for (HbDataStore emfds : dataStores) { + emfds.close(); + } + emfDataStores.clear(); + dataStoreByPersistentClass.clear(); + } + + /** Deregisters a session factory from the registry */ + public synchronized void deRegisterDataStore(String name) { + if (name == null) { + throw new HbMapperException("An unique name should be specified when deregistering a session factory"); + } + final HbDataStore emfds = emfDataStores.get(name); + if (emfds == null) { + return; + } + deRegisterDataStore(emfds); + } + + /** Deregisters a datastore from the registry */ + public synchronized void deRegisterDataStore(HbDataStore emfds) { + // changed for bugzilla 281036 + final List<Object> toRemove = new ArrayList<Object>(); + for (Object key : dataStoreByPersistentClass.keySet()) { + if (emfds == dataStoreByPersistentClass.get(key)) { + toRemove.add(key); + } + } + for (Object key : toRemove) { + dataStoreByPersistentClass.remove(key); + } + if (emfds.getName() != null) { + emfDataStores.remove(emfds.getName()); + } + if (emfds.isInitialized()) { + emfds.close(); + } + } + + /** + * Creates and register a HibernateEMFDataStore, initialization has to be done by the caller + */ + public synchronized HbDataStore createRegisterDataStore(String name) { + HbDataStore emfds = emfDataStores.get(name); + if (emfds != null) { + log.warn("EMF Data Store already registered under name: " + name + ", returning it"); + return emfds; + } + + log.info("Creating emf data store and registering it under name: " + name); + emfds = emfDataStoreFactory.createHbDataStore(); + emfds.setName(name); + // next call is done automatically + // emfDataStores.put(name, emfds); + log.info("Returning created emf data store, initialize this newly created data store!"); + return emfds; + } + + /** Register a datastore */ + public void register(HbDataStore hbDataStore) { + emfDataStores.put(hbDataStore.getName(), hbDataStore); + } + + /** Return a emf data store */ + public HbDataStore getDataStore(String name) { + final HbDataStore hds = emfDataStores.get(name); + if (hds == null) { + log.debug("No datastore found using " + name); + } + return hds; + } + + /** + * Separate utility method, generates a hibernate mapping for a set of epackages and options. The hibernate.hbm.xml + * is returned as a string. The mapping is not registered or used in any other way by Elver. + */ + public String generateMapping(EPackage[] epackages, Properties props) { + return generateMapping(epackages, props, ExtensionManagerFactory.getInstance().create()); + } + + /** + * Separate utility method, generates a hibernate mapping for a set of epackages and options. The hibernate.hbm.xml + * is returned as a string. The mapping is not registered or used in any other way by Elver. + */ + public String generateMapping(EPackage[] epackages, Properties props, ExtensionManager extensionManager) { + MappingUtil.registerHbExtensions(extensionManager); + + log.debug("Generating mapping file passed epackages"); + // DCB: Use Hibernate-specific annotation processing mechanism. This + // allows use of + // Hibernate-specific annotations. + final PersistenceOptions po = extensionManager.getExtension(PersistenceOptions.class, new Object[] { props }); + final PAnnotatedModel paModel = extensionManager.getExtension(PersistenceMappingBuilder.class).buildMapping( + epackages, po, extensionManager); + final HibernateMappingGenerator hmg = extensionManager.getExtension(HibernateMappingGenerator.class); + hmg.setPersistenceOptions(po); + + return hmg.generateToString(paModel); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbMapperException.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbMapperException.java new file mode 100755 index 000000000..4e0f02964 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbMapperException.java @@ -0,0 +1,46 @@ +/** + * <copyright> Copyright (c) 2005, 2006, 2007, 2008 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 </copyright> $Id: + * HbMapperException.java,v 1.2 2007/02/01 12:35:55 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import org.eclipse.emf.teneo.TeneoException; + +/** + * Local Runtime Exception which logs. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.1 $ + */ + +public class HbMapperException extends TeneoException { + /** + * Serializable id + */ + private static final long serialVersionUID = 7433341056815136417L; + + /** + * The constructor, logs the exception also + */ + public HbMapperException(String msg, Throwable cause) { + super(msg, cause); + } + + /** + * The constructor, logs the exception also + */ + public HbMapperException(Throwable cause) { + this(cause.getMessage(), cause); + } + + /** + * The constructor, logs the exception also + */ + public HbMapperException(String msg) { + super(msg); + } +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbSessionDataStore.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbSessionDataStore.java new file mode 100755 index 000000000..2a5ce35fa --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbSessionDataStore.java @@ -0,0 +1,274 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HbSessionDataStore.java,v 1.32 2011/07/05 05:09:41 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Iterator; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.teneo.PackageRegistryProvider; +import org.eclipse.emf.teneo.annotations.mapper.PersistenceFileProvider; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage; +import org.eclipse.emf.teneo.hibernate.mapper.MappingUtil; +import org.eclipse.emf.teneo.hibernate.mapping.EMFInitializeCollectionEventListener; +import org.eclipse.emf.teneo.hibernate.mapping.eav.EAVGenericIDUserType; +import org.hibernate.Cache; +import org.hibernate.Interceptor; +import org.hibernate.TypeHelper; +import org.hibernate.cfg.Configuration; +import org.hibernate.event.InitializeCollectionEventListener; + +/** + * Holds the SessionFactory and performs different initialization related + * actions. Initializes the database and offers xml import and export methods. + * In addition can be used to retrieve all referers to a certain eobject. + * <p> + * The behavior can be overridden by overriding the protected methods and + * implementing/registering your own HbDataStoreFactory in the HibernateHelper. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.32 $ + */ + +@SuppressWarnings("unchecked") +public class HbSessionDataStore extends HbBaseSessionDataStore { + + private static final long serialVersionUID = 1L; + + /** The logger */ + private static Log log = LogFactory.getLog(HbSessionDataStore.class); + + /** The used Hibernate configuration */ + private Configuration hbConfiguration; + + @Override + public void close() { + super.close(); + hbConfiguration = null; + } + + /** Initializes this Data Store */ + @Override + public void initialize() { + + if (hbConfiguration != null && isResetConfigurationOnInitialization()) { + hbConfiguration = null; + } + + MappingUtil.registerHbExtensions(getExtensionManager()); + + PackageRegistryProvider.getInstance().setThreadPackageRegistry( + getPackageRegistry()); + + try { + log.debug("Initializing Hb Session DataStore"); + + // check a few things + if (getEPackages() == null) { + throw new HbMapperException("EPackages are not set"); + // if (getName() == null) + // throw new HbStoreException("Name is not set"); + } + + // reset interceptor + setInterceptor(null); + + log.debug(">>>>> Creating HB Configuration"); + + getConfiguration(); + + mapModel(); + + setPropertiesInConfiguration(); + + initializeDataStore(); + + // will close the current sessionfactory if it was set + closeSessionFactory(); + + buildSessionFactory(); + + setInitialized(true); + } finally { + PackageRegistryProvider.getInstance() + .setThreadPackageRegistry(null); + } + } + + /** Set the event listener, can be overridden */ + @Override + protected void setEventListeners() { + final EMFInitializeCollectionEventListener initializeCollectionEventListener = getExtensionManager() + .getExtension(EMFInitializeCollectionEventListener.class); + getConfiguration() + .getEventListeners() + .setInitializeCollectionEventListeners( + new InitializeCollectionEventListener[] { initializeCollectionEventListener }); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.hibernate.HbContext#createConfiguration() + */ + protected Configuration createConfiguration() { + return new Configuration(); + } + + /** Return the Classmappings as an iterator */ + @Override + public Iterator<?> getClassMappings() { + return getConfiguration().getClassMappings(); + } + + /** Build the mappings in the configuration */ + @Override + protected void buildMappings() { + getConfiguration().buildMappings(); + } + + /** Sets the interceptor */ + @Override + protected void setInterceptor() { + if (getInterceptor() != null) { // probably overridden + return; + } + final Interceptor interceptor = getHbContext().createInterceptor( + getHibernateConfiguration(), getEntityNameStrategy()); + getConfiguration().setInterceptor(interceptor); + setInterceptor(interceptor); + } + + /** Sets the properties in the Hibernate Configuration. */ + protected void setPropertiesInConfiguration() { + Properties properties = getDataStoreProperties(); + if (properties != null) { + setDefaultProperties(properties); + getConfiguration().addProperties(properties); + } + } + + /** + * Maps an ecore model of one ore more epackages into a hibernate xml String + * which is added to the passed configuration + */ + protected void mapModel() { + + if (getPersistenceOptions().getMappingFilePath() != null + || getPersistenceOptions().isUseMappingFile()) { + final String[] fileList = getMappingFileList(); + for (String element : fileList) { + log.debug("Adding file " + element + + " to Hibernate Configuration"); + final PersistenceFileProvider pfp = getExtensionManager() + .getExtension(PersistenceFileProvider.class); + final InputStream is = pfp.getFileContent(this.getClass(), + element); + if (is == null) { + throw new HbStoreException("Path to mapping file: " + + element + " does not exist!"); + } + getConfiguration().addInputStream(is); + } + } else { + setMappingXML(mapEPackages()); + + boolean hasEAVMapping = false; + for (PAnnotatedEPackage aPackage : getPaModel().getPaEPackages()) { + for (PAnnotatedEClass aClass : aPackage.getPaEClasses()) { + if (aClass.getEavMapping() != null) { + hasEAVMapping = true; + break; + } + } + } + if (hasEAVMapping) { + try { + if (getPersistenceOptions().getEAVMappingFile() != null) { + final PersistenceFileProvider pfp = getExtensionManager() + .getExtension(PersistenceFileProvider.class); + final InputStream is = pfp.getFileContent(this + .getClass(), getPersistenceOptions() + .getEAVMappingFile()); + getConfiguration().addXML(processEAVMapping(is)); + is.close(); + } else { + final PersistenceFileProvider pfp = getExtensionManager() + .getExtension(PersistenceFileProvider.class); + final InputStream is = pfp.getFileContent( + EAVGenericIDUserType.class, "eav.hbm.xml"); + getConfiguration().addXML(processEAVMapping(is)); + is.close(); + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + getConfiguration().addXML(getMappingXML()); + } + } + + /** Build the session factory */ + protected void buildSessionFactory() { + setSessionFactory(getConfiguration().buildSessionFactory()); + } + + /** Return a new session wrapper */ + @Override + public SessionWrapper createSessionWrapper() { + return new HbSessionWrapper(this); + } + + /** + * @return the hbConfiguration + */ + public Configuration getConfiguration() { + if (hbConfiguration == null) { + hbConfiguration = createConfiguration(); + } + return hbConfiguration; + } + + public void setConfiguration(Configuration configuration) { + hbConfiguration = configuration; + } + + /** + * @return the hbConfiguration + */ + @Override + public Configuration getHibernateConfiguration() { + return getConfiguration(); + } + + public boolean containsFetchProfileDefinition(String arg0) { + return getSessionFactory().containsFetchProfileDefinition(arg0); + } + + public Cache getCache() { + return getSessionFactory().getCache(); + } + + public TypeHelper getTypeHelper() { + return getSessionFactory().getTypeHelper(); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbSessionWrapper.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbSessionWrapper.java new file mode 100755 index 000000000..59373dcb7 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbSessionWrapper.java @@ -0,0 +1,224 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * Benjamin Cabe + * </copyright> + * + * $Id: HbSessionWrapper.java,v 1.12 2010/11/12 09:33:33 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import org.eclipse.emf.teneo.annotations.pannotation.InheritanceType; +import org.hibernate.FlushMode; +import org.hibernate.LockOptions; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.impl.SessionImpl; +import org.hibernate.metadata.ClassMetadata; +import org.hibernate.persister.entity.JoinedSubclassEntityPersister; +import org.hibernate.persister.entity.SingleTableEntityPersister; +import org.hibernate.persister.entity.UnionSubclassEntityPersister; + +/** + * Wraps a standard hibernate session. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.12 $ + */ +public class HbSessionWrapper implements SessionWrapper { + + /** The hibernate session */ + private Session session = null; + + /** The datastore which created me */ + private final HbDataStore hbDataStore; + + private FlushMode flushMode; + + /** Constructor */ + public HbSessionWrapper(HbDataStore hbDataStore) { + this.hbDataStore = hbDataStore; + } + + /** Set the session in the constructor */ + public HbSessionWrapper(HbDataStore hbDataStore, Session session) { + this.hbDataStore = hbDataStore; + this.session = session; + } + + /** + * Return the session, return is an object to support both session as well + * as entitymanager. + */ + public Object getSession() { + if (session == null) { + session = hbDataStore.getSessionFactory().openSession(); + } + return session; + } + + /** Convenience which casts */ + private Session getSessionInternal() { + return (Session) getSession(); + } + + /** Begin a transaction */ + public void beginTransaction() { + getSessionInternal().beginTransaction(); + } + + /** Commit a transaction */ + public void commitTransaction() { + getSessionInternal().getTransaction().commit(); + } + + /** Rollback transaction */ + public void rollbackTransaction() { + getSessionInternal().getTransaction().rollback(); + } + + /** Return an object using the entityname and a serializable id */ + public Object get(String entityName, Serializable id) { + return getSessionInternal().get(entityName, id); + } + + /** Query */ + public List<?> executeQuery(String qry) { + final Query query = getSessionInternal().createQuery(qry); + return query.list(); + } + + /** Query */ + public List<?> executeQuery(String qry, String entityParameter, + Object entity) { + final Query query = getSessionInternal().createQuery(qry); + query.setEntity(entityParameter, entity); + return query.list(); + } + + /** Query */ + public List<?> executeQuery(String qry, List<Object> parameters) { + final Query query = getSessionInternal().createQuery(qry); + int pos = 0; + for (Object obj : parameters) { + query.setParameter(pos++, obj); + } + return query.list(); + } + + /** Query */ + public List<?> executeQuery(String qry, boolean cacheable) { + final Query query = getSessionInternal().createQuery(qry); + query.setCacheable(cacheable); + return query.list(); + } + + /** Query with named parameters */ + public List<?> executeQuery(String qry, Map<String, Object> namedParameters) { + final Query query = getSessionInternal().createQuery(qry); + for (Map.Entry<String, Object> entry : namedParameters.entrySet()) { + query.setParameter(entry.getKey(), entry.getValue()); + } + return query.list(); + } + + /** Does this impl. wrap an entitymanager */ + public boolean isEJB3EntityManager() { + return false; + } + + public void restorePreviousFlushMode() { + if (flushMode != null) { + getSessionInternal().setFlushMode(flushMode); + flushMode = null; + } + } + + /** Set the flushmode */ + public void setFlushModeManual() { + flushMode = getSessionInternal().getFlushMode(); + getSessionInternal().setFlushMode(FlushMode.MANUAL); + } + + /** Close the underlying session */ + public void close() { + getSessionInternal().close(); + } + + /** Save or update the pass object */ + public void saveOrUpdate(Object obj) { + getSessionInternal().saveOrUpdate(obj); + } + + /** Delete the object */ + public void delete(Object obj) { + getSessionInternal().delete(obj); + } + + /** Flush the session */ + public void flush() { + getSessionInternal().flush(); + } + + /** Is transaction active */ + public boolean isTransactionActive() { + return ((SessionImpl) getSessionInternal()).isTransactionInProgress(); + } + + /** Refresh the object */ + public void refresh(Object obj) { + getSessionInternal().refresh(obj, LockOptions.NONE); + } + + /** Check if a certain class is mapped using a certain inheritance strategy */ + public boolean isInheritanceStrategy(Class<?> cls, InheritanceType strategy) { + final String clsName = cls.getName(); + final String realName = clsName.substring(clsName.lastIndexOf('.') + 1, + clsName.length() - 4); + final ClassMetadata cmd = hbDataStore.getSessionFactory() + .getClassMetadata(realName); + if (strategy.equals(InheritanceType.SINGLE_TABLE)) { + return cmd instanceof SingleTableEntityPersister; + } + if (strategy.equals(InheritanceType.JOINED)) { + return cmd instanceof JoinedSubclassEntityPersister; + } + if (strategy.equals(InheritanceType.TABLE_PER_CLASS)) { + return cmd instanceof UnionSubclassEntityPersister; + } + throw new HbStoreException("Strategy: " + strategy.toString() + + " not supported "); + } + + /** Clear the session */ + public void clear() { + getSessionInternal().clear(); + } + + /** Merge with the datastore */ + public Object merge(Object obj) { + return getSessionInternal().merge(obj); + } + + public void persist(Object obj) { + getSessionInternal().save(obj); + } + + public Session getHibernateSession() { + return getSessionInternal(); + } + +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbStoreException.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbStoreException.java new file mode 100755 index 000000000..2f4d3e62b --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbStoreException.java @@ -0,0 +1,49 @@ +/** + * <copyright> Copyright (c) 2005, 2006, 2007, 2008 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 </copyright> $Id: + * HbStoreException.java,v 1.3 2007/02/08 23:11:37 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import org.eclipse.emf.teneo.TeneoException; + +/** + * Is used to throw runtime emf/jpox integration exceptions. This class offers automatic logging to + * commons logging. Note that this class extends RuntimeException, so no forced throws and catch + * statements. Although there are very differing views on this topic but it is our experience that + * to many checked exceptions only distract the programmer and have no added value. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.5 $ + */ + +public class HbStoreException extends TeneoException { + /** + * Serializable id + */ + private static final long serialVersionUID = 7433341056815136417L; + + /** + * The constructor, logs the exception also + */ + public HbStoreException(String msg, Throwable cause) { + super(msg, cause); + } + + /** + * The constructor, logs the exception also + */ + public HbStoreException(Throwable cause) { + this(cause.getMessage(), cause); + } + + /** + * The constructor, logs the exception also + */ + public HbStoreException(String msg) { + super(msg); + } +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbUtil.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbUtil.java new file mode 100755 index 000000000..b62cf01ec --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbUtil.java @@ -0,0 +1,399 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HbUtil.java,v 1.38 2010/11/12 14:39:12 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.util.FeatureMapUtil; +import org.eclipse.emf.teneo.Constants; +import org.eclipse.emf.teneo.ERuntime; +import org.eclipse.emf.teneo.PackageRegistryProvider; +import org.eclipse.emf.teneo.hibernate.mapper.HbMapperConstants; +import org.eclipse.emf.teneo.hibernate.mapping.econtainer.NewEContainerFeatureIDPropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierCacheHandler; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierPropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierUtil; +import org.eclipse.emf.teneo.hibernate.mapping.property.EAttributePropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.property.EReferencePropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.property.SyntheticPropertyHandler; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.Session; +import org.hibernate.cfg.Environment; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.mapping.Collection; +import org.hibernate.mapping.Component; +import org.hibernate.mapping.MetaAttribute; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.property.EmbeddedPropertyAccessor; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.proxy.HibernateProxy; +import org.hibernate.type.IdentifierType; +import org.hibernate.type.PrimitiveType; +import org.hibernate.type.StringType; +import org.hibernate.type.Type; + +/** + * Contains some utility methods. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.38 $ + */ +public class HbUtil { + + /** The logger */ + private static Log log = LogFactory.getLog(HbUtil.class); + + public static EClass getEClassFromMeta(Component component) { + final MetaAttribute ePackageMetaAttribute = component + .getMetaAttribute(HbMapperConstants.EPACKAGE_PARAM); + if (ePackageMetaAttribute == null) { + return null; + } + final EPackage epackage = PackageRegistryProvider.getInstance() + .getPackageRegistry() + .getEPackage(ePackageMetaAttribute.getValue()); + if (epackage == null) { + throw new IllegalArgumentException( + "Could not find ePackage using nsuri " + + ePackageMetaAttribute.getValue()); + } + final MetaAttribute eClassMetaAttribute = component + .getMetaAttribute(HbMapperConstants.ECLASS_NAME_META); + if (eClassMetaAttribute == null) { + return null; + } + return (EClass) epackage.getEClassifier(eClassMetaAttribute.getValue()); + } + + /** + * A merge method which does not use Session.merge but uses the EMF api to + * travers object references and execute merge through the object tree. The + * merge will traverse all EReferences. The maximum level it will traverse + * is passed in as the maxMergeLevel parameters. + * + * @param session + * the hibernate session + * @param eObject + * the eObject to merge + * @return the object read from the database with Merge support. + */ + public static EObject merge(Session session, EObject eObject, + int maxMergeLevel) { + SessionImplementor sessionImplementor = (SessionImplementor) session; + return merge(sessionImplementor, eObject, + new HashMap<EObject, EObject>(), maxMergeLevel, 0); + } + + private static EObject merge(SessionImplementor sessionImplementor, + EObject eObject, Map<EObject, EObject> copyCache, + int maxMergeLevel, int currentMergeLevel) { + if (copyCache.containsKey(eObject)) { + return copyCache.get(eObject); + } + final String entityName = sessionImplementor.guessEntityName(eObject); + final EntityPersister persister = sessionImplementor + .getEntityPersister(entityName, eObject); + final Serializable id = persister.getIdentifier(eObject, + sessionImplementor); + if (id != null) { + final EObject source = (EObject) ((Session) sessionImplementor) + .get(entityName, id); + copyCache.put(eObject, source); + if (maxMergeLevel == currentMergeLevel) { + return source; + } + // now copy the features + for (EStructuralFeature eFeature : source.eClass() + .getEAllStructuralFeatures()) { + if (eFeature instanceof EAttribute) { + source.eSet(eFeature, eObject.eGet(eFeature)); + } else if (eFeature.isMany()) { + final List<EObject> newValues = new ArrayList<EObject>(); + @SuppressWarnings("unchecked") + final List<EObject> currentValues = (List<EObject>) eObject + .eGet(eFeature); + for (EObject currentValue : currentValues) { + newValues + .add(merge(sessionImplementor, currentValue, + copyCache, maxMergeLevel, + currentMergeLevel + 1)); + } + source.eSet(eFeature, newValues); + } else { + source.eSet( + eFeature, + merge(sessionImplementor, + (EObject) eObject.eGet(eFeature), + copyCache, maxMergeLevel, + currentMergeLevel + 1)); + } + } + return source; + } else { + return eObject; + } + } + + public static boolean isEAVMapped(PersistentClass mappedEntity) { + if (mappedEntity.getEntityName() != null + && mappedEntity.getEntityName().equals( + Constants.EAV_EOBJECT_ENTITY_NAME)) { + return true; + } + if (mappedEntity.getSuperclass() == null) { + return false; + } + return isEAVMapped(mappedEntity.getSuperclass()); + } + + /** Encode the id of an eobject */ + @SuppressWarnings("unchecked") + public static String idToString(EObject eobj, HbDataStore hd) { + final PersistentClass pc = hd.getPersistentClass(hd + .getEntityNameStrategy().toEntityName(eobj.eClass())); + if (pc == null) { // can happen with map entries + return null; + } + Object id; + if (eobj instanceof HibernateProxy) { + id = ((HibernateProxy) eobj).getHibernateLazyInitializer() + .getIdentifier(); + } else { + id = IdentifierUtil.getID(eobj, hd); + } + if (id == null) { + id = IdentifierCacheHandler.getInstance().getID(eobj); + if (id == null) { + return null; + } + } + final Type t = pc.getIdentifierProperty().getType(); + if (t instanceof PrimitiveType) { + return ((PrimitiveType<Object>) t).toString(id); + } else if (t instanceof StringType) { + return (String) id; + } + return null; + } + + /** Encode the id of an eobject */ + @SuppressWarnings("unchecked") + public static Object stringToId(EClass eclass, HbDataStore hd, String id) { + try { + final PersistentClass pc = hd.getPersistentClass(hd + .getEntityNameStrategy().toEntityName(eclass)); + final Type t = pc.getIdentifierProperty().getType(); + if (t instanceof IdentifierType) { + return ((IdentifierType<Object>) t).stringToObject(id); + } else if (t instanceof StringType) { + return id; + } + return null; + } catch (Exception e) { + throw new HbStoreException("Exception while converting id: " + id + + " of eclass " + eclass.getName()); + } + } + + /** Returns the correct accessor on the basis of the type of property */ + public static PropertyAccessor getPropertyAccessor(Property mappedProperty, + HbDataStore ds, String entityName, EClass mappedEClass) { + if (mappedProperty + .getMetaAttribute(HbConstants.SYNTHETIC_PROPERTY_INDICATOR) != null) { // synthetic + return new SyntheticPropertyHandler(mappedProperty.getName()); + } else if (mappedProperty.getMetaAttribute(HbMapperConstants.ID_META) != null) { // synthetic + // ID + return new IdentifierPropertyHandler(); + } else if (mappedProperty + .getMetaAttribute(HbMapperConstants.VERSION_META) != null) { + return ds.getHbContext().createVersionAccessor(); + } else if (mappedProperty.getName().compareToIgnoreCase( + "_identifierMapper") == 0) { // name + // is + // used + // by + // hb + return new EmbeddedPropertyAccessor(); // new + // DummyPropertyHandler(); + } else if (mappedProperty.getName().compareToIgnoreCase( + HbConstants.PROPERTY_ECONTAINER) == 0) { + return ds.getHbContext().createEContainerAccessor(); + } else if (mappedProperty.getName().compareToIgnoreCase( + HbConstants.PROPERTY_ECONTAINER_FEATURE_NAME) == 0) { + return ds.getExtensionManager().getExtension( + NewEContainerFeatureIDPropertyHandler.class); + } else if (mappedProperty.getName().compareToIgnoreCase( + HbConstants.PROPERTY_ECONTAINER_FEATURE_ID) == 0) { + return ds.getHbContext().createEContainerFeatureIDAccessor(); + } + + EClass eClass = null; + if (mappedEClass != null) { + eClass = mappedEClass; + } else { + eClass = ds.getEntityNameStrategy().toEClass(entityName); + if (eClass == null) { + // for components this is the case + eClass = ERuntime.INSTANCE.getEClass(entityName); + } + } + final EStructuralFeature efeature = StoreUtil.getEStructuralFeature( + eClass, mappedProperty.getName()); + + if (efeature == null) { + throw new HbMapperException( + "Feature not found for eclass/entity/property " + + eClass.getName() + "/" + entityName + "/" + + mappedProperty.getName()); + } + + log.debug("Creating property accessor for " + mappedProperty.getName() + + "/" + entityName + "/" + efeature.getName()); + + // check extra lazy + final boolean extraLazy = mappedProperty.getValue() instanceof Collection + && ((Collection) mappedProperty.getValue()).isExtraLazy(); + + if (FeatureMapUtil.isFeatureMap(efeature)) { + return ds.getHbContext().createFeatureMapPropertyAccessor(efeature); + } else if (efeature instanceof EReference) { + final EReference eref = (EReference) efeature; + if (eref.isMany()) { + return ds.getHbContext().createEListAccessor(efeature, + extraLazy, + ds.getPersistenceOptions().isMapEMapAsTrueMap()); + } else { + PropertyAccessor erefPropertyHandler = ds.getHbContext() + .createEReferenceAccessor(eref); + if (erefPropertyHandler instanceof EReferencePropertyHandler) { + if (mappedProperty.getPersistentClass() != null) { + ((EReferencePropertyHandler) erefPropertyHandler) + .setId(mappedProperty == mappedProperty + .getPersistentClass() + .getIdentifierProperty()); + } + } + return erefPropertyHandler; + } + } else { + final EAttribute eattr = (EAttribute) efeature; + if (eattr.isMany()) { + return ds.getHbContext().createEListAccessor(efeature, + extraLazy, + ds.getPersistenceOptions().isMapEMapAsTrueMap()); + } else { + // note also array types are going here! + final PropertyAccessor pa = ds.getHbContext() + .createEAttributeAccessor(eattr); + // note this check is necessary because maybe somebody override + // HBContext.createEAttributeAccessor + // to not return a EAttributePropertyHandler + if (pa instanceof EAttributePropertyHandler) { + final EAttributePropertyHandler eAttributePropertyHandler = (EAttributePropertyHandler) pa; + eAttributePropertyHandler.setPersistenceOptions(ds + .getPersistenceOptions()); + if (mappedProperty.getPersistentClass() != null) { + eAttributePropertyHandler + .setId(mappedProperty == mappedProperty + .getPersistentClass() + .getIdentifierProperty()); + } + } + return pa; + } + } + } + + /** Returns the meta class uri, if not found then null is returned */ + public static String getEClassNameFromFeatureMapMeta(PersistentClass pc) { + MetaAttribute ma = pc + .getMetaAttribute(HbMapperConstants.FEATUREMAP_META); + if (ma == null) { + return null; + } + return ma.getValue(); + } + + /** + * Returns the structural feature, handles the case of structural features + * which are part of a feature map entry. public static EStructuralFeature + * getFeature(PersistentClass pc, String propName, EPackage[] epacks) { + * final MetaAttribute ma = pc.getMetaAttribute("eclass"); // TODO: + * externalize final String eclassName; if (ma != null) { eclassName = + * ma.getValue(); } else { eclassName = pc.getEntityName(); } return + * StoreUtil.getEStructuralFeature(eclassName, propName, epacks); } + */ + + /** + * Creates and registers an emf data store using a set of generic store + * properties + */ + public static HbDataStore getCreateDataStore(Properties props) { + final String name = props.getProperty(Constants.PROP_NAME); + HbDataStore eds = HbHelper.INSTANCE.getDataStore(name); + if (eds != null) { + return eds; + } + + final Properties hbProps = new Properties(); + hbProps.putAll(props); + hbProps.put(Environment.USER, + doTrim(props.getProperty(Constants.PROP_DB_USER))); + hbProps.put(Environment.PASS, + doTrim(props.getProperty(Constants.PROP_DB_PWD))); + hbProps.put(Environment.DRIVER, + doTrim(props.getProperty(Constants.PROP_DB_DRIVER))); + hbProps.put(Environment.URL, + doTrim(props.getProperty(Constants.PROP_DB_URL))); + hbProps.put(Environment.DIALECT, + doTrim(props.getProperty(Constants.PROP_DB_DIALECT))); + + EPackage[] epacks = StoreUtil.getEPackages(doTrim(props + .getProperty(Constants.PROP_EPACKAGE_NSURI))); + + // create a EMF Data Store, this is retrieved later again + eds = HbHelper.INSTANCE.createRegisterDataStore(name); + eds.setDataStoreProperties(hbProps); + eds.setEPackages(epacks); + eds.initialize(); + return eds; + } + + /** Convenience method */ + private static String doTrim(String totrim) { + if (totrim == null) { + return null; + } + return totrim.trim(); + } + +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/LazyCollectionUtils.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/LazyCollectionUtils.java new file mode 100644 index 000000000..ba3f3fbb1 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/LazyCollectionUtils.java @@ -0,0 +1,307 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: LazyCollectionUtils.java,v 1.9 2010/08/18 11:50:38 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import org.eclipse.emf.teneo.hibernate.mapping.eav.EAVDelegatingList; +import org.eclipse.emf.teneo.hibernate.mapping.eav.EAVValueHolder; +import org.eclipse.emf.teneo.mapping.elist.PersistableDelegateList; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.collection.AbstractPersistentCollection; +import org.hibernate.engine.CollectionEntry; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.hql.ast.util.SessionFactoryHelper; +import org.hibernate.persister.collection.AbstractCollectionPersister; +import org.hibernate.persister.collection.QueryableCollection; + +/** + * A utility class providing methods related to lazy loading of collections. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.9 $ + */ +public class LazyCollectionUtils { + + public final static int DEFAULT_PAGE_SIZE = 100; + + /** + * Returns an iterator which loads the underlying data from the collection + * in pages (controlled by the pageSize parameter). Note if the collection + * is not lazy loadable then a normal iterator is returned. This is checked + * using the {@link #isLazyLoadableCollection(Collection)} method. + * + * Note: this method can only handle collections of EObjects so not collections + * of primitive typed objects. Paged iteration of these collections is not + * supported by Hibernate. + * + * @param coll + * the collection to iterate lazily over + * @param pageSize + * the pageSize, this determines the pagesize of the page of data + * read each time from the database + * @return a paging iterator or if not a lazy loadable collection a normal + * iterator + * @see PagingIterator + */ + public static <E> Iterator<E> getPagedLoadingIterator(Collection<E> coll, + int pageSize) { + if (!isLazyLoadableCollection(coll)) { + return coll.iterator(); + } + final PersistableDelegateList<?> persistableList = (PersistableDelegateList<?>) coll; + final AbstractPersistentCollection persistentCollection = (AbstractPersistentCollection) persistableList + .getDelegate(); + + final SessionImplementor session = persistentCollection.getSession(); + final PagingIterator<E> pagingIterator = new PagingIterator<E>(); + pagingIterator.setCollection(persistentCollection); + pagingIterator.setPageSize(pageSize); + pagingIterator.setSession((Session) session); + + final CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(persistentCollection); + final AbstractCollectionPersister persister = (AbstractCollectionPersister)entry.getLoadedPersister(); + pagingIterator.setEavCollection(coll instanceof EAVDelegatingList); + pagingIterator.setIndexColumnNames(persister.getIndexColumnNames()); + return pagingIterator; + } + + /** + * Reads the size of a collection in a lazy manner, i.e. will try to not + * load the collection from the database. The size is cached in the object, + * so subsequent calls to this method will not result in additional database + * queries. This until the collection changes then the cache is cleared. + * + * Note if the collection can not be lazy loaded (see the + * {@link #isLazyLoadableCollection(Collection)}) then the size method is + * called on the collection. This method call is probably not lazy. + * + * @param coll + * the collection to get the size from + * @return the size of the collection + */ + public static int size(Collection<?> coll) { + if (!isLazyLoadableCollection(coll)) { + return coll.size(); + } + final PersistableDelegateList<?> persistableList = (PersistableDelegateList<?>) coll; + final AbstractPersistentCollection persistentCollection = (AbstractPersistentCollection) persistableList + .getDelegate(); + final SessionImplementor session = persistentCollection.getSession(); + final QueryableCollection persister = new SessionFactoryHelper(session + .getFactory()).getCollectionPersister(persistentCollection + .getRole()); + return persister.getSize(persistentCollection.getKey(), session); + } + + /** + * Determines if a collection can be lazy loaded. A lazy loadable collection + * must be a {@link PersistableDelegateList} which has a + * {@link AbstractPersistentCollection} as the delegate list which also must + * have an open Hibernate session. + * + * @param coll + * the collection for which to determine if it can be lazy loaded + * @return false if not lazy loadable, true otherwise + */ + public static <E> boolean isLazyLoadableCollection(Collection<E> coll) { + boolean lazyLoadable = coll instanceof PersistableDelegateList<?>; + if (!lazyLoadable) { + return false; + } + final PersistableDelegateList<?> persistableList = (PersistableDelegateList<?>) coll; + lazyLoadable &= persistableList.getDelegate() instanceof AbstractPersistentCollection; + if (!lazyLoadable) { + return false; + } + final AbstractPersistentCollection persistentCollection = (AbstractPersistentCollection) persistableList + .getDelegate(); + final SessionImplementor session = persistentCollection.getSession(); + // if not a valid session then go away + if (session == null + || !session.isOpen() + || !session.getPersistenceContext().containsCollection( + persistentCollection)) { + return false; + } + return true; + } + + /** + * A paging iterator reads the underlying data from the database in pages. + * Everytime the iterator reaches the end of a page it reads the next page + * from the database. + * + * @author mtaal + */ + public static class PagingIterator<E> implements Iterator<E> { + + private Session session; + private int pageSize; + private Boolean hasNext = null; + private int currentIteratorIndex = 0; + private int nextPageStart = 0; + private List<E> content; + private Object collection; + private String[] indexColumnNames; + private String orderBy = ""; + private boolean eavCollection; + + public boolean hasNext() { + if (content == null) { + setPageInformation(); + } + + if (currentIteratorIndex < content.size()) { + return true; + } + + if (hasNext != null) { + return hasNext; + } + + if (content.size() < pageSize) { + hasNext = false; + return hasNext; + } + + // load the next page to see if there is any content + hasNext = !loadNextPage().isEmpty(); + + return hasNext; + } + + public E next() { + if (currentIteratorIndex < content.size()) { + return convert(content.get(currentIteratorIndex++)); + } + + // load the next page + setPageInformation(); + if (content.isEmpty()) { + throw new NoSuchElementException(); + } + return convert(content.get(currentIteratorIndex++)); + } + + @SuppressWarnings("unchecked") + private E convert(E value) { + if (value instanceof EAVValueHolder) { + return (E) ((EAVValueHolder) value).getValue(); + } + return value; + } + + private void setPageInformation() { + content = loadNextPage(); + currentIteratorIndex = 0; + hasNext = null; + nextPageStart += content.size(); + } + + @SuppressWarnings("unchecked") + private List<E> loadNextPage() { + final Query query; + if (isEavCollection()) { + query = session.createFilter(collection, + " order by this.listIndex "); + } else { + query = session.createFilter(collection, orderBy); + } + query.setMaxResults(pageSize); + query.setFirstResult(nextPageStart); + return (List<E>) query.list(); + } + + public void remove() { + throw new UnsupportedOperationException( + "Removal is not supported by the paging iterator"); + } + + public Session getSession() { + return session; + } + + public void setSession(Session session) { + this.session = session; + } + + public int getPageSize() { + return pageSize; + } + + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + public Object getCollection() { + return collection; + } + + public void setCollection(Object collection) { + this.collection = collection; + } + + public String[] getIndexColumnNames() { + return indexColumnNames; + } + + public void setIndexColumnNames(String[] indexColumnNames) { + this.indexColumnNames = indexColumnNames; + final StringBuilder sb = new StringBuilder(); + if (indexColumnNames != null) { + for (String indexColumnName : indexColumnNames) { + if (sb.length() == 0) { + sb.append(" order by "); + } else { + sb.append(", "); + } + sb.append(indexColumnName.replaceAll("`", "").replaceAll( + "\"", "")); + } + } + orderBy = sb.toString(); + } + + public String getOrderBy() { + return orderBy; + } + + /** + * Note the parameter must include the term: order by. Refer to properties of + * the collection content using the this keyword. + * + * @param orderBy the order by clause including the order by keyword, for example: order by this.name + */ + public void setOrderBy(String orderBy) { + this.orderBy = orderBy; + } + + public boolean isEavCollection() { + return eavCollection; + } + + public void setEavCollection(boolean eavCollection) { + this.eavCollection = eavCollection; + } + + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/SessionWrapper.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/SessionWrapper.java new file mode 100755 index 000000000..d14b930e8 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/SessionWrapper.java @@ -0,0 +1,109 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * Benjamin Cabe + * </copyright> + * + * $Id: SessionWrapper.java,v 1.9 2009/05/23 13:57:55 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import org.eclipse.emf.teneo.annotations.pannotation.InheritanceType; +import org.hibernate.Session; + +/** + * Wraps a session or an entity manager. Is used to support both standard hibernate as well as hibernate entitymanager. + * The differences between these two are hidden behind this interface (with different implementations for either case). + * The Teneo runtime code uses this interface to start and commit transactions and perform queries. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.9 $ + */ +public interface SessionWrapper { + + /** + * Return the session, return is an object to support both session as well as entitymanager. + */ + Object getSession(); + + /** Begin a transaction */ + void beginTransaction(); + + /** Commit a transaction */ + void commitTransaction(); + + /** Rollback transaction */ + void rollbackTransaction(); + + /** Return an object using the entityname and a serializable id */ + Object get(String entityName, Serializable id); + + /** Query */ + List<?> executeQuery(String qry); + + /** Query */ + List<?> executeQuery(String qry, String entityParameter, Object entity); + + /** Query */ + List<?> executeQuery(String qry, boolean cacheable); + + /** Query */ + List<?> executeQuery(String qry, List<Object> parameters); + + /** Query with named parameters */ + List<?> executeQuery(String qry, Map<String, Object> namedParameters); + + /** Does this impl. wrap an entitymanager */ + boolean isEJB3EntityManager(); + + public void restorePreviousFlushMode(); + + /** Set the flushmode in the session */ + void setFlushModeManual(); + + /** Close the session/entitymanager */ + void close(); + + /** Save or update the pass object */ + void saveOrUpdate(Object obj); + + /** Delete the object */ + void delete(Object obj); + + /** Flush the session */ + void flush(); + + /** Clear the session */ + void clear(); + + /** Is transaction active */ + boolean isTransactionActive(); + + /** Refresh the object */ + void refresh(Object obj); + + /** Check if a certain class is mapped using a certain inheritance strategy */ + public boolean isInheritanceStrategy(Class<?> cls, InheritanceType strategy); + + /** Persist a new object */ + public void persist(Object obj); + + /** Merge with the datastore */ + public Object merge(Object obj); + + /** Return the underlying session */ + public Session getHibernateSession(); +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/AnyEObjectType.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/AnyEObjectType.java new file mode 100755 index 000000000..450e422fd --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/AnyEObjectType.java @@ -0,0 +1,472 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: AnyEObjectType.java,v 1.7 2010/11/12 09:33:33 mtaal Exp $ + */ +package org.eclipse.emf.teneo.hibernate.mapping; + +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.dom4j.Node; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.teneo.hibernate.HbStoreException; +import org.hibernate.EntityMode; +import org.hibernate.FetchMode; +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.engine.CascadeStyle; +import org.hibernate.engine.ForeignKeys; +import org.hibernate.engine.Mapping; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.persister.entity.Joinable; +import org.hibernate.type.AbstractType; +import org.hibernate.type.AssociationType; +import org.hibernate.type.CompositeType; +import org.hibernate.type.ForeignKeyDirection; +import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.Type; + +/** + * Supports persisting the reference to any persistable EObect, it stores the + * entity name, and the id in a string field + * + * @author <a href="mailto:mkanaley@tibco.com">Mike Kanaley</a> + */ +public class AnyEObjectType extends AbstractType implements CompositeType, + AssociationType { + + /** + * Generated Serial ID + */ + private static final long serialVersionUID = 3857353606004705457L; + + private static final String[] PROPERTY_NAMES = new String[] { "class", + "idtype", "idstr" }; + + private static final int[] SQL_TYPES = { Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR }; + + /** Constructor by id */ + private final HashMap<String, Constructor<?>> constructors = new HashMap<String, Constructor<?>>(); + + /** + * Return the types of the columns that this UserType will serialize into. + * + * @return a single column of type VARCHAR. + */ + public int[] sqlTypes() { + return SQL_TYPES; + } + + /** Just returns the value */ + public Object deepCopy(Object value, EntityMode entityMode, + SessionFactoryImplementor factory) throws HibernateException { + return value; + } + + /* See superclass */ + public boolean isMethodOf(Method method) { + return false; + } + + /** Checks using equals */ + @Override + public boolean isSame(Object x, Object y, EntityMode entityMode) + throws HibernateException { + if (x != null) { + return x.equals(y); + } + return x == y; + } + + /** Compare is not implemented, returning 0 for now */ + @Override + public int compare(Object x, Object y, EntityMode entityMode) { + return 0; + } + + /** Return the column span */ + public int getColumnSpan(Mapping session) throws MappingException { + return SQL_TYPES.length; + } + + /** The name of the type */ + public String getName() { + return "AnyEObject"; + } + + /** Return false for safety */ + public boolean isMutable() { + return false; + } + + /** Returns unsupportedexception */ + public Object nullSafeGet(ResultSet rs, String name, + SessionImplementor session, Object owner) + throws HibernateException, SQLException { + throw new UnsupportedOperationException("Type is a multicolumn type"); + } + + /** Returns the object from the resultset */ + public Object nullSafeGet(ResultSet rs, String[] names, + SessionImplementor session, Object owner) + throws HibernateException, SQLException { + final String entityName = rs.getString(names[0]); + if (rs.wasNull()) { + return null; + } + final String idType = rs.getString(names[1]); + if (rs.wasNull()) { + return null; + } + final String idStr = rs.getString(names[2]); + if (rs.wasNull()) { + return null; + } + + return session.internalLoad(entityName, getId(idStr, idType), true, + false); + } + + /** Creates an id object of the correct type */ + private Serializable getId(String idStr, String idType) { + try { + Constructor<?> constructor = constructors.get(idType); + if (constructor == null) { + final Class<?> idClass = this.getClass().getClassLoader() + .loadClass(idType); + constructor = idClass + .getConstructor(new Class[] { String.class }); + constructors.put(idType, constructor); + } + return (Serializable) constructor + .newInstance(new Object[] { idStr }); + } catch (Exception e) { + throw new HbStoreException("Could not create id type for " + idType + + " and id " + idStr, e); + } + } + + @Override + public Object hydrate(ResultSet rs, String[] names, + SessionImplementor session, Object owner) + throws HibernateException, SQLException { + final String entityName = rs.getString(names[0]); + if (rs.wasNull()) { + return null; + } + final String idType = rs.getString(names[1]); + if (rs.wasNull()) { + return null; + } + final String idStr = rs.getString(names[2]); + if (rs.wasNull()) { + return null; + } + + return new EObjectCacheEntry(entityName, getId(idStr, idType)); + } + + @Override + public Object resolve(Object value, SessionImplementor session, Object owner) + throws HibernateException { + EObjectCacheEntry entry = (EObjectCacheEntry) value; + return session.internalLoad(entry.entityName, entry.id, true, false); + } + + /* + * public Object semiResolve(Object value, SessionImplementor session, + * Object owner) throws HibernateException { throw new + * UnsupportedOperationException("Any mappings may not form part of a + * property-ref"); } + */ + + public void nullSafeSet(PreparedStatement st, Object value, int index, + SessionImplementor session) throws HibernateException, SQLException { + nullSafeSet(st, value, index, null, session); + } + + public void nullSafeSet(PreparedStatement st, Object value, int index, + boolean[] settable, SessionImplementor session) + throws HibernateException, SQLException { + + String entityName = null; + String idStr = null; + String idType = null; + if (value != null) { + entityName = session.bestGuessEntityName(value); + Serializable id = ForeignKeys.getEntityIdentifierIfNotUnsaved( + entityName, value, session); + idType = id.getClass().getName(); + idStr = id.toString(); + st.setString(index, entityName); + st.setString(index + 1, idType); + st.setString(index + 2, idStr); + } else { + st.setNull(index, SQL_TYPES[0]); + st.setNull(index, SQL_TYPES[1]); + st.setNull(index, SQL_TYPES[2]); + } + } + + /** Returns EObject */ + public Class<?> getReturnedClass() { + return EObject.class; + } + + public int[] sqlTypes(Mapping mapping) throws MappingException { + return SQL_TYPES; + } + + public void setToXMLNode(Node xml, Object value, + SessionFactoryImplementor factory) { + throw new UnsupportedOperationException( + "Any types cannot be stringified"); + } + + public String toLoggableString(Object value, + SessionFactoryImplementor factory) throws HibernateException { + return value == null ? "null" : value.getClass().getName(); + } + + public Object fromXMLNode(Node xml, Mapping factory) + throws HibernateException { + throw new UnsupportedOperationException(); // TODO: is this right?? + } + + public static final class EObjectCacheEntry implements Serializable { + /** + * Serial Version ID + */ + private static final long serialVersionUID = 1030890286147221359L; + + /** The cached entityName */ + String entityName; + + /** And its id */ + Serializable id; + + EObjectCacheEntry(String entityName, Serializable id) { + this.entityName = entityName; + this.id = id; + } + } + + @Override + public Object assemble(Serializable cached, SessionImplementor session, + Object owner) throws HibernateException { + final EObjectCacheEntry entry = (EObjectCacheEntry) cached; + return entry == null ? null : session.internalLoad(entry.entityName, + entry.id, true, false); + } + + @Override + public Serializable disassemble(Object value, SessionImplementor session, + Object owner) throws HibernateException { + if (value == null) { + return null; + } + final String entityName = session.bestGuessEntityName(value); + final Serializable id = ForeignKeys.getEntityIdentifierIfNotUnsaved( + entityName, value, session); + return new EObjectCacheEntry(entityName, id); + } + + @Override + public boolean isAnyType() { + return true; + } + + @SuppressWarnings("rawtypes") + public Object replace(Object original, Object target, + SessionImplementor session, Object owner, Map copyCache) + throws HibernateException { + if (original == null) { + return null; + } else { + final String entityName = session.bestGuessEntityName(original); + final Serializable id = ForeignKeys + .getEntityIdentifierIfNotUnsaved(entityName, original, + session); + return session.internalLoad(entityName, id, true, false); + } + } + + public CascadeStyle getCascadeStyle(int i) { + return CascadeStyle.NONE; + } + + public FetchMode getFetchMode(int i) { + return FetchMode.SELECT; + } + + public String[] getPropertyNames() { + return PROPERTY_NAMES; + } + + public Object getPropertyValue(Object component, int i, + SessionImplementor session) throws HibernateException { + if (component != null) { + final String entityName = session.bestGuessEntityName(component); + Serializable id = ForeignKeys.getEntityIdentifierIfNotUnsaved( + entityName, component, session); + switch (i) { + case 0: + return session.bestGuessEntityName(component); + case 1: + return id.getClass().getName(); + case 2: + return id.toString(); + default: + throw new HbStoreException("Index " + i + "not supported"); + } + } + return null; + } + + public Object[] getPropertyValues(Object component, + SessionImplementor session) throws HibernateException { + if (component != null) { + final String entityName = session.bestGuessEntityName(component); + Serializable id = ForeignKeys.getEntityIdentifierIfNotUnsaved( + entityName, component, session); + return new Object[] { session.bestGuessEntityName(component), + id.getClass().getName(), id.toString() }; + } + return null; + } + + public Type[] getSubtypes() { + return new Type[] { StandardBasicTypes.STRING, + StandardBasicTypes.STRING, StandardBasicTypes.STRING }; + } + + public void setPropertyValues(Object component, Object[] values, + EntityMode entityMode) throws HibernateException { + throw new UnsupportedOperationException(); + } + + public Object[] getPropertyValues(Object component, EntityMode entityMode) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isComponentType() { + return true; + } + + public ForeignKeyDirection getForeignKeyDirection() { + return ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT; + } + + @Override + public boolean isAssociationType() { + return true; + } + + public boolean useLHSPrimaryKey() { + return false; + } + + public Joinable getAssociatedJoinable(SessionFactoryImplementor factory) { + throw new UnsupportedOperationException( + "any types do not have a unique referenced persister"); + } + + @Override + public boolean isModified(Object old, Object current, boolean[] checkable, + SessionImplementor session) throws HibernateException { + if (current == null) { + return old != null; + } + if (old == null) { + return current != null; + } + + final EObjectCacheEntry entry = (EObjectCacheEntry) old; + final String entityName = session.bestGuessEntityName(current); + final Serializable id = ForeignKeys.getEntityIdentifierIfNotUnsaved( + entityName, current, session); + if (checkable[0] && entry.entityName.compareTo(entityName) != 0) { + return true; + } + if ((checkable[1] || checkable[2]) && !id.equals(entry.id)) { + return true; + } + return false; + } + + public String getAssociatedEntityName(SessionFactoryImplementor factory) + throws MappingException { + throw new UnsupportedOperationException( + "any types do not have a unique referenced persister"); + } + + public boolean[] getPropertyNullability() { + return null; + } + + @SuppressWarnings("rawtypes") + public String getOnCondition(String alias, + SessionFactoryImplementor factory, Map enabledFilters) + throws MappingException { + throw new UnsupportedOperationException(); + } + + public boolean isReferenceToPrimaryKey() { + return true; + } + + public String getRHSUniqueKeyPropertyName() { + return null; + } + + public String getLHSPropertyName() { + return null; + } + + public boolean isAlwaysDirtyChecked() { + return false; + } + + public boolean isEmbeddedInXML() { + return false; + } + + public boolean[] toColumnNullness(Object value, Mapping mapping) { + boolean[] result = new boolean[getColumnSpan(mapping)]; + if (value != null) { + Arrays.fill(result, true); + } + return result; + } + + public boolean isDirty(Object old, Object current, boolean[] checkable, + SessionImplementor session) throws HibernateException { + return isDirty(old, current, session); + } + + public boolean isEmbedded() { + return false; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/DefaultToStringUserType.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/DefaultToStringUserType.java new file mode 100755 index 000000000..dd2272e96 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/DefaultToStringUserType.java @@ -0,0 +1,247 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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: + * Michael Kanaley, TIBCO Software Inc. + * </copyright> + * + * $Id: DefaultToStringUserType.java,v 1.6 2009/10/15 20:35:48 mtaal Exp $ + */ +package org.eclipse.emf.teneo.hibernate.mapping; + +import java.io.Serializable; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Properties; + +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EFactory; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.teneo.PackageRegistryProvider; +import org.eclipse.emf.teneo.hibernate.mapper.HbMapperConstants; +import org.hibernate.usertype.ParameterizedType; +import org.hibernate.usertype.UserType; + +/** + * Provides a Hibernate extension (called a UserType) to support serializing EMF custom datatypes into VARCHAR columns. + * The custom DataType mappers provided by this plugin have the job of registering Hibernate typedefs that use this + * UserType implementation. + * + * This class is intended for contribution to Teneo. + * + * @author <a href="mailto:mkanaley@tibco.com">Mike Kanaley</a> + */ +public class DefaultToStringUserType implements UserType, ParameterizedType { + + private static final int[] SQL_TYPES = { Types.VARCHAR }; + private EFactory eFactory; + private EDataType eDataType; + + private EPackage.Registry registry; + + public DefaultToStringUserType() { + registry = PackageRegistryProvider.getInstance().getPackageRegistry(); + } + + /** + * Return the types of the columns that this UserType will serialize into. + * + * @return a single column of type VARCHAR. + */ + public int[] sqlTypes() { + return SQL_TYPES; + } + + /** + * Return the Java class of the object that is serialized for the column. + * + * @return the Java instance class associated with the EMF DataType. + */ + public Class<?> returnedClass() { + return this.eDataType.getInstanceClass(); + } + + /** + * Is this datatype mutable? + * + * @return Being conservative - false always. + */ + public boolean isMutable() { + return false; + } + + /** + * Provide a copy of the datatypes. Converts to String and then back to datatype again. + * + * @param value + * the value to copy. + * @return the value always. + */ + public Object deepCopy(Object value) { + String data = this.eFactory.convertToString(this.eDataType, value); + return this.eFactory.createFromString(this.eDataType, data); + } + + /** + * Are the two objects equal? + * + * @param x + * an object to compare. + * @param y + * an object to compare. + * @return a standard equals test between the objects. + */ + public boolean equals(Object x, Object y) { + if (x == y) + return true; + if (x == null || y == null) + return false; + return x.equals(y); + } + + /** + * Populate the model object property from the ResultSet. + * + * @param resultSet + * the non-null ResultSet from which the field will be populated. + * @param names + * the names of the columns. + * @param owner + * the owning object. + * @return null if the column's value is null; otherwise, use the EMF factory to construct a new instance of the + * custom EMF data type from the contents of the String value of the column. + * @throws SQLException + * if the value cannot be retrieved from the ResultSet. + */ + public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws SQLException { + + String data = resultSet.getString(names[0]); + if (data == null) { + return null; + } + return this.eFactory.createFromString(this.eDataType, data); + } + + /** + * Populate the database statement from the model object property. + * + * @param statement + * the non-null Statement to insert the value into. + * @param value + * the object to convert. + * @param index + * the index into the statement where to insert the converted value. + * @throws SQLException + * if the converted value cannot be set in the statement. + */ + public void nullSafeSet(PreparedStatement statement, Object value, int index) throws SQLException { + String pvalue = null; + if (value != null) { + pvalue = this.eFactory.convertToString(this.eDataType, value); + } + if (pvalue != null) { + statement.setString(index, pvalue); + } else { + statement.setNull(index, Types.VARCHAR); + } + } + + /** + * No-op implementation. + * + * @param value + * the value to dissemble. + * @return the value passed in. + */ + public Serializable disassemble(Object value) { + return (Serializable) value; + } + + /** + * No-op implementation. + * + * @param cachedValue + * the value to assemble. + * @param owner + * the owning object. + * @return the cachedValue passed in. + */ + public Object assemble(Serializable cachedValue, Object owner) { + return cachedValue; + } + + /** + * No-op implementation. + * + * @param original + * the value to replace. + * @param target + * the target object. + * @param owner + * the owning object. + * @return the original value passed in. + */ + public Object replace(Object original, Object target, Object owner) { + return original; + } + + /** + * No-op implementation. + * + * @param x + * the object to get the hashcode for. + * @return x's hashcode. + */ + public int hashCode(Object x) { + return x.hashCode(); + } + + /************************************************************************ + * ParameterizedType implementation + ************************************************************************/ + /** + * Read in the type parameters from the Hibernate mapping and determine the EMF factory and custom data type to use. + * + * @param properties + * the properties containing key value pairs for the {@link #PACKAGE_IMPLEMENTATION_CLASS_NAME_PROPERTY} + * and {@link #ATTRIBUTE_NAME_PROPERTY} parameters. + */ + public void setParameterValues(Properties properties) { + final String ePackageNsUri = properties.getProperty(HbMapperConstants.EPACKAGE_PARAM); + if (ePackageNsUri == null || ePackageNsUri.length() == 0) { + throw new IllegalArgumentException("Could not find custom UserType property " + + HbMapperConstants.EPACKAGE_PARAM); + } + final EPackage epackage = registry.getEPackage(ePackageNsUri); + if (epackage == null) { + throw new IllegalArgumentException("Could not find ePackage using nsuri " + ePackageNsUri); + } + this.eFactory = epackage.getEFactoryInstance(); + final String edatatypeName = properties.getProperty(HbMapperConstants.EDATATYPE_PARAM); + if (edatatypeName == null) { + throw new IllegalArgumentException("Could not find custom UserType property " + + HbMapperConstants.EDATATYPE_PARAM); + } + final EClassifier eclassifier = epackage.getEClassifier(edatatypeName); + if (eclassifier instanceof EDataType) { + this.eDataType = (EDataType) eclassifier; + } else { + if (eclassifier == null) { + throw new IllegalArgumentException("Missing attribute " + edatatypeName + " in package implementation " + + epackage.getName()); + } else { + throw new IllegalArgumentException("Found property of type " + eclassifier.getClass().getName() + + " when an EDataType was expected."); + } + } + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/DynamicENumUserIntegerType.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/DynamicENumUserIntegerType.java new file mode 100755 index 000000000..599f23df0 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/DynamicENumUserIntegerType.java @@ -0,0 +1,87 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: DynamicENumUserIntegerType.java,v 1.6 2008/02/28 07:08:24 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; + +import org.eclipse.emf.common.util.Enumerator; +import org.hibernate.HibernateException; + +/** + * Implements the EMF UserType for an Enum in a dynamic model, for an integer field. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.6 $ $Date: 2008/02/28 07:08:24 $ + */ + +public class DynamicENumUserIntegerType extends DynamicENumUserType { + + /** The sql types used for enums */ + private static final int[] SQL_TYPES = new int[] { Types.INTEGER }; + + /** Hashmap with string to enum mappings */ + private final HashMap<Integer, Enumerator> localCache = new HashMap<Integer, Enumerator>(); + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], + * java.lang.Object) + */ + @Override + public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + final int value = rs.getInt(names[0]); + if (rs.wasNull()) { + return null; + } + + Integer objValue = new Integer(value); + Enumerator enumValue = localCache.get(objValue); + if (enumValue != null) { + return enumValue; + } + + enumValue = enumInstance.getEEnumLiteral(objValue.intValue()); + localCache.put(objValue, enumValue); + return enumValue; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, + * java.lang.Object, int) + */ + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + if (value == null) { + st.setNull(index, Types.INTEGER); + } else { + st.setInt(index, ((Enumerator) value).getValue()); + } + } + + /** An enum is stored in one varchar */ + @Override + public int[] sqlTypes() { + return SQL_TYPES; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/DynamicENumUserType.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/DynamicENumUserType.java new file mode 100755 index 000000000..b2ab68f3e --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/DynamicENumUserType.java @@ -0,0 +1,182 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: DynamicENumUserType.java,v 1.9 2009/10/15 20:35:48 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping; + +import java.io.Serializable; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; +import java.util.Properties; + +import org.eclipse.emf.common.util.Enumerator; +import org.eclipse.emf.ecore.EEnum; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.teneo.PackageRegistryProvider; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.mapper.HbMapperConstants; +import org.hibernate.HibernateException; +import org.hibernate.usertype.ParameterizedType; +import org.hibernate.usertype.UserType; + +/** + * Implements the EMF UserType for an Enum + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.9 $ $Date: 2009/10/15 20:35:48 $ + */ + +public class DynamicENumUserType implements UserType, ParameterizedType { + /** The sql types used for enums */ + private static final int[] SQL_TYPES = new int[] { Types.VARCHAR }; + + /** The enum type we are handling here */ + protected EEnum enumInstance; + + /** Hashmap with string to enum mappings */ + private final HashMap<String, Enumerator> localCache = new HashMap<String, Enumerator>(); + + private EPackage.Registry registry; + + public DynamicENumUserType() { + registry = PackageRegistryProvider.getInstance().getPackageRegistry(); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#assemble(java.io.Serializable, java.lang.Object) + */ + public Object assemble(Serializable cached, Object owner) throws HibernateException { + return cached; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object) + */ + public Object deepCopy(Object value) throws HibernateException { + return value; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#disassemble(java.lang.Object) + */ + public Serializable disassemble(Object value) throws HibernateException { + return (Serializable) value; + } + + /** Compares the int values of the enumerates */ + public boolean equals(Object x, Object y) throws HibernateException { + // todo: check compare on null values + if (x == null && y == null) { + return true; + } + + if (x == null || y == null) { + return false; + } + + if (x.getClass() != y.getClass()) { + return false; + } + return ((Enumerator) x).getValue() == ((Enumerator) y).getValue(); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#hashCode(java.lang.Object) + */ + public int hashCode(Object x) throws HibernateException { + return x.hashCode(); + } + + /** Not mutable */ + public boolean isMutable() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object) + */ + public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + final String name = rs.getString(names[0]); + if (rs.wasNull()) { + return null; + } + + Enumerator enumValue = localCache.get(name); + if (enumValue != null) { + return enumValue; + } + + enumValue = enumInstance.getEEnumLiteralByLiteral(name.trim()); + if (enumValue == null) { + throw new HbMapperException("The enum value " + name + " is not valid for enumerator: " + + enumInstance.getName()); + } + localCache.put(name, enumValue); + return enumValue; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int) + */ + public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + if (value == null) { + st.setNull(index, Types.VARCHAR); + } else { + st.setString(index, ((Enumerator) value).getName()); + } + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#replace(java.lang.Object, java.lang.Object, java.lang.Object) + */ + public Object replace(Object original, Object target, Object owner) throws HibernateException { + return original; + } + + /** Returns the parameterizezd enumType */ + public Class<?> returnedClass() { + return enumInstance.getClass(); + } + + /** An enum is stored in one varchar */ + public int[] sqlTypes() { + return SQL_TYPES; + } + + /** Sets the enumclass */ + public void setParameterValues(Properties parameters) { + final String epackUri = parameters.getProperty(HbMapperConstants.EPACKAGE_PARAM); + final String eclassifier = parameters.getProperty(HbMapperConstants.ECLASSIFIER_PARAM); + final EPackage epack = registry.getEPackage(epackUri); + enumInstance = (EEnum) epack.getEClassifier(eclassifier); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/EMFInitializeCollectionEventListener.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/EMFInitializeCollectionEventListener.java new file mode 100755 index 000000000..ddda27817 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/EMFInitializeCollectionEventListener.java @@ -0,0 +1,68 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EMFInitializeCollectionEventListener.java,v 1.3 2008/06/02 07:15:33 mtaal Exp $ + */ +package org.eclipse.emf.teneo.hibernate.mapping; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.hibernate.HibernateException; +import org.hibernate.event.InitializeCollectionEvent; +import org.hibernate.event.def.DefaultInitializeCollectionEventListener; + +/** + * Sets eDeliver to false for the owner of the collection during the initialization of the + * collection. + * + * @author <a href="mailto:mtaal@elver.org">Mike Kanaley</a> + */ +public class EMFInitializeCollectionEventListener extends DefaultInitializeCollectionEventListener implements + ExtensionPoint { + + private static final long serialVersionUID = 1L; + + /* + * (non-Javadoc) + * + * @see org.hibernate.event.def.DefaultInitializeCollectionEventListener#onInitializeCollection(org.hibernate.event.InitializeCollectionEvent) + */ + @Override + public void onInitializeCollection(InitializeCollectionEvent event) throws HibernateException { + final Object owner = event.getCollection().getOwner(); + boolean setDeliver = false; + boolean eDeliver = false; + EObject eobj = null; + if (owner instanceof EObject) { + eobj = (EObject) owner; + eDeliver = eobj.eDeliver(); + try { + // only set to false if it was true + if (eDeliver) { + eobj.eSetDeliver(false); + setDeliver = true; + } + } catch (UnsupportedOperationException e) { + // in this case the eSetDeliver was not overridden from the baseclass + // ignore + } + } + try { + super.onInitializeCollection(event); + } finally { + if (setDeliver) { + eobj.eSetDeliver(eDeliver); + } + } + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/ENumUserIntegerType.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/ENumUserIntegerType.java new file mode 100755 index 000000000..6d3bf5d80 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/ENumUserIntegerType.java @@ -0,0 +1,89 @@ +package org.eclipse.emf.teneo.hibernate.mapping; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; +import java.util.Properties; + +import org.eclipse.emf.common.util.Enumerator; +import org.eclipse.emf.teneo.classloader.ClassLoaderResolver; +import org.eclipse.emf.teneo.classloader.StoreClassLoadException; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.mapper.HbMapperConstants; +import org.hibernate.HibernateException; + +/** + * Stores a java enum + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.6 $ $Date: 2007/04/17 15:49:44 $ + */ + +public class ENumUserIntegerType extends ENumUserType { + + /** The sql types used for enums */ + private static final int[] SQL_TYPES = new int[] { Types.INTEGER }; + + /** Hashmap with string to enum mappings */ + private final HashMap<Integer, Enumerator> localCache = new HashMap<Integer, Enumerator>(); + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object) + */ + public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + final int value = rs.getInt(names[0]); + if (rs.wasNull()) + return null; + + Integer objValue = new Integer(value); + Enumerator enumValue = (Enumerator) localCache.get(objValue); + if (enumValue != null) + return enumValue; + + // call the getMethod! + try { + // use non + enumValue = (Enumerator) getMethod.invoke(null, new Object[] { objValue }); + localCache.put(objValue, enumValue); + return enumValue; + } catch (Exception e) { + throw new HbMapperException("Exception when getting enum for class: " + enumType.getName() + + " using int value: " + value, e); + } + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int) + */ + public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + if (value == null) { + st.setNull(index, Types.INTEGER); + } else { + st.setInt(index, ((Enumerator) value).getValue()); + } + } + + /** An enum is stored in one varchar */ + public int[] sqlTypes() { + return SQL_TYPES; + } + + /** Sets the enumclass */ + public void setParameterValues(Properties parameters) { + final String enumClassName = parameters.getProperty(HbMapperConstants.ENUM_CLASS_PARAM); + try { + enumType = ClassLoaderResolver.classForName(enumClassName); + getMethod = enumType.getMethod("get", new Class[] { int.class }); + } catch (StoreClassLoadException e) { + throw new HbMapperException("Enum class " + enumClassName + " can not be found", e); + } catch (NoSuchMethodException e) { + throw new HbMapperException("Get method not present in enum class " + enumClassName, e); + } + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/ENumUserType.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/ENumUserType.java new file mode 100755 index 000000000..e877be172 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/ENumUserType.java @@ -0,0 +1,196 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: ENumUserType.java,v 1.8 2008/02/28 07:08:24 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; +import java.util.Properties; + +import org.eclipse.emf.common.util.Enumerator; +import org.eclipse.emf.teneo.classloader.ClassLoaderResolver; +import org.eclipse.emf.teneo.classloader.StoreClassLoadException; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.mapper.HbMapperConstants; +import org.hibernate.HibernateException; +import org.hibernate.usertype.ParameterizedType; +import org.hibernate.usertype.UserType; + +/** + * Implements the EMF UserType for an Enum + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.8 $ $Date: 2008/02/28 07:08:24 $ + */ + +public class ENumUserType implements UserType, ParameterizedType { + + /** The sql types used for enums */ + private static final int[] SQL_TYPES = new int[] { Types.VARCHAR }; + + /** The enum type we are handling here */ + protected Class<?> enumType; + + /** The method which translates a string to an instance of the emf enum */ + protected Method getMethod; + + /** Hashmap with string to enum mappings */ + private final HashMap<String, Enumerator> localCache = new HashMap<String, Enumerator>(); + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#assemble(java.io.Serializable, java.lang.Object) + */ + public Object assemble(Serializable cached, Object owner) throws HibernateException { + return cached; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object) + */ + public Object deepCopy(Object value) throws HibernateException { + return value; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#disassemble(java.lang.Object) + */ + public Serializable disassemble(Object value) throws HibernateException { + return (Serializable) value; + } + + /** Compares the int values of the enumerates */ + public boolean equals(Object x, Object y) throws HibernateException { + // todo: check compare on null values + if (x == null && y == null) { + return true; + } + + if (x == null || y == null) { + return false; + } + + if (x.getClass() != y.getClass()) { + return false; + } + assert (x instanceof Enumerator); + return ((Enumerator) x).getValue() == ((Enumerator) y).getValue(); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#hashCode(java.lang.Object) + */ + public int hashCode(Object x) throws HibernateException { + return x.hashCode(); + } + + /** Not mutable */ + public boolean isMutable() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], + * java.lang.Object) + */ + public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + final String name = rs.getString(names[0]); + if (rs.wasNull()) { + return null; + } + + Enumerator enumValue = localCache.get(name); + if (enumValue != null) { + return enumValue; + } + + // call the getMethod! + try { + enumValue = (Enumerator) getMethod.invoke(null, new Object[] { name.trim() }); + } catch (Exception e) { + throw new HbMapperException("Exception when getting enum for class: " + enumType.getName() + + " using value: " + name, e); + } + if (enumValue == null) { + throw new HbMapperException("The enum value " + name + " is not valid for enumerator: " + + enumType.getName()); + } + + localCache.put(name, enumValue); + return enumValue; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, + * java.lang.Object, int) + */ + public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + if (value == null) { + st.setNull(index, Types.VARCHAR); + } else { + st.setString(index, ((Enumerator) value).getLiteral()); + } + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#replace(java.lang.Object, java.lang.Object, + * java.lang.Object) + */ + public Object replace(Object original, Object target, Object owner) throws HibernateException { + return original; + } + + /** Returns the parameterizezd enumType */ + public Class<?> returnedClass() { + return enumType; + } + + /** An enum is stored in one varchar */ + public int[] sqlTypes() { + return SQL_TYPES; + } + + /** Sets the enumclass */ + public void setParameterValues(Properties parameters) { + final String enumClassName = parameters.getProperty(HbMapperConstants.ENUM_CLASS_PARAM); + try { + enumType = ClassLoaderResolver.classForName(enumClassName); + getMethod = enumType.getMethod("get", new Class[] { String.class }); + } catch (StoreClassLoadException e) { + throw new HbMapperException("Enum class " + enumClassName + " can not be found", e); + } catch (NoSuchMethodException e) { + throw new HbMapperException("Get method not present in enum class " + enumClassName, e); + } + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/EcoreModelElementType.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/EcoreModelElementType.java new file mode 100644 index 000000000..2b3d22593 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/EcoreModelElementType.java @@ -0,0 +1,166 @@ +package org.eclipse.emf.teneo.hibernate.mapping; + +/** + * <copyright> + * + * Copyright (c) 2009 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 + * </copyright> + * + * $Id: EcoreModelElementType.java,v 1.5 2011/02/27 20:10:36 mtaal Exp $ + */ + +import java.io.Serializable; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Properties; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.teneo.PackageRegistryProvider; +import org.hibernate.HibernateException; +import org.hibernate.usertype.ParameterizedType; +import org.hibernate.usertype.UserType; + +/** + * Persists references to EClassifiers and EStructuralFeatures as a varchar + * field. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.5 $ $Date: 2011/02/27 20:10:36 $ + */ + +public class EcoreModelElementType implements UserType, ParameterizedType { + + private static final int[] SQL_TYPES = new int[] { Types.VARCHAR }; + private static final String SEPARATOR = "_;_"; + + private EPackage.Registry registry; + + public EcoreModelElementType() { + registry = PackageRegistryProvider.getInstance().getPackageRegistry(); + } + + public Object assemble(Serializable cached, Object owner) + throws HibernateException { + return convertFromString((String) cached); + } + + public Object deepCopy(Object value) throws HibernateException { + return value; + } + + public Serializable disassemble(Object value) throws HibernateException { + return convertToString(value); + } + + public boolean equals(Object x, Object y) throws HibernateException { + if (x == null && y == null) { + return true; + } + + if (x == null || y == null) { + return false; + } + + if (x.getClass() != y.getClass()) { + return false; + } + return x.equals(y); + } + + public int hashCode(Object x) throws HibernateException { + return x.hashCode(); + } + + public boolean isMutable() { + return false; + } + + public Object nullSafeGet(ResultSet rs, String[] names, Object owner) + throws HibernateException, SQLException { + final String value = rs.getString(names[0]); + if (rs.wasNull()) { + return null; + } + return convertFromString(value); + } + + private Object convertFromString(String value) { + final String[] values = value.split(SEPARATOR); + final String nsuri = values[0]; + final EPackage ePackage = registry.getEPackage(nsuri); + if (values.length == 1) { // EPackage + return ePackage; + } else if (values.length == 2) { // EClassifier + final String eClassifierName = values[1]; + final EClassifier eClassifier = ePackage + .getEClassifier(eClassifierName); + return eClassifier; + } else { + final String eClassifierName = values[1]; + final EClassifier eClassifier = ePackage + .getEClassifier(eClassifierName); + final EClass eClass = (EClass) eClassifier; + final String eFeatureName = values[2]; + return eClass.getEStructuralFeature(eFeatureName); + } + } + + public void nullSafeSet(PreparedStatement st, Object value, int index) + throws HibernateException, SQLException { + if (value == null) { + st.setNull(index, Types.VARCHAR); + } else { + st.setString(index, convertToString(value)); + } + } + + private String convertToString(Object value) { + if (value instanceof EPackage) { + final String uri = ((EPackage) value).getNsURI(); + return uri; + + } else if (value instanceof EClassifier) { + final EClassifier eClassifier = (EClassifier) value; + final String uri = eClassifier.getEPackage().getNsURI(); + final String eClassifierName = eClassifier.getName(); + return uri + SEPARATOR + eClassifierName; + + } else { + final EStructuralFeature feature = (EStructuralFeature) value; + final String uri = feature.getEContainingClass().getEPackage() + .getNsURI(); + final String eClassName = feature.getEContainingClass().getName(); + final String eFeatureName = feature.getName(); + return uri + SEPARATOR + eClassName + SEPARATOR + eFeatureName; + } + } + + public Object replace(Object original, Object target, Object owner) + throws HibernateException { + return original; + } + + public Class<?> returnedClass() { + return EStructuralFeature.class; + } + + public int[] sqlTypes() { + return SQL_TYPES; + } + + public void setParameterValues(Properties parameters) { + // TODO Auto-generated method stub + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/ExternalType.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/ExternalType.java new file mode 100755 index 000000000..ec0ebcde1 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/ExternalType.java @@ -0,0 +1,151 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * + * </copyright> + * + * $Id: ExternalType.java,v 1.4 2009/10/15 20:35:48 mtaal Exp $ + */ +package org.eclipse.emf.teneo.hibernate.mapping; + +import java.io.Serializable; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Properties; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.teneo.PackageRegistryProvider; +import org.eclipse.emf.teneo.hibernate.mapper.HbMapperConstants; +import org.hibernate.usertype.ParameterizedType; +import org.hibernate.usertype.UserType; + +/** + * Provides a way to store external references (references to objects not in the same datastore) as a string/uri. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + */ +public class ExternalType implements UserType, ParameterizedType { + + private static final int[] SQL_TYPES = { Types.VARCHAR }; + private EClass eClass; + + private EPackage.Registry registry; + + public int[] sqlTypes() { + return SQL_TYPES; + } + + public Class<?> returnedClass() { + return eClass.getInstanceClass(); + } + + public boolean isMutable() { + return true; + } + + public ExternalType() { + registry = PackageRegistryProvider.getInstance().getPackageRegistry(); + } + + public Object deepCopy(Object value) { + return value; + } + + public boolean equals(Object x, Object y) { + if (x == y) { + return true; + } + if (x == null || y == null) { + return false; + } + return x.equals(y); + } + + public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws SQLException { + + final String data = resultSet.getString(names[0]); + if (data == null) { + return null; + } + + // now create a new instance and set its proxyuri + final InternalEObject newValue = (InternalEObject) eClass.getEPackage().getEFactoryInstance().create(eClass); + final URI uri = URI.createURI(data); + newValue.eSetProxyURI(uri); + return newValue; + } + + public void nullSafeSet(PreparedStatement statement, Object value, int index) throws SQLException { + String pvalue = null; + if (value != null) { + final Resource res = ((InternalEObject) value).eResource(); + URI uri = res.getURI(); + final String fragment = res.getURIFragment((EObject) value); + uri = uri.appendFragment(fragment); + pvalue = uri.toString(); + } + if (pvalue != null) { + statement.setString(index, pvalue); + } else { + statement.setNull(index, Types.VARCHAR); + } + } + + public Serializable disassemble(Object value) { + return (Serializable) value; + } + + public Object assemble(Serializable cachedValue, Object owner) { + return cachedValue; + } + + public Object replace(Object original, Object target, Object owner) { + return original; + } + + public int hashCode(Object x) { + return x.hashCode(); + } + + public void setParameterValues(Properties properties) { + final String ePackageNsUri = properties.getProperty(HbMapperConstants.EPACKAGE_PARAM); + if (ePackageNsUri == null || ePackageNsUri.length() == 0) { + throw new IllegalArgumentException("Could not find custom UserType property " + + HbMapperConstants.EPACKAGE_PARAM); + } + final EPackage epackage = registry.getEPackage(ePackageNsUri); + if (epackage == null) { + throw new IllegalArgumentException("Could not find ePackage using nsuri " + ePackageNsUri); + } + final String eClassName = properties.getProperty(HbMapperConstants.ECLASS_NAME_META); + if (eClassName == null) { + throw new IllegalArgumentException("Could not find custom UserType property " + + HbMapperConstants.ECLASS_NAME_META); + } + final EClassifier eclassifier = epackage.getEClassifier(eClassName); + if (eclassifier instanceof EClass) { + eClass = (EClass) eclassifier; + } else { + if (eclassifier == null) { + throw new IllegalArgumentException("Missing eClass " + eClassName + " in package implementation " + + epackage.getName()); + } else { + throw new IllegalArgumentException("Found property of type " + eclassifier.getClass().getName() + + " when an EClass was expected."); + } + } + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/HibernatePersistentStoreAdapter.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/HibernatePersistentStoreAdapter.java new file mode 100644 index 000000000..b7e9a2c1c --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/HibernatePersistentStoreAdapter.java @@ -0,0 +1,65 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: HibernatePersistentStoreAdapter.java,v 1.1 2009/03/15 08:09:22 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.teneo.hibernate.mapping.elist.HibernateFeatureMapEntry; +import org.eclipse.emf.teneo.type.PersistentStoreAdapter; + +/** + * See superclass. + * + * This class adds translation of featuremapentries to hibernate feature map + * entries. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.1 $ + */ + +public class HibernatePersistentStoreAdapter extends PersistentStoreAdapter { + private static final long serialVersionUID = 1L; + + @Override + protected Object replaceValue(Object value, EStructuralFeature eFeature) { + if (value instanceof FeatureMap.Entry) { + final FeatureMap.Entry entry = (FeatureMap.Entry) value; + final HibernateFeatureMapEntry fme = new HibernateFeatureMapEntry(); + fme.setFeatureValue(entry.getEStructuralFeature(), + entry.getValue(), + (FeatureMap.Internal) ((EObject) getTarget()) + .eGet(eFeature)); + return fme; + } + return value; + } + + @Override + protected List<Object> replaceValues(List<Object> values, + EStructuralFeature eFeature) { + final List<Object> result = new ArrayList<Object>(); + for (Object value : values) { + result.add(replaceValue(value, eFeature)); + } + return result; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/QNameUserType.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/QNameUserType.java new file mode 100755 index 000000000..77df05b0d --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/QNameUserType.java @@ -0,0 +1,175 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: QNameUserType.java,v 1.2 2008/02/28 07:08:24 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping; + +import java.io.Serializable; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; + +import javax.xml.namespace.QName; + +import org.eclipse.emf.teneo.hibernate.HbStoreException; +import org.hibernate.HibernateException; +import org.hibernate.usertype.UserType; + +/** + * Implements the Hibernate UserType for the QName. It stores the three parts of the qname in one + * varchar. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.2 $ $Date: 2008/02/28 07:08:24 $ + */ + +public class QNameUserType implements UserType { + + private static final int[] SQL_TYPES = new int[] { Types.VARCHAR }; + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#assemble(java.io.Serializable, java.lang.Object) + */ + public Object assemble(Serializable cached, Object owner) throws HibernateException { + return cached; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object) + */ + public Object deepCopy(Object value) throws HibernateException { + return value; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#disassemble(java.lang.Object) + */ + public Serializable disassemble(Object value) throws HibernateException { + return (Serializable) value; + } + + /** Compares the int values of the enumerates */ + public boolean equals(Object x, Object y) throws HibernateException { + // todo: check compare on null values + if (x == null && y == null) { + return true; + } + + if (x == null || y == null) { + return false; + } + + if (x.getClass() != y.getClass()) { + return false; + } + + final QName q1 = (QName) x; + final QName q2 = (QName) y; + + return q1.toString().compareTo(q2.toString()) == 0; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#hashCode(java.lang.Object) + */ + public int hashCode(Object x) throws HibernateException { + return x.toString().hashCode(); + } + + /** Not mutable */ + public boolean isMutable() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], + * java.lang.Object) + */ + public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + final String str = rs.getString(names[0]); + if (rs.wasNull()) { + return null; + } + return convertFromString(str); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, + * java.lang.Object, int) + */ + public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + if (value == null) { + st.setNull(index, Types.VARCHAR); + } else { + st.setString(index, convertToString((QName) value)); + } + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.UserType#replace(java.lang.Object, java.lang.Object, + * java.lang.Object) + */ + public Object replace(Object original, Object target, Object owner) throws HibernateException { + return original; + } + + /** Returns the parameterizezd enumType */ + public Class<?> returnedClass() { + return QName.class; + } + + /** An enum is stored in one varchar */ + public int[] sqlTypes() { + return SQL_TYPES; + } + + protected String convertToString(QName qName) { + return "{" + qName.getNamespaceURI() + "}" + qName.getPrefix() + ":" + qName.getLocalPart(); + } + + protected QName convertFromString(String str) { + if (str.indexOf("{") == -1) { + throw new HbStoreException("String " + str + " can not be converted to a QName, missing starting {"); + } + final int endIndexNS = str.indexOf("}"); + if (endIndexNS == -1) { + throw new HbStoreException("String " + str + + " can not be converted to a QName, missing end ns delimiter } "); + } + final int prefixIndex = str.indexOf(":", endIndexNS); + if (prefixIndex == -1) { + throw new HbStoreException("String " + str + " can not be converted to a QName, missing prefix delimiter :"); + } + final String ns = str.substring(1, endIndexNS); + final String prefix = str.substring(endIndexNS + 1, prefixIndex); + final String localPart = str.substring(prefixIndex + 1); + return new QName(ns, localPart, prefix); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/SerializableDynamicEObjectImpl.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/SerializableDynamicEObjectImpl.java new file mode 100644 index 000000000..4747f4c44 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/SerializableDynamicEObjectImpl.java @@ -0,0 +1,122 @@ +/** + * <copyright> Copyright (c) 2005, 2006, 2007, 2008 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 </copyright> $Id: + * DynamicAction.java,v 1.4 2007/03/20 23:33:38 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.impl.DynamicEObjectImpl; + +/** + * A DynamicEObjectImpl which implements Serializable. This is required by Hibernate. + * + * TODO: probably serialization code has to be added to actually support serialization of a + * DynamicEObjectImpl. Often however Hibernate won't really serialize the object, so it might not be + * necessary for most cases. + * + * Implements Map so that Hibernate can use the MapAccessor to get to the values. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.2 $ + */ +public class SerializableDynamicEObjectImpl extends DynamicEObjectImpl implements Serializable, Map<String, Object> { + + private static final long serialVersionUID = 1L; + + public SerializableDynamicEObjectImpl(EClass eClass) { + super(eClass); + } + + public int size() { + return eClass().getEAllStructuralFeatures().size(); + } + + public boolean isEmpty() { + // an eobject is never empty + return false; + } + + public boolean containsKey(Object key) { + if (!(key instanceof String)) { + return false; + } + final String keyString = (String)key; + final EStructuralFeature eFeature = eClass().getEStructuralFeature(keyString); + if (eFeature == null) { + return false; + } + return true; + } + + public boolean containsValue(Object value) { + if (value == null) { + return false; + } + for (EStructuralFeature eFeature : eClass().getEAllStructuralFeatures()) { + final Object featureValue = eGet(eFeature); + if (featureValue != null && value.equals(featureValue)) { + return true; + } + } + return false; + } + + public Object get(Object key) { + return eGet(eClass().getEStructuralFeature((String)key)); + } + + public Object put(String key, Object value) { + final Object currentValue = eGet(eClass().getEStructuralFeature(key)); + eSet(eClass().getEStructuralFeature(key), value); + return currentValue; + } + + public Object remove(Object key) { + final Object value = get(key); + eSet(eClass().getEStructuralFeature((String)key), null); + return value; + } + + public void putAll(Map<? extends String, ? extends Object> t) { + for (String key : t.keySet()) { + put(key, t.get(key)); + } + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public Set<String> keySet() { + final HashSet<String> keySet = new HashSet<String>(); + for (EStructuralFeature eFeature : eClass().getEAllStructuralFeatures()) { + keySet.add(eFeature.getName()); + } + return keySet; + } + + public Collection<Object> values() { + final List<Object> values = new ArrayList<Object>(); + for (EStructuralFeature eFeature : eClass().getEAllStructuralFeatures()) { + values.add(eGet(eFeature)); + } + return values; + } + + public Set<java.util.Map.Entry<String, Object>> entrySet() { + throw new UnsupportedOperationException(); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/XSDDate.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/XSDDate.java new file mode 100755 index 000000000..9a506ec8a --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/XSDDate.java @@ -0,0 +1,104 @@ +/** + * <copyright> + * + * 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: + * Brian Vetter + * </copyright> + * + * $Id: XSDDate.java,v 1.2 2007/07/04 19:27:28 mtaal Exp $ + */ +package org.eclipse.emf.teneo.hibernate.mapping; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Date; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.eclipse.emf.teneo.hibernate.HbStoreException; +import org.eclipse.emf.teneo.util.EcoreDataTypes; +import org.hibernate.HibernateException; + +/** + * Implements the hibernate UserType for EMF's XMLGregorianCalendar ("date" type in XSD). + * + * @author <a href="mailto:bvetter@alterpoint.com">Brian Vetter</a> + * @version $Id + */ +public class XSDDate extends XSDDateTime { + + static final long serialVersionUID = 1; + + // local copy of the datatype facatory + private final DatatypeFactory dataTypeFactory; + + public XSDDate() { + try { + dataTypeFactory = DatatypeFactory.newInstance(); + } catch (DatatypeConfigurationException e) { + throw new HbStoreException("Exception ", e); + } + } + + /* + * Returns the DATETIME type that maps to the sql TIMESTAMP type + * + * @see org.hibernate.type.NullableType#sqlType() + */ + @Override + public int sqlType() { + return Types.DATE; + } + + /* + * returns a name for the user type + * + * @see org.hibernate.type.Type#getName() + */ + @Override + public String getName() { + return "xmldate"; + } + + /* + * Transform the date in the resultSet into a XMLGregorianCalendar instance. + * + * @see org.hibernate.type.NullableType#get(java.sql.ResultSet, java.lang.String) + */ + @Override + public Object get(ResultSet resultSet, String name) throws SQLException { + Date date = resultSet.getDate(name); + if (date == null) { + return null; + } + return EcoreDataTypes.INSTANCE.getXMLGregorianCalendar(date); + } + + /* + * Transform the XMLCalendar into a date type to store in the database + * + * @see org.hibernate.type.NullableType#set(java.sql.PreparedStatement, java.lang.Object, int) + */ + @Override + public void set(PreparedStatement statement, Object value, int index) throws SQLException { + java.sql.Date d = new java.sql.Date(((XMLGregorianCalendar) value).toGregorianCalendar().getTime().getTime()); + statement.setDate(index, d); + } + + /* + * @see org.hibernate.type.NullableType#fromStringValue(java.lang.String) + */ + @Override + public Object fromStringValue(String s) throws HibernateException { + return dataTypeFactory.newXMLGregorianCalendar(s); + } +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/XSDDateTime.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/XSDDateTime.java new file mode 100755 index 000000000..807e0c085 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/XSDDateTime.java @@ -0,0 +1,173 @@ +/** + * <copyright> + * + * 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: + * Brian Vetter + * Martin Taal + * Alexandros Karypidis (bugzilla 207799) + * </copyright> + * + * $Id: XSDDateTime.java,v 1.4 2010/11/12 09:33:33 mtaal Exp $ + */ +package org.eclipse.emf.teneo.hibernate.mapping; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.sql.Types; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.eclipse.emf.teneo.hibernate.HbStoreException; +import org.eclipse.emf.teneo.util.EcoreDataTypes; +import org.hibernate.EntityMode; +import org.hibernate.HibernateException; +import org.hibernate.type.MutableType; + +/** + * Implements the hibernate UserType for EMF's XMLGregorianCalendar ("datetime" + * type in XSD). + * + * @author <a href="mailto:bvetter@alterpoint.com">Brian Vetter</a> + * @version $Revision + */ +@SuppressWarnings("deprecation") +public class XSDDateTime extends MutableType { + + static final long serialVersionUID = 1; + + // local copy of the datatype facatory + private final DatatypeFactory dataTypeFactory; + + public XSDDateTime() { + try { + dataTypeFactory = DatatypeFactory.newInstance(); + } catch (DatatypeConfigurationException e) { + throw new HbStoreException("Exception ", e); + } + } + + /* + * Returns the DATETIME type that maps to the sql TIMESTAMP type + * + * @see org.hibernate.type.NullableType#sqlType() + */ + @Override + public int sqlType() { + return Types.TIMESTAMP; + } + + /* + * Copy the XMLGregorianCalendar object + * + * @see org.hibernate.type.MutableType#deepCopyNotNull(java.lang.Object) + */ + @Override + public Object deepCopyNotNull(Object value) { + return dataTypeFactory + .newXMLGregorianCalendar(((XMLGregorianCalendar) value) + .toGregorianCalendar()); + } + + /* + * returns a name for the user type + * + * @see org.hibernate.type.Type#getName() + */ + public String getName() { + return "xmldatetime"; + } + + /* + * This returns an XMLGregorianCalendar.class type + * + * @see org.hibernate.type.Type#getReturnedClass() + */ + public Class<?> getReturnedClass() { + return XMLGregorianCalendar.class; + } + + /* + * @see org.hibernate.type.NullableType#isEqual(java.lang.Object, + * java.lang.Object) + */ + @Override + public boolean isEqual(Object x, Object y) throws HibernateException { + if (x == y) { + return true; + } + if (x == null || y == null) { + return false; + } + if (x.getClass() != y.getClass()) { + return false; + } + return x.equals(y); + } + + /* + * @see org.hibernate.type.AbstractType#getHashCode(java.lang.Object, + * org.hibernate.EntityMode) + */ + @Override + public int getHashCode(Object x, EntityMode entityMode) + throws HibernateException { + return x.hashCode(); + } + + /* + * Transform the date in the resultSet into a XMLGregorianCalendar instance. + * + * @see org.hibernate.type.NullableType#get(java.sql.ResultSet, + * java.lang.String) + */ + @Override + public Object get(ResultSet resultSet, String name) throws SQLException { + // MT: changed this to timestamp to get the seconds right + Timestamp ts = resultSet.getTimestamp(name); + if (ts == null) { + return null; + } + return EcoreDataTypes.INSTANCE.getXMLGregorianCalendarDateTime(ts); + } + + /* + * Transform the XMLGregorianCalendar into a timestamp type to store in the + * database + * + * @see org.hibernate.type.NullableType#set(java.sql.PreparedStatement, + * java.lang.Object, int) + */ + @Override + public void set(PreparedStatement statement, Object value, int index) + throws SQLException { + Timestamp d = new Timestamp(((XMLGregorianCalendar) value) + .toGregorianCalendar().getTime().getTime()); + statement.setTimestamp(index, d); + } + + /* + * @see org.hibernate.type.NullableType#toString(java.lang.Object) + */ + @Override + public String toString(Object val) { + + return ((XMLGregorianCalendar) val).toString(); + } + + /* + * @see org.hibernate.type.NullableType#fromStringValue(java.lang.String) + */ + @Override + public Object fromStringValue(String s) throws HibernateException { + return dataTypeFactory.newXMLGregorianCalendar(s); + } +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/XSDDuration.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/XSDDuration.java new file mode 100755 index 000000000..4d131ee3c --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/XSDDuration.java @@ -0,0 +1,212 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: XSDDuration.java,v 1.5 2008/09/04 10:45:17 mtaal Exp $ + */ +package org.eclipse.emf.teneo.hibernate.mapping; + +import java.io.Serializable; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; + +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.Duration; + +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.hibernate.usertype.UserType; + +/** + * Provides a Hibernate extension (called a UserType) to support the xml Duration type. The duration + * is persisted as a string. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + */ +public class XSDDuration implements UserType { + + private static final int[] SQL_TYPES = { Types.VARCHAR }; + private final DatatypeFactory factory; + + /** + * Construct a new VARCHAR custom data type. + */ + public XSDDuration() { + try { + factory = DatatypeFactory.newInstance(); + } catch (Exception e) { + throw new HbMapperException("Exception while creating datatypefactory ", e); + } + } + + /** + * Return the types of the columns that this UserType will serialize into. + * + * @return a single column of type VARCHAR. + */ + public int[] sqlTypes() { + return SQL_TYPES; + } + + /** + * Return the Java class of the object that is serialized for the column. + * + * @return the Java instance class associated with the EMF DataType. + */ + public Class<?> returnedClass() { + return javax.xml.datatype.Duration.class; + } + + /** + * Is this datatype mutable? + * + * @return Being conservative - false always. + */ + public boolean isMutable() { + return false; + } + + /** + * Provide a copy of the datatypes. Converts to String and then back to datatype again. + * + * @param value + * the value to copy. + * @return the value always. + */ + public Object deepCopy(Object value) { + if (value == null) { + return null; + } + return factory.newDuration(((Duration) value).toString()); + } + + /** + * Are the two objects equal? + * + * @param x + * an object to compare. + * @param y + * an object to compare. + * @return a standard equals test between the objects. + */ + public boolean equals(Object x, Object y) { + if (x == y) { + return true; + } + if (x == null || y == null) { + return false; + } + return x.equals(y); + } + + /** + * Populate the model object property from the ResultSet. + * + * @param resultSet + * the non-null ResultSet from which the field will be populated. + * @param names + * the names of the columns. + * @param owner + * the owning object. + * @return null if the column's value is null; otherwise, use the EMF factory to construct a new + * instance of the custom EMF data type from the contents of the String value of the + * column. + * @throws SQLException + * if the value cannot be retrieved from the ResultSet. + */ + public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws SQLException { + + final String data = resultSet.getString(names[0]); + if (data == null) { + return null; + } + return factory.newDuration(data); + } + + /** + * Populate the database statement from the model object property. + * + * @param statement + * the non-null Statement to insert the value into. + * @param value + * the object to convert. + * @param index + * the index into the statement where to insert the converted value. + * @throws SQLException + * if the converted value cannot be set in the statement. + */ + public void nullSafeSet(PreparedStatement statement, Object value, int index) throws SQLException { + String pvalue = null; + if (value != null) { + pvalue = ((Duration) value).toString(); + } + if (pvalue != null) { + statement.setString(index, pvalue); + } else { + statement.setNull(index, Types.VARCHAR); + } + } + + /** + * No-op implementation. + * + * @param value + * the value to dissemble. + * @return the value passed in. + */ + public Serializable disassemble(Object value) { + if (value == null) { + return null; + } + return ((Duration) value).toString(); + } + + /** + * No-op implementation. + * + * @param cachedValue + * the value to assemble. + * @param owner + * the owning object. + * @return the cachedValue passed in. + */ + public Object assemble(Serializable cachedValue, Object owner) { + return cachedValue; + } + + /** + * No-op implementation. + * + * @param original + * the value to replace. + * @param target + * the target object. + * @param owner + * the owning object. + * @return the original value passed in. + */ + public Object replace(Object original, Object target, Object owner) { + return original; + } + + /** + * No-op implementation. + * + * @param x + * the object to get the hashcode for. + * @return x's hashcode. + */ + public int hashCode(Object x) { + return x.hashCode(); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/DelegatingLateLoadingList.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/DelegatingLateLoadingList.java new file mode 100644 index 000000000..71b345832 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/DelegatingLateLoadingList.java @@ -0,0 +1,205 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: DelegatingLateLoadingList.java,v 1.1 2009/09/12 05:47:13 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.util.FeatureMap; + +/** + * A list implementation which initializes its delegate when it is really called and not earlier. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + * @deprecated not used at the moment + */ +public class DelegatingLateLoadingList<E extends Object> implements List<E> { + + private List<?> persistentList = null; + private List<E> delegateList = null; + + private void initialize() { + if (delegateList != null) { + return; + } + delegateList = new ArrayList<E>(); + for (Object eavValueObj : persistentList) { + delegateList.add(getConvertedValue(eavValueObj)); + } + } + + @SuppressWarnings("unchecked") + protected E getConvertedValue(Object value) { + return (E) ((EAVValueHolder) value).getValue(); + } + + public List<?> getPersistentList() { + return persistentList; + } + + public void setPersistentList(List<?> persistentList) { + this.persistentList = persistentList; + } + + public boolean add(E e) { + initialize(); + return delegateList.add(e); + } + + public void add(int index, E element) { + initialize(); + delegateList.add(index, element); + } + + public boolean addAll(Collection<? extends E> c) { + initialize(); + return delegateList.addAll(c); + } + + public boolean addAll(int index, Collection<? extends E> c) { + initialize(); + return delegateList.addAll(index, c); + } + + public void clear() { + initialize(); + delegateList.clear(); + } + + public boolean contains(Object o) { + initialize(); + return delegateList.contains(o); + } + + public boolean containsAll(Collection<?> c) { + initialize(); + return delegateList.containsAll(c); + } + + public boolean equals(Object o) { + initialize(); + return delegateList.equals(o); + } + + public E get(int index) { + initialize(); + return delegateList.get(index); + } + + public int hashCode() { + initialize(); + return delegateList.hashCode(); + } + + public int indexOf(Object o) { + initialize(); + return delegateList.indexOf(o); + } + + public boolean isEmpty() { + initialize(); + return delegateList.isEmpty(); + } + + public Iterator<E> iterator() { + initialize(); + return delegateList.iterator(); + } + + public int lastIndexOf(Object o) { + initialize(); + return delegateList.lastIndexOf(o); + } + + public ListIterator<E> listIterator() { + initialize(); + return delegateList.listIterator(); + } + + public ListIterator<E> listIterator(int index) { + initialize(); + return delegateList.listIterator(index); + } + + public E remove(int index) { + initialize(); + return delegateList.remove(index); + } + + public boolean remove(Object o) { + initialize(); + return delegateList.remove(o); + } + + public boolean removeAll(Collection<?> c) { + initialize(); + return delegateList.removeAll(c); + } + + public boolean retainAll(Collection<?> c) { + initialize(); + return delegateList.retainAll(c); + } + + public E set(int index, E element) { + initialize(); + return delegateList.set(index, element); + } + + public int size() { + initialize(); + return delegateList.size(); + } + + public List<E> subList(int fromIndex, int toIndex) { + initialize(); + return delegateList.subList(fromIndex, toIndex); + } + + public Object[] toArray() { + initialize(); + return delegateList.toArray(); + } + + public <T> T[] toArray(T[] a) { + initialize(); + return delegateList.toArray(a); + } + + public static class FeatureMapList extends DelegatingLateLoadingList<FeatureMap.Entry> { + + private InternalEObject owner; + + protected FeatureMap.Entry getConvertedValue(Object value) { + return (FeatureMap.Entry) ((EAVValueHolder) value).get(owner); + } + + public InternalEObject getOwner() { + return owner; + } + + public void setOwner(InternalEObject owner) { + this.owner = owner; + } + + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVBlobValue.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVBlobValue.java new file mode 100644 index 000000000..61f5c1fcb --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVBlobValue.java @@ -0,0 +1,64 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVBlobValue.java,v 1.1 2009/09/11 22:52:36 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +/** + * Holds a blob value. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVBlobValue { + + private long id; + private int version; + + private byte[] blobValue; + private EAVSingleEAttributeValueHolder valueHolder; + + public EAVSingleEAttributeValueHolder getValueHolder() { + return valueHolder; + } + + public void setValueHolder(EAVSingleEAttributeValueHolder valueHolder) { + this.valueHolder = valueHolder; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public byte[] getBlobValue() { + return blobValue; + } + + public void setBlobValue(byte[] blobValue) { + this.blobValue = blobValue; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVDelegatingEMap.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVDelegatingEMap.java new file mode 100644 index 000000000..2224b5ab9 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVDelegatingEMap.java @@ -0,0 +1,593 @@ +/** + * Copyright (c) 2009 Martin Taal 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 + */ +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import org.eclipse.emf.common.notify.NotificationChain; +import org.eclipse.emf.common.util.BasicEMap; +import org.eclipse.emf.common.util.EMap; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EFactory; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.util.EcoreEMap; +import org.eclipse.emf.ecore.util.InternalEList; +import org.eclipse.emf.teneo.hibernate.LazyCollectionUtils; +import org.eclipse.emf.teneo.mapping.elist.PersistableDelegateList; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.collection.AbstractPersistentCollection; +import org.hibernate.collection.PersistentCollection; +import org.hibernate.collection.PersistentList; +import org.hibernate.engine.SessionImplementor; + +/** + * The emap which initializes itself from the persistent collection when first + * accessed. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVDelegatingEMap<K, V> implements EMap<K, V>, EAVDelegatingList, + InternalEList.Unsettable<Map.Entry<K, V>>, EStructuralFeature.Setting, + PersistableDelegateList<Map.Entry<K, V>> { + + private static final long serialVersionUID = 1L; + private List<EAVValueHolder> persistentList; + private EcoreEMap<K, V> delegatingEMap; + private EClass entryEClass; + private Class<?> entryClass; + private InternalEObject owner; + private int featureID; + private EStructuralFeature eStructuralFeature; + private EAVMultiValueHolder valueHolderOwner; + + public EAVDelegatingEMap(EClass entryEClass, Class<?> entryClass, + InternalEObject owner, int featureID) { + this.entryClass = entryClass; + this.entryEClass = entryEClass; + this.owner = owner; + this.featureID = featureID; + } + + public boolean isDelegateInitialized() { + return delegatingEMap != null; + } + + @SuppressWarnings("unchecked") + private void initialize() { + if (delegatingEMap != null) { + return; + } + delegatingEMap = new EcoreEMap<K, V>(entryEClass, entryClass, owner, + featureID); + + int index = 0; + for (Object obj : persistentList) { + EAVSingleContainmentEReferenceValueHolder valueHolder = (EAVSingleContainmentEReferenceValueHolder) obj; + valueHolder.setListIndex(index++); + valueHolder.setValueOwner(getValueHolderOwner()); + delegatingEMap.basicAdd((BasicEMap.Entry<K, V>) valueHolder + .getReferenceValue(), null); + } + // force the map to be computed, this sets the internal entrydata/size + // member + delegatingEMap.get(null); + } + + public boolean add(Entry<K, V> object) { + initialize(); + return delegatingEMap.add(object); + } + + public void add(int index, Entry<K, V> object) { + initialize(); + delegatingEMap.add(index, object); + } + + public boolean addAll(Collection<? extends Entry<K, V>> collection) { + initialize(); + return delegatingEMap.addAll(collection); + } + + public boolean addAll(int index, + Collection<? extends Entry<K, V>> collection) { + initialize(); + return delegatingEMap.addAll(index, collection); + } + + public boolean addAllUnique(Collection<? extends Entry<K, V>> collection) { + initialize(); + return delegatingEMap.addAllUnique(collection); + } + + public boolean addAllUnique(int index, + Collection<? extends Entry<K, V>> collection) { + initialize(); + return delegatingEMap.addAllUnique(index, collection); + } + + public void addUnique(Entry<K, V> object) { + initialize(); + delegatingEMap.addUnique(object); + } + + public void addUnique(int index, Entry<K, V> object) { + initialize(); + delegatingEMap.addUnique(index, object); + } + + public NotificationChain basicAdd(Entry<K, V> object, + NotificationChain notifications) { + initialize(); + return delegatingEMap.basicAdd(object, notifications); + } + + public boolean basicContains(Object object) { + initialize(); + return delegatingEMap.basicContains(object); + } + + public boolean basicContainsAll(Collection<?> collection) { + initialize(); + return delegatingEMap.basicContainsAll(collection); + } + + public org.eclipse.emf.common.util.BasicEMap.Entry<K, V> basicGet(int index) { + initialize(); + return delegatingEMap.basicGet(index); + } + + public int basicIndexOf(Object object) { + initialize(); + return delegatingEMap.basicIndexOf(object); + } + + public Iterator<Entry<K, V>> basicIterator() { + initialize(); + return delegatingEMap.basicIterator(); + } + + public int basicLastIndexOf(Object object) { + initialize(); + return delegatingEMap.basicLastIndexOf(object); + } + + public List<Entry<K, V>> basicList() { + initialize(); + return delegatingEMap.basicList(); + } + + public ListIterator<Entry<K, V>> basicListIterator() { + initialize(); + return delegatingEMap.basicListIterator(); + } + + public ListIterator<Entry<K, V>> basicListIterator(int index) { + initialize(); + return delegatingEMap.basicListIterator(index); + } + + public NotificationChain basicRemove(Object object, + NotificationChain notifications) { + initialize(); + return delegatingEMap.basicRemove(object, notifications); + } + + public Object[] basicToArray() { + initialize(); + return delegatingEMap.basicToArray(); + } + + public <T> T[] basicToArray(T[] array) { + initialize(); + return delegatingEMap.basicToArray(array); + } + + public void clear() { + initialize(); + delegatingEMap.clear(); + } + + public Object clone() { + initialize(); + return delegatingEMap.clone(); + } + + public boolean contains(Object object) { + initialize(); + return delegatingEMap.contains(object); + } + + public boolean containsAll(Collection<?> collection) { + initialize(); + return delegatingEMap.containsAll(collection); + } + + public boolean containsKey(Object key) { + initialize(); + return delegatingEMap.containsKey(key); + } + + public boolean containsValue(Object value) { + initialize(); + return delegatingEMap.containsValue(value); + } + + public Set<Entry<K, V>> entrySet() { + initialize(); + return delegatingEMap.entrySet(); + } + + public boolean equals(Object object) { + initialize(); + return delegatingEMap.equals(object); + } + + public Object get(boolean resolve) { + initialize(); + return delegatingEMap.get(resolve); + } + + public org.eclipse.emf.common.util.BasicEMap.Entry<K, V> get(int index) { + initialize(); + return delegatingEMap.get(index); + } + + @SuppressWarnings("unchecked") + public V get(Object key) { + if (isExtraLazyAndNotInitialized()) { + final AbstractPersistentCollection persistentCollection = (AbstractPersistentCollection) getDelegate(); + final SessionImplementor sessionImplementor = ((AbstractPersistentCollection) persistentCollection) + .getSession(); + final Session session = (Session)sessionImplementor; + session.flush(); + + // create a query + // the owner is a EAVMultiValueHolder which has a list of referenceValues + // each referenceValue is an EAV_Object which has a values containing + // the key and value values. The key can be a primitive or a + + final StringBuilder qryStr = new StringBuilder(); + if (((EReference)getEStructuralFeature()).isContainment()) { + qryStr.append("select singleValue from EAVSingleContainmentEReferenceValueHolder singleValue left join fetch singleValue.eavObjectReference"); + } else { + qryStr.append("select singleValue.referenceValue from EAVSingleNonContainmentEReferenceValueHolder singleValue left join fetch singleValue.eavObjectReference"); + } + final EStructuralFeature keyFeature = entryEClass.getEStructuralFeature("key"); + final Object keyParameter; + if (keyFeature instanceof EReference) { + final EReference eReference = (EReference)keyFeature; + if (eReference.isContainment()) { + qryStr.append(", EAVSingleContainmentEReferenceValueHolder keyValue where"); + } else { + qryStr.append(", EAVSingleNonContainmentEReferenceValueHolder keyValue where"); + } + + // a reference + qryStr.append(" keyValue.referenceValue=:keyParameter "); + keyParameter = key; + } else { + qryStr.append(", EAVSingleEAttributeValueHolder keyValue where"); + qryStr.append(" keyValue.typeNeutralValue=:keyParameter"); + final EAttribute eAttribute = (EAttribute)keyFeature; + final EFactory eFactory = eAttribute.getEAttributeType().getEPackage().getEFactoryInstance(); + keyParameter = eFactory.convertToString(eAttribute.getEAttributeType(), key); + } + qryStr.append( " and keyValue.feature=:feature and singleValue.eavObjectReference=keyValue.owner and singleValue.valueOwner=:owner"); + + final Query qry = session.createQuery(qryStr.toString()); + qry.setParameter("keyParameter", keyParameter); + qry.setParameter("feature", keyFeature); + qry.setParameter("owner", persistentCollection.getOwner()); + for (Object o : qry.list()) { + final EAVSingleEReferenceValueHolder valueHolder = (EAVSingleEReferenceValueHolder)o; + final Object result = valueHolder.getReferenceValue(); + if (!(result instanceof EObject)) { + continue; + } + + final EObject eContainer = ((EObject)result).eContainer(); + final EObject owner = getEObject(); + if (result instanceof Map.Entry<?, ?> && eContainer == owner) { + final Map.Entry<K, V> entry = (Map.Entry<K, V>)result; + return entry.getValue(); + } + } + return null; + } + initialize(); + return delegatingEMap.get(key); + } + + public EObject getEObject() { + return owner; + } + + public EStructuralFeature getEStructuralFeature() { + return eStructuralFeature; + } + + public int hashCode() { + initialize(); + return delegatingEMap.hashCode(); + } + + public int indexOf(Object object) { + initialize(); + return delegatingEMap.indexOf(object); + } + + public int indexOfKey(Object key) { + initialize(); + return delegatingEMap.indexOfKey(key); + } + + public boolean isEmpty() { + return size() == 0; + } + + public boolean isSet() { + return !isEmpty(); + } + + public Iterator<Entry<K, V>> iterator() { + if (isExtraLazyAndNotInitialized()) { + // return a paging iterator + return LazyCollectionUtils.getPagedLoadingIterator(this, + LazyCollectionUtils.DEFAULT_PAGE_SIZE); + } + initialize(); + return delegatingEMap.iterator(); + } + + public Set<K> keySet() { + initialize(); + return delegatingEMap.keySet(); + } + + public int lastIndexOf(Object object) { + initialize(); + return delegatingEMap.lastIndexOf(object); + } + + public ListIterator<Entry<K, V>> listIterator() { + initialize(); + return delegatingEMap.listIterator(); + } + + public ListIterator<Entry<K, V>> listIterator(int index) { + initialize(); + return delegatingEMap.listIterator(index); + } + + public Map<K, V> map() { + initialize(); + return delegatingEMap.map(); + } + + public void move(int index, Entry<K, V> object) { + initialize(); + delegatingEMap.move(index, object); + } + + public Entry<K, V> move(int targetIndex, int sourceIndex) { + initialize(); + return delegatingEMap.move(targetIndex, sourceIndex); + } + + @SuppressWarnings("unchecked") + public V put(K key, V value) { + if (isExtraLazyAndNotInitialized()) { + final Map.Entry<K, V> entry = (Map.Entry<K, V>) get(key); + if (entry != null + && entry instanceof org.eclipse.emf.common.util.BasicEMap.Entry<?, ?>) { + final V result = entry.getValue(); + entry.setValue(value); + return result; + } else { + final EAVValueHolder valueHolder = (EAVValueHolder) getValueHolderOwner() + .getElement(newEntry(key, value)); + valueHolder.setListIndex(getPersistentList().size()); + getPersistentList().add(valueHolder); + return null; + } + } else { + initialize(); + return delegatingEMap.put(key, value); + } + } + + public void putAll(EMap<? extends K, ? extends V> map) { + for (Map.Entry<? extends K, ? extends V> entry : map) { + put(entry.getKey(), entry.getValue()); + } + } + + public void putAll(Map<? extends K, ? extends V> map) { + for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + public Entry<K, V> remove(int index) { + initialize(); + return delegatingEMap.remove(index); + } + + public boolean remove(Object object) { + initialize(); + return delegatingEMap.remove(object); + } + + public boolean removeAll(Collection<?> collection) { + initialize(); + return delegatingEMap.removeAll(collection); + } + + public V removeKey(Object key) { + initialize(); + return delegatingEMap.removeKey(key); + } + + public boolean retainAll(Collection<?> collection) { + initialize(); + return delegatingEMap.retainAll(collection); + } + + public Entry<K, V> set(int index, Entry<K, V> object) { + initialize(); + return delegatingEMap.set(index, object); + } + + public void set(Object value) { + initialize(); + delegatingEMap.set(value); + } + + public Entry<K, V> setUnique(int index, Entry<K, V> object) { + initialize(); + return delegatingEMap.setUnique(index, object); + } + + public int size() { + if (isInitialized()) { + return delegatingEMap.size(); + } + return persistentList.size(); + } + + public List<Entry<K, V>> subList(int start, int end) { + initialize(); + return delegatingEMap.subList(start, end); + } + + public Object[] toArray() { + initialize(); + return delegatingEMap.toArray(); + } + + public <T> T[] toArray(T[] array) { + initialize(); + return delegatingEMap.toArray(array); + } + + public String toString() { + initialize(); + return delegatingEMap.toString(); + } + + public void unset() { + initialize(); + delegatingEMap.unset(); + } + + public Collection<V> values() { + initialize(); + return delegatingEMap.values(); + } + + public List<EAVValueHolder> getPersistentList() { + return persistentList; + } + + @SuppressWarnings("unchecked") + public void setPersistentList(List<?> persistentList) { + this.persistentList = (List<EAVValueHolder>) persistentList; + if (isHibernateListPresent() && getHibernatePersistentList().wasInitialized()) { + initialize(); + } if (persistentList instanceof ArrayList<?>) { + // newly persisted + initialize(); + } + } + + public Object getDelegate() { + return persistentList; + } + + public boolean isInitialized() { + return delegatingEMap != null; + } + + public boolean isLoaded() { + return delegatingEMap != null; + } + + public void setEStructuralFeature(EStructuralFeature eStructuralFeature) { + this.eStructuralFeature = eStructuralFeature; + } + + private boolean isHibernateListPresent() { + return (persistentList instanceof AbstractPersistentCollection); + } + + private EAVMultiValueHolder getValueHolderOwner() { + return valueHolderOwner; + } + + private PersistentList getHibernatePersistentList() { + return (PersistentList) persistentList; + } + + protected final boolean isConnectedToSession() { + if (!(getDelegate() instanceof AbstractPersistentCollection)) { + return false; + } + final AbstractPersistentCollection persistentCollection = (AbstractPersistentCollection) getDelegate(); + final SessionImplementor session = ((AbstractPersistentCollection) persistentCollection) + .getSession(); + return isConnectedToSession(session); + } + + private final boolean isConnectedToSession(SessionImplementor session) { + final PersistentCollection persistentCollection = (PersistentCollection) getDelegate(); + return session != null + && session.isOpen() + && session.getPersistenceContext().containsCollection( + persistentCollection); + } + + private boolean isExtraLazyAndNotInitialized() { + if (!isInitialized() && isHibernateListPresent() + && isConnectedToSession()) { + boolean extraLazyLoaded = getValueHolderOwner() instanceof EAVExtraMultiContainmentEReferenceValueHolder; + extraLazyLoaded |= getValueHolderOwner() instanceof EAVExtraMultiNonContainmentEReferenceValueHolder; + extraLazyLoaded |= getValueHolderOwner() instanceof EAVExtraMultiEAttributeValueHolder; + return extraLazyLoaded; + } + return false; + } + + protected org.eclipse.emf.common.util.BasicEMap.Entry<K, V> newEntry(K key, V value) { + @SuppressWarnings("unchecked") + org.eclipse.emf.common.util.BasicEMap.Entry<K, V> entry = (org.eclipse.emf.common.util.BasicEMap.Entry<K, V>) entryEClass.getEPackage() + .getEFactoryInstance().create(entryEClass); + entry.setHash(key.hashCode()); + entry.setKey(key); + entry.setValue(value); + return entry; + } + + public void setValueHolderOwner(EAVMultiValueHolder valueHolderOwner) { + this.valueHolderOwner = valueHolderOwner; + } +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVDelegatingEcoreEList.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVDelegatingEcoreEList.java new file mode 100644 index 000000000..9772195c9 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVDelegatingEcoreEList.java @@ -0,0 +1,388 @@ +/** + * Copyright (c) 2009 Martin Taal 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 + */ +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.util.DelegatingEcoreEList; +import org.eclipse.emf.teneo.hibernate.LazyCollectionUtils; +import org.eclipse.emf.teneo.mapping.elist.PersistableDelegateList; +import org.hibernate.collection.AbstractPersistentCollection; +import org.hibernate.collection.PersistentCollection; +import org.hibernate.collection.PersistentList; +import org.hibernate.engine.SessionImplementor; + +/** + * The list used in instances mapped using the EAV schema. The persistentList is + * the Hibernate list present as the referenceValues in the + * EAVMulti*ContainmentEReferenceValueHolder. + */ +public class EAVDelegatingEcoreEList<E> extends DelegatingEcoreEList<E> + implements EAVDelegatingList, PersistableDelegateList<E> { + + private static final long serialVersionUID = 1L; + private EStructuralFeature eStructuralFeature; + private List<E> delegate; + private List<EAVValueHolder> persistentList; + private EAVMultiValueHolder valueHolderOwner; + + public EAVDelegatingEcoreEList(InternalEObject owner) { + super(owner); + } + + protected void initialize() { + if (isDelegateInitialized()) { + return; + } + doInitialize(); + } + + public boolean isDelegateInitialized() { + return delegate != null; + } + + protected void doInitialize() { + delegate = new ArrayList<E>(); + int index = 0; + for (Object eavValueObj : persistentList) { + final EAVValueHolder eavValueHolder = (EAVValueHolder) eavValueObj; + eavValueHolder.setListIndex(index++); + eavValueHolder.setValueOwner(getValueHolderOwner()); + delegate.add(getConvertedValue(eavValueObj)); + } + } + + @SuppressWarnings("unchecked") + protected E getConvertedValue(Object value) { + return (E) ((EAVValueHolder) value).getValue(); + } + + @Override + protected List<E> delegateList() { + initialize(); + return delegate; + } + + public List<?> getDelegate() { + return persistentList; + } + + public void setDelegate(List<E> delegate) { + this.delegate = delegate; + } + + public EStructuralFeature getEStructuralFeature() { + return eStructuralFeature; + } + + public void setEStructuralFeature(EStructuralFeature eStructuralFeature) { + this.eStructuralFeature = eStructuralFeature; + } + + public List<EAVValueHolder> getPersistentList() { + return persistentList; + } + + @SuppressWarnings("unchecked") + public void setPersistentList(List<?> persistentList) { + this.persistentList = (List<EAVValueHolder>) persistentList; + if (isHibernateListPresent() + && getHibernatePersistentList().wasInitialized()) { + doInitialize(); + } else if (persistentList instanceof ArrayList<?>) { + // newly persisted + doInitialize(); + } + } + + public boolean isInitialized() { + return isDelegateInitialized(); + } + + public boolean isLoaded() { + return isDelegateInitialized(); + } + + @Override + /** + * Will always return false, means that the unique check is not performed + * for the eav list. This is a small price to pay for increased performance. + */ + public boolean isUnique() { + return false; + } + + private boolean isHibernateListPresent() { + return (persistentList instanceof AbstractPersistentCollection); + } + + private PersistentList getHibernatePersistentList() { + return (PersistentList) persistentList; + } + + protected final boolean isConnectedToSession() { + if (!(getDelegate() instanceof AbstractPersistentCollection)) { + return false; + } + final AbstractPersistentCollection persistentCollection = (AbstractPersistentCollection) getDelegate(); + final SessionImplementor session = ((AbstractPersistentCollection) persistentCollection) + .getSession(); + return isConnectedToSession(session); + } + + private final boolean isConnectedToSession(SessionImplementor session) { + final PersistentCollection persistentCollection = (PersistentCollection) getDelegate(); + return session != null + && session.isOpen() + && session.getPersistenceContext().containsCollection( + persistentCollection); + } + + @Override + protected void delegateAdd(E object) { + final EAVValueHolder valueHolder = (EAVValueHolder) getValueHolderOwner() + .getElement(object); + valueHolder.setListIndex(getHibernatePersistentList().size()); + persistentList.add(valueHolder); + + if (isDelegateInitialized()) { + super.delegateAdd(object); + } + } + + @Override + protected void delegateAdd(int index, E object) { + if (index == size() && !isDelegateInitialized()) { + delegateAdd(object); + // stop here as the delegate is not yet set + return; + } + + // insert in the middle, load the whole list + delegateList(); + + final EAVValueHolder valueHolder = (EAVValueHolder) getValueHolderOwner() + .getElement(object); + + persistentList.add(index, valueHolder); + + int newIndex = index; + // note, can not use the size() call, must do persistentList.size() + for (EAVValueHolder element : persistentList.subList(index, + persistentList.size())) { + element.setListIndex(newIndex++); + } + + super.delegateAdd(index, object); + } + + @Override + protected List<E> delegateBasicList() { + return super.delegateBasicList(); + } + + @Override + protected void delegateClear() { + for (EAVValueHolder valueHolder : persistentList) { + valueHolder.setOwner(null); + valueHolder.setValueOwner(null); + } + + super.delegateClear(); + } + + @Override + protected boolean delegateContains(Object object) { + // TODO: consider building a query to support lazy contains + return super.delegateContains(object); + } + + @Override + protected boolean delegateContainsAll(Collection<?> collection) { + // will read the persistent list anyway + return super.delegateContainsAll(collection); + } + + @Override + protected boolean delegateEquals(Object object) { + // will read the persistent list anyway + return super.delegateEquals(object); + } + + @SuppressWarnings("unchecked") + @Override + protected E delegateGet(int index) { + final EAVValueHolder valueHolder = persistentList.get(index); + return (E) valueHolder.getValue(); + } + + @Override + protected int delegateHashCode() { + // hashcode will read the persistentlist always anyway + return super.delegateHashCode(); + } + + @Override + protected int delegateIndexOf(Object object) { + // indexof will read the persistentlist always anyway + return super.delegateIndexOf(object); + } + + @Override + protected boolean delegateIsEmpty() { + return delegateSize() == 0; + } + + @Override + public Iterator<E> delegateIterator() { + return iterator(); + } + + @Override + public Iterator<E> iterator() { + if (!isDelegateInitialized() && isHibernateListPresent() + && isConnectedToSession()) { + boolean extraLazyLoaded = getValueHolderOwner() instanceof EAVExtraMultiContainmentEReferenceValueHolder; + extraLazyLoaded |= getValueHolderOwner() instanceof EAVExtraMultiNonContainmentEReferenceValueHolder; + extraLazyLoaded |= getValueHolderOwner() instanceof EAVExtraMultiEAttributeValueHolder; + if (extraLazyLoaded) { + // return a paging iterator + return LazyCollectionUtils.getPagedLoadingIterator(this, + LazyCollectionUtils.DEFAULT_PAGE_SIZE); + } + } + return super.iterator(); + } + + @Override + protected int delegateLastIndexOf(Object object) { + // will read the persistentlist always anyway + return super.delegateLastIndexOf(object); + } + + @Override + protected ListIterator<E> delegateListIterator() { + // will read the persistentlist always anyway + return super.delegateListIterator(); + } + + @Override + protected E delegateMove(int targetIndex, int sourceIndex) { + final EAVValueHolder result = persistentList.remove(sourceIndex); + + int newIndex = sourceIndex; + for (EAVValueHolder element : persistentList.subList(sourceIndex, + size())) { + element.setListIndex(newIndex++); + } + + persistentList.add(targetIndex, result); + + newIndex = targetIndex; + for (EAVValueHolder element : persistentList.subList(sourceIndex, + size())) { + element.setListIndex(newIndex++); + } + return super.delegateMove(targetIndex, sourceIndex); + } + + @Override + @SuppressWarnings("unchecked") + protected E delegateRemove(int index) { + final boolean reallyLazy = index == (size() - 1) + && !isDelegateInitialized(); + if (!reallyLazy) { + // force a load before removing + delegateList(); + } + final EAVValueHolder result = persistentList.remove(index); + result.setOwner(null); + result.setValueOwner(null); + + if (reallyLazy) { + // no need to update other things + return (E) result.getValue(); + } + + int newIndex = index; + // must use persistentList.size() as the delegate size has not yet been + // updated! + for (EAVValueHolder element : persistentList.subList(index, + persistentList.size())) { + element.setListIndex(newIndex++); + } + return super.delegateRemove(index); + } + + @SuppressWarnings("unchecked") + @Override + protected E delegateSet(int index, E object) { + final EAVValueHolder newValueHolder = (EAVValueHolder) getValueHolderOwner() + .getElement(object); + newValueHolder.setListIndex(index); + final EAVValueHolder oldValueHolder = persistentList.set(index, + newValueHolder); + + // clear old object + if (oldValueHolder != null) { + oldValueHolder.setOwner(null); + oldValueHolder.setValueOwner(null); + } + if (isDelegateInitialized()) { + return super.delegateSet(index, object); + } + if (oldValueHolder != null) { + return (E) oldValueHolder.getValue(); + } + return null; + } + + @Override + protected int delegateSize() { + if (!isDelegateInitialized()) { + return persistentList.size(); + } + return delegate.size(); + } + + @Override + protected Object[] delegateToArray() { + // will load list anyway + return super.delegateToArray(); + } + + @Override + protected <T> T[] delegateToArray(T[] array) { + // will load list anyway + return super.delegateToArray(array); + } + + @Override + protected String delegateToString() { + // will load list anyway + return super.delegateToString(); + } + + public void setValueHolderOwner(EAVMultiValueHolder valueHolderOwner) { + this.valueHolderOwner = valueHolderOwner; + } + + private EAVMultiValueHolder getValueHolderOwner() { + return valueHolderOwner; + } + +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVDelegatingFeatureMap.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVDelegatingFeatureMap.java new file mode 100644 index 000000000..3a3332e83 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVDelegatingFeatureMap.java @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2009 Martin Taal 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 + */ +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.util.DelegatingFeatureMap; +import org.eclipse.emf.ecore.util.FeatureMap; + +/** + * The list used in instances mapped using the EAV schema. + */ +public class EAVDelegatingFeatureMap extends DelegatingFeatureMap implements EAVDelegatingList { + + private static final long serialVersionUID = 1L; + private List<FeatureMap.Entry> delegate; + private List<?> persistentList; + + public EAVDelegatingFeatureMap(InternalEObject owner, EStructuralFeature eFeature) { + super(owner, eFeature); + } + + private void initialize() { + if (delegate != null) { + return; + } + delegate = new ArrayList<FeatureMap.Entry>(); + for (Object eavValueObj : persistentList) { + delegate.add((FeatureMap.Entry) ((EAVValueHolder) eavValueObj).get(owner)); + } + } + + public boolean isDelegateInitialized() { + return delegate != null; + } + + @Override + protected List<FeatureMap.Entry> delegateList() { + initialize(); + return delegate; + } + + public List<FeatureMap.Entry> getDelegate() { + initialize(); + return delegate; + } + + public void setDelegate(List<FeatureMap.Entry> delegate) { + this.delegate = delegate; + } + + public List<?> getPersistentList() { + return persistentList; + } + + public void setPersistentList(List<?> persistentList) { + this.persistentList = persistentList; + } +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVDelegatingList.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVDelegatingList.java new file mode 100644 index 000000000..0056a98d4 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVDelegatingList.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2009 Martin Taal 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 + */ +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.util.List; + +/** + * Tags EAV list and featuremap. + */ +public interface EAVDelegatingList { + boolean isDelegateInitialized(); + + void setPersistentList(List<?> persistentList); +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVExtraMultiContainmentEReferenceValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVExtraMultiContainmentEReferenceValueHolder.java new file mode 100644 index 000000000..4cd260c69 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVExtraMultiContainmentEReferenceValueHolder.java @@ -0,0 +1,27 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVExtraMultiContainmentEReferenceValueHolder.java,v 1.1 2010/04/02 15:24:11 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + + +/** + * Variant of super class which loads all lists extra-lazily. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVExtraMultiContainmentEReferenceValueHolder extends EAVMultiContainmentEReferenceValueHolder { +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVExtraMultiEAttributeValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVExtraMultiEAttributeValueHolder.java new file mode 100644 index 000000000..7f397cc7b --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVExtraMultiEAttributeValueHolder.java @@ -0,0 +1,27 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVExtraMultiEAttributeValueHolder.java,v 1.1 2010/04/02 15:24:12 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + + +/** + * Variant of super class which loads all lists extra-lazily. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVExtraMultiEAttributeValueHolder extends EAVMultiEAttributeValueHolder { +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVExtraMultiNonContainmentEReferenceValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVExtraMultiNonContainmentEReferenceValueHolder.java new file mode 100644 index 000000000..f9c55d73e --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVExtraMultiNonContainmentEReferenceValueHolder.java @@ -0,0 +1,27 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVExtraMultiNonContainmentEReferenceValueHolder.java,v 1.1 2010/04/02 15:24:11 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + + +/** + * Variant of super class which loads all lists extra-lazily. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVExtraMultiNonContainmentEReferenceValueHolder extends EAVMultiNonContainmentEReferenceValueHolder { +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVFeatureMapEntryValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVFeatureMapEntryValueHolder.java new file mode 100644 index 000000000..599a9588c --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVFeatureMapEntryValueHolder.java @@ -0,0 +1,106 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVFeatureMapEntryValueHolder.java,v 1.3 2009/08/22 00:09:57 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.impl.EStructuralFeatureImpl; +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.ecore.util.FeatureMapUtil; + +/** + * This class holds a feature map entry which can have a primitive value or an eReference .* + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVFeatureMapEntryValueHolder extends EAVSingleEAttributeValueHolder { + + private EObject referenceValue; + private EObject containedReferenceValue; + private boolean isEReference; + private boolean isContainment; + + private FeatureMap.Entry featureMapEntry; + + public void set(Object value) { + + setMandatoryValue(null); + + ; + final FeatureMap.Entry entry = (FeatureMap.Entry) value; + featureMapEntry = entry; + if (entry.getValue() != null) { + setMandatoryValue(NOT_NULL_VALUE); + } + setEStructuralFeature(entry.getEStructuralFeature()); + if (isEReference) { + referenceValue = (EObject) entry.getValue(); + if (isContainment) { + containedReferenceValue = (EObject) entry.getValue(); + } + } else { + super.set(entry.getValue()); + } + } + + public FeatureMap.Entry get(InternalEObject owner) { + if (featureMapEntry != null) { + return featureMapEntry; + } + + featureMapEntry = ((EStructuralFeatureImpl) getEStructuralFeature()).getFeatureMapEntryPrototype(); + if (isEReference) { + featureMapEntry = FeatureMapUtil.createEntry(getEStructuralFeature(), referenceValue); + } else { + featureMapEntry = FeatureMapUtil.createEntry(getEStructuralFeature(), super.get(owner)); + } + return featureMapEntry; + } + + public void setValueInOwner(InternalEObject owner) { + throw new UnsupportedOperationException("This method should not be called"); + } + + public EObject getReferenceValue() { + return referenceValue; + } + + public void setReferenceValue(EObject referenceValue) { + this.referenceValue = referenceValue; + } + + @Override + public void setEStructuralFeature(EStructuralFeature eStructuralFeature) { + super.setEStructuralFeature(eStructuralFeature); + isEReference = eStructuralFeature instanceof EReference; + if (isEReference) { + isContainment = ((EReference) eStructuralFeature).isContainment(); + } + } + + public EObject getContainedReferenceValue() { + return containedReferenceValue; + } + + public void setContainedReferenceValue(EObject containedReferenceValue) { + this.containedReferenceValue = containedReferenceValue; + } + +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVFeatureMapValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVFeatureMapValueHolder.java new file mode 100755 index 000000000..60eb6aee4 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVFeatureMapValueHolder.java @@ -0,0 +1,73 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVFeatureMapValueHolder.java,v 1.5 2010/04/02 15:24:11 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.ecore.InternalEObject; + +/** + * This class holds a multi (ismany) EAttribute value. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVFeatureMapValueHolder extends EAVMultiValueHolder { + + private List<EAVFeatureMapEntryValueHolder> values; + + public void set(Object value) { + setMandatoryValue(null); + final List<?> listValues = (List<?>) value; + values = new ArrayList<EAVFeatureMapEntryValueHolder>(); + for (Object o : listValues) { + values.add((EAVFeatureMapEntryValueHolder) getElement(o)); + setMandatoryValue(NOT_NULL_VALUE); + } + } + + public Object getValue() { + return getValues(); + } + + public Object getElement(Object value) { + final EAVFeatureMapEntryValueHolder valueHolder = new EAVFeatureMapEntryValueHolder(); + valueHolder.setOwner(getOwner()); + valueHolder.setHbDataStore(getHbDataStore()); + valueHolder.set(value); + return valueHolder; + } + + public Object get(InternalEObject owner) { + final EAVDelegatingFeatureMap featureMap = new EAVDelegatingFeatureMap((InternalEObject) owner, + getEStructuralFeature()); + // final DelegatingLateLoadingList.FeatureMapList objValues = new DelegatingLateLoadingList.FeatureMapList(); + // objValues.setOwner(owner); + // objValues.setPersistentList(values); + featureMap.setPersistentList(values); + return featureMap; + } + + public List<EAVFeatureMapEntryValueHolder> getValues() { + return values; + } + + public void setValues(List<EAVFeatureMapEntryValueHolder> values) { + this.values = values; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVGenericIDUserType.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVGenericIDUserType.java new file mode 100644 index 000000000..461c291a7 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVGenericIDUserType.java @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2004 - 2009 Martin Taal 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 + * Eike Stepper - maintenance + */ +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; + +import org.hibernate.type.StandardBasicTypes; +import org.hibernate.usertype.UserType; + +/** + * Is used in a many-to-any to support any type of id. + */ +public class EAVGenericIDUserType implements UserType { + private static final int[] SQL_TYPES = { Types.VARCHAR }; + + private static final String SEPARATOR = "__;__"; + + /** Constructor by id */ + private final HashMap<String, Constructor<?>> constructors = new HashMap<String, Constructor<?>>(); + + public EAVGenericIDUserType() { + } + + public int[] sqlTypes() { + return SQL_TYPES; + } + + public Class<?> returnedClass() { + return Object.class; + } + + public boolean isMutable() { + return false; + } + + public Object deepCopy(Object value) { + return value; + } + + public boolean equals(Object x, Object y) { + if (x == y) { + return true; + } + + if (x == null || y == null) { + return false; + } + + return x.equals(y); + } + + public Object nullSafeGet(ResultSet rs, String[] names, Object owner) + throws SQLException { + final String value = (String) StandardBasicTypes.STRING.nullSafeGet(rs, + names[0]); + if (rs.wasNull()) { + return null; + } + + final int end1 = value.indexOf(SEPARATOR); + final int start2 = end1 + SEPARATOR.length(); + + final String idStr = value.substring(0, end1); + final String idClassName = value.substring(start2); + final Serializable id = getId(idStr, idClassName); + return id; + } + + public void nullSafeSet(PreparedStatement statement, Object value, int index) + throws SQLException { + if (value == null) { + statement.setNull(index, Types.VARCHAR); + } else { + statement.setString(index, value.toString() + SEPARATOR + + value.getClass().getName()); + } + } + + public Serializable disassemble(Object value) { + return (Serializable) value; + } + + public Object assemble(Serializable cachedValue, Object owner) { + return cachedValue; + } + + public Object replace(Object original, Object target, Object owner) { + return original; + } + + public int hashCode(Object x) { + return x.hashCode(); + } + + /** Creates an id object of the correct type */ + private Serializable getId(String idStr, String idType) { + try { + Constructor<?> constructor = constructors.get(idType); + if (constructor == null) { + Class<?> idClass = this.getClass().getClassLoader() + .loadClass(idType); + constructor = idClass + .getConstructor(new Class[] { String.class }); + constructors.put(idType, constructor); + } + + return (Serializable) constructor + .newInstance(new Object[] { idStr }); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVInstantiator.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVInstantiator.java new file mode 100755 index 000000000..bcc7e8728 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVInstantiator.java @@ -0,0 +1,59 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EAVInstantiator.java,v 1.1 2009/08/21 10:16:36 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.io.Serializable; + +import org.eclipse.emf.ecore.EObject; +import org.hibernate.tuple.Instantiator; + +/** + * Instantiator for the EAV_EObject root. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.1 $ + */ + +public class EAVInstantiator implements Instantiator { + + /** + * Generated Serial Version ID + */ + private static final long serialVersionUID = 6946442685247491904L; + + /** Constructor */ + public EAVInstantiator() { + } + + /** Instantiates using EcoreUtil.create() */ + public Object instantiate() { + throw new UnsupportedOperationException(); + } + + /** Instantiates using EcoreUtil.create() */ + public Object instantiate(Serializable id) { + throw new UnsupportedOperationException(); + } + + /** Checks using the mapped class or the proxy interface */ + public boolean isInstance(Object object) { + if (object instanceof EObject) { + return true; + } + return false; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVMultiContainmentEReferenceValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVMultiContainmentEReferenceValueHolder.java new file mode 100644 index 000000000..e4b598adc --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVMultiContainmentEReferenceValueHolder.java @@ -0,0 +1,124 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVMultiContainmentEReferenceValueHolder.java,v 1.11 2010/04/05 05:33:31 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.common.util.BasicEMap; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.teneo.util.StoreUtil; + +/** + * Stores a multi containment EReference value. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVMultiContainmentEReferenceValueHolder extends + EAVMultiValueHolder { + + private List<EAVSingleContainmentEReferenceValueHolder> referenceValues; + private EAVDelegatingList ecoreObjectList = null; + + @SuppressWarnings("unchecked") + public void set(Object value) { + // set to null first, if there is at least one value then it is set to a + // value + setMandatoryValue(null); + final List<?> values = (List<Object>) value; + referenceValues = new ArrayList<EAVSingleContainmentEReferenceValueHolder>(); + int index = 0; + for (Object o : values) { + final EAVSingleContainmentEReferenceValueHolder eavValue = (EAVSingleContainmentEReferenceValueHolder) getElement(o); + eavValue.setVirtualListIndex(index++); + referenceValues.add(eavValue); + setMandatoryValue(NOT_NULL_VALUE); + } + } + + public Object getElement(Object value) { + EAVSingleContainmentEReferenceValueHolder valueHolder = new EAVSingleContainmentEReferenceValueHolder(); + valueHolder.setEStructuralFeature(getEStructuralFeature()); + valueHolder.setHbDataStore(getHbDataStore()); + valueHolder.setOwner(getOwner()); + valueHolder.setValueOwner(this); + valueHolder.set(value); + return valueHolder; + } + + public Object get(InternalEObject owner) { + if (ecoreObjectList != null) { + return ecoreObjectList; + } + setEcoreObjectList(); + return ecoreObjectList; + } + + private void setEcoreObjectList() { + if (StoreUtil.isMap(getEStructuralFeature())) { + final EClass entryEClass = (EClass) getEStructuralFeature() + .getEType(); + Class<?> entryClass = entryEClass.getInstanceClass(); + // prevents a failing assertion in the EcoreEMap + if (entryClass == null + || !BasicEMap.Entry.class.isAssignableFrom(entryClass)) { + entryClass = BasicEMap.Entry.class; + } + + final int featureID = getOwner().eClass().getFeatureID( + getEStructuralFeature()); + final EAVDelegatingEMap<Object, Object> eMap = new EAVDelegatingEMap<Object, Object>( + entryEClass, entryClass, (InternalEObject) getOwner(), + featureID); + eMap.setValueHolderOwner(this); + ecoreObjectList = eMap; + eMap.setEStructuralFeature(getEStructuralFeature()); + eMap.setPersistentList(referenceValues); + } else { + // final DelegatingLateLoadingList<Object> lateLoadingList = new + // DelegatingLateLoadingList<Object>(); + // lateLoadingList.setPersistentList((List<?>) referenceValues); + final EAVDelegatingEcoreEList<Object> ecoreList = new EAVDelegatingEcoreEList<Object>( + (InternalEObject) getOwner()); + ecoreList.setValueHolderOwner(this); + ecoreList.setEStructuralFeature(getEStructuralFeature()); + ecoreList.setPersistentList(referenceValues); + ecoreObjectList = ecoreList; + } + + } + + public Object getValue() { + return referenceValues; + } + + public List<EAVSingleContainmentEReferenceValueHolder> getReferenceValues() { + return referenceValues; + } + + public void setReferenceValues( + List<EAVSingleContainmentEReferenceValueHolder> referenceValues) { + this.referenceValues = referenceValues; + if (ecoreObjectList == null) { + setEcoreObjectList(); + } else { + ecoreObjectList.setPersistentList(referenceValues); + } + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVMultiEAttributeValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVMultiEAttributeValueHolder.java new file mode 100644 index 000000000..6073060a0 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVMultiEAttributeValueHolder.java @@ -0,0 +1,83 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVMultiEAttributeValueHolder.java,v 1.5 2010/04/05 05:33:32 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.ecore.InternalEObject; + +/** + * This class holds a multi (ismany) EAttribute value. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVMultiEAttributeValueHolder extends EAVMultiValueHolder { + + private List<EAVSingleEAttributeValueHolder> values; + private EAVDelegatingList ecoreObjectList = null; + + public void set(Object value) { + // set to null first, if there is at least one value then it is set to a value + setMandatoryValue(null); + final List<?> listValues = (List<?>) value; + values = new ArrayList<EAVSingleEAttributeValueHolder>(); + int index = 0; + for (Object o : listValues) { + final EAVSingleEAttributeValueHolder eavValue = (EAVSingleEAttributeValueHolder) getElement(o); + eavValue.setListIndex(index++); + values.add(eavValue); + setMandatoryValue(NOT_NULL_VALUE); + } + } + + public Object getValue() { + return values; + } + + public Object getElement(Object value) { + final EAVSingleEAttributeValueHolder valueHolder = new EAVSingleEAttributeValueHolder(); + valueHolder.setEStructuralFeature(getEStructuralFeature()); + valueHolder.setHbDataStore(getHbDataStore()); + valueHolder.setOwner(getOwner()); + valueHolder.setValueOwner(this); + valueHolder.set(value); + return valueHolder; + } + + public Object get(InternalEObject owner) { + if (ecoreObjectList != null) { + return ecoreObjectList; + } + final EAVDelegatingEcoreEList<Object> ecoreList = new EAVDelegatingEcoreEList<Object>((InternalEObject) owner); + ecoreList.setValueHolderOwner(this); + ecoreList.setEStructuralFeature(getEStructuralFeature()); + ecoreList.setPersistentList(values); + ecoreObjectList = ecoreList; + return ecoreList; + } + + public List<EAVSingleEAttributeValueHolder> getValues() { + return values; + } + + public void setValues(List<EAVSingleEAttributeValueHolder> values) { + this.values = values; + ((EAVDelegatingList)get((InternalEObject)getOwner())).setPersistentList(values); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVMultiNonContainmentEReferenceValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVMultiNonContainmentEReferenceValueHolder.java new file mode 100644 index 000000000..ffa818f57 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVMultiNonContainmentEReferenceValueHolder.java @@ -0,0 +1,86 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVMultiNonContainmentEReferenceValueHolder.java,v 1.7 2010/04/05 05:33:30 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.ecore.InternalEObject; + +/** + * Stores a multi containment EReference value. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVMultiNonContainmentEReferenceValueHolder extends EAVMultiValueHolder { + + private List<EAVSingleNonContainmentEReferenceValueHolder> referenceValues; + private EAVDelegatingList ecoreObjectList = null; + + @SuppressWarnings("unchecked") + public void set(Object value) { + // set to null first, if there is at least one value then it is set to a value + setMandatoryValue(null); + final List<?> values = (List<Object>) value; + referenceValues = new ArrayList<EAVSingleNonContainmentEReferenceValueHolder>(); + int index = 0; + for (Object o : values) { + final EAVSingleNonContainmentEReferenceValueHolder eavValue = (EAVSingleNonContainmentEReferenceValueHolder) getElement(o); + eavValue.setListIndex(index++); + referenceValues.add(eavValue); + setMandatoryValue(NOT_NULL_VALUE); + } + } + + public Object getElement(Object value) { + EAVSingleNonContainmentEReferenceValueHolder valueHolder = new EAVSingleNonContainmentEReferenceValueHolder(); + valueHolder.setEStructuralFeature(getEStructuralFeature()); + valueHolder.setOwner(getOwner()); + valueHolder.setValueOwner(this); + valueHolder.setHbDataStore(getHbDataStore()); + valueHolder.set(value); + return valueHolder; + } + + public Object get(InternalEObject owner) { + if (ecoreObjectList != null) { + return ecoreObjectList; + } + // final DelegatingLateLoadingList<Object> lateLoadingList = new DelegatingLateLoadingList<Object>(); + // lateLoadingList.setPersistentList(referenceValues); + final EAVDelegatingEcoreEList<Object> ecoreList = new EAVDelegatingEcoreEList<Object>((InternalEObject) owner); + ecoreList.setValueHolderOwner(this); + ecoreList.setEStructuralFeature(getEStructuralFeature()); + ecoreList.setPersistentList(referenceValues); + ecoreObjectList = ecoreList; + return ecoreList; + } + + public Object getValue() { + return referenceValues; + } + + public List<EAVSingleNonContainmentEReferenceValueHolder> getReferenceValues() { + return referenceValues; + } + + public void setReferenceValues(List<EAVSingleNonContainmentEReferenceValueHolder> referenceValues) { + this.referenceValues = referenceValues; + ((EAVDelegatingList)get((InternalEObject)getOwner())).setPersistentList(referenceValues); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVMultiValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVMultiValueHolder.java new file mode 100644 index 000000000..dd1278686 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVMultiValueHolder.java @@ -0,0 +1,71 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVMultiValueHolder.java,v 1.4 2010/04/02 15:24:11 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.lang.reflect.Field; + +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.InternalEObject.EStore; +import org.eclipse.emf.ecore.impl.BasicEObjectImpl; +import org.eclipse.emf.teneo.hibernate.mapping.property.EcoreAccess; +import org.eclipse.emf.teneo.util.FieldUtil; +import org.eclipse.emf.teneo.util.StoreUtil; + +/** + * This class holds a multi (ismany) EStructuralFeature value. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public abstract class EAVMultiValueHolder extends EAVValueHolder { + + public abstract Object getElement(Object value); + + public void setValueInOwner(InternalEObject owner) { + + if (!EcoreAccess.isStaticFeature(getEStructuralFeature(), (BasicEObjectImpl) owner)) { + Object currentValue = EcoreAccess.getManyEFeatureValue(getEStructuralFeature(), (BasicEObjectImpl) owner); + + if (StoreUtil.isEStoreList(currentValue)) { + final EStore eStore = owner.eStore(); + if (eStore.size(owner, getEStructuralFeature()) != -1) { + currentValue = eStore.get((InternalEObject) owner, getEStructuralFeature(), EStore.NO_INDEX); + } + } + + if (currentValue instanceof EAVDelegatingEcoreEList<?>) { + return; + } + + final Object newValue = get(owner); + EcoreAccess.setManyEFeatureValue(getEStructuralFeature(), newValue, (BasicEObjectImpl) owner); + } else { + final Field javaField = FieldUtil.getField(owner.getClass(), getEStructuralFeature().getName()); + + try { + final Object currentValue = javaField.get(owner); + if (currentValue instanceof EAVDelegatingEcoreEList<?>) { + return; + } + final Object newValue = get(owner); + javaField.set(owner, newValue); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVObjectTuplizer.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVObjectTuplizer.java new file mode 100755 index 000000000..6090ac250 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVObjectTuplizer.java @@ -0,0 +1,341 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EAVObjectTuplizer.java,v 1.4 2010/11/12 09:33:33 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.impl.EObjectImpl; +import org.eclipse.emf.teneo.Constants; +import org.eclipse.emf.teneo.hibernate.HbDataStore; +import org.eclipse.emf.teneo.hibernate.HbHelper; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.HbStoreException; +import org.eclipse.emf.teneo.hibernate.HbUtil; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierCacheHandler; +import org.eclipse.emf.teneo.hibernate.mapping.internal.TeneoInternalEObject; +import org.eclipse.emf.teneo.hibernate.tuplizer.EMFInstantiator; +import org.hibernate.EntityMode; +import org.hibernate.EntityNameResolver; +import org.hibernate.HibernateException; +import org.hibernate.cfg.Environment; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; +import org.hibernate.mapping.Subclass; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; +import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.ProxyFactory; +import org.hibernate.tuple.Instantiator; +import org.hibernate.tuple.entity.AbstractEntityTuplizer; +import org.hibernate.tuple.entity.EntityMetamodel; +import org.hibernate.type.CompositeType; +import org.hibernate.util.ReflectHelper; + +/** + * The Tuplizer for objects mapped according to the EAV Schema. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.4 $ + */ + +public class EAVObjectTuplizer extends AbstractEntityTuplizer { + + /** The logger */ + private static Log log = LogFactory.getLog(EAVObjectTuplizer.class); + + /** + * The mapped class, defaults to EObject for entities and to the real impl + * class for mapped classes + */ + private Class<?> mappedClass; + + private PersistentClass persistentClass; + + /** The entitymetamodel for which this is all done */ + // private final EntityMetamodel theEntityMetamodel; + /** Constructor */ + public EAVObjectTuplizer(EntityMetamodel entityMetamodel, + PersistentClass mappedEntity) { + super(entityMetamodel, mappedEntity); + // theEntityMetamodel = entityMetamodel; + if (mappedEntity.getMappedClass() != null) { + mappedClass = mappedEntity.getMappedClass(); + } else { + mappedClass = EObject.class; + } + persistentClass = mappedEntity; + } + + /** + * First checks the id cache and if not found uses the superclass. + */ + @Override + public Serializable getIdentifier(Object object) throws HibernateException { + Serializable id = (Serializable) IdentifierCacheHandler.getInstance() + .getID(object); + if (id != null) { + return id; + } + return super.getIdentifier(object); + } + + /* + * (non-Javadoc) + * + * @see + * org.hibernate.tuple.entity.EntityTuplizer#determineConcreteSubclassEntityName + * (java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + public String determineConcreteSubclassEntityName(Object entityInstance, + SessionFactoryImplementor factory) { + final Class<?> concreteEntityClass = entityInstance.getClass(); + if (concreteEntityClass == getMappedClass()) { + return getEntityName(); + } else { + String entityName = getEntityMetamodel() + .findEntityNameByEntityClass(concreteEntityClass); + if (entityName == null) { + throw new HibernateException( + "Unable to resolve entity name from Class [" + + concreteEntityClass.getName() + "]" + + " expected instance/subclass of [" + + getEntityName() + "]"); + } + return entityName; + } + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.entity.EntityTuplizer#getEntityNameResolvers() + */ + public EntityNameResolver[] getEntityNameResolvers() { + final HbDataStore ds = HbHelper.INSTANCE.getDataStore(persistentClass); + return new EntityNameResolver[] { ds.getEntityNameResolver() }; + } + + /** + * Uses the identifiercache to get the version. + */ + @Override + public Object getVersion(Object object) throws HibernateException { + final Object version = super.getVersion(object); + if (version != null) { + return version; + } + + return IdentifierCacheHandler.getInstance().getVersion(object); + } + + /** + * Sets the identifier in the cache. + */ + @Override + public void setIdentifier(Object object, Serializable id) + throws HibernateException { + IdentifierCacheHandler.getInstance().setID(object, id); + super.setIdentifier(object, id); + } + + /** Creates an EMF Instantiator */ + @Override + protected Instantiator buildInstantiator(PersistentClass persistentClass) { + if (persistentClass.getEntityName().equals( + Constants.EAV_EOBJECT_ENTITY_NAME)) { + return null; + } + final HbDataStore ds = HbHelper.INSTANCE.getDataStore(persistentClass); + final EClass eclass = ds.getEntityNameStrategy().toEClass( + persistentClass.getEntityName()); + if (eclass == null) { + throw new HbMapperException("No eclass found for entityname: " + + persistentClass.getEntityName()); + } + return new EMFInstantiator(eclass, persistentClass); + } + + /* + * (non-Javadoc) + * + * @see + * org.hibernate.tuple.AbstractEntityTuplizer#buildPropertyGetter(org.hibernate + * .mapping.Property , org.hibernate.mapping.PersistentClass) + */ + @Override + protected Getter buildPropertyGetter(Property mappedProperty, + PersistentClass mappedEntity) { + if (mappedProperty.getName().equals("values")) { + return mappedProperty.getGetter(EObjectImpl.class); + } + return getPropertyAccessor(mappedProperty, mappedEntity).getGetter( + null, mappedProperty.getName()); + } + + /* + * (non-Javadoc) + * + * @see + * org.hibernate.tuple.AbstractEntityTuplizer#buildPropertySetter(org.hibernate + * .mapping.Property , org.hibernate.mapping.PersistentClass) + */ + @Override + protected Setter buildPropertySetter(Property mappedProperty, + PersistentClass mappedEntity) { + if (mappedProperty.getName().equals("values")) { + return mappedProperty.getSetter(EObjectImpl.class); + } + return getPropertyAccessor(mappedProperty, mappedEntity).getSetter( + null, mappedProperty.getName()); + } + + /* + * (non-Javadoc) + * + * @seeorg.hibernate.tuple.AbstractEntityTuplizer#buildProxyFactory(org. + * hibernate.mapping. PersistentClass, org.hibernate.property.Getter, + * org.hibernate.property.Setter) + */ + @Override + protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, + Getter idGetter, Setter idSetter) { + if (persistentClass.getClassName() == null) { // an entity, no proxy + return null; + } + + final HbDataStore ds = HbHelper.INSTANCE.getDataStore(persistentClass); + final EClass eclass = ds.getEntityNameStrategy().toEClass( + persistentClass.getEntityName()); + if (eclass == null) { + throw new HbMapperException("No eclass found for entityname: " + + persistentClass.getEntityName()); + } + + // get all the interfaces from the main class, add the real interface + // first + final Set<Class<?>> proxyInterfaces = new LinkedHashSet<Class<?>>(); + final Class<?> pInterface = persistentClass.getProxyInterface(); + if (pInterface != null) { + proxyInterfaces.add(pInterface); + } + final Class<?> mappedClass = persistentClass.getMappedClass(); + if (mappedClass.isInterface()) { + proxyInterfaces.add(mappedClass); + } + proxyInterfaces.add(HibernateProxy.class); + proxyInterfaces.add(TeneoInternalEObject.class); + + for (Class<?> interfaces : mappedClass.getInterfaces()) { + proxyInterfaces.add(interfaces); + } + + // iterate over all subclasses and add them also + final Iterator<?> iter = persistentClass.getSubclassIterator(); + while (iter.hasNext()) { + final Subclass subclass = (Subclass) iter.next(); + final Class<?> subclassProxy = subclass.getProxyInterface(); + final Class<?> subclassClass = subclass.getMappedClass(); + if (subclassProxy != null && !subclassClass.equals(subclassProxy)) { + proxyInterfaces.add(subclassProxy); + } + } + + // get the idgettters/setters + final Method theIdGetterMethod = idGetter == null ? null : idGetter + .getMethod(); + final Method theIdSetterMethod = idSetter == null ? null : idSetter + .getMethod(); + + final Method proxyGetIdentifierMethod = theIdGetterMethod == null + || pInterface == null ? null : ReflectHelper.getMethod( + pInterface, theIdGetterMethod); + final Method proxySetIdentifierMethod = theIdSetterMethod == null + || pInterface == null ? null : ReflectHelper.getMethod( + pInterface, theIdSetterMethod); + + ProxyFactory pf = Environment.getBytecodeProvider() + .getProxyFactoryFactory().buildProxyFactory(); + try { + pf.postInstantiate( + getEntityName(), + mappedClass, + proxyInterfaces, + proxyGetIdentifierMethod, + proxySetIdentifierMethod, + persistentClass.hasEmbeddedIdentifier() ? (CompositeType) persistentClass + .getIdentifier().getType() : null); + } catch (HbStoreException e) { + log.warn("could not create proxy factory for:" + getEntityName(), e); + pf = null; + } + return pf; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.AbstractEntityTuplizer#getEntityMode() + */ + public EntityMode getEntityMode() { + return EntityMode.POJO; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.EntityTuplizer#getConcreteProxyClass() + */ + public Class<?> getConcreteProxyClass() { + return EObject.class; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.EntityTuplizer#isInstrumented() + */ + public boolean isInstrumented() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.Tuplizer#getMappedClass() + */ + public Class<?> getMappedClass() { + return mappedClass; + } + + /** Returns the correct accessor on the basis of the type of property */ + protected PropertyAccessor getPropertyAccessor(Property mappedProperty, + PersistentClass pc) { + final HbDataStore ds = HbHelper.INSTANCE.getDataStore(pc); + return HbUtil.getPropertyAccessor(mappedProperty, ds, + pc.getEntityName(), null); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVPropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVPropertyHandler.java new file mode 100755 index 000000000..42851217b --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVPropertyHandler.java @@ -0,0 +1,407 @@ +/** + * <copyright> Copyright (c) 2009 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 </copyright> $Id: + * EReferencePropertyHandler.java,v 1.4 2007/04/07 12:43:51 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.eclipse.emf.common.notify.Adapter; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.notify.Notifier; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.HbDataStore; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * The property handler which takes care of setting/getting the + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.11 $ + */ +@SuppressWarnings("unchecked") +public class EAVPropertyHandler implements Getter, Setter, PropertyAccessor, + ExtensionPoint { + + private static final long serialVersionUID = -3712366809398761331L; + + private HbDataStore hbDataStore = null; + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#get(java.lang.Object) + */ + public Object get(Object owner) throws HibernateException { + + final EObject eOwner = (EObject) owner; + for (Adapter adapter : eOwner.eAdapters()) { + if (adapter instanceof EAVObjectAdapter) { + final EAVObjectAdapter eavAdapter = (EAVObjectAdapter) adapter; + return eavAdapter.getValueList(); + } + } + + final EAVObjectAdapter eavAdapter = new EAVObjectAdapter(); + eavAdapter.setTarget(eOwner); + final List<EAVValueHolder> valueList = createValueList(eOwner); + // note this will replace the values in the eobject + // i.e. list instances + fillTargetObject((EObject) eOwner, valueList); + eavAdapter.setValueList(valueList); + eOwner.eAdapters().add(eavAdapter); + return valueList; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getForInsert(java.lang.Object, + * java.util.Map, org.hibernate.engine.SessionImplementor) + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object owner, Map mergeMap, + SessionImplementor session) throws HibernateException { + return get(owner); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#set(java.lang.Object, + * java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + final EObject eOwner = (EObject) target; + for (Adapter adapter : eOwner.eAdapters()) { + if (adapter instanceof EAVObjectAdapter) { + final EAVObjectAdapter eavAdapter = (EAVObjectAdapter) adapter; + // todo: is the value every different, I don't think so..) + eavAdapter.setValueList((List<EAVValueHolder>) value); + return; + } + } + fillTargetObject((EObject) target, (List<EAVValueHolder>) value); + final EAVObjectAdapter eavAdapter = new EAVObjectAdapter(); + eavAdapter.setTarget(eOwner); + eavAdapter.setValueList((List<EAVValueHolder>) value); + eOwner.eAdapters().add(eavAdapter); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getReturnType() + */ + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return InternalEObject.class; + } + + private List<EAVValueHolder> createValueList(EObject target) { + final List<EAVValueHolder> valueHolders = new ArrayList<EAVValueHolder>(); + for (EStructuralFeature eFeature : target.eClass() + .getEAllStructuralFeatures()) { + if (eFeature.isDerived() || eFeature.isTransient() + || eFeature.isVolatile()) { + continue; + } + final EAVValueHolder valueHolder = EAVValueHolder.create(target, + eFeature, hbDataStore); + valueHolder.set(target.eGet(eFeature)); + if (eFeature.isUnsettable()) { + valueHolder.setValueIsSet(target.eIsSet(eFeature)); + } + valueHolders.add(valueHolder); + } + return valueHolders; + } + + private void fillTargetObject(EObject target, List<EAVValueHolder> valueList) { + for (EAVValueHolder valueHolder : valueList) { + valueHolder.setValueInOwner((InternalEObject) target); + } + } + + private static class EAVObjectAdapter implements Adapter { + + private Notifier target; + + private List<EAVValueHolder> valueList; + + public Notifier getTarget() { + return target; + } + + public void setTarget(Notifier newTarget) { + target = newTarget; + } + + public List<EAVValueHolder> getValueList() { + return valueList; + } + + public void setValueList(List<EAVValueHolder> valueList) { + this.valueList = valueList; + } + + public boolean isAdapterForType(Object type) { + return false; + } + + private EAVValueHolder getValueHolder(EStructuralFeature eFeature) { + for (EAVValueHolder valueHolder : valueList) { + if (valueHolder.getEStructuralFeature() == eFeature) { + return valueHolder; + } + } + // can happen when adding + return null; + } + + public void notifyChanged(Notification notification) { + final EStructuralFeature eFeature = (EStructuralFeature) notification + .getFeature(); + + final EAVValueHolder valueHolder = getValueHolder(eFeature); + EAVMultiValueHolder multiValueHolder = null; + + List<Object> list = null; + if (valueHolder instanceof EAVMultiValueHolder) { + list = (List<Object>) valueHolder.getValue(); + multiValueHolder = (EAVMultiValueHolder) valueHolder; + } + + // this can happen in case of a featuremap + if (valueHolder == null) { + return; + } + + final Object currentEMFValue = valueHolder.getOwner() + .eGet(eFeature); + if (currentEMFValue instanceof EAVDelegatingEcoreEList<?>) { + // this type of list manages the changes directly + return; + } + + // note for list features we can only get here for new objects which + // have not been + // read from the db but which have been persisted. Objects read from + // the database + // will always have a EAVDelegatingEcoreEList. + // The code below is also executed in case of changes to an EAV EMap + + int repairFromIndex = -1; + + switch (notification.getEventType()) { + case Notification.ADD: { + if (notification.getPosition() != Notification.NO_INDEX) { + repairFromIndex = notification.getPosition(); + list.add(notification.getPosition(), multiValueHolder + .getElement(notification.getNewValue())); + } else { + repairFromIndex = list.size(); + list.add(multiValueHolder.getElement(notification + .getNewValue())); + } + } + break; + case Notification.ADD_MANY: { + final List<Object> values = new ArrayList<Object>(); + for (Object o : (List<Object>) notification.getNewValue()) { + values.add(multiValueHolder.getElement(o)); + } + if (notification.getPosition() != Notification.NO_INDEX) { + repairFromIndex = notification.getPosition(); + list.addAll(notification.getPosition(), values); + } else { + repairFromIndex = list.size(); + list.addAll(values); + } + } + break; + case Notification.REMOVE: { + int removeIndex = notification.getPosition(); + if (removeIndex == Notification.NO_INDEX) { + final Object oldValue = notification.getOldValue(); + for (Object o : list) { + final EAVValueHolder elemValue = (EAVValueHolder) o; + if (elemValue.getValue() != null && oldValue != null + && elemValue.getValue().equals(oldValue)) { + removeIndex = list.indexOf(o); + break; + } else if (elemValue.getValue() == oldValue) { + removeIndex = list.indexOf(o); + break; + } + } + } + + if (removeIndex != Notification.NO_INDEX) { + repairFromIndex = removeIndex; + list.remove(removeIndex); + } + } + break; + case Notification.REMOVE_MANY: + final List<?> oldValues = (List<?>) notification.getOldValue(); + for (Object oldValue : oldValues) { + int removeIndex = notification.getPosition(); + if (removeIndex == Notification.NO_INDEX) { + for (Object o : list) { + final EAVValueHolder elemValue = (EAVValueHolder) o; + if (elemValue.getValue() != null + && oldValue != null + && elemValue.getValue().equals(oldValue)) { + removeIndex = list.indexOf(o); + break; + } else if (elemValue.getValue() == oldValue) { + removeIndex = list.indexOf(o); + break; + } + elemValue.setListIndex(-1); + elemValue.setValueOwner(null); + elemValue.setOwner(null); + } + + if (removeIndex != Notification.NO_INDEX) { + repairFromIndex = 0; + list.remove(removeIndex); + } + } + } + break; + case Notification.MOVE: + if (list != null) { + final int oldPosition = (Integer) notification + .getOldValue(); + final int newPosition = notification.getPosition(); + final Object o = list.remove(oldPosition); + list.add(newPosition, o); + if (newPosition < oldPosition) { + repairFromIndex = newPosition; + } else { + repairFromIndex = oldPosition; + } + } + break; + case Notification.SET: + if (eFeature.isMany()) { + final int position = notification.getPosition(); + final EAVValueHolder elementValueHolder = (EAVValueHolder) list + .set(position, multiValueHolder + .getElement(notification.getNewValue())); + repairFromIndex = notification.getPosition(); + if (elementValueHolder != null) { + elementValueHolder.setListIndex(0); + elementValueHolder.setValueOwner(null); + elementValueHolder.setOwner(null); + } + } else { + valueHolder.set(notification.getNewValue()); + } + break; + case Notification.UNSET: + if (!eFeature.isMany()) { + valueHolder.set(notification.getNewValue()); + } + break; + } + if (repairFromIndex != -1) { + int index = repairFromIndex; + for (Object o : list.subList(repairFromIndex, list.size())) { + + if (o instanceof EObject) { + StoreUtil.setSyntheticListIndex(eFeature, o, index++); + StoreUtil.setSyntheticListOwner(eFeature, o, + notification.getNotifier()); + } + if (o instanceof EAVValueHolder) { + final EAVValueHolder eavValueHolder = (EAVValueHolder) o; + eavValueHolder.setListIndex(index++); + eavValueHolder + .setValueOwner((EAVMultiValueHolder) valueHolder); + } + } + } + } + } + + public HbDataStore getHbDataStore() { + return hbDataStore; + } + + public void setHbDataStore(HbDataStore hbDataStore) { + this.hbDataStore = hbDataStore; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVSingleContainmentEReferenceValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVSingleContainmentEReferenceValueHolder.java new file mode 100644 index 000000000..0210d8ebb --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVSingleContainmentEReferenceValueHolder.java @@ -0,0 +1,26 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVSingleContainmentEReferenceValueHolder.java,v 1.1 2009/08/20 15:59:38 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +/** + * Stores a single EReference value when the EReference is containment. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVSingleContainmentEReferenceValueHolder extends EAVSingleEReferenceValueHolder { +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVSingleEAttributeValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVSingleEAttributeValueHolder.java new file mode 100644 index 000000000..af87962d3 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVSingleEAttributeValueHolder.java @@ -0,0 +1,263 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVSingleEAttributeValueHolder.java,v 1.11 2010/10/31 21:50:36 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.util.Date; + +import org.eclipse.emf.common.util.Enumerator; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EFactory; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEDataType; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature; +import org.eclipse.emf.teneo.annotations.pannotation.FetchType; +import org.eclipse.emf.teneo.hibernate.HbDataStore; + +/** + * This class holds a single EAttribute value. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVSingleEAttributeValueHolder extends EAVValueHolder { + + private static final int MAX_PRECISION = 38; + + private String type; + private String typeNeutralValue; + private String stringValue; + private Date dateValue; + private BigDecimal numericValue; + private double doubleValue; + private long longValue; + private Object objectValue; + private EAVBlobValue blobValue; + private EAVTextValue textValue; + + public void set(Object value) { + + // nullify old data + stringValue = null; + dateValue = null; + numericValue = null; + longValue = 0; + setValueIsSet(false); + setMandatoryValue(null); + + objectValue = value; + + // stop here as everything has been nullified anyway + if (value == null) { + return; + } + + // value is not null, set the mandatory trigger + setMandatoryValue(NOT_NULL_VALUE); + + // do type specific handling + final boolean isBlob = value instanceof byte[] + || (value instanceof String && isClob(getEStructuralFeature())); + final EDataType eDataType = (EDataType) getEStructuralFeature() + .getEType(); + final EFactory eFactory = eDataType.getEPackage().getEFactoryInstance(); + if (!isBlob) { + typeNeutralValue = eFactory.convertToString(eDataType, value); + } + type = value.getClass().getName(); + + if (value instanceof byte[]) { + blobValue = new EAVBlobValue(); + blobValue.setBlobValue((byte[]) value); + blobValue.setValueHolder(this); + } else if (value instanceof Enumerator) { + stringValue = ((Enumerator) value).getName(); + } else if (value instanceof String && isBlob) { + textValue = new EAVTextValue(); + textValue.setTextValue((String) value); + textValue.setValueHolder(this); + } else if (value instanceof String) { + stringValue = (String) value; + } else if (value instanceof Date) { + dateValue = (Date) value; + } else if (value instanceof Number) { + if (value instanceof BigDecimal) { + final BigDecimal bdValue = (BigDecimal) value; + if (bdValue.precision() > MAX_PRECISION) { + final MathContext mathContext = new MathContext( + MAX_PRECISION); + numericValue = bdValue.round(mathContext); + } else { + numericValue = bdValue; + } + } else if (value instanceof BigInteger) { + longValue = ((BigInteger) value).longValue(); + } else if (value instanceof Double || value instanceof Float) { + doubleValue = ((Number) value).doubleValue(); + } else if (value instanceof Integer || value instanceof Long + || value instanceof Short || value instanceof Byte) { + longValue = ((Number) value).longValue(); + } else { + throw new UnsupportedOperationException("Primitive type " + + value.getClass() + " not supported here."); + } + } + } + + public Object get(InternalEObject owner) { + if (objectValue == null && blobValue != null) { + objectValue = blobValue.getBlobValue(); + } else if (objectValue == null && textValue != null) { + objectValue = textValue.getTextValue(); + } else if (objectValue == null && typeNeutralValue != null) { + final EDataType eDataType = (EDataType) getEStructuralFeature() + .getEType(); + final EFactory eFactory = eDataType.getEPackage() + .getEFactoryInstance(); + objectValue = eFactory + .createFromString(eDataType, typeNeutralValue); + } + + return objectValue; + } + + public Object getValue() { + return get(null); + } + + public void setValueInOwner(InternalEObject owner) { + if (getEStructuralFeature().isUnsettable() && !isValueIsSet()) { + owner.eUnset(getEStructuralFeature()); + } else { + owner.eSet(getEStructuralFeature(), get(owner)); + } + } + + public String getStringValue() { + return stringValue; + } + + public void setStringValue(String stringValue) { + this.stringValue = stringValue; + } + + public Date getDateValue() { + return dateValue; + } + + public void setDateValue(Date dateValue) { + this.dateValue = dateValue; + } + + public BigDecimal getNumericValue() { + return numericValue; + } + + public void setNumericValue(BigDecimal numericValue) { + this.numericValue = numericValue; + } + + public long getLongValue() { + return longValue; + } + + public void setLongValue(long longValue) { + this.longValue = longValue; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getTypeNeutralValue() { + return typeNeutralValue; + } + + public void setTypeNeutralValue(String typeNeutralValue) { + this.typeNeutralValue = typeNeutralValue; + } + + public EAVBlobValue getBlobValue() { + return blobValue; + } + + public void setBlobValue(EAVBlobValue blobValue) { + this.blobValue = blobValue; + } + + public EAVTextValue getTextValue() { + return textValue; + } + + public void setTextValue(EAVTextValue textValue) { + this.textValue = textValue; + } + + private boolean isClob(EStructuralFeature eFeature) { + final EAttribute eAttribute = (EAttribute) eFeature; + try { + final PAnnotatedEAttribute paEAttribute = getHbDataStore() + .getPaModel().getPAnnotated(eAttribute); + if (paEAttribute == null) { + return false; + } + if (paEAttribute.getLob() != null) { + return true; + } + final PAnnotatedEDataType paDataType = getHbDataStore() + .getPaModel().getPAnnotated(eAttribute.getEAttributeType()); + if (paDataType == null) { + return false; + } + return paDataType.getLob() != null; + } catch (IllegalArgumentException e) { + // no problem, happens in some cases with featuremaps + return false; + } + } + + protected static boolean isFeatureExtraLazy(HbDataStore hbDataStore, + EStructuralFeature eFeature) { + if (hbDataStore.getPersistenceOptions().isFetchAssociationExtraLazy()) { + return true; + } + final PAnnotatedEStructuralFeature paFeature = hbDataStore.getPaModel() + .getPAnnotated(eFeature); + if (paFeature.getOneToMany() != null + && paFeature.getOneToMany().getFetch().equals(FetchType.EXTRA)) { + return Boolean.TRUE; + } + return false; + } + + public double getDoubleValue() { + return doubleValue; + } + + public void setDoubleValue(double doubleValue) { + this.doubleValue = doubleValue; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVSingleEReferenceValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVSingleEReferenceValueHolder.java new file mode 100644 index 000000000..162d98d77 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVSingleEReferenceValueHolder.java @@ -0,0 +1,140 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVSingleEReferenceValueHolder.java,v 1.5 2010/04/04 12:10:51 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import org.eclipse.emf.common.notify.NotificationChain; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.impl.DynamicEObjectImpl; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass; +import org.eclipse.emf.teneo.hibernate.HbUtil; +import org.hibernate.mapping.PersistentClass; + +/** + * Stores a single EReference value when the EReference is containment. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVSingleEReferenceValueHolder extends EAVValueHolder { + + private EObject referenceValue; + + private EObject eavObjectReference; + + private EReference getEReference() { + return (EReference) getEStructuralFeature(); + } + + public void setValueInOwner(InternalEObject owner) { + final Object curValue = owner.eGet(getEStructuralFeature()); + final int featureId = owner.eClass().getFeatureID( + getEStructuralFeature()); + if (curValue == referenceValue) { + // note that == works fine if the + // curValue and value have been read in the same jvm. + return; // do nothing in this case + } + + if (getEReference().getEOpposite() != null + || (owner instanceof DynamicEObjectImpl && getEReference() + .isContainment())) { + // these are handled a bit differently because + if (referenceValue == null) { // remove + // Note that the eInverseRemove is called on the target itself + // and the value is passed + // therefore the eReference featureid is passed and not the + // opposite + final NotificationChain nots = ((InternalEObject) owner) + .eInverseRemove((InternalEObject) curValue, featureId, + getEReference().getEType().getInstanceClass(), + null); + if (nots != null) { + nots.dispatch(); + } + } else { + final NotificationChain nots = ((InternalEObject) owner) + .eInverseAdd((InternalEObject) referenceValue, + featureId, getEReference().getEType() + .getInstanceClass(), null); + if (nots != null) { + nots.dispatch(); + } + } + } else { + owner.eSet(getEReference(), referenceValue); + } + } + + public void set(Object value) { + setMandatoryValue(null); + referenceValue = (EObject) value; + if (referenceValue != null) { + setMandatoryValue(NOT_NULL_VALUE); + if (isEAVMapped(referenceValue.eClass())) { + setEavObjectReference(referenceValue); + } + } else { + setEavObjectReference(null); + } + + } + + public Object getValue() { + return getReferenceValue(); + } + + public Object get(InternalEObject owner) { + return referenceValue; + } + + public EObject getReferenceValue() { + return referenceValue; + } + + public void setReferenceValue(EObject referenceValue) { + this.referenceValue = referenceValue; + } + + public EObject getEavObjectReference() { + return eavObjectReference; + } + + public void setEavObjectReference(EObject eavObjectReference) { + this.eavObjectReference = eavObjectReference; + } + + private boolean isEAVMapped(EClass eClass) { + try { + final PAnnotatedEClass paClass = getHbDataStore().getPaModel() + .getPAnnotated(eClass); + if (paClass.getEntity() == null) { + return false; + } + final String entityName = paClass.getEntity().getName(); + final PersistentClass pc = getHbDataStore().getPersistentClass( + entityName); + return HbUtil.isEAVMapped(pc); + } catch (IllegalArgumentException e) { + // not mapped + return false; + } + } + +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVSingleNonContainmentEReferenceValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVSingleNonContainmentEReferenceValueHolder.java new file mode 100644 index 000000000..143a61dc7 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVSingleNonContainmentEReferenceValueHolder.java @@ -0,0 +1,27 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVSingleNonContainmentEReferenceValueHolder.java,v 1.1 2009/08/20 15:59:38 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + + +/** + * Stores a single EReference value when the EReference is non containment. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVSingleNonContainmentEReferenceValueHolder extends EAVSingleEReferenceValueHolder { +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVTextValue.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVTextValue.java new file mode 100644 index 000000000..a26122d14 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVTextValue.java @@ -0,0 +1,64 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVTextValue.java,v 1.1 2009/09/11 22:52:36 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +/** + * Holds a text value. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ +public class EAVTextValue { + + private long id; + private int version; + + private String textValue; + private EAVSingleEAttributeValueHolder valueHolder; + + public EAVSingleEAttributeValueHolder getValueHolder() { + return valueHolder; + } + + public void setValueHolder(EAVSingleEAttributeValueHolder valueHolder) { + this.valueHolder = valueHolder; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public String getTextValue() { + return textValue; + } + + public void setTextValue(String textValue) { + this.textValue = textValue; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVTuplizer.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVTuplizer.java new file mode 100644 index 000000000..43ac9286a --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVTuplizer.java @@ -0,0 +1,87 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVTuplizer.java,v 1.3 2010/04/02 22:10:11 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import java.util.Iterator; + +import org.hibernate.HibernateException; +import org.hibernate.collection.PersistentList; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.intercept.LazyPropertyInitializer; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.tuple.Instantiator; +import org.hibernate.tuple.entity.EntityMetamodel; +import org.hibernate.tuple.entity.PojoEntityTuplizer; + +/** + * Tuplizer created to work around this issue: http://opensource.atlassian.com/projects/hibernate/browse/HHH-4078 + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ + +public class EAVTuplizer extends PojoEntityTuplizer { + + private PersistentClass persistentClass; + + public EAVTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) { + super(entityMetamodel, mappedEntity); + persistentClass = mappedEntity; + } + + /** + * {@inheritDoc} + */ + public String determineConcreteSubclassEntityName(Object entityInstance, SessionFactoryImplementor factory) { + final Class<?> concreteEntityClass = entityInstance.getClass(); + if (concreteEntityClass == getMappedClass()) { + return getEntityName(); + } else { + final Iterator<?> iter = persistentClass.getSubclassIterator(); + while (iter.hasNext()) { + final PersistentClass pc = (PersistentClass) iter.next(); + if (pc.getMappedClass() == concreteEntityClass) { + return pc.getEntityName(); + } + } + throw new HibernateException("Unable to resolve entity name from Class [" + concreteEntityClass.getName() + + "]" + " expected instance/subclass of [" + getEntityName() + "]"); + } + } + + // overridden to make sure that the owner is set earlier + public void setPropertyValues(Object entity, Object[] values) throws HibernateException { + boolean setAll = !getEntityMetamodel().hasLazyProperties(); + + for ( int j = 0; j < getEntityMetamodel().getPropertySpan(); j++ ) { + if ( setAll || values[j] != LazyPropertyInitializer.UNFETCHED_PROPERTY ) { + if (values[j] instanceof PersistentList) { + final PersistentList persistentList = (PersistentList)values[j]; + if (persistentList.getOwner() == null) { + persistentList.setOwner(entity); + } + } + setters[j].set( entity, values[j], getFactory() ); + } + } + } + + @Override + protected Instantiator buildInstantiator(PersistentClass persistentClass) { + return new EAVValueInstantiator( persistentClass, null ); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVValueHolder.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVValueHolder.java new file mode 100755 index 000000000..e30314920 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVValueHolder.java @@ -0,0 +1,283 @@ +/** + * <copyright> + * + * Copyright (c) 2009 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: EAVValueHolder.java,v 1.7 2010/10/29 09:35:28 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.util.FeatureMapUtil; +import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature; +import org.eclipse.emf.teneo.annotations.pannotation.FetchType; +import org.eclipse.emf.teneo.hibernate.HbDataStore; + +/** + * The base class of the value stored in an EAV schema. The value in an EAV + * schema is both the type (the EStructuralFeature) and its value. The following + * different types of values can be identified: + * <ul> + * <li>EAttribute: a single primitive value</li> + * <li>EReference: a single reference to another object, containment or + * non-containment</li> + * <li>MultiEAttribute: a multi-occurrence EAttribute</li> + * <li>MultiEReference: a multi-occurrence EReference</li> + * </ul> + * In addition there is the FeatureMap and Map support which needs to be + * handled. In EMF both are lists with EAttributes. + * + * The above structure is reflected in the EAVValueHolder class hierarchy. + * + * @author <a href="mtaal@elver.org">Martin Taal</a> + */ + +// NOTES: +// the container reference is stored in the eobject itself! + +public abstract class EAVValueHolder { + + protected static Integer NOT_NULL_VALUE = new Integer(1); + + public static EAVValueHolder create(EObject owner, + EStructuralFeature eFeature, HbDataStore hbDataStore) { + final EAVValueHolder valueHolder; + if (eFeature instanceof EReference) { + final EReference eReference = (EReference) eFeature; + if (eReference.isMany()) { + if (eReference.isContainment()) { + if (isFeatureExtraLazy(hbDataStore, eFeature)) { + valueHolder = new EAVExtraMultiContainmentEReferenceValueHolder(); + } else { + valueHolder = new EAVMultiContainmentEReferenceValueHolder(); + } + } else { + if (isFeatureExtraLazy(hbDataStore, eFeature)) { + valueHolder = new EAVExtraMultiNonContainmentEReferenceValueHolder(); + } else { + valueHolder = new EAVMultiNonContainmentEReferenceValueHolder(); + } + } + } else { + if (eReference.isContainment()) { + valueHolder = new EAVSingleContainmentEReferenceValueHolder(); + } else { + valueHolder = new EAVSingleNonContainmentEReferenceValueHolder(); + } + } + } else { + if (FeatureMapUtil.isFeatureMap(eFeature)) { + valueHolder = new EAVFeatureMapValueHolder(); + } else if (eFeature.isMany()) { + if (isFeatureExtraLazy(hbDataStore, eFeature)) { + valueHolder = new EAVExtraMultiEAttributeValueHolder(); + } else { + valueHolder = new EAVMultiEAttributeValueHolder(); + } + } else { + valueHolder = new EAVSingleEAttributeValueHolder(); + } + } + valueHolder.setEStructuralFeature(eFeature); + valueHolder.setOwner(owner); + valueHolder.setHbDataStore(hbDataStore); + return valueHolder; + } + + protected static boolean isFeatureExtraLazy(HbDataStore hbDataStore, + EStructuralFeature eFeature) { + if (hbDataStore.getPersistenceOptions().isFetchAssociationExtraLazy()) { + return true; + } + try { + final PAnnotatedEStructuralFeature paFeature = hbDataStore + .getPaModel().getPAnnotated(eFeature); + if (paFeature.getOneToMany() != null + && paFeature.getOneToMany().getFetch().equals( + FetchType.EXTRA)) { + return Boolean.TRUE; + } + return false; + } catch (IllegalArgumentException e) { + // be robust about model elements not annotated + return false; + } + + } + + private HbDataStore hbDataStore; + private long id; + private int version; + private EStructuralFeature eStructuralFeature; + private boolean valueIsSet; + private EObject owner; + + private EAVMultiValueHolder valueOwner; + + // is used when a value is held in a list + private int listIndex; + + // the mandatoryValue is used as follows. + // it is defined as mandatory in the hibernate mapping + // if !eStructuralFeature.isRequired then it is always set to the + // NOT_NULL_VALUE + // if eStructuralFeature.isRequired then it is set if the value of the + // EStructuralFeature + // is set. + // in this way the mandatory value check is executed by hibernate on the + // basis + // of eStructuralFeature.isRequired + private Integer mandatoryValue = null; + + public abstract void set(Object value); + + public abstract Object get(InternalEObject owner); + + public abstract void setValueInOwner(InternalEObject owner); + + public abstract Object getValue(); + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public EStructuralFeature getEStructuralFeature() { + return eStructuralFeature; + } + + public void setEStructuralFeature(EStructuralFeature eStructuralFeature) { + this.eStructuralFeature = eStructuralFeature; + } + + // extra getter and setter because hibernate gets confused with the other + // getter/setter and the uppercase 2 characters + public EStructuralFeature getFeature() { + return eStructuralFeature; + } + + public void setFeature(EStructuralFeature eStructuralFeature) { + // setEStructuralFeature is overridden by subclasses + setEStructuralFeature(eStructuralFeature); + } + + public boolean isValueIsSet() { + return valueIsSet; + } + + public void setValueIsSet(boolean valueIsSet) { + this.valueIsSet = valueIsSet; + } + + public Integer getMandatoryValue() { + // in case of merging the estructuralfeature is not yet set + if (getEStructuralFeature() == null) { + return NOT_NULL_VALUE; + } + // if not required then the not-value is set always + if (!getEStructuralFeature().isRequired() + || getEStructuralFeature().isUnsettable()) { + return NOT_NULL_VALUE; + } + return mandatoryValue; + } + + public void setMandatoryValue(Integer mandatoryValue) { + this.mandatoryValue = mandatoryValue; + } + + public EObject getOwner() { + return owner; + } + + public void setOwner(EObject owner) { + this.owner = owner; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof EAVValueHolder)) { + return false; + } + final EAVValueHolder eavHolder = (EAVValueHolder) obj; + if (eavHolder.getEStructuralFeature() != getEStructuralFeature()) { + return false; + } + // handles null + if (getValue() == eavHolder.getValue()) { + return true; + } + if (getValue() == null) { + return false; + } + if (eavHolder.getValue() == null) { + return false; + } + return getValue().equals(eavHolder.getValue()); + } + + @Override + public int hashCode() { + if (getValue() == null) { + return getEStructuralFeature().hashCode(); + } + return getEStructuralFeature().hashCode() ^ getValue().hashCode(); + } + + public int getListIndex() { + return listIndex; + } + + public void setListIndex(int listIndex) { + this.listIndex = listIndex; + } + + public int getVirtualListIndex() { + return listIndex; + } + + public void setVirtualListIndex(int listIndex) { + this.listIndex = listIndex; + } + + public EAVMultiValueHolder getValueOwner() { + return valueOwner; + } + + public void setValueOwner(EAVMultiValueHolder valueOwner) { + this.valueOwner = valueOwner; + } + + public HbDataStore getHbDataStore() { + return hbDataStore; + } + + public void setHbDataStore(HbDataStore hbDataStore) { + this.hbDataStore = hbDataStore; + } + +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVValueInstantiator.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVValueInstantiator.java new file mode 100644 index 000000000..ecd872a73 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/EAVValueInstantiator.java @@ -0,0 +1,58 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EAVValueInstantiator.java,v 1.1 2010/04/02 15:24:11 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.eav; + +import org.eclipse.emf.teneo.hibernate.HbDataStore; +import org.eclipse.emf.teneo.hibernate.HbHelper; +import org.hibernate.bytecode.ReflectionOptimizer; +import org.hibernate.mapping.Component; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.tuple.PojoInstantiator; + +/** + * Instantiator for the EAV value objects, sets the datastore in the object. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.1 $ + */ + +public class EAVValueInstantiator extends PojoInstantiator { + + private static final long serialVersionUID = 6946442685247491904L; + + private HbDataStore hbDataStore; + + public EAVValueInstantiator(Component component, ReflectionOptimizer.InstantiationOptimizer optimizer) { + super(component, optimizer); + hbDataStore = HbHelper.INSTANCE.getDataStore(component); + } + + public EAVValueInstantiator(PersistentClass persistentClass, ReflectionOptimizer.InstantiationOptimizer optimizer) { + super(persistentClass, optimizer); + hbDataStore = HbHelper.INSTANCE.getDataStore(persistentClass); + } + + public Object instantiate() { + final Object object = super.instantiate(); + if (object instanceof EAVValueHolder) { + final EAVValueHolder valueHolder = (EAVValueHolder)object; + valueHolder.setHbDataStore(hbDataStore); + } + return object; + } + +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/eav.hbm.xml b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/eav.hbm.xml new file mode 100755 index 000000000..347ac43be --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/eav/eav.hbm.xml @@ -0,0 +1,296 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> + +<hibernate-mapping auto-import="false"> + <class name="org.eclipse.emf.ecore.impl.EObjectImpl" entity-name="EAV_EObject" + abstract="true" lazy="true" discriminator-value="eav_eobject" + table="`{tableprefix}eaveobject`" proxy="org.eclipse.emf.ecore.EObject"> + + <tuplizer entity-mode="pojo" + class="org.eclipse.emf.teneo.hibernate.tuplizer.EMFTuplizer" /> + <tuplizer entity-mode="dynamic-map" + class="org.eclipse.emf.teneo.hibernate.tuplizer.EMFTuplizer" /> + + <id type="long" name="id" column="`eid`" + access="org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierPropertyHandler"> + <meta attribute="syntheticId">true</meta> + <generator class="native" /> + </id> + <discriminator column="`dtype`" type="string" /> + <version name="e_version" column="`eversion`" + access="org.eclipse.emf.teneo.hibernate.mapping.property.VersionPropertyHandler"> + <meta attribute="syntheticVersion">true</meta> + </version> + + <list name="values" lazy="true" cascade="all,delete-orphan" + access="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVPropertyHandler"> + <key column="`listkey`"/> + <list-index column="`idx`" /> + <one-to-many entity-name="EAV_Value" /> + </list> + </class> + <class name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVValueHolder" + entity-name="EAV_Value" abstract="true" lazy="false" table="`{tableprefix}eavvalue`"> + + <tuplizer entity-mode="pojo" + class="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVTuplizer" /> + + <id type="long" name="id" column="`eavid`"> + <generator class="native" /> + </id> + <discriminator column="`discriminator`" /> + <version name="version" column="`eavversion`" /> + <property name="feature" + type="org.eclipse.emf.teneo.hibernate.mapping.EcoreModelElementType" + not-null="true" /> + <property name="valueIsSet" /> + <property name="mandatoryValue" not-null="true" /> + <property name="listIndex" column="`listindex`" /> + <many-to-one name="owner" entity-name="EAV_EObject" column="`owner`" /> + <many-to-one name="valueOwner" entity-name="EAV_Value" + not-null="false" column="`valueowner`" /> + </class> + <subclass + name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVSingleEAttributeValueHolder" + entity-name="EAVSingleEAttributeValueHolder" abstract="false" lazy="false" + extends="EAV_Value" discriminator-value="EAVSingleEAttributeValueHolder"> + + <tuplizer entity-mode="pojo" + class="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVTuplizer" /> + + <property name="typeNeutralValue" /> + <property name="type" /> + <property name="stringValue" /> + <property name="dateValue" /> + <property name="doubleValue" /> + <property name="numericValue" precision="31" scale="19" /> + <property name="longValue" /> + <one-to-one name="blobValue" property-ref="valueHolder" + entity-name="EAV_Blob" cascade="all" /> + <one-to-one name="textValue" property-ref="valueHolder" + entity-name="EAV_Text" cascade="all" /> + </subclass> + <subclass + name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVMultiEAttributeValueHolder" + entity-name="EAVMultiEAttributeValueHolder" abstract="false" lazy="false" + extends="EAV_Value" discriminator-value="EAVMultiEAttributeValueHolder"> + + <tuplizer entity-mode="pojo" + class="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVTuplizer" /> + + <list name="values" lazy="true" cascade="all,delete-orphan" + inverse="true"> + <key update="true"> + <column name="`valueowner`" not-null="false" unique="false" /> + </key> + <list-index column="`listindex`" /> + <one-to-many entity-name="EAVSingleEAttributeValueHolder" /> + </list> + </subclass> + <subclass + name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVExtraMultiEAttributeValueHolder" + entity-name="EAVExtraMultiEAttributeValueHolder" abstract="false" lazy="false" + extends="EAV_Value" discriminator-value="EAVExtraMultiEAttributeValueHolder"> + + <tuplizer entity-mode="pojo" + class="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVTuplizer" /> + + <list name="values" lazy="extra" cascade="all,delete-orphan" + inverse="true"> + <key update="true"> + <column name="`valueowner`" not-null="false" unique="false" /> + </key> + <list-index column="`listindex`" /> + <one-to-many entity-name="EAVSingleEAttributeValueHolder" /> + </list> + </subclass> + <subclass + name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVFeatureMapValueHolder" + entity-name="EAVFeatureMapValueHolder" abstract="false" lazy="false" + extends="EAV_Value" discriminator-value="EAVFeatureMapValueHolder"> + + <tuplizer entity-mode="pojo" + class="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVTuplizer" /> + + <list name="values" lazy="false" cascade="all,delete-orphan"> + <key update="true"> + <column name="`valuesholderid`" not-null="false" unique="false" /> + </key> + <list-index column="`valuesholderidx`" /> + <one-to-many entity-name="EAVFeatureMapEntryValueHolder" /> + </list> + </subclass> + <subclass + name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVFeatureMapEntryValueHolder" + entity-name="EAVFeatureMapEntryValueHolder" abstract="false" lazy="false" + extends="EAVSingleEAttributeValueHolder" discriminator-value="EAVFeatureMapEntryValueHolder"> + + <tuplizer entity-mode="pojo" + class="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVTuplizer" /> + + <any name="referenceValue" cascade="persist, save-update, merge, evict, replicate, refresh" + id-type="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVGenericIDUserType" + meta-type="string"> + <column not-null="false" unique="false" name="`reftype`" /> + <column not-null="false" unique="false" name="`refid`" /> + </any> + + <any name="containedReferenceValue" + cascade="persist, save-update, merge, delete, evict, replicate, refresh" + id-type="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVGenericIDUserType" + meta-type="string"> + <column not-null="false" unique="false" name="`conreftype`" /> + <column not-null="false" unique="false" name="`conrefid`" /> + </any> + </subclass> + <subclass + name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVSingleNonContainmentEReferenceValueHolder" + entity-name="EAVSingleNonContainmentEReferenceValueHolder" abstract="false" + lazy="false" extends="EAV_Value" discriminator-value="EAVSingleNonContainmentEReferenceValueHolder"> + + <tuplizer entity-mode="pojo" + class="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVTuplizer" /> + + <any name="referenceValue" cascade="persist, save-update, merge, evict, replicate, refresh" + id-type="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVGenericIDUserType" + meta-type="string"> + <column not-null="false" unique="false" name="`reftype`" /> + <column not-null="false" unique="false" name="`refid`" /> + </any> + + <!-- + this many-to-one is added to support efficient querying in case an object is an eav object + foreign key to none prevents a foreign key, hibernate does not do cascade delete in the correct order sometimes + the foreign key to none is save as the value is the same as for the referencevalue + NOTE: this many-to-one must be declared after the referencevalue tag above to hint to Hibernate + what the correct proxy is to use. If the order is turned around hibernate will add all proxy interfaces (of all classes to the + hibernate proxy + --> + <many-to-one name="eavObjectReference" entity-name="EAV_EObject" cascade="persist, save-update, merge, evict, replicate, refresh" foreign-key="none"/> + + </subclass> + <subclass + name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVSingleContainmentEReferenceValueHolder" + entity-name="EAVSingleContainmentEReferenceValueHolder" abstract="false" + lazy="false" extends="EAV_Value" discriminator-value="EAVSingleContainmentEReferenceValueHolder"> + + <tuplizer entity-mode="pojo" + class="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVTuplizer" /> + + <any name="referenceValue" + cascade="persist, merge, save-update, evict, delete, replicate, refresh" + id-type="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVGenericIDUserType" + meta-type="string"> + <column not-null="false" unique="false" name="`conreftype`" /> + <column not-null="false" unique="false" name="`conrefid`" /> + </any> + + <!-- + this many-to-one is added to support efficient querying in case an object is an eav object + foreign key to none prevents a foreign key, hibernate does not do cascade delete in the correct order sometimes + the foreign key to none is save as the value is the same as for the referencevalue + NOTE: this many-to-one must be declared after the referencevalue tag above to hint to Hibernate + what the correct proxy is to use. If the order is turned around hibernate will add all proxy interfaces (of all classes to the + hibernate proxy + --> + <many-to-one name="eavObjectReference" entity-name="EAV_EObject" cascade="all" foreign-key="none"/> + + </subclass> + <subclass + name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVMultiContainmentEReferenceValueHolder" + entity-name="EAVMultiContainmentEReferenceValueHolder" abstract="false" + lazy="false" extends="EAV_Value" discriminator-value="EAVMultiContainmentEReferenceValueHolder"> + + <tuplizer entity-mode="pojo" + class="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVTuplizer" /> + + <list name="referenceValues" lazy="true" + cascade="all,delete-orphan" inverse="true"> + <key update="true"> + <column name="`valueowner`" not-null="false" unique="false" /> + </key> + <list-index column="`listindex`" /> + <one-to-many entity-name="EAVSingleContainmentEReferenceValueHolder" /> + </list> + </subclass> + <subclass + name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVExtraMultiContainmentEReferenceValueHolder" + entity-name="EAVExtraMultiContainmentEReferenceValueHolder" abstract="false" + lazy="false" extends="EAV_Value" discriminator-value="EAVExtraMultiContainmentEReferenceValueHolder"> + + <tuplizer entity-mode="pojo" + class="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVTuplizer" /> + + <list name="referenceValues" lazy="extra" + cascade="all,delete-orphan" inverse="true"> + <key update="true"> + <column name="`valueowner`" not-null="false" unique="false" /> + </key> + <list-index column="`listindex`" /> + <one-to-many entity-name="EAVSingleContainmentEReferenceValueHolder" /> + </list> + </subclass> + <subclass + name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVMultiNonContainmentEReferenceValueHolder" + entity-name="EAVMultiNonContainmentEReferenceValueHolder" abstract="false" + lazy="false" extends="EAV_Value" discriminator-value="EAVMultiNonContainmentEReferenceValueHolder"> + + <tuplizer entity-mode="pojo" + class="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVTuplizer" /> + + <list name="referenceValues" lazy="true" + cascade="all,delete-orphan" inverse="true"> + <key update="true"> + <column name="`valueowner`" not-null="false" unique="false" /> + </key> + <list-index column="`listindex`" /> + <one-to-many entity-name="EAVSingleNonContainmentEReferenceValueHolder" /> + </list> + </subclass> + <subclass + name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVExtraMultiNonContainmentEReferenceValueHolder" + entity-name="EAVExtraMultiNonContainmentEReferenceValueHolder" abstract="false" + lazy="false" extends="EAV_Value" discriminator-value="EAVExtraMultiNonContainmentEReferenceValueHolder"> + + <tuplizer entity-mode="pojo" + class="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVTuplizer" /> + + <list name="referenceValues" lazy="extra" + cascade="all,delete-orphan" inverse="true"> + <key update="true"> + <column name="`valueowner`" not-null="false" unique="false" /> + </key> + <list-index column="`listindex`" /> + <one-to-many entity-name="EAVSingleNonContainmentEReferenceValueHolder" /> + </list> + </subclass> + <class name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVBlobValue" + entity-name="EAV_Blob" abstract="true" lazy="false" table="`{tableprefix}eavblob`"> + + <id type="long" name="id" column="`eavid`"> + <generator class="native" /> + </id> + <version name="version" column="`eavversion`" /> + <property name="blobValue" type="binary" column="`blobvalue`" + length="10000" /> + + <many-to-one name="valueHolder" entity-name="EAVSingleEAttributeValueHolder" + column="`valueholder`" unique="true" not-null="true" /> + + </class> + <class name="org.eclipse.emf.teneo.hibernate.mapping.eav.EAVTextValue" + entity-name="EAV_Text" abstract="true" lazy="false" table="`{tableprefix}eavtext`"> + + <id type="long" name="id" column="`eavid`"> + <generator class="native" /> + </id> + <version name="version" column="`eavversion`" /> + <property name="textValue" type="text" column="`textvalue`" + length="10000" /> + + <many-to-one name="valueHolder" entity-name="EAVSingleEAttributeValueHolder" + column="`valueholder`" unique="true" not-null="true" /> + + </class> + +</hibernate-mapping>
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerAccessor.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerAccessor.java new file mode 100755 index 000000000..65da5f6c9 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerAccessor.java @@ -0,0 +1,68 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EContainerAccessor.java,v 1.6 2010/02/04 10:53:07 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.econtainer; + +import org.eclipse.emf.teneo.extension.ExtensionManager; +import org.eclipse.emf.teneo.extension.ExtensionManagerAware; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * Creates the getter and setter for eContainer members. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.6 $ + */ +public class EContainerAccessor implements PropertyAccessor, ExtensionPoint, ExtensionManagerAware { + + private ExtensionManager extensionManager; + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) throws PropertyNotFoundException { + final EContainerPropertyHandler handler = extensionManager.getExtension(EContainerPropertyHandler.class); + handler.initialize(propertyName); + return handler; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) throws PropertyNotFoundException { + final EContainerPropertyHandler handler = extensionManager.getExtension(EContainerPropertyHandler.class); + handler.initialize(propertyName); + return handler; + } + + /** + * @param extensionManager + * the extensionManager to set + */ + public void setExtensionManager(ExtensionManager extensionManager) { + this.extensionManager = extensionManager; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerFeatureIDAccessor.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerFeatureIDAccessor.java new file mode 100755 index 000000000..fbc6a7a31 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerFeatureIDAccessor.java @@ -0,0 +1,71 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EContainerFeatureIDAccessor.java,v 1.6 2010/02/04 10:53:07 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.econtainer; + +import org.eclipse.emf.teneo.extension.ExtensionManager; +import org.eclipse.emf.teneo.extension.ExtensionManagerAware; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * Creates the getter and setter for eContainerFeatureID members. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.6 $ + */ +public class EContainerFeatureIDAccessor implements PropertyAccessor, ExtensionPoint, ExtensionManagerAware { + + private ExtensionManager extensionManager; + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) throws PropertyNotFoundException { + final EContainerFeatureIDPropertyHandler handler = + extensionManager.getExtension(EContainerFeatureIDPropertyHandler.class); + handler.initialize(propertyName); + return handler; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) throws PropertyNotFoundException { + final EContainerFeatureIDPropertyHandler handler = + extensionManager.getExtension(EContainerFeatureIDPropertyHandler.class); + handler.initialize(propertyName); + return handler; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.teneo.extension.ExtensionManagerAware#setExtensionManager(org.eclipse.emf.teneo.extension.ExtensionManager) + */ + public void setExtensionManager(ExtensionManager extensionManager) { + this.extensionManager = extensionManager; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerFeatureIDPropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerFeatureIDPropertyHandler.java new file mode 100755 index 000000000..2f813c7d0 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerFeatureIDPropertyHandler.java @@ -0,0 +1,147 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EContainerFeatureIDPropertyHandler.java,v 1.10 2010/11/11 10:28:18 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.econtainer; + +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.impl.BasicEObjectImpl; +import org.eclipse.emf.ecore.impl.EObjectImpl; +import org.eclipse.emf.ecore.impl.MinimalEObjectImpl; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.util.FieldUtil; +import org.hibernate.HibernateException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.Setter; + +/** + * Implements the setter for the eContainerFeatureID member of an EObject. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.10 $ + */ +public class EContainerFeatureIDPropertyHandler implements Getter, Setter, + ExtensionPoint { + /** + * Generated Serial ID + */ + private static final long serialVersionUID = -7360171596936226424L; + + /** The logger */ + private static Log log = LogFactory + .getLog(EContainerFeatureIDPropertyHandler.class); + + /** The javafield of the eContainer */ + private Field ecField; + + /** Constructor */ + public void initialize(String field) { + ecField = FieldUtil.getField(EObjectImpl.class, "eContainerFeatureID"); + log.debug("Created eContainerFeatureID handler"); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#set(java.lang.Object, + * java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + if (target instanceof MinimalEObjectImpl) { + // TODO: externalize this + FieldUtil.callMethod(target, "eBasicSetContainerFeatureID", + new Object[] { value }); + } else { + assert (target instanceof EObjectImpl); + assert (value instanceof Integer); + try { + ecField.set(target, value); + } catch (Exception e) { + throw new HbMapperException( + "Exception when setting eContainerFeatureID for: " + + target.getClass().getName() + " to value: " + + value, e); + } + } + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#get(java.lang.Object) + */ + public Object get(Object owner) throws HibernateException { + return new Integer(((BasicEObjectImpl) owner).eContainerFeatureID()); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getForInsert(java.lang.Object, + * java.util.Map, org.hibernate.engine.SessionImplementor) + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object owner, Map mergeMap, + SessionImplementor session) throws HibernateException { + return new Integer(((BasicEObjectImpl) owner).eContainerFeatureID()); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getReturnType() + */ + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return Integer.class; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerFeatureIDUserType.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerFeatureIDUserType.java new file mode 100644 index 000000000..ef7074c0c --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerFeatureIDUserType.java @@ -0,0 +1,228 @@ +package org.eclipse.emf.teneo.hibernate.mapping.econtainer; + +/** + * <copyright> + * + * Copyright (c) 2009 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 + * Jan Haesli - solution for equals test on feature holder + * </copyright> + * + * $Id: EContainerFeatureIDUserType.java,v 1.5 2010/05/02 14:24:11 mtaal Exp $ + */ + +import java.io.Serializable; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.teneo.PackageRegistryProvider; +import org.hibernate.HibernateException; +import org.hibernate.usertype.UserType; + +/** + * Persists an EContainerFeatureID as a varchar which contains both the EClass of the container as the complete + * reference to the EFeature. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.5 $ $Date: 2010/05/02 14:24:11 $ + */ + +public class EContainerFeatureIDUserType implements UserType { + + private static final int[] SQL_TYPES = new int[] { Types.VARCHAR }; + private static final String SEPARATOR = "_;_"; + + public static String convertEContainerRelationToString(EClass eClass, EStructuralFeature eFeature) { + StringBuilder result = new StringBuilder(); + { + final String uri = eClass.getEPackage().getNsURI(); + final String eClassifierName = eClass.getName(); + result.append(uri + SEPARATOR + eClassifierName); + } + + { + final String uri = eFeature.getEContainingClass().getEPackage().getNsURI(); + final String eClassName = eFeature.getEContainingClass().getName(); + final String eFeatureName = eFeature.getName(); + result.append(SEPARATOR + uri + SEPARATOR + eClassName + SEPARATOR + eFeatureName); + } + return result.toString(); + } + + private EPackage.Registry registry; + + public EContainerFeatureIDUserType() { + registry = PackageRegistryProvider.getInstance().getPackageRegistry(); + } + + public Object assemble(Serializable cached, Object owner) throws HibernateException { + final EContainerFeatureIDHolder holder = new EContainerFeatureIDHolder(); + holder.convertFromString((String) cached, registry); + return holder; + } + + public Object deepCopy(Object value) throws HibernateException { + return value; + } + + public Serializable disassemble(Object value) throws HibernateException { + if (value == null) { + return null; + } + return ((EContainerFeatureIDHolder) value).convertToString(); + } + + public boolean equals(Object x, Object y) throws HibernateException { + if (x == null && y == null) { + return true; + } + + if (x == null || y == null) { + return false; + } + + if (x.getClass() != y.getClass()) { + return false; + } + return x.equals(y); + } + + public int hashCode(Object x) throws HibernateException { + return x.hashCode(); + } + + public boolean isMutable() { + return false; + } + + public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + final String value = rs.getString(names[0]); + if (rs.wasNull()) { + return null; + } + final EContainerFeatureIDHolder holder = new EContainerFeatureIDHolder(); + holder.convertFromString(value, registry); + return holder; + } + + public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + if (value == null) { + st.setNull(index, Types.VARCHAR); + } else { + st.setString(index, ((EContainerFeatureIDHolder) value).convertToString()); + } + } + + public Object replace(Object original, Object target, Object owner) throws HibernateException { + return original; + } + + public Class<?> returnedClass() { + return EStructuralFeature.class; + } + + public int[] sqlTypes() { + return SQL_TYPES; + } + + public static class EContainerFeatureIDHolder { + private EClass eClass; + private EStructuralFeature eFeature; + + /** + * @return the eFeature + */ + public EStructuralFeature getEFeature() { + return eFeature; + } + + /** + * @param feature + * the eFeature to set + */ + public void setEFeature(EStructuralFeature feature) { + eFeature = feature; + } + + public void convertFromString(String value, EPackage.Registry theRegistry) { + final String[] values = value.split(SEPARATOR); + final String nsuri = values[0]; + final EPackage eContainerPackage = theRegistry.getEPackage(nsuri); + final String eContainerEClassName = values[1]; + eClass = (EClass) eContainerPackage.getEClassifier(eContainerEClassName); + + final EPackage eFeaturePackage = theRegistry.getEPackage(values[2]); + + final String eClassifierName = values[3]; + final EClassifier eClassifier = eFeaturePackage.getEClassifier(eClassifierName); + final EClass eClass = (EClass) eClassifier; + final String eFeatureName = values[4]; + eFeature = eClass.getEStructuralFeature(eFeatureName); + } + + public String convertToString() { + return convertEContainerRelationToString(eClass, eFeature); + } + + /** + * @return the eClass + */ + public EClass getEClass() { + return eClass; + } + + /** + * @param class1 + * the eClass to set + */ + public void setEClass(EClass class1) { + eClass = class1; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((eClass == null) ? 0 : eClass.hashCode()); + result = prime * result + ((eFeature == null) ? 0 : eFeature.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + EContainerFeatureIDHolder other = (EContainerFeatureIDHolder) obj; + if (eClass == null && other.eClass != null) { + return false; + } else if (!eClass.equals(other.eClass)) { + return false; + } + if (eFeature == null && other.eFeature != null) { + return false; + } else if (!eFeature.equals(other.eFeature)) { + return false; + } + return true; + } + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerPropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerPropertyHandler.java new file mode 100755 index 000000000..6de96cad7 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerPropertyHandler.java @@ -0,0 +1,148 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EContainerPropertyHandler.java,v 1.10 2010/11/11 10:28:18 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.econtainer; + +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.impl.EObjectImpl; +import org.eclipse.emf.ecore.impl.MinimalEObjectImpl; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.util.AssertUtil; +import org.eclipse.emf.teneo.util.FieldUtil; +import org.hibernate.HibernateException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.Setter; + +/** + * Implements the accessor for eContainer member + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.10 $ + */ + +public class EContainerPropertyHandler implements Getter, Setter, + ExtensionPoint { + /** + * Generated Serial Version UID + */ + private static final long serialVersionUID = -414024662032391298L; + + /** The logger */ + private static Log log = LogFactory.getLog(EContainerPropertyHandler.class); + + /** The javafield of the eContainer */ + private Field ecField; + + /** Constructor */ + public void initialize(String field) { + log.debug("Created eContainer property handler"); + ecField = FieldUtil.getField(EObjectImpl.class, "eContainer"); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#get(java.lang.Object) + */ + public Object get(Object owner) throws HibernateException { + return ((EObject) owner).eContainer(); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getForInsert(java.lang.Object, + * java.util.Map, org.hibernate.engine.SessionImplementor) + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object owner, Map mergeMap, + SessionImplementor session) throws HibernateException { + return ((EObject) owner).eContainer(); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#set(java.lang.Object, + * java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + if (target instanceof MinimalEObjectImpl) { + // TODO: externalize this + FieldUtil.callMethod(target, "eBasicSetContainer", + new Object[] { value }); + } else { + AssertUtil.assertInstanceOfNotNull(target, InternalEObject.class); + AssertUtil.assertInstanceOf(value, EObject.class); + try { + ecField.set(target, value); + } catch (Exception e) { + throw new HbMapperException( + "Exception when setting econtainer for: " + + target.getClass().getName() + " to value: " + + value, e); + } + } + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getReturnType() + */ + public Class<?> getReturnType() { + return EObject.class; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerUserType.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerUserType.java new file mode 100755 index 000000000..700f86cdb --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/EContainerUserType.java @@ -0,0 +1,549 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EContainerUserType.java,v 1.13 2010/11/12 09:33:33 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.econtainer; + +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Hashtable; +import java.util.Map; + +import org.dom4j.Node; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.teneo.classloader.ClassLoaderResolver; +import org.eclipse.emf.teneo.classloader.StoreClassLoadException; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierCacheHandler; +import org.hibernate.EntityMode; +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.TransientObjectException; +import org.hibernate.engine.ForeignKeys; +import org.hibernate.engine.Mapping; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.impl.SessionImpl; +import org.hibernate.persister.entity.Joinable; +import org.hibernate.type.AbstractStandardBasicType; +import org.hibernate.type.AbstractType; +import org.hibernate.type.AssociationType; +import org.hibernate.type.ForeignKeyDirection; +import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.Type; +import org.hibernate.usertype.CompositeUserType; + +/** + * Implements the EMF UserType for an Enum + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.13 $ $Date: 2010/11/12 09:33:33 $ + */ + +public class EContainerUserType extends AbstractType implements + CompositeUserType, AssociationType { + /** + * Serial version id + */ + private static final long serialVersionUID = 6385066726834417274L; + + /** Separator used in encoding the class name and value */ + private static final String ENCODING_SEPARATOR = ";"; + + /** The property names */ + private static final String[] propertyNames = new String[] { + "containerclass", "containerid" }; + + /** The property types (two strings) */ + private static final Type[] propertyTypes = new Type[] { + StandardBasicTypes.STRING, StandardBasicTypes.STRING }; + + /** The sql types */ + private static final int[] sqlTypes = new int[] { Types.VARCHAR, + Types.VARCHAR }; + + /** HashTable with cached constructors */ + private final Hashtable<String, Constructor<?>> constructorCache = new Hashtable<String, Constructor<?>>(); + + /** HashTable with identifier types hashed by entityname */ + private final Hashtable<String, Type> identifierTypeCache = new Hashtable<String, Type>(); + + /** + * Abstract method from super class, currently does not really print + * anything meaningfull + */ + public String toLoggableString(Object value, + SessionFactoryImplementor factory) throws HibernateException { + return (value != null ? "EContainer: " + value.getClass().getName() + : "EContainer null value"); + } + + /** The generic class returned (nl. Object) */ + public Class<?> getReturnedClass() { + return Object.class; + } + + /** Just returns passed value */ + public Object deepCopy(Object value, EntityMode entityMode, + SessionFactoryImplementor factory) throws HibernateException { + return value; + } + + /** Not supported */ + public Object fromXMLNode(Node xml, Mapping factory) + throws HibernateException { + throw new UnsupportedOperationException("not supported for econtainer"); + } + + /** Two columns */ + public int getColumnSpan(Mapping mapping) throws MappingException { + return 2; + } + + /** A name */ + public String getName() { + return "econtainer"; + } + + /** Does nothing */ + public boolean isDirty(Object old, Object current, boolean[] checkable, + SessionImplementor session) throws HibernateException { + return isDirty(old, current, session); + } + + /** Not supported */ + public Object nullSafeGet(ResultSet rs, String name, + SessionImplementor session, Object owner) + throws HibernateException, SQLException { + throw new UnsupportedOperationException("not supported for econtainer"); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.type.Type#nullSafeSet(java.sql.PreparedStatement, + * java.lang.Object, int, boolean[], + * org.hibernate.engine.SessionImplementor) + */ + public void nullSafeSet(PreparedStatement st, Object value, int index, + boolean[] settable, SessionImplementor session) + throws HibernateException, SQLException { + // TODO Auto-generated method stub + if (settable == null || settable[0]) { + nullSafeSet(st, value, index, session); + } + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.type.Type#replace(java.lang.Object, java.lang.Object, + * org.hibernate.engine.SessionImplementor, java.lang.Object, java.util.Map) + */ + @SuppressWarnings("rawtypes") + public Object replace(Object original, Object target, + SessionImplementor session, Object owner, Map copyCache) + throws HibernateException { + return replace(original, target, session, owner); + } + + /** Not supported */ + public void setToXMLNode(Node node, Object value, + SessionFactoryImplementor factory) throws HibernateException { + throw new UnsupportedOperationException("not supported for econtainer"); + } + + /** Two varchars */ + public int[] sqlTypes(Mapping mapping) throws MappingException { + return sqlTypes; + } + + /** + * Returns array of boolean denoting which columns are null when the value + * is null + */ + public boolean[] toColumnNullness(Object value, Mapping mapping) { + boolean[] result = new boolean[getColumnSpan(mapping)]; + if (value != null) { + for (int i = 0; i < result.length; i++) { + result[i] = true; + } + } + return result; + } + + /** + * True as this is very similar to anytype, needed to return true because + * otherwise Hibernate would not recognize that the container object should + * be saved before this object and saving transient instance was called. + */ + @Override + public boolean isAnyType() { + return true; + } + + /** + * Methods from + * + * /** Reference to other object so true + */ + @Override + public boolean isAssociationType() { + return true; + } + + /** And consists of multiple other objects */ + @Override + public boolean isComponentType() { + return false; + } + + /** Not supported */ + public String getAssociatedEntityName(SessionFactoryImplementor factory) + throws MappingException { + throw new UnsupportedOperationException( + "Econtainer type is a generic type, no specific associated entity"); + } + + /** Not supported */ + public Joinable getAssociatedJoinable(SessionFactoryImplementor factory) + throws MappingException { + throw new UnsupportedOperationException( + "Econtainer type is a generic type, no specific associated entity"); + } + + /** From parent */ + public ForeignKeyDirection getForeignKeyDirection() { + return ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT; + } + + /** Returns null */ + public String getLHSPropertyName() { + return null; + } + + /** Not supported */ + @SuppressWarnings("rawtypes") + public String getOnCondition(String alias, + SessionFactoryImplementor factory, Map enabledFilters) + throws MappingException { + throw new UnsupportedOperationException("not supported for econtainer"); + } + + /** Returns null */ + public String getRHSUniqueKeyPropertyName() { + return null; + } + + /** False */ + public boolean isAlwaysDirtyChecked() { + return false; + } + + /** False */ + public boolean isEmbeddedInXML() { + return false; + } + + /** False */ + public boolean useLHSPrimaryKey() { + return false; + } + + /** Does nothing */ + public Object deepCopy(Object value) throws HibernateException { + return value; + } + + /** Is equal, does object equality? */ + public boolean equals(Object x, Object y) throws HibernateException { + return x == y; + } + + /** Just returns the hashcode of the passed object */ + public int hashCode(Object x) throws HibernateException { + return x.hashCode(); + } + + /** Not mutable */ + public boolean isMutable() { + return false; + } + + /** Can be any object */ + public Class<?> returnedClass() { + return Object.class; + } + + /** + * Translates the serialized cached object to a real object + */ + @Override + public Object assemble(Serializable cached, SessionImplementor session, + Object owner) throws HibernateException { + + // palash: fix for ALL our teneo/ehcache woes!! + // if cache is null, just return null, without guessing; hibernate is + // smart enough to fetch it from the db + if (cached == null) { + return null; + } + + // already correct + if (!(cached instanceof ContainerPointer)) { + final String entityName = session.bestGuessEntityName(cached); + final Serializable idObject = getID(entityName, cached, session); + return session.internalLoad(entityName, idObject, false, false); + } else { + final ContainerPointer cp = (ContainerPointer) cached; + return cp.getObject(session); + } + } + + /** Create a containerpointer */ + public Serializable disassemble(Object value, SessionImplementor session) + throws HibernateException { + if (value == null) { + return null; + } + try { + final String entityName = session.bestGuessEntityName(value); + final Object idObject = getID(entityName, value, session); + return new ContainerPointer(getIdentifierType(entityName, session), + entityName, idObject.toString()); + } catch (TransientObjectException toe) { + return null; + } + } + + @Override + public Serializable disassemble(Object value, SessionImplementor session, + Object owner) throws HibernateException { + return disassemble(value, session); + } + + /** Propertynames: containerclass, containerid */ + public String[] getPropertyNames() { + return propertyNames; + } + + /** The propertyTypes */ + public Type[] getPropertyTypes() { + return propertyTypes; + } + + /** Not supported */ + public Object getPropertyValue(Object component, int property) + throws HibernateException { + final Object container = ((InternalEObject) component).eContainer(); + if (container == null) { + return null; + } + + if (property == 0) { + return container.getClass().getName(); + } + if (property == 1) { + return IdentifierCacheHandler.getInstance().getID(container); + } + + throw new HbMapperException("Property: " + property + + " not supported in " + component.getClass().getName()); + } + + /** Load the object on the basis of the data in the resultset */ + public Object nullSafeGet(ResultSet rs, String[] names, + SessionImplementor session, Object owner) + throws HibernateException, SQLException { + final String cc = rs.getString(names[0]); // container class + if (cc == null) { + return null; + } + final String idStr = rs.getString(names[1]); + if (idStr == null) { + return null; + } + + final Object obj = session.internalLoad(cc, + extractID(getIdentifierType(cc, session), idStr), false, false); + return obj; + } + + /** Set the data in the resultset */ + public void nullSafeSet(PreparedStatement st, Object value, int index, + SessionImplementor session) throws HibernateException, SQLException { + if (value == null) { + st.setNull(index, Types.VARCHAR); + st.setNull(index + 1, Types.VARCHAR); + } else { + // EObject eobj = (EObject) value; + final String ename = session.bestGuessEntityName(value); + st.setString(index, ename); + st.setString( + index + 1, + createIDString(getIdentifierType(ename, session), + getID(ename, value, session))); + } + } + + /** + * Returns the identifiertype on the basis of the class of the passed object + */ + private Type getIdentifierType(String entityName, SessionImplementor session) { + Type type = identifierTypeCache.get(entityName); + if (type != null) { + return type; + } + + final Type identifierType = ((SessionImpl) session).getFactory() + .getClassMetadata(entityName).getIdentifierType(); + identifierTypeCache.put(entityName, identifierType); + return identifierType; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.usertype.CompositeUserType#replace(java.lang.Object, + * java.lang.Object, org.hibernate.engine.SessionImplementor, + * java.lang.Object) + */ + public Object replace(Object original, Object target, + SessionImplementor session, Object owner) throws HibernateException { + if (original == null) { + return null; + } + final String ename = session.bestGuessEntityName(original); + final Serializable id = getID(ename, original, session); + return session.internalLoad(ename, id, false, false); + } + + /** Returns the id of the passed object */ + private Serializable getID(String entityName, Object value, + SessionImplementor session) { + Serializable result = ForeignKeys.getEntityIdentifierIfNotUnsaved( + entityName, value, session); + + if (result != null) { + return result; + } + return (Serializable) IdentifierCacheHandler.getInstance().getID(value); + } + + /** + * (non-Javadoc) + * + * @see org.hibernate.usertype.CompositeUserType#setPropertyValue(java.lang.Object, + * int, java.lang.Object) + */ + public void setPropertyValue(Object component, int property, Object value) + throws HibernateException { + // do nothing and hope for the best + } + + /** Creates the serializable id object from a string */ + private Serializable extractID(Type type, String idString) { + // first handle the most common case + if (type instanceof AbstractStandardBasicType) { + final AbstractStandardBasicType<?> ntype = (AbstractStandardBasicType<?>) type; + return (Serializable) ntype.fromStringValue(idString); + } + + // for all other cases the classname is encoded into the field + final String className = idString.substring(0, + idString.indexOf(ENCODING_SEPARATOR)); + final String strValue = idString.substring(1 + idString + .indexOf(ENCODING_SEPARATOR)); + + Constructor<?> constructor = constructorCache.get(className); + if (constructor == null) { + try { + final Class<?> clazz = ClassLoaderResolver + .classForName(className); + constructor = clazz + .getConstructor(new Class[] { String.class }); + } catch (StoreClassLoadException e) { + throw new HbMapperException("Class " + className + " not found"); + } catch (NoSuchMethodException e) { + throw new HbMapperException( + "Class " + + className + + " does not have a constructor with a String parameter!"); + } + } + if (constructor == null) { + throw new HbMapperException("Class " + className + + " does not have a constructor with a String parameter!"); + } + + try { + return (Serializable) constructor + .newInstance(new Object[] { strValue }); + } catch (InvocationTargetException e) { + throw new HbMapperException("Can not instantiate: " + className + + " using value " + strValue); + } catch (InstantiationException e) { + throw new HbMapperException("Can not instantiate: " + className + + " using value " + strValue); + } catch (IllegalAccessException e) { + throw new HbMapperException("Can not instantiate: " + className + + " using value " + strValue); + } + } + + /** Creates an id string from a serializable object */ + private String createIDString(Type type, Serializable id) { + if (type instanceof AbstractStandardBasicType) { + @SuppressWarnings("unchecked") + final AbstractStandardBasicType<Object> ntype = (AbstractStandardBasicType<Object>) type; + return ntype.toString(id); + } + + return id.getClass().getName() + ENCODING_SEPARATOR + id.toString(); + } + + /** + * Creates a type of proxy object which keeps the container class and + * container id + */ + private class ContainerPointer implements Serializable { + /** + * Serial version id + */ + private static final long serialVersionUID = -2777938032663239346L; + + /** The container class */ + private final String container; + + /** The id object */ + private final Serializable id; + + /** Constructor */ + ContainerPointer(Type type, String theContainer, String theIDStr) { + container = theContainer; + id = extractID(type, theIDStr); + } + + /** Returns the container object pointed to */ + private Object getObject(SessionImplementor session) { + return session.internalLoad(container, id, false, false); + } + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/NewEContainerFeatureIDPropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/NewEContainerFeatureIDPropertyHandler.java new file mode 100644 index 000000000..ea403a2ed --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/econtainer/NewEContainerFeatureIDPropertyHandler.java @@ -0,0 +1,168 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: NewEContainerFeatureIDPropertyHandler.java,v 1.4 2010/11/11 10:28:18 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.econtainer; + +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.impl.EObjectImpl; +import org.eclipse.emf.ecore.impl.MinimalEObjectImpl; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.mapping.econtainer.EContainerFeatureIDUserType.EContainerFeatureIDHolder; +import org.eclipse.emf.teneo.util.AssertUtil; +import org.eclipse.emf.teneo.util.FieldUtil; +import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * Handles the eContainerFeatureId field of an EObjectImpl. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.4 $ + */ + +public class NewEContainerFeatureIDPropertyHandler implements PropertyAccessor, + Getter, Setter, ExtensionPoint { + /** + * Generated Serial Version UID + */ + private static final long serialVersionUID = -414024662032391298L; + + private static Log log = LogFactory + .getLog(NewEContainerFeatureIDPropertyHandler.class); + + private Field ecField; + + public NewEContainerFeatureIDPropertyHandler() { + log.debug("Created eContainer property handler"); + ecField = FieldUtil.getField(EObjectImpl.class, "eContainerFeatureID"); + } + + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + public Object get(Object owner) throws HibernateException { + final InternalEObject eObject = (InternalEObject) owner; + if (eObject.eContainer() == null) { + return null; + } + final EContainerFeatureIDHolder holder = new EContainerFeatureIDHolder(); + holder.setEClass(eObject.eContainer().eClass()); + holder.setEFeature(eObject.eContainingFeature()); + return holder; + } + + @SuppressWarnings("rawtypes") + public Object getForInsert(Object owner, Map mergeMap, + SessionImplementor session) throws HibernateException { + return get(owner); + } + + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + AssertUtil.assertInstanceOfNotNull(target, InternalEObject.class); + AssertUtil.assertInstanceOf(value, EContainerFeatureIDHolder.class); + + if (value != null) { + EContainerFeatureIDHolder holder = (EContainerFeatureIDHolder) value; + if (target instanceof MinimalEObjectImpl) { + // TODO: externalize this + FieldUtil.callMethod( + target, + "eBasicSetContainerFeatureID", + new Object[] { getContainerFeatureId( + holder.getEClass(), (EObject) target, + holder.getEFeature()) }); + } else { + try { + ecField.set( + target, + getContainerFeatureId(holder.getEClass(), + (EObject) target, holder.getEFeature())); + } catch (Exception e) { + throw new HbMapperException( + "Exception when setting econtainer for: " + + target.getClass().getName() + + " to value: " + value, e); + } + } + } + } + + public int getContainerFeatureId(EClass containingEClass, + EObject contained, EStructuralFeature eFeature) { + if (eFeature instanceof EAttribute) { + return InternalEObject.EOPPOSITE_FEATURE_BASE + - containingEClass.getFeatureID(eFeature); + + } + final EReference eReference = (EReference) eFeature; + if (eReference.getEOpposite() != null) { + final EReference containerEReference = eReference.getEOpposite(); + return contained.eClass().getFeatureID(containerEReference); + } else { + return InternalEObject.EOPPOSITE_FEATURE_BASE + - containingEClass.getFeatureID(eReference); + } + } + + public Method getMethod() { + return null; + } + + public String getMethodName() { + return null; + } + + public Class<?> getReturnType() { + return EStructuralFeature.class; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/FeatureMapEntryComponentInstantiator.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/FeatureMapEntryComponentInstantiator.java new file mode 100644 index 000000000..7bf17783b --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/FeatureMapEntryComponentInstantiator.java @@ -0,0 +1,47 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008, 2009 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 + * </copyright> + */ + +package org.eclipse.emf.teneo.hibernate.mapping.elist; + +import java.io.Serializable; + +import org.hibernate.mapping.Component; +import org.hibernate.tuple.Instantiator; + +/** + * Instantiates feature map entries which are mapped as components. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.2 $ + */ + +public class FeatureMapEntryComponentInstantiator implements Instantiator { + private static final long serialVersionUID = -1219767393020090471L; + + public FeatureMapEntryComponentInstantiator(Component component) { + } + + public Object instantiate() { + final HibernateFeatureMapEntry fme = new HibernateFeatureMapEntry(); + return fme; + } + + public Object instantiate(Serializable id) { + return instantiate(); + } + + public boolean isInstance(Object object) { + return HibernateFeatureMapEntry.class.isInstance(object); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/FeatureMapEntryComponentTuplizer.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/FeatureMapEntryComponentTuplizer.java new file mode 100644 index 000000000..59f3c6b13 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/FeatureMapEntryComponentTuplizer.java @@ -0,0 +1,107 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: FeatureMapEntryComponentTuplizer.java,v 1.3 2010/02/04 10:53:08 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.elist; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.teneo.Constants; +import org.eclipse.emf.teneo.hibernate.HbDataStore; +import org.eclipse.emf.teneo.hibernate.HbHelper; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.mapper.HbMapperConstants; +import org.eclipse.emf.teneo.hibernate.mapping.property.WildCardAttributePropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.property.WildCardReferencePropertyHandler; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.mapping.Component; +import org.hibernate.mapping.MetaAttribute; +import org.hibernate.mapping.Property; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; +import org.hibernate.tuple.Instantiator; +import org.hibernate.tuple.component.AbstractComponentTuplizer; + +/** + * Tuplizer for feature map entries. These types are mapped using the dynamic capabilities of Hibernate. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.3 $ + */ + +public class FeatureMapEntryComponentTuplizer extends AbstractComponentTuplizer { + + private static final long serialVersionUID = 1L; + private static Log log = LogFactory.getLog(FeatureMapEntryComponentTuplizer.class); + + public FeatureMapEntryComponentTuplizer(Component component) { + super(component); + } + + protected Instantiator buildInstantiator(Component component) { + return new FeatureMapEntryComponentInstantiator(component); + } + + protected Getter buildGetter(Component component, Property prop) { + return getPropertyAccessor(prop, component).getGetter(component.getComponentClass(), prop.getName()); + } + + protected Setter buildSetter(Component component, Property prop) { + return getPropertyAccessor(prop, component).getSetter(component.getComponentClass(), prop.getName()); + } + + protected PropertyAccessor getPropertyAccessor(Property mappedProperty, Component component) { + final HbDataStore hds = HbHelper.INSTANCE.getDataStore(component.getOwner()); + if (mappedProperty.getMetaAttribute(HbMapperConstants.VERSION_META) != null) { + return hds.getHbContext().createVersionAccessor(); + } else if (mappedProperty.getName().compareToIgnoreCase(HbMapperConstants.PROPERTY_FEATURE) == 0) { + return hds.getHbContext().createFeatureMapEntryFeatureURIAccessor(); + } else if (mappedProperty.getName().compareToIgnoreCase(HbMapperConstants.PROPERTY_MIXED_CDATA) == 0) { + return hds.getHbContext().createFeatureMapEntryAccessor(Constants.CDATA); + } else if (mappedProperty.getName().compareToIgnoreCase(HbMapperConstants.PROPERTY_MIXED_COMMENT) == 0) { + return hds.getHbContext().createFeatureMapEntryAccessor(Constants.COMMENT); + } else if (mappedProperty.getName().compareToIgnoreCase(HbMapperConstants.PROPERTY_MIXED_TEXT) == 0) { + return hds.getHbContext().createFeatureMapEntryAccessor(Constants.TEXT); + } else if (mappedProperty.getName().endsWith(HbMapperConstants.PROPERTY_ANY_PRIMITIVE)) { + return hds.getExtensionManager().getExtension(WildCardAttributePropertyHandler.class); + } else if (mappedProperty.getName().endsWith(HbMapperConstants.PROPERTY_ANY_REFERENCE)) { + return hds.getExtensionManager().getExtension(WildCardReferencePropertyHandler.class); + } + + final MetaAttribute ma = component.getMetaAttribute(HbMapperConstants.FEATUREMAP_META); + final String eclassUri = ma.getValue(); + final EClass eClass = hds.getEntityNameStrategy().toEClass(eclassUri); + final EStructuralFeature efeature = StoreUtil.getEStructuralFeature(eClass, mappedProperty.getName()); + + if (efeature == null) { + throw new HbMapperException("Feature not found for property " + mappedProperty.getName()); + } + + if (log.isDebugEnabled()) { + log.debug("Creating property accessor for " + mappedProperty.getName() + "/" + eclassUri + "/" + + efeature.getName()); + } + + return hds.getHbContext().createFeatureMapEntryAccessor(efeature); + } + + @SuppressWarnings("rawtypes") + public Class getMappedClass() { + return HibernateFeatureMapEntry.class; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/FeatureMapEntryInstantiator.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/FeatureMapEntryInstantiator.java new file mode 100755 index 000000000..6c4e56d23 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/FeatureMapEntryInstantiator.java @@ -0,0 +1,79 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: FeatureMapEntryInstantiator.java,v 1.5 2008/02/28 07:08:24 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.elist; + +import java.io.Serializable; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.teneo.hibernate.mapper.HbMapperConstants; +import org.eclipse.emf.teneo.util.AssertUtil; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.tuple.Instantiator; + +/** + * Instantiates feature map entries. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.5 $ + */ + +public class FeatureMapEntryInstantiator implements Instantiator { + + /** + * Serial Version ID + */ + private static final long serialVersionUID = -1219767393020090471L; + + /** The logger */ + private static Log log = LogFactory + .getLog(FeatureMapEntryInstantiator.class); + + /** The persistentclass for which we do all this */ + private final PersistentClass persistentClass; + + /** The proxy interface if used */ + private final Class<?> proxyInterface; + + /** Constructor */ + public FeatureMapEntryInstantiator(PersistentClass pc) { + AssertUtil.assertTrue(pc.getEntityName() + + " does not have a meta attribute", pc + .getMetaAttribute(HbMapperConstants.FEATUREMAP_META) != null); + log.debug("Creating fme instantiator for " + pc.getEntityName()); + proxyInterface = pc.getProxyInterface(); + persistentClass = pc; + } + + /** Instantiates using the EFactory */ + public Object instantiate() { + final HibernateFeatureMapEntry fme = new HibernateFeatureMapEntry(); + fme.setEntityName(persistentClass.getEntityName()); + return fme; + } + + /** Instantiates using the EFactory */ + public Object instantiate(Serializable id) { + return instantiate(); + } + + /** Checks using the mapped class or the proxy interface */ + public boolean isInstance(Object object) { + return HibernateFeatureMapEntry.class.isInstance(object) + || (proxyInterface != null && proxyInterface.isInstance(object)); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/FeatureMapEntryTuplizer.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/FeatureMapEntryTuplizer.java new file mode 100755 index 000000000..39ffca94e --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/FeatureMapEntryTuplizer.java @@ -0,0 +1,119 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: FeatureMapEntryTuplizer.java,v 1.15 2009/06/28 02:04:54 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.elist; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.teneo.Constants; +import org.eclipse.emf.teneo.hibernate.HbDataStore; +import org.eclipse.emf.teneo.hibernate.HbHelper; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.HbUtil; +import org.eclipse.emf.teneo.hibernate.mapper.HbMapperConstants; +import org.eclipse.emf.teneo.hibernate.mapping.property.WildCardAttributePropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.property.WildCardReferencePropertyHandler; +import org.eclipse.emf.teneo.hibernate.tuplizer.EMFTuplizer; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.tuple.Instantiator; +import org.hibernate.tuple.entity.EntityMetamodel; + +/** + * Tuplizer for feature map entries. These types are mapped using the dynamic capabilities of Hibernate. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.15 $ + */ + +public class FeatureMapEntryTuplizer extends EMFTuplizer { + + /** The logger */ + private static Log log = LogFactory.getLog(FeatureMapEntryTuplizer.class); + + /** Constructor */ + public FeatureMapEntryTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) { + super(entityMetamodel, mappedEntity); + } + + /** Creates an EMF Instantiator */ + @Override + protected Instantiator buildInstantiator(PersistentClass persistentClass) { + return new FeatureMapEntryInstantiator(persistentClass); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.EntityTuplizer#getConcreteProxyClass() + */ + @Override + public Class<?> getConcreteProxyClass() { + return EObject.class; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.Tuplizer#getMappedClass() + */ + @Override + public Class<?> getMappedClass() { + return EObject.class; + } + + /** Returns the correct accessor on the basis of the type of property */ + @Override + protected PropertyAccessor getPropertyAccessor(Property mappedProperty, PersistentClass pc) { + final HbDataStore hds = HbHelper.INSTANCE.getDataStore(pc); + if (mappedProperty.getMetaAttribute(HbMapperConstants.VERSION_META) != null) { + return hds.getHbContext().createVersionAccessor(); + } else if (mappedProperty.getName().compareToIgnoreCase(HbMapperConstants.PROPERTY_FEATURE) == 0) { + return hds.getHbContext().createFeatureMapEntryFeatureURIAccessor(); + } else if (mappedProperty.getName().compareToIgnoreCase(HbMapperConstants.PROPERTY_MIXED_CDATA) == 0) { + return hds.getHbContext().createFeatureMapEntryAccessor(Constants.CDATA); + } else if (mappedProperty.getName().compareToIgnoreCase(HbMapperConstants.PROPERTY_MIXED_COMMENT) == 0) { + return hds.getHbContext().createFeatureMapEntryAccessor(Constants.COMMENT); + } else if (mappedProperty.getName().compareToIgnoreCase(HbMapperConstants.PROPERTY_MIXED_TEXT) == 0) { + return hds.getHbContext().createFeatureMapEntryAccessor(Constants.TEXT); + } else if (mappedProperty.getName().endsWith(HbMapperConstants.PROPERTY_ANY_PRIMITIVE)) { + return hds.getExtensionManager().getExtension(WildCardAttributePropertyHandler.class); + } else if (mappedProperty.getName().endsWith(HbMapperConstants.PROPERTY_ANY_REFERENCE)) { + return hds.getExtensionManager().getExtension(WildCardReferencePropertyHandler.class); + } + + final String eclassUri = HbUtil.getEClassNameFromFeatureMapMeta(pc); + final EClass eClass = hds.getEntityNameStrategy().toEClass(eclassUri); + final EStructuralFeature efeature = StoreUtil.getEStructuralFeature(eClass, mappedProperty.getName()); + + if (efeature == null) { + throw new HbMapperException("Feature not found for entity/property " + pc.getEntityName() + "/" + + mappedProperty.getName()); + } + + if (log.isDebugEnabled()) { + log.debug("Creating property accessor for " + mappedProperty.getName() + "/" + pc.getEntityName() + "/" + + eclassUri + "/" + efeature.getName()); + } + + return hds.getHbContext().createFeatureMapEntryAccessor(efeature); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HbExtraLazyPersistableEList.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HbExtraLazyPersistableEList.java new file mode 100755 index 000000000..305b687d6 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HbExtraLazyPersistableEList.java @@ -0,0 +1,382 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HbExtraLazyPersistableEList.java,v 1.18 2010/04/04 12:10:51 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.elist; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.teneo.EContainerRepairControl; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.LazyCollectionUtils; +import org.eclipse.emf.teneo.hibernate.SessionWrapper; +import org.eclipse.emf.teneo.hibernate.resource.HbResource; +import org.eclipse.emf.teneo.resource.StoreResource; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.Session; +import org.hibernate.collection.AbstractPersistentCollection; +import org.hibernate.collection.PersistentBag; +import org.hibernate.collection.PersistentCollection; +import org.hibernate.collection.PersistentIdentifierBag; +import org.hibernate.collection.PersistentList; + +/** + * Implements the hibernate persistable elist with extra lazy behavior, most + * operations should not load the complete list. This is targeted at very large + * lists. Note that this list can not work in a detached mode. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.18 $ + */ + +public class HbExtraLazyPersistableEList<E> extends + HibernatePersistableEList<E> implements ExtensionPoint { + + /** The logger */ + // private static Log log = + // LogFactory.getLog(HbExtraLazyPersistableEList.class); + /** + * Serial version id + */ + private static final long serialVersionUID = 5479222310361594394L; + + private boolean previousDeliverSetting = false; + + /** Constructor */ + public HbExtraLazyPersistableEList(InternalEObject owner, + EStructuralFeature feature, List<E> list) { + super(owner, feature, list); + } + + @Override + /** + * Always returns false because this prevents full loading of the list. + * Prevents checks on uniqueness. This is a small price to pay for better performance. + */ + public boolean isUnique() { + return false; + } + + // done in superclass: + // - delegateSize and delegateIsEmpty: super implementation is already extra + // lazy + // - delegateBasicList: will result in a full load + // - delegateContains and delegateContainsAll: will result in a full load + // - delegateEquals and delegatehashCode: will result in a full load + // - delegateIndexOf and delegateLastIndexOf: will result in a full load + // - delegateToArray: will result in a full load + // - delegateIterator and delegateListIterator: will result in a full load + // - delegateToString: will result in a full load + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.common.util.DelegatingEList#delegateAdd(int, + * java.lang.Object) + */ + @Override + protected void delegateAdd(int index, E object) { + if (index == size()) { + delegateAdd(object); + return; + } + + // force a load + delegateList().iterator(); + + delegateList().add(index, object); + + int newIndex = index; + for (Object element : delegateList().subList(index, size())) { + // for the new one set the owner + if (newIndex == index) { + StoreUtil.setSyntheticListOwner(getEStructuralFeature(), + element, getOwner()); + } + StoreUtil.setSyntheticListIndex(getEStructuralFeature(), element, + newIndex++); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.emf.common.util.DelegatingEList#delegateAdd(java.lang.Object) + */ + @Override + protected void delegateAdd(E object) { + int newIndex = delegateList().size(); + delegateList().add(object); + StoreUtil.setSyntheticListIndex(getEStructuralFeature(), object, + newIndex); + StoreUtil.setSyntheticListOwner(getEStructuralFeature(), object, + getOwner()); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.common.util.DelegatingEList#delegateClear() + */ + @Override + protected void delegateClear() { + for (Object element : delegateList()) { + StoreUtil.resetSyntheticListInfo(getEStructuralFeature(), element); + } + delegateList().clear(); + } + + @Override + public Iterator<E> delegateIterator() { + return iterator(); + } + + @Override + public Iterator<E> iterator() { + // return a paging iterator + return LazyCollectionUtils.getPagedLoadingIterator(this, LazyCollectionUtils.DEFAULT_PAGE_SIZE); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.emf.common.util.DelegatingEList#delegateContains(java.lang + * .Object) + */ + @Override + protected boolean delegateContains(Object object) { + return delegateList().contains(object); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.emf.common.util.DelegatingEList#delegateContainsAll(java. + * util.Collection) + */ + @Override + protected boolean delegateContainsAll(Collection<?> collection) { + return delegateList().containsAll(collection); + } + + /** Returns the underlying elist */ + @Override + protected List<E> delegateList() { + return getDelegate(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.common.util.DelegatingEList#delegateGet(int) + */ + @Override + protected E delegateGet(int index) { + boolean callAfterLoadInstance = false; + if (!isLoaded()) { + beforeLoadInstance(); + callAfterLoadInstance = true; + } + final E object = delegateList().get(index); + if (callAfterLoadInstance && object instanceof EObject) { + final EObject eObject = (EObject) object; + afterLoadInstance(eObject); + } + return object; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.common.util.DelegatingEList#delegateRemove(int) + */ + @Override + protected E delegateRemove(int index) { + if (index == (size() - 1) && !isInitialized() && isConnectedToSession()) { + // removing the last one + final E result = delegateList().remove(index); + StoreUtil.resetSyntheticListInfo(getEStructuralFeature(), result); + if (getEStructuralFeature() instanceof EReference + && ((EReference) getEStructuralFeature()).isContainment()) { + // remove the removed object + // if the list is not initialized then cascade deletes won't + // work + final Session session = (Session) ((PersistentList) getDelegate()) + .getSession(); + session.delete(result); + } + return result; + } + + // force a full load + delegateList().iterator(); + + final E result = delegateList().remove(index); + StoreUtil.resetSyntheticListInfo(getEStructuralFeature(), result); + + int newIndex = index; + for (Object element : delegateList().subList(index, size())) { + StoreUtil.setSyntheticListIndex(getEStructuralFeature(), element, + newIndex++); + } + + return result; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.common.util.DelegatingEList#delegateSet(int, + * java.lang.Object) + */ + @Override + protected E delegateSet(int index, E object) { + final E oldObject = delegateList().set(index, object); + + // clear old object + if (oldObject != null) { + StoreUtil + .resetSyntheticListInfo(getEStructuralFeature(), oldObject); + } + + // set new object + StoreUtil.setSyntheticListIndex(getEStructuralFeature(), object, index); + StoreUtil.setSyntheticListOwner(getEStructuralFeature(), object, + getOwner()); + return oldObject; + } + + /** + * Implements the actions which need to be done before getting/loading an + * instance. + */ + protected synchronized void beforeLoadInstance() { + final Resource res = owner.eResource(); + if (res != null && res instanceof HbResource) { + final SessionWrapper sessionWrapper = ((HbResource) res) + .getSessionWrapper(); + if (res.isLoaded()) // resource is loaded reopen transaction + { + // if the delegate is already loaded then no transaction is + // required + final boolean isDelegateLoaded = delegate instanceof AbstractPersistentCollection + && ((AbstractPersistentCollection) delegate) + .wasInitialized(); + if (!isDelegateLoaded && !sessionWrapper.isTransactionActive()) { + sessionWrapper.setFlushModeManual(); + } + ((StoreResource) res).setIsLoading(true); + } + } + previousDeliverSetting = owner.eDeliver(); + try { + // only set to false if it was true + if (previousDeliverSetting) { + owner.eSetDeliver(false); + } + } catch (UnsupportedOperationException e) { + // in this case the eSetDeliver was not overridden from the + // baseclass + // ignore + } + } + + protected void afterLoadInstance(EObject eObject) { + + // disabled for now as containers are persisted by hibernate + // anyway + if (isContainment() && eObject.eContainer() == null) { + EContainerRepairControl.setContainer(owner, + (InternalEObject) eObject, getEStructuralFeature()); + } + final Resource res = owner.eResource(); + if (res != null && res instanceof HbResource) { + // attach the new contained objects so that they are adapted + // when required + ((StoreResource) res).addToContentOrAttach( + (InternalEObject) eObject, + (EReference) getEStructuralFeature()); + ((StoreResource) res).setIsLoading(false); + } + + try { + // only set to false if it was true + if (previousDeliverSetting) { + owner.eSetDeliver(true); + } + } catch (UnsupportedOperationException e) { + // in this case the eSetDeliver was not overridden from the + // baseclass + // ignore + } + } + + /** If the delegate has been initialized */ + public boolean isInitialized() { + return ((PersistentCollection) delegate).wasInitialized(); + } + + /** Overridden because general list type is not supported as a replacement */ + @Override + public void replaceDelegate(List<E> newDelegate) { + if (newDelegate instanceof PersistentList) { + // disabled this assertion because in case of a session refresh it + // is possible + // that the list is replaced by a persistent list + // AssertUtil.assertTrue("This elist " + logString + " contains a + // different list than the " + + // " passed list", + // ((PersistentList)newDelegate).isWrapper(delegate)); + super.replaceDelegate(newDelegate); + } else if (newDelegate instanceof PersistentBag) { + // disabled this assertion because in case of a session refresh it + // is possible + // that the list is replaced by a persistent list + // AssertUtil.assertTrue("This elist " + logString + " contains a + // different list than the " + + // " passed list", + // ((PersistentBag)newDelegate).isWrapper(delegate)); + super.replaceDelegate(newDelegate); + } else if (newDelegate instanceof PersistentIdentifierBag) { + // Added to support <idbag> + super.replaceDelegate(newDelegate); + } else if (newDelegate == delegate) // this can occur and is okay, do + // nothing in this case + { + + } else { + throw new HbMapperException("Type " + + newDelegate.getClass().getName() + " can not be " + + " used as a replacement for elist " + logString); + } + } + + /** Returns true if the wrapped list is a persistency layer specific list */ + @Override + public boolean isPersistencyWrapped() { + return delegate instanceof PersistentCollection; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HbExtraLazyPersistableEMap.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HbExtraLazyPersistableEMap.java new file mode 100644 index 000000000..c7ebccd08 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HbExtraLazyPersistableEMap.java @@ -0,0 +1,193 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HbExtraLazyPersistableEMap.java,v 1.3 2010/08/18 11:50:38 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.elist; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.emf.common.util.BasicEMap; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.teneo.hibernate.LazyCollectionUtils; +import org.eclipse.emf.teneo.mapping.elist.PersistableEList; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.collection.AbstractPersistentCollection; +import org.hibernate.collection.PersistentList; +import org.hibernate.engine.CollectionEntry; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.persister.collection.AbstractCollectionPersister; +import org.hibernate.type.EntityType; + +/** + * Extends the default hibernate persistable emap with extra lazy behavior. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.3 $ + */ + +public class HbExtraLazyPersistableEMap<K, V> extends HibernatePersistableEMap<K, V> { + + private static final long serialVersionUID = 1L; + + /** Constructor */ + public HbExtraLazyPersistableEMap(InternalEObject owner, EReference eref, List<Entry<K, V>> list) { + super(owner, eref, list); + } + + @Override + public Iterator<java.util.Map.Entry<K, V>> iterator() { + return LazyCollectionUtils.getPagedLoadingIterator(this, LazyCollectionUtils.DEFAULT_PAGE_SIZE); + } + + @Override + public int size() { + // if we are not loaded yet, we return the size of the buffered lazy + // load delegate + + if (!isLoaded() && isHibernateListPresent()) { + try { + size = ((PersistentList)((PersistableEList<?>) delegateEList).getDelegate()).size(); + return size; + } catch (Throwable t) { + // ignore on purpose, let the call to super handle it + } + } + + // didnt work, so we simply call the parent version + return super.size(); + } + + @SuppressWarnings("unchecked") + @Override + public V get(Object key) { + // do a lazy get + if (key != null && !isLoaded() && isHibernateListPresent()) { + final Session session = getSession(); + + session.flush(); + + // create a query + final AbstractPersistentCollection collection = (AbstractPersistentCollection)getDelegate(); + final CollectionEntry collectionEntry = ((SessionImplementor)session).getPersistenceContext().getCollectionEntry(collection); + final AbstractCollectionPersister persister = (AbstractCollectionPersister)collectionEntry.getLoadedPersister(); + final String entityName = ((EntityType)persister.getCollectionMetadata().getElementType()).getAssociatedEntityName(); + final Query qry = session.createQuery("select e from " + entityName + " as e where e.key=:key and e." + StoreUtil.getExtraLazyInversePropertyName(getEStructuralFeature()) + "=:owner"); + qry.setParameter("key", key); + qry.setParameter("owner", getOwner()); + final Object result = qry.uniqueResult(); + if (result instanceof Map.Entry<?, ?>) { + final Map.Entry<K, V> entry = (Map.Entry<K, V>)result; + return entry.getValue(); + } + return null; + } + // TODO Auto-generated method stub + return super.get(key); + } + + @SuppressWarnings("unchecked") + @Override + public V put(K key, V value) { + if (!isLoaded() && isHibernateListPresent()) { + final Map.Entry<K, V> entry = (Map.Entry<K, V>)get(key); + if (entry != null && entry instanceof org.eclipse.emf.common.util.BasicEMap.Entry<?, ?>) { + V result = putEntry((org.eclipse.emf.common.util.BasicEMap.Entry<K, V>)entry, value); + didModify((org.eclipse.emf.common.util.BasicEMap.Entry<K, V>)entry, result); + return result; + } else { + // we get here, create a new one and add it to the persistablelist... + org.eclipse.emf.common.util.BasicEMap.Entry<K, V> newEntry = newEntry(hashOf(key), key, value); + delegateEList.add(newEntry); + return null; + } + } + return super.put(key, value); + } + + + /** Needs to be implemented by concrete subclass */ + @Override + protected EList<BasicEMap.Entry<K, V>> createDelegateEList(InternalEObject owner, EStructuralFeature feature, + List<BasicEMap.Entry<K, V>> delegateORMList) { + return new HbExtraLazyPersistableEList<Entry<K, V>>(owner, feature, delegateORMList) { + private static final long serialVersionUID = 1L; + + @Override + protected void didAdd(int index, Entry<K, V> newObject) { + doPut(newObject); + } + + @Override + protected void didSet(int index, Entry<K, V> newObject, Entry<K, V> oldObject) { + didRemove(index, oldObject); + didAdd(index, newObject); + } + + @Override + protected void didRemove(int index, Entry<K, V> oldObject) { + HbExtraLazyPersistableEMap.this.doRemove(oldObject); + } + + @Override + protected void didClear(int size, Object[] oldObjects) { + doClear(); + } + + @Override + protected void didMove(int index, Entry<K, V> movedObject, int oldIndex) { + HbExtraLazyPersistableEMap.this.doMove(movedObject); + } + }; + } + + + @Override + public boolean remove(Object object) { + // TODO Auto-generated method stub + return super.remove(object); + } + + @Override + public boolean removeAll(Collection<?> collection) { + // TODO Auto-generated method stub + return super.removeAll(collection); + } + + @Override + public V removeKey(Object key) { + // TODO Auto-generated method stub + return super.removeKey(key); + } + + private boolean isHibernateListPresent() { + return getDelegate() instanceof AbstractPersistentCollection; + } + + private Session getSession() { + final AbstractPersistentCollection persistentCollection = (AbstractPersistentCollection) getDelegate(); + final SessionImplementor session = ((AbstractPersistentCollection) persistentCollection) + .getSession(); + return (Session)session; + } + +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HibernateFeatureMapEntry.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HibernateFeatureMapEntry.java new file mode 100755 index 000000000..04d59a25c --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HibernateFeatureMapEntry.java @@ -0,0 +1,597 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HibernateFeatureMapEntry.java,v 1.11 2010/02/04 10:53:08 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.elist; + +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +import org.eclipse.emf.common.notify.NotificationChain; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.util.ExtendedMetaData; +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.teneo.EContainerRepairControl; +import org.eclipse.emf.teneo.util.AssertUtil; +import org.eclipse.emf.teneo.util.StoreUtil; + +/** + * Is used to replace the EMF feature map entry with an entry which can be handled by the or layer. + * + * The special feature of this entry is that all allowed features can be set, internally it keeps a list of feature + * value pairs. Only one of these pairs is the valid one, which one is determined by the value of the eStructuralFeature + * member. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.11 $ + */ + +public class HibernateFeatureMapEntry implements FeatureMap.Entry.Internal, Serializable { + + /** + * Generated serial ID + */ + private static final long serialVersionUID = 3946138277481892125L; + + /** + * Gets an 'normal' FeatureMap.Entry and if it is not a FeatureMapEntry replaces it with a specific implementation. + */ + public static HibernateFeatureMapEntry replaceEntry(Object obj, FeatureMap.Internal owningMap) { + // do special check, in case the featuremap entry does not need to be + // changed + if (obj instanceof HibernateFeatureMapEntry) { + final HibernateFeatureMapEntry fmEntry = (HibernateFeatureMapEntry) obj; + + // return the entry if it is not yet set, in this case it does not + // yet belong to a + // featuremap and can be used. This happens with a featuremap which + // has already been + // replaced. + if (!fmEntry.isFeatureMapSet() || fmEntry.belongsToFeatureMap(owningMap)) { + return fmEntry; + } + } + HibernateFeatureMapEntry entry = new HibernateFeatureMapEntry(); + entry.setEntry((FeatureMap.Entry) obj, owningMap); + return entry; + } + + /** + * Replaces standard FeatureMap.Entry with a FeatureMapEntry for a collection + */ + public static Collection<HibernateFeatureMapEntry> replaceEntryAll(Collection<FeatureMap.Entry> c, + Class<?> replaceByType, FeatureMap.Internal owningMap) { + final ArrayList<HibernateFeatureMapEntry> newEntries = new ArrayList<HibernateFeatureMapEntry>(); + final Iterator<FeatureMap.Entry> it = c.iterator(); + while (it.hasNext()) { + newEntries.add(replaceEntry(it.next(), owningMap)); + } + return newEntries; + } + + /** Creates an entry with the correct type */ + public static FeatureMap.Entry createEntry(EStructuralFeature feature, Object value, FeatureMap.Internal owningMap) { + HibernateFeatureMapEntry entry = new HibernateFeatureMapEntry(); + entry.setFeatureValue(feature, value, owningMap); + return entry; + } + + /** + * Method which creates a list of entries based on one feature and multiple values + */ + public static Collection<FeatureMap.Entry> createEntryAll(EStructuralFeature feature, Collection<?> values, + FeatureMap.Internal owningMap) { + final ArrayList<FeatureMap.Entry> entries = new ArrayList<FeatureMap.Entry>(); + final Iterator<?> it = values.iterator(); + while (it.hasNext()) { + entries.add(createEntry(feature, it.next(), owningMap)); + } + return entries; + } + + /** The structural feature which defines which element this is */ + private EStructuralFeature eStructuralFeature; + + /** To store the efeature during serialization */ + private String eFeaturePath; + + /** + * The featuremap to which we are connected. Is used to determine if entries have been added to another featuremap. + * This happens in copy actions. + */ + private FeatureMap.Internal owningMap; + + /** The feature value map */ + private ArrayList<FeatureValue> featureValues = new ArrayList<FeatureValue>(); + + // is used to hold a value temporarily until a feature is set. + private Object tempValue; + + /** + * The entity name of this entry, is filled when the object is read from the db + */ + private String entityName = null; + + /** + * Constructor called by the storage layer, fields need to be set by calls to subclass + */ + public HibernateFeatureMapEntry() { + } + + /** Sets the featuremap, is done when an entry is added to the featuremap */ + public void setFeatureMap(FeatureMap.Internal featureMap) { + owningMap = featureMap; + if (featureMap != null) { + entityName = StoreUtil.getEntityName(featureMap.getEStructuralFeature()); + } + } + + /** Unsets the featuremap, is done when an entry is removed */ + public void unsetFeatureMap() { + owningMap = null; + } + + /** Is true if this featureMap already belongs to a Map */ + public boolean isFeatureMapSet() { + return owningMap != null; + } + + /** Is true if this featureMap already belongs to the passed map */ + public boolean belongsToFeatureMap(FeatureMap.Internal fm) { + return owningMap == fm; // object equality! + } + + /** Takes care of serializing the efeature */ + private void writeObject(java.io.ObjectOutputStream out) throws IOException { + eFeaturePath = StoreUtil.structuralFeatureToString(eStructuralFeature); + eStructuralFeature = null; + out.defaultWriteObject(); + } + + /** Takes care of deserializing the efeature */ + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + eStructuralFeature = StoreUtil.stringToStructureFeature(eFeaturePath); + } + + /** Set the value from a previous entry */ + public void setEntry(FeatureMap.Entry entry, FeatureMap.Internal owningMap) { + eStructuralFeature = entry.getEStructuralFeature(); + featureValues.add(createFeatureValue(eStructuralFeature, entry.getValue())); + setFeatureMap(owningMap); + } + + /** Returns structural feature */ + public EStructuralFeature getEStructuralFeature() { + return eStructuralFeature; + } + + /** + * @param structuralFeature + * the eStructuralFeature to set + */ + private void setEStructuralFeature(EStructuralFeature structuralFeature) { + eStructuralFeature = structuralFeature; + if (tempValue != null) { + // is a string needs to be translated + final Object value = doPossibleConversion(tempValue); + addFeatureValue(eStructuralFeature, value); + tempValue = null; + } + } + + /** Return the string repr. of the feature */ + public String getFeatureURI() { + return StoreUtil.structuralFeatureToString(getEStructuralFeature()); + } + + /** Set the feature on the basis of the string */ + public void setEStructuralFeature(String featureURI) { + setEStructuralFeature(StoreUtil.stringToStructureFeature(featureURI)); + } + + /** Returns the value */ + public Object getValue() { + return getValue(getEStructuralFeature()); + } + + /** + * Add a feature value combination to the entry, only one of these values is the valid one but the other nullable + * values are stored in the db + */ + public void addFeatureValue(EStructuralFeature feature, Object value) { + // final FeatureValue fv = getFeatureValue(feature); + // if (fv != null) { + // featureValues.add(createFeatureValue(feature, value)); + // } else { + featureValues.add(createFeatureValue(feature, value)); + // } + } + + /** + * Sets a value in this feature map entry, if no eStructuralFeature is set then it is set in the tempValue until an + * estructural feature is set. This is done because it is not certain in which order hibernate calls the property + * handlers. + */ + public void setValue(Object value) { + if (getEStructuralFeature() != null) { + // is a string needs to be translated + addFeatureValue(getEStructuralFeature(), doPossibleConversion(value)); + } else { + tempValue = value; + } + } + + private Object doPossibleConversion(Object value) { + // is a string needs to be translated + if (getEStructuralFeature() instanceof EAttribute) { + final EAttribute eAttribute = (EAttribute) getEStructuralFeature(); + final EDataType eDataType = eAttribute.getEAttributeType(); + + final Object realValue = eDataType.getEPackage().getEFactoryInstance().createFromString(eDataType, + (String) value); + return realValue; + } + return value; + } + + /** Sets the exact feature value for this entry */ + public void setFeatureValue(EStructuralFeature feature, Object value, FeatureMap.Internal owningMap) { + featureValues.add(createFeatureValue(feature, value)); + setEStructuralFeature(feature); + setFeatureMap(owningMap); + } + + /** Returns the value for a specific feature */ + public Object getValue(EStructuralFeature feature) { + for (FeatureValue fv : featureValues) { + if (fv.matchesFeature(feature)) { + return fv.getValue(); + } + } + return null; // TODO: maybe throw error? + } + + /** get the real feature value */ + private FeatureValue getFeatureValue() { + final EStructuralFeature feature = getEStructuralFeature(); + + AssertUtil.assertTrue("Feature is not set", feature != null); + + for (FeatureValue fv : featureValues) { + if (fv.matchesFeature(feature)) { + return fv; + } + } + + // can not get here, see assertion above + return null; + } + + /** + * Sets the container property of the value if the value is an EObject and the feature is a containment feature. + */ + public void setContainer(InternalEObject owner) { + final Object value = getValue(); + if (value != null && value instanceof InternalEObject && eStructuralFeature instanceof EReference + && ((EReference) eStructuralFeature).isContainment()) { + EContainerRepairControl.setContainer(owner, (InternalEObject) value, eStructuralFeature); + } + } + + /** Code copied from FeatureMapUtil.EntryImpl */ + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } else if (!(that instanceof FeatureMap.Entry)) { + return false; + } else { + final FeatureMap.Entry entry = (FeatureMap.Entry) that; + final Object value = getValue(); + return entry.getEStructuralFeature() == eStructuralFeature + && (value == null ? entry.getValue() == null : value.equals(entry.getValue())); + } + } + + /** Code copied from FeatureMapUtil.EntryImpl */ + @Override + public int hashCode() { + /* + * Used to create a hashcode which maps all instances of one class to the same hashcode Is required because the + * normal hashcode method (see hashcode impl in emf EntryImpl) resulted in null-pointer exceptions in hibernate + * because the content of the entry was used for determining the hashcode while the object was not initialized + * from the db + */ + return this.getClass().hashCode(); + } + + /** Code copied from FeatureMapUtil.EntryImpl */ + @Override + public String toString() { + String prefix = eStructuralFeature.getEContainingClass().getEPackage().getNsPrefix(); + eStructuralFeature.getName(); + return (prefix != null && prefix.length() != 0 ? prefix + ":" + eStructuralFeature.getName() + : eStructuralFeature.getName()) + + "=" + getValue(); + } + + /** + * @return the entityName + */ + public String getEntityName() { + return entityName; + } + + /** + * @param entityName + * the entityName to set + */ + public void setEntityName(String entityName) { + this.entityName = entityName; + } + + /** Create the correct feature value type */ + private FeatureValue createFeatureValue(EStructuralFeature feature, Object value) { + if (feature instanceof EReference && ((EReference) feature).getEOpposite() != null) { + return new InverseFeatureValue(feature, value); + } else if (feature instanceof EReference && ((EReference) feature).isContainment()) { + return new ContainmentFeatureValue(feature, value); + } else { + return new FeatureValue(feature, value); + } + } + + /** Create a copy of this entry with a different value */ + public Internal createEntry(InternalEObject value) { + HibernateFeatureMapEntry hfm = new HibernateFeatureMapEntry(); + hfm.setFeatureValue(getEStructuralFeature(), value, owningMap); + return hfm; + } + + /** + * Create a copy of this entry with a different value, calls createEntry(InternalEObject value) + */ + public Internal createEntry(Object value) { + return createEntry((InternalEObject) value); + } + + /** Does inverse action on other end */ + public final NotificationChain inverseAdd(InternalEObject owner, int featureID, NotificationChain notifications) { + return getFeatureValue().inverseAdd(owner, getValue(), featureID, notifications); + } + + /** Does inverse action on other end */ + public final NotificationChain inverseRemove(InternalEObject owner, int featureID, NotificationChain notifications) { + return getFeatureValue().inverseRemove(owner, getValue(), featureID, notifications); + } + + /** Does inverse action on other end */ + public final NotificationChain inverseAdd(InternalEObject owner, Object otherEnd, int featureID, + NotificationChain notifications) { + return getFeatureValue().inverseAdd(owner, getValue(), featureID, notifications); + } + + /** Does inverse action on other end */ + public NotificationChain inverseRemove(InternalEObject owner, Object otherEnd, int featureID, + NotificationChain notifications) { + return getFeatureValue().inverseRemove(owner, otherEnd, featureID, notifications); + } + + /** validate the type of the value with the type expected by the efeature */ + public void validate(Object value) { + getFeatureValue().validate(value); + } + + /** Class to store feature value pairs together with their validator */ + private class FeatureValue implements Serializable { + + /** + * Generated Serial Version ID + */ + private static final long serialVersionUID = 3665363921316852811L; + + /** The feature */ + protected EStructuralFeature feature; + + /** The featurepath, is used during serialization */ + private String featurePath; + + /** Its value (can be null) */ + protected Object value; + + /** Constructor */ + private FeatureValue(EStructuralFeature feature, Object value) { + this.feature = feature; + this.value = value; + } + + /** Takes care of serializing the efeature */ + private void writeObject(java.io.ObjectOutputStream out) throws IOException { + featurePath = StoreUtil.structuralFeatureToString(feature); + feature = null; + out.defaultWriteObject(); + } + + /** Takes care of deserializing the efeature */ + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + feature = StoreUtil.stringToStructureFeature(featurePath); + } + + /** + * Returns true if this feature value corresponds to the passed feature (taking into account substitution groups + */ + private boolean matchesFeature(EStructuralFeature eFeature) { + if (feature.equals(eFeature)) { + return true; + } + + // an entry which is the value of another entry + if (owningMap == null) { + return false; + } + + // compare on the basis of the affiliates (substitutiongroup) + final EStructuralFeature aff1 = ExtendedMetaData.INSTANCE.getAffiliation(owningMap.getEObject().eClass(), + feature); + final EStructuralFeature aff2 = ExtendedMetaData.INSTANCE.getAffiliation(owningMap.getEObject().eClass(), + eFeature); + if (aff1 != null && aff2 != null && aff1 == aff2) { + return true; + } + return false; + } + + /** Returns the value */ + private Object getValue() { + return value; + } + + /** Handles inverse action, differs on the basis of the feature type */ + public NotificationChain inverseAdd(InternalEObject owner, Object otherEnd, int featureID, + NotificationChain notifications) { + return notifications; + } + + /** Handles inverse action, differs on the basis of the feature type */ + public NotificationChain inverseRemove(InternalEObject owner, Object otherEnd, int featureID, + NotificationChain notifications) { + return notifications; + } + + /** + * validate the type of the value with the type expected by the efeature + */ + public void validate(Object value) { + if (value != null && !eStructuralFeature.getEType().isInstance(value)) { + String valueClass = value instanceof EObject ? ((EObject) value).eClass().getName() : value.getClass() + .getName(); + throw new ClassCastException("The feature '" + eStructuralFeature.getName() + "'s type '" + + eStructuralFeature.getEType().getName() + "' does not permit a value of type '" + valueClass + + "'"); + } + } + } + + /** Containment feature value */ + private class ContainmentFeatureValue extends FeatureValue { + + /** + * Generated serial id + */ + private static final long serialVersionUID = -5915172909939056481L; + + /** Constructor */ + private ContainmentFeatureValue(EStructuralFeature feature, Object value) { + super(feature, value); + } + + /** Handles inverse action, differs on the basis of the feature type */ + @Override + public NotificationChain inverseAdd(InternalEObject owner, Object otherEnd, int featureID, + NotificationChain notifications) { + return inverseAdd(owner, (InternalEObject) value, featureID, notifications); + } + + /** Handles inverse action, differs on the basis of the feature type */ + @Override + public NotificationChain inverseRemove(InternalEObject owner, Object otherEnd, int featureID, + NotificationChain notifications) { + return inverseRemove(owner, (InternalEObject) value, featureID, notifications); + } + + /** Does inverse action on other end */ + private NotificationChain inverseAdd(InternalEObject owner, InternalEObject otherEnd, int featureID, + NotificationChain notifications) { + if (otherEnd != null) { + int containmentFeatureID = owner.eClass().getFeatureID(eStructuralFeature); + notifications = otherEnd.eInverseAdd(owner, InternalEObject.EOPPOSITE_FEATURE_BASE + - (containmentFeatureID == -1 ? featureID : containmentFeatureID), null, notifications); + } + + return notifications; + } + + /** Does inverse action on other end */ + private NotificationChain inverseRemove(InternalEObject owner, InternalEObject otherEnd, int featureID, + NotificationChain notifications) { + if (otherEnd != null) { + int containmentFeatureID = owner.eClass().getFeatureID(eStructuralFeature); + notifications = otherEnd.eInverseRemove(owner, InternalEObject.EOPPOSITE_FEATURE_BASE + - (containmentFeatureID == -1 ? featureID : containmentFeatureID), null, notifications); + } + + return notifications; + } + } + + /** Bidirectional feature value */ + private class InverseFeatureValue extends FeatureValue { + + /** + * Generated Serial Version ID + */ + private static final long serialVersionUID = 7207038502480577523L; + + /** Constructor */ + private InverseFeatureValue(EStructuralFeature feature, Object value) { + super(feature, value); + } + + /** Handles inverse action, differs on the basis of the feature type */ + @Override + public NotificationChain inverseAdd(InternalEObject owner, Object otherEnd, int featureID, + NotificationChain notifications) { + return inverseAdd(owner, (InternalEObject) value, featureID, notifications); + } + + /** Handles inverse action, differs on the basis of the feature type */ + @Override + public NotificationChain inverseRemove(InternalEObject owner, Object otherEnd, int featureID, + NotificationChain notifications) { + return inverseRemove(owner, (InternalEObject) value, featureID, notifications); + } + + /** Does inverse action on other end */ + private final NotificationChain inverseAdd(InternalEObject owner, InternalEObject otherEnd, int featureID, + NotificationChain notifications) { + if (otherEnd != null) { + notifications = otherEnd.eInverseAdd(owner, otherEnd.eClass().getFeatureID( + ((EReference) eStructuralFeature).getEOpposite()), null, notifications); + } + + return notifications; + } + + /** Does inverse action on other end */ + private final NotificationChain inverseRemove(InternalEObject owner, InternalEObject otherEnd, int featureID, + NotificationChain notifications) { + if (otherEnd != null) { + notifications = otherEnd.eInverseRemove(owner, otherEnd.eClass().getFeatureID( + ((EReference) eStructuralFeature).getEOpposite()), null, notifications); + } + return notifications; + } + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HibernatePersistableEList.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HibernatePersistableEList.java new file mode 100755 index 000000000..a43c7ec37 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HibernatePersistableEList.java @@ -0,0 +1,622 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HibernatePersistableEList.java,v 1.35 2010/03/25 01:05:53 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.elist; + +import java.io.Serializable; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.teneo.EContainerRepairControl; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.SessionWrapper; +import org.eclipse.emf.teneo.hibernate.resource.HbResource; +import org.eclipse.emf.teneo.mapping.elist.PersistableEList; +import org.eclipse.emf.teneo.resource.StoreResource; +import org.eclipse.emf.teneo.util.AssertUtil; +import org.hibernate.HibernateException; +import org.hibernate.collection.AbstractPersistentCollection; +import org.hibernate.collection.PersistentBag; +import org.hibernate.collection.PersistentCollection; +import org.hibernate.collection.PersistentIdentifierBag; +import org.hibernate.collection.PersistentList; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.loader.CollectionAliases; +import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.type.Type; + +/** + * Implements the hibernate persistable elist. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.35 $ + */ + +public class HibernatePersistableEList<E> extends PersistableEList<E> implements + ExtensionPoint, PersistentCollection { + /** + * Serial Version ID + */ + private static final long serialVersionUID = -4553160393592497834L; + /** The logger */ + private static Log log = LogFactory.getLog(HibernatePersistableEList.class); + + /** Constructor */ + public HibernatePersistableEList(InternalEObject owner, + EStructuralFeature feature, List<E> list) { + super(owner, feature, list); + } + + /** If the delegate has been initialized */ + public boolean isInitialized() { + return ((PersistentCollection) delegate).wasInitialized(); + } + + /** + * Override isLoaded to check if the delegate lists was not already loaded + * by hibernate behind the scenes, this happens with eagerly loaded lists. + */ + @Override + public boolean isLoaded() { + // if the delegated list was loaded under the hood and this + // HibernatePersistableEList did + // not yet notice it then do the local load behavior. + // delegate is loaded in case of subselect or eager loading + final boolean isDelegateLoaded = delegate instanceof AbstractPersistentCollection + && ((AbstractPersistentCollection) delegate).wasInitialized(); + if (!super.isLoaded() && !isLoading() && isDelegateLoaded) { + if (log.isDebugEnabled()) { + log + .debug("Persistentlist already initialized, probably eagerly loaded: " + + getLogString()); + } + try { + setIsLoading(true); + // do load to load the resource + doLoad(); + setIsLoaded(true); + } finally { + setIsLoading(false); + } + } + return super.isLoaded(); + } + + /** Do the actual load can be overridden */ + @Override + protected synchronized void doLoad() { + // TODO, read the following link and reconsider transaction usage + // http://community.jboss.org/wiki/Non-transactionaldataaccessandtheauto-commitmode + + AssertUtil.assertTrue("EList " + logString, !isLoaded()); + + log.debug("Started loading elist " + logString); + + SessionWrapper sessionWrapper = null; + boolean controlsTransaction = false; + boolean err = true; + Resource res = null; + try { + res = owner.eResource(); + if (res != null && res instanceof HbResource) { + sessionWrapper = ((HbResource) res).getSessionWrapper(); + if (res.isLoaded()) // resource is loaded reopen transaction + { + // if the delegate is already loaded then no transaction is + // required + final boolean isDelegateLoaded = delegate instanceof AbstractPersistentCollection + && ((AbstractPersistentCollection) delegate) + .wasInitialized(); + if (!isDelegateLoaded + && !sessionWrapper.isTransactionActive()) { + log + .debug("Reconnecting session to read a lazy collection, elist: " + + logString); + controlsTransaction = true; + sessionWrapper.beginTransaction(); + sessionWrapper.setFlushModeManual(); + } else { + log + .debug("Delegate loaded or resource session is still active, using it"); + } + } else { + log.debug("Elist uses session from resource, " + logString); + } + } else { + log.debug("EList is not loaded in session context"); + } + + if (controlsTransaction) { + assert (res instanceof HbResource); + ((StoreResource) res).setIsLoading(true); + } + + try { + Object[] objs = delegate.toArray(); // this forces the load + + // disabled for now as containers are persisted by hibernate + // anyway + if (isContainment()) { + for (Object element : objs) { + if (element instanceof InternalEObject) { + EContainerRepairControl.setContainer(owner, + (InternalEObject) element, + getEStructuralFeature()); + } + } + } + + // add the new objects to the resource so they are tracked + if (res != null && res instanceof StoreResource) { + // attach the new contained objects so that they are adapted + // when required + for (Object element : objs) { + if (element instanceof EObject) { + ((StoreResource) res).addToContentOrAttach( + (InternalEObject) element, + (EReference) getEStructuralFeature()); + } + } + } + + log.debug("Loaded " + objs.length + " from backend store for " + + logString); + } finally { + if (controlsTransaction) { + ((StoreResource) res).setIsLoading(false); + } + } + err = false; + } finally { + if (controlsTransaction) { + if (err) { + sessionWrapper.rollbackTransaction(); + sessionWrapper.restorePreviousFlushMode(); + } else { + // a bit rough but delete from the persitence context + // otherwise + // hibernate will think that this collection is not attached + // to anything and + // will delete me + // getSession().getPersistenceContext().getCollectionEntries().remove(this); + sessionWrapper.commitTransaction(); + sessionWrapper.restorePreviousFlushMode(); + } + } + if (sessionWrapper != null) { + ((HbResource) res).returnSessionWrapper(sessionWrapper); + } + } + log.debug("Finished loading elist " + logString); + } + + /** Overridden because general list type is not supported as a replacement */ + @Override + public void replaceDelegate(List<E> newDelegate) { + if (newDelegate instanceof PersistentList) { + // disabled this assertion because in case of a session refresh it + // is possible + // that the list is replaced by a persistent list + // AssertUtil.assertTrue("This elist " + logString + " contains a + // different list than the " + + // " passed list", + // ((PersistentList)newDelegate).isWrapper(delegate)); + super.replaceDelegate(newDelegate); + } else if (newDelegate instanceof PersistentBag) { + // disabled this assertion because in case of a session refresh it + // is possible + // that the list is replaced by a persistent list + // AssertUtil.assertTrue("This elist " + logString + " contains a + // different list than the " + + // " passed list", + // ((PersistentBag)newDelegate).isWrapper(delegate)); + super.replaceDelegate(newDelegate); + } else if (newDelegate instanceof PersistentIdentifierBag) { + // Added to support <idbag> + super.replaceDelegate(newDelegate); + } else if (newDelegate == delegate) // this can occur and is okay, do + // nothing in this case + { + + } else { + throw new HbMapperException("Type " + + newDelegate.getClass().getName() + " can not be " + + " used as a replacement for elist " + logString); + } + } + + /** Returns true if the wrapped list is a persistency layer specific list */ + public boolean isPersistencyWrapped() { + return delegate instanceof PersistentCollection; + } + + public boolean afterInitialize() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).afterInitialize(); + } + return false; + } + + public void afterRowInsert(CollectionPersister persister, Object entry, + int i) throws HibernateException { + if (isPersistencyWrapped()) { + ((PersistentCollection) delegate).afterRowInsert(persister, entry, + i); + } + } + + public void beforeInitialize(CollectionPersister persister, + int anticipatedSize) { + if (isPersistencyWrapped()) { + ((PersistentCollection) delegate).beforeInitialize(persister, + anticipatedSize); + } + } + + public void beginRead() { + if (isPersistencyWrapped()) { + ((PersistentCollection) delegate).beginRead(); + } + } + + public void clearDirty() { + if (isPersistencyWrapped()) { + ((PersistentCollection) delegate).clearDirty(); + } + } + + public void dirty() { + if (isPersistencyWrapped()) { + ((PersistentCollection) delegate).dirty(); + } + } + + public Serializable disassemble(CollectionPersister persister) + throws HibernateException { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).disassemble(persister); + } + return null; + } + + public boolean empty() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).empty(); + } + return false; + } + + public boolean endRead() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).endRead(); + } + return false; + } + + public Iterator<?> entries(CollectionPersister persister) { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).entries(persister); + } + return null; + } + + public boolean entryExists(Object entry, int i) { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).entryExists(entry, i); + } + return false; + } + + public boolean equalsSnapshot(CollectionPersister persister) + throws HibernateException { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).equalsSnapshot(persister); + } + return false; + } + + public void forceInitialization() throws HibernateException { + if (isPersistencyWrapped()) { + ((PersistentCollection) delegate).forceInitialization(); + } + } + + public Iterator<?> getDeletes(CollectionPersister persister, + boolean indexIsFormula) throws HibernateException { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).getDeletes(persister, + indexIsFormula); + } + return null; + } + + public Object getElement(Object entry) { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).getElement(entry); + } + return null; + } + + public Object getIdentifier(Object entry, int i) { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).getIdentifier(entry, i); + } + return null; + } + + public Object getIndex(Object entry, int i, CollectionPersister persister) { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).getIndex(entry, i, + persister); + } + return null; + } + + public Serializable getKey() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).getKey(); + } + return null; + } + + public Collection<?> getOrphans(Serializable snapshot, String entityName) + throws HibernateException { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).getOrphans(snapshot, + entityName); + } + return null; + } + + public Object getOwner() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).getOwner(); + } + return getEObject(); + } + + public Collection<?> getQueuedOrphans(String entityName) { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate) + .getQueuedOrphans(entityName); + } + return null; + } + + public String getRole() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).getRole(); + } + return null; + } + + public Serializable getSnapshot(CollectionPersister persister) + throws HibernateException { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).getSnapshot(persister); + } + return null; + } + + public Object getSnapshotElement(Object entry, int i) { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).getSnapshotElement(entry, + i); + } + return null; + } + + public Serializable getStoredSnapshot() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).getStoredSnapshot(); + } + return null; + } + + public Object getValue() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).getValue(); + } + return null; + } + + public boolean hasQueuedOperations() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).hasQueuedOperations(); + } + return false; + } + + public void initializeFromCache(CollectionPersister persister, + Serializable disassembled, Object owner) throws HibernateException { + if (isPersistencyWrapped()) { + ((PersistentCollection) delegate).initializeFromCache(persister, + disassembled, owner); + } + } + + public boolean isDirectlyAccessible() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).isDirectlyAccessible(); + } + return false; + } + + public boolean isDirty() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).isDirty(); + } + return false; + } + + public boolean isRowUpdatePossible() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).isRowUpdatePossible(); + } + return false; + } + + public boolean isSnapshotEmpty(Serializable snapshot) { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).isSnapshotEmpty(snapshot); + } + return false; + } + + public boolean isUnreferenced() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).isUnreferenced(); + } + return false; + } + + public boolean isWrapper(Object collection) { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).isWrapper(collection); + } + return false; + } + + public boolean needsInserting(Object entry, int i, Type elemType) + throws HibernateException { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).needsInserting(entry, i, + elemType); + } + return false; + } + + public boolean needsRecreate(CollectionPersister persister) { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).needsRecreate(persister); + } + return false; + } + + public boolean needsUpdating(Object entry, int i, Type elemType) + throws HibernateException { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).needsUpdating(entry, i, + elemType); + } + return false; + } + + public void postAction() { + if (isPersistencyWrapped()) { + ((PersistentCollection) delegate).postAction(); + } + } + + @Override + protected int delegateSize() { + return delegateList().size(); + } + + protected final boolean isConnectedToSession() { + if (!(getDelegate() instanceof AbstractPersistentCollection)) { + return false; + } + final AbstractPersistentCollection persistentCollection = (AbstractPersistentCollection) getDelegate(); + final SessionImplementor session = ((AbstractPersistentCollection) persistentCollection) + .getSession(); + return isConnectedToSession(session); + } + + private final boolean isConnectedToSession(SessionImplementor session) { + final PersistentCollection persistentCollection = (PersistentCollection) getDelegate(); + return session != null + && session.isOpen() + && session.getPersistenceContext().containsCollection( + persistentCollection); + } + + @Override + protected boolean delegateIsEmpty() { + return delegateSize() == 0; + } + + public void preInsert(CollectionPersister persister) + throws HibernateException { + if (isPersistencyWrapped()) { + ((PersistentCollection) delegate).preInsert(persister); + } + } + + public Iterator<?> queuedAdditionIterator() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).queuedAdditionIterator(); + } + return null; + } + + public Object readFrom(ResultSet rs, CollectionPersister role, + CollectionAliases descriptor, Object owner) + throws HibernateException, SQLException { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).readFrom(rs, role, + descriptor, owner); + } + return null; + } + + public boolean setCurrentSession(SessionImplementor session) + throws HibernateException { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).setCurrentSession(session); + } + return false; + } + + public void setOwner(Object entity) { + if (isPersistencyWrapped()) { + ((PersistentCollection) delegate).setOwner(entity); + } + } + + public void setSnapshot(Serializable key, String role, Serializable snapshot) { + if (isPersistencyWrapped()) { + ((PersistentCollection) delegate).setSnapshot(key, role, snapshot); + } + } + + public boolean unsetSession(SessionImplementor currentSession) { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate) + .unsetSession(currentSession); + } + return false; + } + + public boolean wasInitialized() { + if (isPersistencyWrapped()) { + return ((PersistentCollection) delegate).wasInitialized(); + } + return false; + } + +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HibernatePersistableEMap.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HibernatePersistableEMap.java new file mode 100755 index 000000000..399636725 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HibernatePersistableEMap.java @@ -0,0 +1,233 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HibernatePersistableEMap.java,v 1.13 2010/11/12 09:33:33 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.elist; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.common.util.BasicEMap; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.SessionWrapper; +import org.eclipse.emf.teneo.hibernate.resource.HbResource; +import org.eclipse.emf.teneo.mapping.elist.PersistableDelegateList; +import org.eclipse.emf.teneo.mapping.elist.PersistableEList; +import org.eclipse.emf.teneo.mapping.elist.PersistableEMap; +import org.eclipse.emf.teneo.resource.StoreResource; +import org.hibernate.Session; +import org.hibernate.collection.AbstractPersistentCollection; +import org.hibernate.collection.PersistentCollection; + +/** + * Implements the hibernate persistable emap. Note an emap is not loaded lazily! + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.13 $ + */ + +public class HibernatePersistableEMap<K, V> extends PersistableEMap<K, V> + implements ExtensionPoint { + /** + * Serial Version ID + */ + private static final long serialVersionUID = -4553160393592497834L; + + /** The logger */ + private static Log log = LogFactory.getLog(HibernatePersistableEMap.class); + + /** Constructor */ + public HibernatePersistableEMap(InternalEObject owner, EReference eref, + List<Entry<K, V>> list) { + super(eref.getEReferenceType(), owner, eref, list); + } + + /** Do the actual load can be overridden */ + @Override + protected void doLoad() { + SessionWrapper sessionWrapper = null; + boolean controlsTransaction = false; + boolean err = true; + Resource res = null; + final List<?> delegate = ((HibernatePersistableEList<?>) delegateEList) + .getDelegate(); + try { + res = getEObject().eResource(); + if (res != null && res instanceof HbResource) { + sessionWrapper = ((HbResource) res).getSessionWrapper(); + if (res.isLoaded()) // resource is loaded reopen transaction + { + // if the delegate is already loaded then no transaction is + // required + final boolean isDelegateLoaded = delegate instanceof AbstractPersistentCollection + && ((AbstractPersistentCollection) delegate) + .wasInitialized(); + if (!isDelegateLoaded + && !sessionWrapper.isTransactionActive()) { + log.debug("Reconnecting session to read a lazy collection, elist: " + + logString); + controlsTransaction = true; + sessionWrapper.beginTransaction(); + sessionWrapper.setFlushModeManual(); + } else { + log.debug("Delegate loaded or resource session is still active, using it"); + } + } else { + log.debug("EMap uses session from resource, " + logString); + } + } else { + log.debug("EMap is not loaded in session context"); + } + + if (controlsTransaction) { + assert (res instanceof HbResource); + ((StoreResource) res).setIsLoading(true); + } + + try { + Object[] objs = delegate.toArray(); // this forces the load + + // add the new objects to the resource so they are tracked + if (res != null && res instanceof StoreResource) { + // attach the new contained objects so that they are adapted + // when required + for (Object element : objs) { + if (element instanceof EObject) { + ((StoreResource) res).addToContentOrAttach( + (InternalEObject) element, + (EReference) getEStructuralFeature()); + } + } + } + log.debug("Loaded " + objs.length + " from backend store for " + + logString); + } finally { + if (controlsTransaction) { + ((StoreResource) res).setIsLoading(false); + } + } + err = false; + } finally { + if (controlsTransaction) { + if (err) { + sessionWrapper.rollbackTransaction(); + sessionWrapper.restorePreviousFlushMode(); + } else { + // a bit rough but delete from the persitence context + // otherwise + // hibernate will think that this collection is not attached + // to anything and + // will delete me + // getSession().getPersistenceContext().getCollectionEntries().remove(this); + sessionWrapper.commitTransaction(); + sessionWrapper.restorePreviousFlushMode(); + } + ((HbResource) res).returnSessionWrapper(sessionWrapper); + } + } + log.debug("Finished loading elist " + logString); + } + + /** + * Overridden because of access to size attribute. This version will try to + * read the collection size without lading it if it is lazy loaded + */ + @Override + public int size() { + // if we are not loaded yet, we return the size of the buffered lazy + // load delegate + + if (!isLoaded() + && delegateEList instanceof PersistableEList<?> + && ((PersistableEList<?>) delegateEList).getDelegate() instanceof AbstractPersistentCollection) { + try { + final Session s = (Session) ((AbstractPersistentCollection) ((PersistableEList<?>) delegateEList) + .getDelegate()).getSession(); + + // now that we have the session, we can query the size of + // the list without loading it + s.flush(); + size = ((Long) s + .createFilter( + ((PersistableEList<?>) delegateEList) + .getDelegate(), + "select count(*)").list().get(0)).intValue(); + return size; + } catch (Throwable t) { + // ignore on purpose, let the call to super handle it + } + } + + // didnt work, so we simply call the parent version + return super.size(); + } + + /** Needs to be implemented by concrete subclass */ + @Override + protected EList<BasicEMap.Entry<K, V>> createDelegateEList( + InternalEObject owner, EStructuralFeature feature, + List<BasicEMap.Entry<K, V>> delegateORMList) { + return new HibernatePersistableEList<Entry<K, V>>(owner, feature, + delegateORMList) { + private static final long serialVersionUID = 1L; + + @Override + protected void didAdd(int index, Entry<K, V> newObject) { + doPut(newObject); + } + + @Override + protected void didSet(int index, Entry<K, V> newObject, + Entry<K, V> oldObject) { + didRemove(index, oldObject); + didAdd(index, newObject); + } + + @Override + protected void didRemove(int index, Entry<K, V> oldObject) { + HibernatePersistableEMap.this.doRemove(oldObject); + } + + @Override + protected void didClear(int size, Object[] oldObjects) { + doClear(); + } + + @Override + protected void didMove(int index, Entry<K, V> movedObject, + int oldIndex) { + HibernatePersistableEMap.this.doMove(movedObject); + } + }; + } + + /** If the delegate has been initialized */ + public boolean isInitialized() { + return ((PersistentCollection) getDelegate()).wasInitialized(); + } + + /** Return the orm backing list */ + @Override + public Object getDelegate() { + return ((PersistableDelegateList<?>) delegateEList).getDelegate(); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HibernatePersistableFeatureMap.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HibernatePersistableFeatureMap.java new file mode 100755 index 000000000..a1292e511 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/HibernatePersistableFeatureMap.java @@ -0,0 +1,244 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HibernatePersistableFeatureMap.java,v 1.15 2009/11/02 10:24:50 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.elist; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.teneo.EContainerRepairControl; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.SessionWrapper; +import org.eclipse.emf.teneo.hibernate.resource.HibernateResource; +import org.eclipse.emf.teneo.mapping.elist.PersistableFeatureMap; +import org.eclipse.emf.teneo.resource.StoreResource; +import org.eclipse.emf.teneo.util.AssertUtil; +import org.hibernate.Session; +import org.hibernate.collection.AbstractPersistentCollection; +import org.hibernate.collection.PersistentBag; +import org.hibernate.collection.PersistentCollection; +import org.hibernate.collection.PersistentList; + +/** + * Implements the hibernate persistable elist. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.15 $ + */ + +public class HibernatePersistableFeatureMap extends PersistableFeatureMap implements ExtensionPoint { + /** + * Serial Version ID + */ + private static final long serialVersionUID = -1916994464446630140L; + + /** The logger */ + private static Log log = LogFactory.getLog(HibernatePersistableFeatureMap.class); + + /** Constructor */ + public HibernatePersistableFeatureMap(InternalEObject owner, EStructuralFeature feature, List<FeatureMap.Entry> list) { + super(owner, feature, list); + + if (isLoaded()) { + for (Entry entry : getDelegate()) { + final HibernateFeatureMapEntry fme = (HibernateFeatureMapEntry) entry; + if (!fme.belongsToFeatureMap(this)) { + fme.setFeatureMap(this); + } + } + } + } + + /** Returns the element type to be used */ + @Override + protected Class<? extends FeatureMap.Entry> determineElementType() { + return HibernateFeatureMapEntry.class; + } + + /** OVerridden to create the correct featuremap entry */ + @Override + protected FeatureMap.Entry createEntry(EStructuralFeature eStructuralFeature, Object value) { + final HibernateFeatureMapEntry entry = new HibernateFeatureMapEntry(); + entry.setFeatureValue(eStructuralFeature, value, this); + return entry; + } + + /** Shortcut to replace entries */ + protected FeatureMap.Entry replaceEntry(Object entry) { + if (entry instanceof HibernateFeatureMapEntry && ((HibernateFeatureMapEntry) entry).belongsToFeatureMap(this)) { + return (HibernateFeatureMapEntry) entry; + } + + final FeatureMap.Entry emfEntry = (FeatureMap.Entry) entry; + final HibernateFeatureMapEntry fme = new HibernateFeatureMapEntry(); + fme.setFeatureValue(emfEntry.getEStructuralFeature(), emfEntry.getValue(), this); + return fme; + } + + /** If the delegate has been initialized */ + public boolean isInitialized() { + return ((PersistentCollection) delegate).wasInitialized(); + } + + /** + * Override isLoaded to check if the delegate lists was not already loaded by hibernate behind the scenes, this + * happens with eagerly loaded lists. + */ + @Override + public boolean isLoaded() { + if (delegate instanceof AbstractPersistentCollection) { + if (((AbstractPersistentCollection) delegate).wasInitialized()) { + // delegate is loaded in case of subselect or eager loading + if (isLoading()) { + // probably are we doing this already return + return false; + } + log.debug("Persistentlist already initialized, probably eagerly loaded: " + getLogString()); + try { + setIsLoading(true); + // do load to load the resource + doLoad(); + setIsLoaded(true); + } finally { + setIsLoading(false); + } + } + } + return super.isLoaded(); + } + + /** Do the actual load can be overridden, called from the subclass */ + @Override + protected synchronized void doLoad() { + AssertUtil.assertTrue("EList " + logString, !isLoaded()); + + SessionWrapper sessionWrapper = null; + boolean controlsSession = false; + boolean err = true; + try { + final Resource res = owner.eResource(); + + if (res != null && res instanceof HibernateResource) { + sessionWrapper = ((HibernateResource) res).getSessionWrapper(); + if (res.isLoaded()) { // resource is loaded reopen transaction + if (!sessionWrapper.isTransactionActive()) { + log.debug("Reconnecting session to read a lazy collection, Featuremap: " + logString); + controlsSession = true; + sessionWrapper.beginTransaction(); + sessionWrapper.setFlushModeManual(); + } else { + log.debug("Resource session is still active, using it"); + } + } else { + log.debug("Featuremap uses session from resource, " + logString); + } + } else { + log.debug("EList is not loaded in session context"); + } + + Object[] objs = delegate.toArray(); // this forces the load + + // set the owner of the feature map entries + // set the econtainer + for (Object element : objs) { + final HibernateFeatureMapEntry fme = (HibernateFeatureMapEntry) element; + fme.setFeatureMap(this); + + if (fme.getEStructuralFeature() instanceof EReference + && ((EReference) fme.getEStructuralFeature()).isContainment()) { + final InternalEObject eobj = (InternalEObject) fme.getValue(); + if (eobj != null) { + EContainerRepairControl.setContainer(owner, eobj, fme.getEStructuralFeature()); + if (res != null && res instanceof StoreResource + && fme.getEStructuralFeature() instanceof EReference) { + ((StoreResource) res).addToContentOrAttach((InternalEObject) fme.getValue(), + (EReference) fme.getEStructuralFeature()); + } + } + } + } + + err = false; + log.debug("Loaded " + objs.length + " from backend store for " + logString); + } finally { + if (controlsSession) { + if (err) { + sessionWrapper.rollbackTransaction(); + sessionWrapper.restorePreviousFlushMode(); + } else { + // a bit rough but delete from the persitence context + // otherwise + // hibernate will think that this collection is not attached + // to anything and + // will delete me + // getSession().getPersistenceContext().getCollectionEntries().remove(this); + sessionWrapper.commitTransaction(); + sessionWrapper.restorePreviousFlushMode(); + } + } + } + } + + /** Overridden because general list type is not supported as a replacement */ + @Override + public void replaceDelegate(List<FeatureMap.Entry> newDelegate) { + if (newDelegate instanceof PersistentList) { + AssertUtil.assertTrue("This elist " + logString + " contains a different list than the " + " passed list", + ((PersistentList) newDelegate).isWrapper(delegate)); + super.replaceDelegate(newDelegate); + } else if (newDelegate instanceof PersistentBag) { + AssertUtil.assertTrue("This elist " + logString + " contains a different list than the " + " passed list", + ((PersistentBag) newDelegate).isWrapper(delegate)); + super.replaceDelegate(newDelegate); + } else { + throw new HbMapperException("Type " + newDelegate.getClass().getName() + " can not be " + + " used as a replacement for elist " + logString); + } + } + + /** Returns true if the wrapped list is a persistency layer specific list */ + @Override + public boolean isPersistencyWrapped() { + return delegate instanceof PersistentCollection; + } + + @Override + protected Entry delegateRemove(int index) { + final Entry old = super.delegateRemove(index); + + if (old.getEStructuralFeature() instanceof EReference && getDelegate() instanceof PersistentList) { + final PersistentList pl = (PersistentList) getDelegate(); + final EReference eref = (EReference) old.getEStructuralFeature(); + if (eref.isContainment()) { + ((Session) pl.getSession()).delete(old.getValue()); + } + } + return old; + } + + @Override + protected Object clone() throws CloneNotSupportedException { + // TODO Auto-generated method stub + return super.clone(); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/MapHibernatePersistableEMap.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/MapHibernatePersistableEMap.java new file mode 100755 index 000000000..02ba29cfd --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/elist/MapHibernatePersistableEMap.java @@ -0,0 +1,257 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: MapHibernatePersistableEMap.java,v 1.9 2010/02/04 10:53:08 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.elist; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.common.util.BasicEMap; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.SessionWrapper; +import org.eclipse.emf.teneo.hibernate.resource.HbResource; +import org.eclipse.emf.teneo.mapping.elist.MapPersistableEMap; +import org.eclipse.emf.teneo.resource.StoreResource; +import org.hibernate.Session; +import org.hibernate.collection.AbstractPersistentCollection; +import org.hibernate.collection.PersistentMap; + +/** + * Implements the hibernate persistable emap using a real map mapping (instead of the previous list + * mapping). + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @author <a href="mailto:jdboudreault@gmail.com">Jean-Denis Boudreault</a> + * @version $Revision: 1.9 $ + */ + +public class MapHibernatePersistableEMap<K, V> extends MapPersistableEMap<K, V> implements ExtensionPoint { + /** + * Serial Version ID + */ + private static final long serialVersionUID = -4553160393592497834L; + + /** The logger */ + private static Log log = LogFactory.getLog(MapHibernatePersistableEMap.class); + + /** + * Constructor: this version will take a natural map as input (probided by hibernate) and + * transform the entries into the EMF keyToValue format + * + * + */ + public MapHibernatePersistableEMap(InternalEObject owner, EReference eref, Map<K, V> map) { + super(eref.getEReferenceType(), owner, eref, map); + } + + /** + * This constructor is usually called when the list is created and filled by the user first. + * when called by a hibernate load, the other overload with a map input is used instead. + * + */ + public MapHibernatePersistableEMap(InternalEObject owner, EReference eref, List<BasicEMap.Entry<K, V>> list) { + super(eref.getEReferenceType(), owner, eref, list); + } + + /** If the delegate has been initialized */ + public boolean isInitialized() { + return isORMMapDelegateLoaded(); + } + + /** + * Override isLoaded to check if the delegate lists was not already loaded by hibernate behind + * the scenes, this happens with eagerly loaded lists. + */ + @Override + public boolean isLoaded() { + // if the lazyload delegate is null, then this map is already loaded + if (ormMapDelegate == null) { + return true; + } + + // if the delegated map was loaded under the hood and this + // HibernatePersistableEMap did + // not yet notice it then do the local load behavior. + // delegate is loaded in case of subselect or eager loading + if (!super.isLoaded() && !isLoading() && isORMMapDelegateLoaded()) { + log.debug("Persistentlist already initialized, probably eagerly loaded: " + getLogString()); + try { + this.setLoading(true); + // do load to load the resource + doLoad(); + this.setLoading(true); + } finally { + this.setLoading(false); + } + } + return super.isLoaded(); + } + + /** + * Overridden because of access to size attribute. This version will try to read the collection + * size without lading it if it is lazy loaded + */ + @Override + public int size() { + if (size != 0) { + return size; + } + + // if we are not loaded yet, we return the size of the buffered lazy + // load delegate + if (!isMapValueIsEAttribute() && this.getORMMapDelegate() != null) { + if (!this.isORMMapDelegateLoaded() && (this.getORMMapDelegate() instanceof AbstractPersistentCollection)) { + try { + // here is a neat trick. we use reflection to get the + // session of the persistanMap. + Field field = AbstractPersistentCollection.class.getDeclaredField("session"); + field.setAccessible(true); + Session s = (Session) field.get(this.getORMMapDelegate()); + + // now that we have the session, we can query the size of + // the list without loading it + size = + ((Long) s.createFilter(this.getORMMapDelegate(), "select count(*)").list().get(0)) + .intValue(); + return size; + } catch (Throwable t) { + // ignore on purpose, let the call to super handle it + } + } + } + + // didnt work, so we simply call the parent version + return super.size(); + } + + /** + * this method is used to determine if the underlying hibernate map collection has been eagerly + * loaded + * + * @return true if is laoded, false if not + */ + @Override + protected boolean isORMMapDelegateLoaded() { + if (this.getORMMapDelegate() == null) { + return false; + } + + return ((this.ormMapDelegate instanceof PersistentMap) && (((PersistentMap) ormMapDelegate).wasInitialized())); + } + + /** + * Do the actual load and wrapping. can be overridden + */ + @Override + @SuppressWarnings({"rawtypes","unchecked"}) + protected void doLoad() { + SessionWrapper sessionWrapper = null; + boolean controlsTransaction = false; + boolean err = true; + Resource res = null; + final Map<K, V> delegate = getORMMapDelegate(); + + try { + res = getEObject().eResource(); + if (res != null && res instanceof HbResource) { + sessionWrapper = ((HbResource) res).getSessionWrapper(); + if (res.isLoaded()) // resource is loaded reopen transaction + { + // if the delegate is already loaded then no transaction is + // required + final boolean isDelegateLoaded = + delegate instanceof AbstractPersistentCollection && + ((AbstractPersistentCollection) delegate).wasInitialized(); + if (!isDelegateLoaded && !sessionWrapper.isTransactionActive()) { + log.debug("Reconnecting session to read a lazy collection, elist: " + logString); + controlsTransaction = true; + sessionWrapper.beginTransaction(); + sessionWrapper.setFlushModeManual(); + } else { + log.debug("Delegate loaded or resource session is still active, using it"); + } + } else { + log.debug("EMap uses session from resource, " + logString); + } + } else { + log.debug("EMap is not loaded in session context"); + } + + if (controlsTransaction) { + assert (res instanceof HbResource); + ((StoreResource) res).setIsLoading(true); + } + + try { + // set all entries in ourselves by wrapping the hibernate map. + // this also forces the load + for (Object o : this.getORMMapDelegate().entrySet()) { + final Map.Entry entry = (Map.Entry) o; + put((K) entry.getKey(), (V) entry.getValue()); + } + + // add the new objects to the resource so they are tracked + if (res != null && res instanceof StoreResource) { + // attach the new contained objects so that they are adapted + // when required + for (Object o : entrySet()) { + if (o instanceof EObject) { + ((StoreResource) res).addToContentOrAttach((InternalEObject) o, + (EReference) getEStructuralFeature()); + } + } + } + log.debug("Loaded " + delegate.size() + " from backend store for " + logString); + } finally { + if (controlsTransaction) { + ((StoreResource) res).setIsLoading(false); + } + } + err = false; + } finally { + if (controlsTransaction) { + if (err) { + sessionWrapper.rollbackTransaction(); + sessionWrapper.restorePreviousFlushMode(); + } else { + // a bit rough but delete from the persitence context + // otherwise + // hibernate will think that this collection is not attached + // to anything and + // will delete me + // getSession().getPersistenceContext().getCollectionEntries().remove(this); + sessionWrapper.commitTransaction(); + sessionWrapper.restorePreviousFlushMode(); + } + ((HbResource) res).returnSessionWrapper(sessionWrapper); + } + } + log.debug("Finished loading emap " + logString); + } + + /** Return the hibernate map */ + @Override + public Object getDelegate() { + return getORMMapDelegate(); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/identifier/IdentifierCacheHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/identifier/IdentifierCacheHandler.java new file mode 100755 index 000000000..f1ad7b7bc --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/identifier/IdentifierCacheHandler.java @@ -0,0 +1,262 @@ +/** + * <copyright> Copyright (c) 2005, 2006, 2007, 2008 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 </copyright> $Id: + * IdentifierCacheHandler.getInstance().java,v 1.5 2007/02/08 23:11:37 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.identifier; + +import java.lang.ref.WeakReference; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Implements two maps for caching identifier and version information. + * Internally uses weakreferences and periodic purge actions to clean the maps. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.21 $ + */ + +public class IdentifierCacheHandler { + /** The logger */ + private static Log log = LogFactory.getLog(IdentifierCacheHandler.class); + + /** At this count the maps will be purged for stale entries */ + public static final int PURGE_TRESHOLD = 100; + + private static IdentifierCacheHandler instance = new IdentifierCacheHandler(); + + public static IdentifierCacheHandler getInstance() { + return instance; + } + + public static void setInstance(IdentifierCacheHandler identifierCacheHandler) { + instance = identifierCacheHandler; + } + + private Map<Key, Object> idMap = new ConcurrentHashMap<Key, Object>(); + private int idModCount = 0; + + private Map<Key, Object> versionMap = new ConcurrentHashMap<Key, Object>(); + private int versionModCount = 0; + + /** Clear the identifier cache */ + public void clear() { + idMap.clear(); + idModCount = 0; + versionMap.clear(); + versionModCount = 0; + } + + public Map<Key, Object> getIdMap() { + return idMap; + } + + public Map<Key, Object> getVersionMap() { + return versionMap; + } + + public void purgeMaps() { + purgeIDMap(); + purgeVersionMap(); + } + + /** Get an identifier from the cache */ + public Object getID(Object obj) { + final Object id = idMap.get(new Key(obj)); + if (id == null) { + log.debug("ID for object " + obj.getClass().getName() + + " not found in id cache"); + return null; + } + if (id instanceof WeakReference<?>) { + return ((WeakReference<?>) id).get(); + } + return id; + } + + /** Set an identifier in the cache */ + public void setID(Object obj, Object id) { + if (log.isDebugEnabled()) { + log.debug("Setting id: " + id + " for object " + + obj.getClass().getName() + " in idcache "); + } + + if (id == null) { // actually a remove of the id + idMap.remove(new Key(obj)); + } else if (useWeakReference(id)) { + idMap.put(new Key(obj), new WeakReference<Object>(id)); + } else { + idMap.put(new Key(obj), id); + } + + // also set the id in the resource + // disabled for now + // if (false && obj instanceof EObject) { + // final EObject eobj = (EObject) obj; + // final Resource res = eobj.eResource(); + // if (res != null && res instanceof XMLResource) { + // if (log.isDebugEnabled()) { + // log.debug("Setting id " + id.toString() + " in resource " + + // res.getClass().getName()); + // } + // ((XMLResource) res).setID(eobj, id.toString()); + // } + // } + + idModCount++; + if (idModCount > getPurgeTreshold()) { + purgeIDMap(); + } + } + + /** Gets a version from the cache */ + public Object getVersion(Object obj) { + final Object version = versionMap.get(new Key(obj)); + if (version == null) { + return version; + } + return version; + } + + private boolean useWeakReference(Object id) { + if (Number.class.isAssignableFrom(id.getClass())) { + return false; + } + if (String.class.isAssignableFrom(id.getClass())) { + return false; + } + return true; + } + + protected int getPurgeTreshold() { + return PURGE_TRESHOLD; + } + + /** Sets a version in the cache */ + public void setVersion(Object obj, Object version) { + if (log.isDebugEnabled()) { + log.debug("Setting version: " + version + " for object " + + obj.getClass().getName() + " in idcache "); + } + if (version == null) { + versionMap.remove(new Key(obj)); + } else { + versionMap.put(new Key(obj), version); + } + versionModCount++; + if (versionModCount > getPurgeTreshold()) { + purgeVersionMap(); + } + } + + /** Purge the versionmap for stale entries */ + private void purgeIDMap() { + purgeMap(idMap); + idModCount = 0; + } + + /** Purge the versionmap for stale entries */ + protected void purgeVersionMap() { + purgeMap(versionMap); + versionModCount = 0; + } + + /** Purges the passed map for stale entries */ + protected void purgeMap(Map<Key, Object> map) { + final Iterator<Key> it = map.keySet().iterator(); + while (it.hasNext()) { + final Key key = it.next(); + if (!key.isValid()) { + it.remove(); + } + } + } + + /** Dumps the idmap */ + public void dumpID() { + dumpContents(idMap); + } + + /** Dumps the content of the passed map */ + private void dumpContents(Map<Key, Object> map) { + Iterator<Key> it = map.keySet().iterator(); + while (it.hasNext()) { + Key key = it.next(); + key.weakRef.get(); + } + } + + /** + * Own implementation of the key in the hashmap to override the equals + * method. Equality for this cache is real memory location equality + */ + + protected static class Key { + /** The real object as a weakreference */ + private final WeakReference<Object> weakRef; + + /** The hashcode of the stored object */ + private final int hashcode; + + /** Constructor */ + Key(Object keyObject) { + weakRef = new WeakReference<Object>(keyObject); + hashcode = keyObject.hashCode(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object arg0) { + assert (arg0 != null); + assert (arg0 instanceof Key); + + final Key key0 = (Key) arg0; + final Object obj0 = key0.weakRef.get(); + final Object obj1 = weakRef.get(); + + // weakreference already gone compare on keys itself + if (obj0 == null || obj1 == null) { + return this == key0; + } + + // still present compare on values + // equals call should maybe also be done but goes wrong for + // featuremap entries + // which are equal if their values and featuremap are equal + // identifier and version caching are only usefull in case of object + // equality + // because it uses weak references and the first level cache of hb + // should + // ensure that only one instance of a certain object is present. + // There should always be one instance anyway in one session + // otherwise + // references between objects can be set wrong (or at least there is + // a great + // change that they go wrong). + return obj0 == obj1; + } + + /** The hashcode of the enclosed object is returned */ + @Override + public int hashCode() { + return hashcode; + } + + /** Returns true if the weakReference is not yet gc'ed */ + public boolean isValid() { + return weakRef.get() != null; + } + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/identifier/IdentifierPropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/identifier/IdentifierPropertyHandler.java new file mode 100755 index 000000000..d13bdba9c --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/identifier/IdentifierPropertyHandler.java @@ -0,0 +1,133 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: IdentifierPropertyHandler.java,v 1.7 2010/11/11 10:28:18 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.identifier; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * Handles getting and setting of id's in the identifiercache handler, is only + * used for synthetic id's. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.7 $ + */ +public class IdentifierPropertyHandler implements Getter, Setter, + PropertyAccessor { + /** + * Serial Version ID + */ + private static final long serialVersionUID = 4707601844087591747L; + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /** Returns the id from the identifier cache */ + public Object get(Object owner) throws HibernateException { + return IdentifierCacheHandler.getInstance().getID(owner); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getForInsert(java.lang.Object, + * java.util.Map, org.hibernate.engine.SessionImplementor) + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object arg0, Map arg1, SessionImplementor arg2) + throws HibernateException { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getReturnType() + */ + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#set(java.lang.Object, + * java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + IdentifierCacheHandler.getInstance().setID(target, value); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/identifier/IdentifierUtil.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/identifier/IdentifierUtil.java new file mode 100755 index 000000000..ab1c4fdc7 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/identifier/IdentifierUtil.java @@ -0,0 +1,179 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: IdentifierUtil.java,v 1.9 2010/11/12 09:33:33 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.identifier; + +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Hashtable; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.teneo.classloader.ClassLoaderResolver; +import org.eclipse.emf.teneo.classloader.StoreClassLoadException; +import org.eclipse.emf.teneo.hibernate.HbDataStore; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.hibernate.EntityMode; +import org.hibernate.engine.ForeignKeys; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.impl.SessionFactoryImpl; +import org.hibernate.impl.SessionImpl; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.type.AbstractStandardBasicType; +import org.hibernate.type.Type; + +/** + * Different identifier related utilities. The current Elver store + * representation does not use the EMF id concept but uses the underlying + * hibernate identifier. This allows more flexibility than the EMF identifier. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.9 $ + */ + +public class IdentifierUtil { + /** The logger */ + // private static Log log = LogFactory.getLog(IdentifierUtil.class); + /** Separator used in encoding the class name and value */ + private static final String ENCODING_SEPARATOR = ";"; + + /** HashTable with identifier types hashed by entityname */ + private static final Hashtable<String, Type> identifierTypeCache = new Hashtable<String, Type>(); + + /** HashTable with cached constructors */ + private static final Hashtable<String, Constructor<?>> constructorCache = new Hashtable<String, Constructor<?>>(); + + /** + * Returns the identifiertype on the basis of the class of the passed object + */ + public static Type getIdentifierType(String className, + SessionImplementor session) { + Type type = identifierTypeCache.get(className); + if (type != null) { + return type; + } + + final Type identifierType = ((SessionImpl) session).getFactory() + .getClassMetadata(className).getIdentifierType(); + identifierTypeCache.put(className, identifierType); + return identifierType; + } + + /** Converts an id to a string representation */ + public static String idToString(Object object, SessionImplementor session) { + + return createIDString( + getIdentifierType(object.getClass().getName(), session), + getID(object, session)); + } + + /** String to id */ + public static Serializable stringToId(String className, + SessionImplementor Session, String idStr) { + return extractID(getIdentifierType(className, Session), idStr); + } + + /** Creates the serializable id object from a string */ + private static Serializable extractID(Type type, String idString) { + // first handle the most common case + if (type instanceof AbstractStandardBasicType) { + final AbstractStandardBasicType<?> ntype = (AbstractStandardBasicType<?>) type; + return (Serializable) ntype.fromStringValue(idString); + } + + // for all other cases the classname of the type is encoded into the + // field + final String className = idString.substring(0, + idString.indexOf(ENCODING_SEPARATOR)); + final String strValue = idString.substring(1 + idString + .indexOf(ENCODING_SEPARATOR)); + + Constructor<?> constructor = constructorCache.get(className); + if (constructor == null) { + try { + final Class<?> clazz = ClassLoaderResolver + .classForName(className); + constructor = clazz + .getConstructor(new Class[] { String.class }); + } catch (StoreClassLoadException e) { + throw new HbMapperException("Class " + className + " not found"); + } catch (NoSuchMethodException e) { + throw new HbMapperException( + "Class " + + className + + " does not have a constructor with a String parameter!"); + } + } + if (constructor == null) { + throw new HbMapperException("Class " + className + + " does not have a constructor with a String parameter!"); + } + + try { + return (Serializable) constructor + .newInstance(new Object[] { strValue }); + } catch (InvocationTargetException e) { + throw new HbMapperException("Can not instantiate: " + className + + " using value " + strValue); + } catch (InstantiationException e) { + throw new HbMapperException("Can not instantiate: " + className + + " using value " + strValue); + } catch (IllegalAccessException e) { + throw new HbMapperException("Can not instantiate: " + className + + " using value " + strValue); + } + } + + /** Returns the id of the passed object */ + @SuppressWarnings("deprecation") + public static Serializable getID(EObject eobj, HbDataStore hd) { + final String entityName = hd.getEntityNameStrategy().toEntityName( + eobj.eClass()); + final EntityPersister entityPersister = ((SessionFactoryImpl) hd + .getSessionFactory()).getEntityPersister(entityName); + return entityPersister.getIdentifier(eobj, EntityMode.MAP); + } + + /** Returns the id of the passed object */ + public static Serializable getID(Object object, SessionImplementor session) { + Serializable id = session.getContextEntityIdentifier(object); + if (id != null) { + return id; + } + + // now with entity name + final String entityName = session.bestGuessEntityName(object); + id = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, object, + session); + if (id != null) { + return id; + } + // now the slow way + return (Serializable) IdentifierCacheHandler.getInstance() + .getID(object); + } + + /** Creates an id string from a serializable object */ + private static String createIDString(Type type, Serializable id) { + if (type instanceof AbstractStandardBasicType) { + @SuppressWarnings("unchecked") + final AbstractStandardBasicType<Object> ntype = (AbstractStandardBasicType<Object>) type; + return ntype.toString(id); + } + + return id.getClass().getName() + ENCODING_SEPARATOR + id.toString(); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/internal/TeneoInternalEObject.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/internal/TeneoInternalEObject.java new file mode 100755 index 000000000..7a85ff477 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/internal/TeneoInternalEObject.java @@ -0,0 +1,14 @@ +package org.eclipse.emf.teneo.hibernate.mapping.internal; + + +import org.eclipse.emf.ecore.InternalEObject; + +/** + * This interface ensures that the cglib proxyfactory does not encounter a security exception + * because the EMF InternalEObject is signed with a different signature. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.1 $ + */ +public interface TeneoInternalEObject extends InternalEObject { +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/DummyPropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/DummyPropertyHandler.java new file mode 100755 index 000000000..33463be2c --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/DummyPropertyHandler.java @@ -0,0 +1,134 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: DummyPropertyHandler.java,v 1.6 2010/11/11 10:28:19 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.property; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * DummyAccessor, does nothing. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.6 $ + */ +public class DummyPropertyHandler implements Getter, Setter, PropertyAccessor { + /** + * Generated Serial Version ID + */ + private static final long serialVersionUID = -5512925601236993580L; + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#get(java.lang.Object) + */ + public Object get(Object owner) throws HibernateException { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getForInsert(java.lang.Object, + * java.util.Map, org.hibernate.engine.SessionImplementor) + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object arg0, Map arg1, SessionImplementor arg2) + throws HibernateException { + return get(arg0); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getReturnType() + */ + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#set(java.lang.Object, + * java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/EAttributePropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/EAttributePropertyHandler.java new file mode 100755 index 000000000..397311ac2 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/EAttributePropertyHandler.java @@ -0,0 +1,391 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EAttributePropertyHandler.java,v 1.20 2010/11/12 14:08:17 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.property; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EEnum; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.teneo.PersistenceOptions; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierCacheHandler; +import org.eclipse.emf.teneo.util.AssertUtil; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * Is a getter and setter for EMF eattribute which uses eGet and eSet.Handles + * many==false properties. + * + * This class implements both the getter, setter and propertyaccessor + * interfaces. When the getGetter and getSetter methods are called it returns + * itself. + * + * This accessor also handles arrays of primitive types. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.20 $ + */ +public class EAttributePropertyHandler implements Getter, Setter, + PropertyAccessor { + /** + * Generated Serial Version ID + */ + private static final long serialVersionUID = 8953817672640618007L; + + /** The logger */ + private static Log log = LogFactory.getLog(EAttributePropertyHandler.class); + + /** The field name for which this elist getter operates */ + protected final EAttribute eAttribute; + + /** The instanceclass */ + protected final Class<?> instanceClass; + + private boolean handleUnsetAsNull = false; + + private boolean convertUnsetToNull = false; + + private boolean isObjectClass = false; + + private boolean isId = false; + + /** Constructor */ + public EAttributePropertyHandler(EAttribute eAttribute) { + this.eAttribute = eAttribute; + instanceClass = eAttribute.getEType().getInstanceClass(); + if (eAttribute.getEType().getInstanceClassName() != null) { + isObjectClass = eAttribute.getEType().getInstanceClassName() + .contains("."); + } + AssertUtil.assertTrue(eAttribute.getName() + + " is a many feature which is not handled by this accessor ", + !eAttribute.isMany()); + log.debug("Created getter/setter for " + StoreUtil.toString(eAttribute)); + } + + public EAttribute getEAttribute() { + return eAttribute; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#get(java.lang.Object) + */ + public Object get(Object owner) throws HibernateException { + if (handleUnsetAsNull || convertUnsetToNull) { + EObject eobj = (EObject) owner; + if (!eobj.eIsSet(eAttribute) && eAttribute.isUnsettable()) { + return null; + } + } + return ((EObject) owner).eGet(eAttribute); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getForInsert(java.lang.Object, + * java.util.Map, org.hibernate.engine.SessionImplementor) + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object arg0, Map arg1, SessionImplementor arg2) + throws HibernateException { + return get(arg0); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getReturnType() + */ + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return eAttribute.getEType().getInstanceClass(); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#set(java.lang.Object, + * java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + + EObject eobj = (EObject) target; + if (value == null) { + if (handleUnsetAsNull && eAttribute.isUnsettable()) { + eobj.eUnset(eAttribute); + } else if (isObjectClass || eAttribute instanceof EEnum) { + eobj.eSet(eAttribute, value); + } + return; + } + + if (isId()) { + IdentifierCacheHandler.getInstance().setID(target, value); + } + + final Object curValue = get(target); + + // do not set if not changed + // note: this does not handle unsettable correctly + // need to make this an option + if (curValue != null && curValue.equals(value)) { + return; + } + if (curValue == value) { + return; + } + + final Object setValue; + if (value != null && instanceClass != null + && value.getClass() != instanceClass) { + final Class<?> valClass = value.getClass(); + if (valClass == Integer[].class) { + setValue = convert((Integer[]) value); + } else if (valClass == Byte[].class) { + setValue = convert((Byte[]) value); + } else if (valClass == Boolean[].class) { + setValue = convert((Boolean[]) value); + } else if (valClass == Double[].class) { + setValue = convert((Double[]) value); + } else if (valClass == Float[].class) { + setValue = convert((Float[]) value); + } else if (valClass == Long[].class) { + setValue = convert((Long[]) value); + } else if (valClass == Short[].class) { + setValue = convert((Short[]) value); + } else { + setValue = convert(value); + } + } else { + setValue = value; + } + eobj.eSet(eAttribute, setValue); + } + + /** Convert to a primitive type */ + private Object convert(Integer[] arr) { + if (instanceClass != int[].class) { + if (log.isDebugEnabled()) { + log.debug("Expecting " + instanceClass.getName() + + " as instance class but it is: " + + arr.getClass().getName()); + } + return arr; + } + final int[] res = new int[arr.length]; + for (int i = 0; i < arr.length; i++) { + res[i] = arr[i].intValue(); + } + return res; + } + + /** Convert to a primitive type */ + private Object convert(Boolean[] arr) { + if (instanceClass != boolean[].class) { + if (log.isDebugEnabled()) { + log.debug("Expecting " + instanceClass.getName() + + " as instance class but it is: " + + arr.getClass().getName()); + } + return arr; + } + final boolean[] res = new boolean[arr.length]; + for (int i = 0; i < arr.length; i++) { + res[i] = arr[i].booleanValue(); + } + return res; + } + + /** Convert to a primitive type */ + private Object convert(Byte[] arr) { + if (instanceClass != byte[].class) { + if (log.isDebugEnabled()) { + log.debug("Expecting " + instanceClass.getName() + + " as instance class but it is: " + + arr.getClass().getName()); + } + return arr; + } + final byte[] res = new byte[arr.length]; + for (int i = 0; i < arr.length; i++) { + res[i] = arr[i].byteValue(); + } + return res; + } + + /** Convert to a primitive type */ + private Object convert(Double[] arr) { + if (instanceClass != double[].class) { + if (log.isDebugEnabled()) { + log.debug("Expecting " + instanceClass.getName() + + " as instance class but it is: " + + arr.getClass().getName()); + } + return arr; + } + final double[] res = new double[arr.length]; + for (int i = 0; i < arr.length; i++) { + res[i] = arr[i].doubleValue(); + } + return res; + } + + /** Convert to a primitive type */ + private Object convert(Float[] arr) { + if (instanceClass != float[].class) { + if (log.isDebugEnabled()) { + log.debug("Expecting " + instanceClass.getName() + + " as instance class but it is: " + + arr.getClass().getName()); + } + return arr; + } + final float[] res = new float[arr.length]; + for (int i = 0; i < arr.length; i++) { + res[i] = arr[i].floatValue(); + } + return res; + } + + /** Convert to a primitive type */ + private Object convert(Long[] arr) { + if (instanceClass != long[].class) { + if (log.isDebugEnabled()) { + log.debug("Expecting [] as instance class but it is: " + + instanceClass.getName()); + } + return arr; + } + final long[] res = new long[arr.length]; + for (int i = 0; i < arr.length; i++) { + res[i] = arr[i].longValue(); + } + return res; + } + + /** Convert to a primitive type */ + private Object convert(Short[] arr) { + if (instanceClass != short[].class) { + if (log.isDebugEnabled()) { + log.debug("Expecting short[] as instance class but it is: " + + instanceClass.getName()); + } + return arr; + } + final short[] res = new short[arr.length]; + for (int i = 0; i < arr.length; i++) { + res[i] = arr[i].shortValue(); + } + return res; + } + + /** Capature all, do not convert */ + private Object convert(Object arr) { + if (arr != null + && instanceClass != null + && (!instanceClass.isPrimitive() || !arr.getClass() + .isPrimitive())) { + log.debug("Expecting " + instanceClass.getName() + + " as instance class but it is: " + + arr.getClass().getName()); + } + return arr; + } + + /** + * Pass in the persistion options. + */ + public void setPersistenceOptions(PersistenceOptions po) { + handleUnsetAsNull = po.getHandleUnsetAsNull(); + convertUnsetToNull = po.getConvertUnsetToNull(); + } + + public boolean isId() { + return isId; + } + + public void setId(boolean isId) { + this.isId = isId; + } + +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/EListPropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/EListPropertyHandler.java new file mode 100755 index 000000000..2d33d4f61 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/EListPropertyHandler.java @@ -0,0 +1,535 @@ +/** + * <copyright> Copyright (c) 2005, 2006, 2007, 2008 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 </copyright> $Id: + * EListPropertyHandler.java,v 1.12 2007/03/20 23:33:48 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.property; + +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.common.util.EMap; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.InternalEObject.EStore; +import org.eclipse.emf.ecore.impl.BasicEObjectImpl; +import org.eclipse.emf.ecore.util.BasicFeatureMap; +import org.eclipse.emf.ecore.util.EcoreEMap; +import org.eclipse.emf.teneo.extension.ExtensionManager; +import org.eclipse.emf.teneo.extension.ExtensionManagerAware; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.mapping.elist.HbExtraLazyPersistableEList; +import org.eclipse.emf.teneo.hibernate.mapping.elist.HbExtraLazyPersistableEMap; +import org.eclipse.emf.teneo.hibernate.mapping.elist.HibernatePersistableEList; +import org.eclipse.emf.teneo.hibernate.mapping.elist.HibernatePersistableEMap; +import org.eclipse.emf.teneo.hibernate.mapping.elist.MapHibernatePersistableEMap; +import org.eclipse.emf.teneo.mapping.elist.MapPersistableEMap; +import org.eclipse.emf.teneo.mapping.elist.PersistableDelegateList; +import org.eclipse.emf.teneo.mapping.elist.PersistableEList; +import org.eclipse.emf.teneo.mapping.elist.PersistableEMap; +import org.eclipse.emf.teneo.type.PersistentStoreAdapter; +import org.eclipse.emf.teneo.util.AssertUtil; +import org.eclipse.emf.teneo.util.FieldUtil; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * Implements the accessor for EMF EList members for Hibernate. This can be an + * EReference or an Eattribute with many=true. This class implements both the + * getter, setter and propertyaccessor interfaces. When the getGetter and + * getSetter methods are called it returns itself. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.39 $ + */ +@SuppressWarnings("unchecked") +public class EListPropertyHandler implements Getter, Setter, PropertyAccessor, + ExtensionPoint, ExtensionManagerAware { + /** + * Generated Serial Version ID + */ + private static final long serialVersionUID = 2255108246093951341L; + + /** The logger */ + private static Log log = LogFactory.getLog(EListPropertyHandler.class); + + /** The EStructuralFeature of this accessor */ + protected EStructuralFeature eFeature; + + /** Extra lazy behavior! */ + private boolean extraLazy; + + /** Map emap as a real map */ + private boolean newEMapMapping; + + /** It this a map */ + private boolean isAMap; + + /** The extension manager */ + private ExtensionManager extensionManager; + + /** Initialize this instance */ + public void initialize(EStructuralFeature eFeature, boolean extraLazy, + boolean newEMapMapping) { + this.extraLazy = extraLazy; + this.eFeature = eFeature; + log.debug("Created getter/setter for " + StoreUtil.toString(eFeature)); + AssertUtil.assertTrue("Many must be true but this isn't the case for " + + StoreUtil.toString(eFeature), eFeature.isMany()); + isAMap = StoreUtil.isMap(eFeature); + this.newEMapMapping = newEMapMapping; + } + + public EStructuralFeature getEFeature() { + return eFeature; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#get(java.lang.Object) + */ + public Object get(Object owner) throws HibernateException { + + final PersistentStoreAdapter adapter = StoreUtil + .getPersistentStoreAdapter((EObject) owner); + final Object value = adapter.getStoreCollection(eFeature); + if (value != null) { + return value; + } + + Object obj = ((EObject) owner).eGet(eFeature); + + if (StoreUtil.isEStoreList(obj)) { + final EStore eStore = ((InternalEObject) owner).eStore(); + // the call to size forces a load, this is a trick to + // force the estore to create a list, otherwise the .get + // will return a null value. + if (eStore.size((InternalEObject) owner, eFeature) != -1) { + obj = eStore.get((InternalEObject) owner, eFeature, + EStore.NO_INDEX); + } + } + + if (obj instanceof PersistableDelegateList<?>) { + return ((PersistableDelegateList<?>) obj).getDelegate(); + } + if (obj instanceof EcoreEMap<?, ?> && newEMapMapping) { + return ((EcoreEMap<?, ?>) obj).map(); + } + + if (adapter.isTargetCreatedByORM() && obj instanceof BasicFeatureMap) { + // this one is replaced here + // because the entries + // need to be changed to hibernate entries + final PersistableDelegateList<?> pelist = (PersistableDelegateList<?>) createPersistableList( + (InternalEObject) owner, eFeature, (List<?>) obj); + final EObject eobj = (EObject) owner; + if (!EcoreAccess.isStaticFeature(eFeature, (BasicEObjectImpl) eobj)) { + if (log.isDebugEnabled()) { + log.debug("Dynamic elist, set using the esettings"); + } + EcoreAccess.setManyEFeatureValue(eFeature, pelist, + (BasicEObjectImpl) owner); + } else { + // TODO: currently it is required to use the field setter + // instead of the eSet method + // because EMF does not support direct setting of the elist + // feature. + // UPDATE: for dynamic eclasses now elists are also supported + // the reason that the javafield is determined here and not at + // construction time + // is that the owner passed in the construction can be an + // interface while there + // are multiple implementors. FieldUtil does caching of + // fieldnames and fields. + final Field javaField = FieldUtil.getField(owner.getClass(), + getFieldName(owner)); + try { + javaField.set(owner, pelist); + } catch (Exception e) { + throw new HbMapperException("The field " + + javaField.getName() + + " can not be set using object " + + pelist.getClass().getName() + " on target " + + owner.getClass().getName(), e); + } + } + } + + if (obj instanceof EList<?>) { + return processList(obj); + } + + return obj; + } + + protected String getFieldName(Object owner) { + return eFeature.getName(); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getForInsert(java.lang.Object, + * java.util.Map, org.hibernate.engine.SessionImplementor) + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object owner, Map mergeMap, + SessionImplementor session) throws HibernateException { + final PersistentStoreAdapter adapter = StoreUtil + .getPersistentStoreAdapter((EObject) owner); + final Object value = adapter.getStoreCollection(eFeature); + if (value != null) { + return value; + } + + Object obj = ((EObject) owner).eGet(eFeature); + + if (StoreUtil.isEStoreList(obj)) { + final EStore eStore = ((InternalEObject) owner).eStore(); + // the call to size forces a load, this is a trick to + // force the estore to create a list, otherwise the .get + // will return a null value. + if (eStore.size((InternalEObject) owner, eFeature) != -1) { + obj = eStore.get((InternalEObject) owner, eFeature, + EStore.NO_INDEX); + } + } + + if (obj instanceof PersistableDelegateList) { + return ((PersistableDelegateList) obj).getDelegate(); + } + if (obj instanceof EcoreEMap && newEMapMapping) { + return ((EcoreEMap<?, ?>) obj).map(); + } + + // if this is a elist then give a normal arraylist to + // hibernate otherwise hb will wrap the elist, the hb wrapper + // is again wrapped by teneo resulting in notifications being send + // out by both the teneo wrapper as the wrapped elist + if (obj instanceof EList<?>) { + final List<Object> objects = processList(obj); + if (extraLazy) { + int index = 0; + for (Object object : objects) { + if (object instanceof EObject) { + final PersistentStoreAdapter elementAdapter = StoreUtil + .getPersistentStoreAdapter((EObject) object); + elementAdapter + .setSyntheticProperty( + StoreUtil + .getExtraLazyInverseIndexPropertyName(eFeature), + index); + elementAdapter.setSyntheticProperty(StoreUtil + .getExtraLazyInversePropertyName(eFeature), + owner); + } + index++; + } + } + return objects; + } + + // todo maybe throw error in all other cases? + return obj; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getReturnType() + */ + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return EList.class; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#set(java.lang.Object, + * java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + @SuppressWarnings("rawtypes") + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + + final PersistentStoreAdapter adapter = StoreUtil + .getPersistentStoreAdapter((EObject) target); + if (!adapter.isTargetCreatedByORM()) { + adapter.addStoreCollection(eFeature, value); + return; + } + + if (!EcoreAccess.isStaticFeature(eFeature, (BasicEObjectImpl) target)) { + if (log.isDebugEnabled()) { + log.debug("Dynamic elist, set using the esettings"); + } + Object currentValue = EcoreAccess.getManyEFeatureValue(eFeature, + (BasicEObjectImpl) target); + + if (StoreUtil.isEStoreList(currentValue)) { + final EStore eStore = ((InternalEObject) target).eStore(); + if (eStore.size((InternalEObject) target, eFeature) != -1) { + currentValue = eStore.get((InternalEObject) target, + eFeature, EStore.NO_INDEX); + } + } + + // if currentvalue is not null then use the passed value + if (currentValue != null + && currentValue instanceof PersistableEList<?>) { + ((PersistableEList<?>) currentValue) + .replaceDelegate((List) value); + } else { + if (value instanceof Map<?, ?>) { + EcoreAccess.setManyEFeatureValue( + eFeature, + createPersistableMap((InternalEObject) target, + eFeature, (Map<?, ?>) value), + (BasicEObjectImpl) target); + } else { + EcoreAccess.setManyEFeatureValue( + eFeature, + createPersistableList((InternalEObject) target, + eFeature, (List<?>) value), + (BasicEObjectImpl) target); + } + } + if (log.isDebugEnabled()) { + log.debug("Set value " + value.getClass().getName() + + " for target " + target.getClass().getName() + + " field " + getFieldName(target)); + } + + } else { + // the reason that the javafield is determined here and not at + // construction time + // is that the owner passed in the construction can be an interface + // while there + // are multiple implementors. FieldUtil does caching of fieldnames + // and fields. + final Field javaField = FieldUtil.getField(target.getClass(), + getFieldName(target)); + + // do not set the java field if not present, but use the store + // adapter + // this happens in case of gmf see bugzilla: 280040 + if (javaField == null) { + adapter.addStoreCollection(eFeature, value); + return; + } + + try { + final Object currentValue = javaField.get(target); + + // if already set then ignore it + if (currentValue == value) { + return; // nothing to do here + } + + // the delegating map was passed to hibernate, now getting it + // back + if (value instanceof EMap.InternalMapView<?, ?> + && (currentValue == ((EMap.InternalMapView<?, ?>) value) + .eMap())) { + return; + } + + // already handled + if (currentValue instanceof PersistableDelegateList<?> + && value == ((PersistableDelegateList<?>) currentValue) + .getDelegate()) { + return; + } + + // the follow 3 if statements handle the refresh action, the + // underlying orm + // collection is replaced + if (currentValue != null + && currentValue instanceof PersistableEList<?> + && value != ((PersistableEList<?>) currentValue) + .getDelegate()) { + ((PersistableEList<?>) currentValue) + .replaceDelegate((List) value); + } else if (currentValue != null + && currentValue instanceof PersistableEMap<?, ?> + && value != ((PersistableEMap<?, ?>) currentValue) + .getDelegate()) { + ((PersistableEMap<?, ?>) currentValue) + .replaceDelegate(value); + } else if (currentValue != null + && currentValue instanceof MapPersistableEMap<?, ?> + && value != ((MapPersistableEMap<?, ?>) currentValue) + .getORMMapDelegate()) { + ((PersistableEMap<?, ?>) currentValue) + .replaceDelegate(value); + } else { // then wrap the hibernate collection + if (value instanceof Map<?, ?>) { + javaField.set( + target, + createPersistableMap((InternalEObject) target, + eFeature, (Map<?, ?>) value)); + } else { + javaField.set( + target, + createPersistableList((InternalEObject) target, + eFeature, (List<?>) value)); + } + } + if (log.isDebugEnabled()) { + log.debug("Set value " + value.getClass().getName() + + " for target " + target.getClass().getName() + + " field " + getFieldName(target)); + } + } catch (Exception e) { + throw new HbMapperException("The field " + + (javaField != null ? javaField.getName() + : getFieldName(target)) + + " can not be set using object " + + value.getClass().getName() + " on target " + + target.getClass().getName(), e); + } + } + } + + /** + * Create a EMap. Create method can be overridden + */ + protected EList<?> createPersistableMap(InternalEObject target, + EStructuralFeature estruct, Map<?, ?> map) { + final EReference eref = (EReference) estruct; + if (log.isDebugEnabled()) { + log.debug("Detected EMAP for " + estruct.getName()); + } + assert (isAMap); + assert (newEMapMapping); + return getExtensionManager().getExtension( + MapHibernatePersistableEMap.class, + new Object[] { target, eref, map }); + } + + /** Creates a persistablemap or list */ + protected EList<?> createPersistableList(InternalEObject target, + EStructuralFeature estruct, List<?> list) { + if (estruct instanceof EReference) { + final EReference eref = (EReference) estruct; + // the test for emap checks: the entry class must have a + // instanceclass: Map.Entry + // and the entry class must have two efeatures with the name key and + // value + if (StoreUtil.isMap(estruct)) { + if (log.isDebugEnabled()) { + log.debug("Detected EMAP for " + estruct.getName()); + } + if (extraLazy) { + return getExtensionManager().getExtension( + HbExtraLazyPersistableEMap.class, + new Object[] { target, eref, list }); + } else { + return getExtensionManager().getExtension( + HibernatePersistableEMap.class, + new Object[] { target, eref, list }); + } + } + } + if (extraLazy) { + return getExtensionManager().getExtension( + HbExtraLazyPersistableEList.class, + new Object[] { target, estruct, list }); + } + return getExtensionManager().getExtension( + HibernatePersistableEList.class, + new Object[] { target, estruct, list }); + } + + protected List<Object> processList(Object list) { + return new ArrayList<Object>((List<Object>) list); + } + + /** + * @return the extensionManager + */ + public ExtensionManager getExtensionManager() { + return extensionManager; + } + + /** + * @param extensionManager + * the extensionManager to set + */ + public void setExtensionManager(ExtensionManager extensionManager) { + this.extensionManager = extensionManager; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/EReferencePropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/EReferencePropertyHandler.java new file mode 100755 index 000000000..9c411e6e7 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/EReferencePropertyHandler.java @@ -0,0 +1,252 @@ +/** + * <copyright> Copyright (c) 2005, 2006, 2007, 2008 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 </copyright> $Id: + * EReferencePropertyHandler.java,v 1.4 2007/04/07 12:43:51 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.property; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.common.notify.NotificationChain; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.impl.DynamicEObjectImpl; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierCacheHandler; +import org.eclipse.emf.teneo.hibernate.resource.HibernateResource; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * Implements the getter for an EReference field. Normally uses the eget/eset + * methods with bidirectional relations the handling is a bit different using + * eInverseRemove and eInverseAdd. This class implements both the getter, setter + * and propertyaccessor interfaces. When the getGetter and getSetter methods are + * called it returns itself. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.21 $ + */ +public class EReferencePropertyHandler implements Getter, Setter, + PropertyAccessor, ExtensionPoint { + + /** + * Serial version id + */ + private static final long serialVersionUID = -3712366809398761331L; + + /** The logger */ + private static Log log = LogFactory.getLog(EReferencePropertyHandler.class); + + /** The feature */ + protected EReference eReference; + + /** Two way reference */ + protected boolean isBidirectional; + + private int featureId = -1; + + private boolean isId = false; + + public void initialize(EReference eReference) { + this.eReference = eReference; + final EClass eClass = eReference.getEContainingClass(); + featureId = eClass.getFeatureID(eReference); + isBidirectional = (eReference.getEOpposite() != null && !eReference + .getEOpposite().isTransient()); + log.debug("Created getter/setter for " + StoreUtil.toString(eReference)); + } + + public EReference getEReference() { + return eReference; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#get(java.lang.Object) + */ + public Object get(Object owner) throws HibernateException { + // see bugzilla: 283680, in case of cascading having this + // to false ment that Hibernate encountered unresolved/empty + // object + // return ((EObject) owner).eGet(eReference, false); + return ((EObject) owner).eGet(eReference, true); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getForInsert(java.lang.Object, + * java.util.Map, org.hibernate.engine.SessionImplementor) + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object owner, Map mergeMap, + SessionImplementor session) throws HibernateException { + return get(owner); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#set(java.lang.Object, + * java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + final Object curValue = get(target); + + if (isId()) { + IdentifierCacheHandler.getInstance().setID(target, value); + } + + if (isBidirectional + || (target instanceof DynamicEObjectImpl && eReference + .isContainment())) { + // these are handled a bit differently because + // the opposite should not be set, this is + // done by hb + if (curValue != value) { // note that == works fine if the + // curValue and value have been read in + // the same + // pm. + // Note that the eInverseRemove is called on the target itself + // and the value is + // passed + // therefore the eReference featureid is passed and not the + // opposite + if (value == null) { // remove + final NotificationChain nots = ((InternalEObject) target) + .eInverseRemove((InternalEObject) curValue, + featureId, eReference.getEType() + .getInstanceClass(), null); + if (nots != null) { + nots.dispatch(); + } + } else { + final NotificationChain nots = ((InternalEObject) target) + .eInverseAdd((InternalEObject) value, featureId, + eReference.getEType().getInstanceClass(), + null); + if (nots != null) { + nots.dispatch(); + } + } + } + } else { + if (curValue == value) { + return; // do nothing in this case + } + final EObject eobj = (EObject) target; + eobj.eSet(eReference, value); + } + final EObject eobj = (EObject) target; + Resource res = eobj.eResource(); + if (value != null && res instanceof HibernateResource + && ((EObject) value).eResource() == null) { + final boolean loading = ((HibernateResource) res).isLoading(); + try { + ((HibernateResource) res).setIsLoading(true); + ((HibernateResource) res).addToContentOrAttach( + (InternalEObject) value, eReference); + } finally { + ((HibernateResource) res).setIsLoading(loading); + } + } + + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=245634 + // container relations should be modeled explicitly in the database or + // not at all + // see the relevant option in PersistenceOptions. + // if (eReference.isContainment() && target instanceof InternalEObject + // && value instanceof InternalEObject) { + // EContainerRepairControl.setContainer((InternalEObject) target, + // (InternalEObject) value, eReference); + // } + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getReturnType() + */ + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return InternalEObject.class; + } + + public boolean isId() { + return isId; + } + + public void setId(boolean isId) { + this.isId = isId; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/EcoreAccess.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/EcoreAccess.java new file mode 100755 index 000000000..56a50970d --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/EcoreAccess.java @@ -0,0 +1,76 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EcoreAccess.java,v 1.9 2010/11/05 09:23:32 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.property; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.EStructuralFeature.Internal.DynamicValueHolder; +import org.eclipse.emf.ecore.impl.BasicEObjectImpl; +import org.eclipse.emf.ecore.impl.DynamicEObjectImpl; +import org.eclipse.emf.teneo.util.FieldUtil; + +/** + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.9 $ + */ +public class EcoreAccess { + + /** Return the DynamicValueHolder */ + public static DynamicValueHolder getValueHolder(BasicEObjectImpl deo) { + if (deo instanceof DynamicValueHolder + && !(deo instanceof DynamicEObjectImpl)) { + return (DynamicValueHolder) deo; + } + return (DynamicValueHolder) FieldUtil + .callMethod(deo, "eSettings", null); + } + + /** Sets an elist using the passed feature */ + public static void setManyEFeatureValue(EStructuralFeature eFeature, + Object value, BasicEObjectImpl owner) { + final DynamicValueHolder dvh = getValueHolder(owner); + dvh.dynamicSet(getFeatureId(owner, eFeature), value); + } + + /** Gets an elist using the passed feature */ + public static EList<?> getManyEFeatureValue(EStructuralFeature eFeature, + BasicEObjectImpl owner) { + final DynamicValueHolder dvh = getValueHolder(owner); + return (EList<?>) dvh.dynamicGet(getFeatureId(owner, eFeature)); + } + + public static int getFeatureId(BasicEObjectImpl owner, + EStructuralFeature eFeature) { + int featureId = owner.eClass().getFeatureID(eFeature); + if (!isStaticFeature(eFeature, owner)) { + final int staticFeatureCount = (Integer) FieldUtil.callMethod( + owner, "eStaticFeatureCount", null); + featureId = featureId - staticFeatureCount; + } + return featureId; + } + + /** Determines if a passed feature is a static feature */ + public static boolean isStaticFeature(EStructuralFeature eFeature, + BasicEObjectImpl owner) { + Integer staticFeatureCount = (Integer) FieldUtil.callMethod(owner, + "eStaticFeatureCount", null); + return owner.eClass().getFeatureID(eFeature) < staticFeatureCount + .intValue(); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/FeatureMapEntryFeatureURIPropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/FeatureMapEntryFeatureURIPropertyHandler.java new file mode 100755 index 000000000..38c16b8b7 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/FeatureMapEntryFeatureURIPropertyHandler.java @@ -0,0 +1,138 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: FeatureMapEntryFeatureURIPropertyHandler.java,v 1.8 2010/11/11 10:28:19 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.property; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.mapping.elist.HibernateFeatureMapEntry; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * Handles the string representation of the feature of the feature map entry in + * the database. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.8 $ + */ +public class FeatureMapEntryFeatureURIPropertyHandler implements Getter, + Setter, PropertyAccessor, ExtensionPoint { + /** + * Generated Version ID + */ + private static final long serialVersionUID = 7334975651233065801L; + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /** + * Reads the version from the versioncache + */ + public Object get(Object owner) throws HibernateException { + if (!(owner instanceof HibernateFeatureMapEntry)) { + final FeatureMap.Entry smf = (FeatureMap.Entry) owner; + return StoreUtil.structuralFeatureToString(smf + .getEStructuralFeature()); + } + final HibernateFeatureMapEntry fme = (HibernateFeatureMapEntry) owner; + return fme.getFeatureURI(); + } + + /** + * Reads the version from the versioncache + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object owner, Map mergeMap, + SessionImplementor session) throws HibernateException { + return get(owner); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /** Returns Integer.class */ + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return String.class; + } + + /** Sets the version in the internal version cache */ + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + if (!(target instanceof HibernateFeatureMapEntry)) { + // do nothing as value has not change... + return; + } + final HibernateFeatureMapEntry fme = (HibernateFeatureMapEntry) target; + fme.setEStructuralFeature((String) value); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/FeatureMapEntryPropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/FeatureMapEntryPropertyHandler.java new file mode 100755 index 000000000..ecedba9c1 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/FeatureMapEntryPropertyHandler.java @@ -0,0 +1,177 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: FeatureMapEntryPropertyHandler.java,v 1.9 2010/11/11 10:28:19 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.property; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.mapping.elist.HibernateFeatureMapEntry; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * Implements the getter/setter for the featuremap entry. + * + * This class implements both the getter, setter and propertyaccessor + * interfaces. When the getGetter and getSetter methods are called it returns + * itself. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.9 $ + */ +public class FeatureMapEntryPropertyHandler implements Getter, Setter, + PropertyAccessor, ExtensionPoint { + + /** + * Generated Version ID + */ + private static final long serialVersionUID = -2659637883475733107L; + + /** The logger */ + private static Log log = LogFactory + .getLog(FeatureMapEntryPropertyHandler.class); + + /** The feature */ + protected EStructuralFeature eFeature; + + /** Constructor */ + public void initialize(EStructuralFeature eFeature) { + this.eFeature = eFeature; + log.debug("Created getter/setter for " + StoreUtil.toString(eFeature)); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#get(java.lang.Object) + */ + public Object get(Object owner) throws HibernateException { + if (!(owner instanceof HibernateFeatureMapEntry)) { + final FeatureMap.Entry smf = (FeatureMap.Entry) owner; + if (smf.getEStructuralFeature() == eFeature) { + return smf.getValue(); + } else { + return null; + } + } + final HibernateFeatureMapEntry fme = (HibernateFeatureMapEntry) owner; + final Object value = fme.getValue(eFeature); + return value; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getForInsert(java.lang.Object, + * java.util.Map, org.hibernate.engine.SessionImplementor) + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object owner, Map mergeMap, + SessionImplementor session) throws HibernateException { + final Object value = get(owner); + return value; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#set(java.lang.Object, + * java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + if (!(target instanceof HibernateFeatureMapEntry)) { + // happens during initial save, value has not changed do nothing! + return; + } + final HibernateFeatureMapEntry fme = (HibernateFeatureMapEntry) target; + fme.addFeatureValue(eFeature, value); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getReturnType() + */ + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return HibernateFeatureMapEntry.class; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/FeatureMapPropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/FeatureMapPropertyHandler.java new file mode 100755 index 000000000..af222c751 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/FeatureMapPropertyHandler.java @@ -0,0 +1,76 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: FeatureMapPropertyHandler.java,v 1.10 2010/02/04 10:53:07 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.property; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.ecore.util.FeatureMapUtil; +import org.eclipse.emf.teneo.extension.ExtensionManagerAware; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.mapping.elist.HibernateFeatureMapEntry; +import org.eclipse.emf.teneo.hibernate.mapping.elist.HibernatePersistableFeatureMap; +import org.eclipse.emf.teneo.util.AssertUtil; +import org.eclipse.emf.teneo.util.StoreUtil; + +/** + * Implements the accessor for EMF FeatureMap members for Hibernate. Overrides the createPersistableList to create a + * HibernatePersistableFeatureMap instead of a normal list. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.10 $ + */ +@SuppressWarnings("unchecked") +public class FeatureMapPropertyHandler extends EListPropertyHandler implements ExtensionPoint, ExtensionManagerAware { + /** + * Generated Serial Version ID + */ + private static final long serialVersionUID = -5220024660708935714L; + + /** Initialize this instance */ + public void initialize(EStructuralFeature eFeature) { + super.initialize(eFeature, false, false); + AssertUtil.assertTrue("Is not a featuremap feature " + StoreUtil.toString(eFeature), FeatureMapUtil + .isFeatureMap(eFeature)); + } + + /** Create method can be overridden */ + @SuppressWarnings("rawtypes") + @Override + protected EList<?> createPersistableList(InternalEObject target, EStructuralFeature estruct, List list) { + return new HibernatePersistableFeatureMap(target, estruct, list); + } + + // replaces all entries in a featuremap with a persistable one + @Override + protected List<Object> processList(Object list) { + final List<Object> result = new ArrayList<Object>(); + + final FeatureMap featureMap = (FeatureMap) list; + for (FeatureMap.Entry entry : featureMap) { + final HibernateFeatureMapEntry fme = new HibernateFeatureMapEntry(); + fme.setFeatureValue(entry.getEStructuralFeature(), entry.getValue(), (FeatureMap.Internal) list); + result.add(fme); + } + return result; + } + +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/SyntheticPropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/SyntheticPropertyHandler.java new file mode 100644 index 000000000..63a9270f7 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/SyntheticPropertyHandler.java @@ -0,0 +1,161 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: SyntheticPropertyHandler.java,v 1.5 2010/11/11 10:28:19 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.property; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.teneo.type.PersistentStoreAdapter; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * Is a getter and setter for EMF eattribute which uses eGet and eSet.Handles + * many==false properties. + * + * This class implements both the getter, setter and propertyaccessor + * interfaces. When the getGetter and getSetter methods are called it returns + * itself. + * + * This accessor also handles arrays of primitive types. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.5 $ + */ +public class SyntheticPropertyHandler implements Getter, Setter, + PropertyAccessor { + + /** + * Generated Serial Version ID + */ + private static final long serialVersionUID = 8953817672640618007L; + + // private static Log log = + // LogFactory.getLog(SyntheticPropertyHandler.class); + + private String propertyName; + + /** Constructor */ + public SyntheticPropertyHandler(String propertyName) { + this.propertyName = propertyName; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#get(java.lang.Object) + */ + public Object get(Object owner) throws HibernateException { + final PersistentStoreAdapter adapter = StoreUtil + .getPersistentStoreAdapter((EObject) owner); + return adapter.getSyntheticProperty(propertyName); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getForInsert(java.lang.Object, + * java.util.Map, org.hibernate.engine.SessionImplementor) + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object arg0, Map arg1, SessionImplementor arg2) + throws HibernateException { + return get(arg0); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getReturnType() + */ + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return Object.class; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#set(java.lang.Object, + * java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + final PersistentStoreAdapter adapter = StoreUtil + .getPersistentStoreAdapter((EObject) target); + adapter.setSyntheticProperty(propertyName, value); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/VersionPropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/VersionPropertyHandler.java new file mode 100755 index 000000000..f9c21f4c3 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/VersionPropertyHandler.java @@ -0,0 +1,124 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: VersionPropertyHandler.java,v 1.8 2010/11/11 10:28:18 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.property; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierCacheHandler; +import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * Reads the version from the internal version cache. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.8 $ + */ +public class VersionPropertyHandler implements Getter, Setter, + PropertyAccessor, ExtensionPoint { + /** + * Generated Serial Version ID + */ + private static final long serialVersionUID = -7004553329654520847L; + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /** + * Reads the version from the versioncache + */ + public Object get(Object owner) throws HibernateException { + return IdentifierCacheHandler.getInstance().getVersion(owner); + } + + /** + * Reads the version from the versioncache + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object owner, Map mergeMap, + SessionImplementor session) throws HibernateException { + return IdentifierCacheHandler.getInstance().getVersion(owner); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /** Returns Integer.class */ + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return Integer.class; + } + + /** Sets the version in the internal version cache */ + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + IdentifierCacheHandler.getInstance().setVersion(target, value); + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/WildCardAttributePropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/WildCardAttributePropertyHandler.java new file mode 100644 index 000000000..196fcae57 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/WildCardAttributePropertyHandler.java @@ -0,0 +1,180 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: WildCardAttributePropertyHandler.java,v 1.3 2010/11/11 10:28:19 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.property; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.mapping.elist.HibernateFeatureMapEntry; +import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * Implements the getter/setter for a wild card EAttribute property. This type + * of property is used in a feature map created for wild cards. + * + * This class implements both the getter, setter and propertyaccessor + * interfaces. When the getGetter and getSetter methods are called it returns + * itself. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.3 $ + */ +public class WildCardAttributePropertyHandler implements Getter, Setter, + PropertyAccessor, ExtensionPoint { + + /** + * Generated Version ID + */ + private static final long serialVersionUID = -2659637883475733107L; + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#get(java.lang.Object) + */ + public Object get(Object owner) throws HibernateException { + final Object value; + final EStructuralFeature eFeature; + if (!(owner instanceof HibernateFeatureMapEntry)) { + final FeatureMap.Entry fme = (FeatureMap.Entry) owner; + value = fme.getValue(); + eFeature = fme.getEStructuralFeature(); + } else { + final HibernateFeatureMapEntry fme = (HibernateFeatureMapEntry) owner; + value = fme.getValue(); + eFeature = fme.getEStructuralFeature(); + } + // not handled by this one + if (value instanceof EObject) { + return null; + } + if (value == null) { + return null; + } + final EAttribute eAttribute = (EAttribute) eFeature; + final EDataType eDataType = eAttribute.getEAttributeType(); + final String valueString = eDataType.getEPackage() + .getEFactoryInstance().convertToString(eDataType, value); + return valueString; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getForInsert(java.lang.Object, + * java.util.Map, org.hibernate.engine.SessionImplementor) + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object owner, Map mergeMap, + SessionImplementor session) throws HibernateException { + final Object value = get(owner); + return value; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#set(java.lang.Object, + * java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + if (!(target instanceof HibernateFeatureMapEntry)) { + // happens during initial save + return; + } + final HibernateFeatureMapEntry fme = (HibernateFeatureMapEntry) target; + if (value != null && !(value instanceof EObject)) { + // will be converted inside the HibernateFeatureMapEntry + fme.setValue(value); + } + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getReturnType() + */ + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return EObject.class; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/WildCardReferencePropertyHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/WildCardReferencePropertyHandler.java new file mode 100644 index 000000000..9be9862eb --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/mapping/property/WildCardReferencePropertyHandler.java @@ -0,0 +1,166 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: WildCardReferencePropertyHandler.java,v 1.3 2010/11/11 10:28:18 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.mapping.property; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Map; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.hibernate.mapping.elist.HibernateFeatureMapEntry; +import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; + +/** + * Implements the getter/setter for a wild card reference property. This type of + * property is used in a feature map created for wild cards. + * + * This class implements both the getter, setter and propertyaccessor + * interfaces. When the getGetter and getSetter methods are called it returns + * itself. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.3 $ + */ +public class WildCardReferencePropertyHandler implements Getter, Setter, + PropertyAccessor, ExtensionPoint { + + /** + * Generated Version ID + */ + private static final long serialVersionUID = -2659637883475733107L; + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getGetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Getter getGetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.PropertyAccessor#getSetter(java.lang.Class, + * java.lang.String) + */ + @SuppressWarnings("rawtypes") + public Setter getSetter(Class theClass, String propertyName) + throws PropertyNotFoundException { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMember() + */ + public Member getMember() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#get(java.lang.Object) + */ + public Object get(Object owner) throws HibernateException { + Object value = null; + if (!(owner instanceof HibernateFeatureMapEntry)) { + value = ((FeatureMap.Entry) owner).getValue(); + } else { + final HibernateFeatureMapEntry fme = (HibernateFeatureMapEntry) owner; + value = fme.getValue(); + } + // handled by this one + if (value instanceof EObject) { + return value; + } + // are handled by other property handler + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getForInsert(java.lang.Object, + * java.util.Map, org.hibernate.engine.SessionImplementor) + */ + @SuppressWarnings("rawtypes") + public Object getForInsert(Object owner, Map mergeMap, + SessionImplementor session) throws HibernateException { + final Object value = get(owner); + return value; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Setter#set(java.lang.Object, + * java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + public void set(Object target, Object value, + SessionFactoryImplementor factory) throws HibernateException { + if (!(target instanceof HibernateFeatureMapEntry)) { + // happens during initial save, value has not changed do nothing + return; + } + final HibernateFeatureMapEntry fme = (HibernateFeatureMapEntry) target; + if (value != null && value instanceof EObject) { + fme.setValue(value); + } + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethod() + */ + public Method getMethod() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getMethodName() + */ + public String getMethodName() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.property.Getter#getReturnType() + */ + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return EObject.class; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HbResource.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HbResource.java new file mode 100755 index 000000000..31d1ca7c4 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HbResource.java @@ -0,0 +1,47 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HbResource.java,v 1.5 2008/02/28 07:08:24 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.resource; + +import org.eclipse.emf.teneo.hibernate.SessionWrapper; +import org.hibernate.Session; + +/** + * Defines the common interface for HbResource Impls. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.5 $ + */ + +public interface HbResource { + + /** + * Returns the session of the resource. + */ + Session getSession(); + + /** Returns the session to the resource so that it can do clean up (or not) */ + void returnSession(Session session); + + /** Set isloading on the resource */ + void setIsLoading(boolean isLoading); + + /** Return the sessionwrapper */ + public SessionWrapper getSessionWrapper(); + + /** Returns the sessionwrapper to the resource so that it can do clean up (or not) */ + void returnSessionWrapper(SessionWrapper sessionWrapper); +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HbResourceImpl.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HbResourceImpl.java new file mode 100755 index 000000000..3ccbece35 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HbResourceImpl.java @@ -0,0 +1,392 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HbResourceImpl.java,v 1.12 2011/02/21 05:06:13 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.resource; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.URIConverter; +import org.eclipse.emf.teneo.Constants; +import org.eclipse.emf.teneo.hibernate.EMFInterceptor; +import org.eclipse.emf.teneo.hibernate.HbConstants; +import org.eclipse.emf.teneo.hibernate.HbDataStore; +import org.eclipse.emf.teneo.hibernate.HbHelper; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.HbSessionWrapper; +import org.eclipse.emf.teneo.hibernate.HbUtil; +import org.eclipse.emf.teneo.hibernate.SessionWrapper; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierUtil; +import org.eclipse.emf.teneo.resource.StoreResource; +import org.hibernate.FlushMode; +import org.hibernate.LockOptions; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.collection.PersistentCollection; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.util.IdentityMap; + +/** + * HbResource. This hibernate resource creates a new session for each load and + * save action. When elists are lazily loaded then a new Session is created and + * the current content is added to the session. + * + * When you create a HbDataStore through the appropriate method in the HbHelper + * class. The name you passed there can be used as a parameter in the uri used + * to create this resource (using the parameter pmfname). The uri is then: + * hibernate://?dsname=myemf. + * + * Another simple trick which is used to fool emf a bit is that the extension of + * the uri can also be used to init a hibernate resource! + * + * WARNING: This is an untested and experimental class, it is not intended to be + * used in production situations. + * + * This class does not support the SessionController. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.12 $ + */ + +public class HbResourceImpl extends StoreResource implements HbResource { + /** The logger */ + private static Log log = LogFactory.getLog(HbResourceImpl.class); + + /** This threadlocal can be used by lazy loaders to store a session */ + // public static final ThreadLocal threadSession = new ThreadLocal(); + /** The store used to determine where to query for the data */ + protected HbDataStore emfDataStore; + + /** + * The constructor, gets an uri and retrieves the backing OJBStore + */ + public HbResourceImpl(URI uri) { + super(uri); + + log.debug("Creating hibernateresource using uri: " + uri.toString()); + + final Map<String, String> params = decodeQueryString(uri.query()); + + String emfdsName = null; + if (uri.query() == null && uri.fileExtension() != null) // this is + // probably a + // platform uri! + { + if (HbConstants.EHB_FILE_EXTENSION.compareTo(uri.fileExtension()) == 0) { + log.debug("Assuming this is a property file " + uri.toString()); + try { + final URIConverter uriConverter = getURIConverter(); + final InputStream is = uriConverter.createInputStream(uri); + final Properties props = new Properties(); + props.load(is); + is.close(); + emfdsName = props.getProperty(Constants.PROP_NAME); + emfDataStore = HbUtil.getCreateDataStore(props); + setDefinedQueries(getQueries(props)); + } catch (IOException e) { + throw new HbMapperException( + "Exception when reading properties from: " + + uri.toString(), e); + } + } else { + log.debug("Trying fileextension: " + uri.fileExtension()); + // then try the extension of the resource + emfdsName = uri.fileExtension(); + } + } else if (params.get(DS_NAME_PARAM) != null) // only the name + { + emfdsName = getParam(params, DS_NAME_PARAM, uri.query()); + setDefinedQueries(getQueries(params)); + } + + if (emfdsName == null) { + throw new HbMapperException( + "The Resource can not be initialized using the querystring: " + + uri.query() + + ". Are all the required parameters present?"); + } + log.debug("Looking for emf data store using " + emfdsName); + + emfDataStore = HbHelper.INSTANCE.getDataStore(emfdsName); + + super.init(emfDataStore.getTopEntities()); + } + + /** Returns the emfdatastore */ + public HbDataStore getEMFDataStore() { + return emfDataStore; + } + + /** + * Creates the session of this resource. As a default the FlushMode is set + * to Never. The loaded objects of this resource are merged into the + * session. It is the responsibility of the caller to close the session or + * call the returnSession method here. + */ + public Session getSession() { + if (log.isDebugEnabled()) { + log.debug("Creating session"); + } + final SessionFactory sessionFactory = emfDataStore.getSessionFactory(); + final Session session = sessionFactory.openSession(); + session.setFlushMode(FlushMode.MANUAL); + + if (loadedEObjects.size() > 0) { + session.beginTransaction(); + + // merge the loaded objects into the session + if (log.isDebugEnabled()) { + log.debug("Merging " + loadedEObjects.size() + + " eobjects into new session "); + } + for (Object obj : loadedEObjects) { + session.buildLockRequest(LockOptions.NONE).lock(obj); + } + session.getTransaction().commit(); + } + + return session; + } + + /** Return a sessionwrapper */ + public SessionWrapper getSessionWrapper() { + return new HbSessionWrapper(getEMFDataStore(), getSession()); + } + + /** + * Returns the sessionwrapper to the resource so that it can do clean up (or + * not) + */ + public void returnSessionWrapper(SessionWrapper sessionWrapper) { + returnSession(sessionWrapper.getHibernateSession()); + } + + /** Returns the session, closes it */ + public void returnSession(Session theSession) { + // solves a bug with older versions of Hibernate, see the EMFInterceptor + Map.Entry<?, ?>[] collectionEntryArray = IdentityMap + .concurrentEntries(((SessionImplementor) theSession) + .getPersistenceContext().getCollectionEntries()); + for (Entry<?, ?> element : collectionEntryArray) { + ((PersistentCollection) element.getKey()) + .unsetSession((SessionImplementor) theSession); + } + + theSession.close(); + } + + /** + * Returns an array of EObjects which refer to a certain EObject, note if + * the array is of length zero then no refering EObjects where found. + */ + @Override + public Object[] getCrossReferencers(EObject referedTo) { + Transaction tx = null; + boolean err = true; + final Session mySession = getSession(); + try { + tx = mySession.beginTransaction(); + final Object[] result = emfDataStore.getCrossReferencers(mySession, + referedTo); + err = false; + + return result; + } catch (Exception e) { + e.printStackTrace(System.err); + throw new HbMapperException( + "Exception when doing cross reference search " + + emfDataStore.getName(), e); + } finally { + if (err) { + if (tx != null) { + tx.rollback(); + } + mySession.close(); + } else { + tx.commit(); + } + } + } + + /** + * Saves the changed objects or removes the detached objects from this + * resource. + */ + @Override + protected void saveResource(Map<?, ?> options) { + log.debug("Saving resource with uri: " + getURI()); + + boolean err = true; + Transaction tx = null; + final Session mySession = getSession(); + try { + tx = mySession.beginTransaction(); + + final List<EObject> list = super.getContents(); + for (int i = 0; i < list.size(); i++) { + final Object obj = list.get(i); + // if (IdentifierCacheHandler.getInstance().getID(obj) == null) + // // new object + // { + mySession.saveOrUpdate(obj); + // } + // else do nothing because hibernate does this automatically?? + } + + // delete all deleted objects + for (Object obj : removedEObjects) { + if (IdentifierUtil.getID(obj, (SessionImplementor) mySession) != null) // persisted + // object + { + mySession.delete(obj); + EMFInterceptor + .registerCollectionsForDereferencing((EObject) obj); + } + } + + // now flush everything + mySession.flush(); + err = false; + } catch (Exception e) { + e.printStackTrace(System.err); + throw new HbMapperException("Exception when saving resource " + + emfDataStore.getName(), e); + } finally { + if (err) { + if (tx != null) { + tx.rollback(); + } + } else { + tx.commit(); + } + returnSession(mySession); + } + } + + /** + * Loads all the objects in the global list + */ + @Override + protected List<EObject> loadResource(Map<?, ?> options) { + log.debug("Loading resource: " + getURI().toString()); + + // first clear the old list + Transaction tx = null; + boolean err = true; + final Session mySession = getSession(); + try { + tx = mySession.beginTransaction(); + + // note we have to a call to the super class otherwise an infinite + // loop is created + final List<EObject> storeList = loadFromStore(mySession); + log.debug("Loaded " + storeList.size() + " objects"); + err = false; + return storeList; + } catch (Exception e) { + e.printStackTrace(System.err); + throw new HbMapperException("Exception when saving resource " + + emfDataStore.getName(), e); + } finally { + if (err) { + if (tx != null) { + tx.rollback(); + } + } else { + tx.commit(); + } + returnSession(mySession); + } + } + + /** + * Rollsback the transaction if any and clears different lists to start with + * an empty resource again. Note that the super.dounload is not called + * because that clears the list resulting in all kinds of undesirable + * inverseremoves. + */ + @Override + protected void doUnload() { + super.doUnload(); + } + + /** + * This method can be overridden to implement specific load behavior. Note + * that a transaction has already been started. The session is passed as a + * parameter, this is the same session which can be retrieved using the + * getSession method. The read objects should be returned in the list. Note + * that after this call the retrieved objects are put in the resource + * content. + */ + protected List<EObject> loadFromStore(Session sess) { + if (definedQueriesPresent()) { + return loadUsingDefinedQueries(sess); + } else { + return loadUsingTopClasses(sess); + } + } + + /** Reads data based on the topclasses list */ + private ArrayList<EObject> loadUsingTopClasses(Session sess) { + log.debug("Loading resource " + getURI() + " using top classes"); + final ArrayList<EObject> readObjects = new ArrayList<EObject>(); + for (final String topClassName : topClassNames) { + log.debug("Loading objects using hql: FROM " + topClassName); + + final Query qry = sess.createQuery("FROM " + topClassName); + final Iterator<?> it = qry.list().iterator(); + while (it.hasNext()) { + final EObject eobj = (EObject) it.next(); + // extra check on container because sometimes contained items + // are still read in + // case of multiple inheritance + if (eobj.eContainer() == null) { + readObjects.add(eobj); + } + } + } + return readObjects; + } + + /** Reads data based using defined queries */ + private ArrayList<EObject> loadUsingDefinedQueries(Session sess) { + log.debug("Loading resource " + getURI() + " using defined queries"); + final ArrayList<EObject> readObjects = new ArrayList<EObject>(); + final String[] qrys = getDefinedQueries(); + for (String element : qrys) { + final Query qry = sess.createQuery(element); + log.debug("Loading objects using hql: " + element); + final Iterator<?> it = qry.list().iterator(); + while (it.hasNext()) { + final Object obj = it.next(); + readObjects.add((EObject) obj); + } + } + return readObjects; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HibernateResource.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HibernateResource.java new file mode 100755 index 000000000..2b1b7000a --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HibernateResource.java @@ -0,0 +1,713 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008, 2011 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 + * </copyright> + * + * $Id: HibernateResource.java,v 1.29 2011/02/21 05:23:20 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.resource; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.resource.URIConverter; +import org.eclipse.emf.teneo.hibernate.EMFInterceptor; +import org.eclipse.emf.teneo.hibernate.HbDataStore; +import org.eclipse.emf.teneo.hibernate.HbHelper; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.HbSessionWrapper; +import org.eclipse.emf.teneo.hibernate.HbUtil; +import org.eclipse.emf.teneo.hibernate.SessionWrapper; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierCacheHandler; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierUtil; +import org.eclipse.emf.teneo.resource.StoreResource; +import org.eclipse.emf.teneo.util.AssertUtil; +import org.hibernate.Criteria; +import org.hibernate.Session; +import org.hibernate.criterion.Restrictions; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.impl.SessionImpl; +import org.hibernate.metadata.ClassMetadata; + +/** + * Hibernate Resource. The hibernate resource has a Session during its lifetime. + * A transaction is started before the load and it is stopped just after the + * save. The session is disconnected and reconnected when loading and saving. + * + * When you create a HbDataStore through the appropriate method in the + * HibernateHelper class. The name you passed there can be used as a parameter + * in the uri used to create this resource (using the parameter pmfname). The + * uri is then: hibernate://?dsname=myemf. + * + * Another simple trick which is used to fool emf a bit is that the extension of + * the uri can also be used to init a hibernate resource! + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.29 $ + */ + +public class HibernateResource extends StoreResource implements HbResource { + /** The logger */ + private static Log log = LogFactory.getLog(HibernateResource.class); + + /** The fragment separator */ + private static String SEPARATOR = "|"; + + /** The store used to determine where to query for the data */ + protected HbDataStore emfDataStore; + + /** The uri parameter under which to store a session controller */ + public static String SESSION_CONTROLLER_PARAM = "sessionController"; + + /** The session wrapper used for long transactions */ + protected SessionWrapper sessionWrapper = null; // is opened at first load + + /** The session controller */ + protected SessionController sessionController = null; + + /** Is set to true if there is a sessionController */ + private boolean hasSessionController = false; + + /** + * The constructor, gets an uri and retrieves the backing OJBStore + */ + public HibernateResource(URI uri) { + super(uri); + + log.debug("Creating hibernateresource using uri: " + uri.toString()); + + final Map<String, String> params = decodeQueryString(uri.query()); + + if (params.get(DS_NAME_PARAM) != null) { // only the name + setDefinedQueries(getQueries(params)); + emfDataStore = HbHelper.INSTANCE.getDataStore(getParam(params, + DS_NAME_PARAM, uri.query())); + } else if (params.get(SESSION_CONTROLLER_PARAM) != null) { + + setDefinedQueries(getQueries(params)); + + final String scName = getParam(params, SESSION_CONTROLLER_PARAM, + uri.query()); + sessionController = SessionController.getSessionController(scName); + log.debug("Using session controller " + scName); + emfDataStore = sessionController.getHbDataStore(); + hasSessionController = true; + } else if (uri.fileExtension() != null) // this is probably a platform + // uri! + { + log.debug("Trying fileextension: " + uri.fileExtension()); + // then try the extension of the resource + emfDataStore = HbHelper.INSTANCE.getDataStore(uri.fileExtension()); + + // if null then assume that this is a properties file + if (emfDataStore == null) { + log.debug("No datastore defined for extension, assuming this is a property file " + + uri.toString()); + try { + final URIConverter uriConverter = getURIConverter(); + final InputStream is = uriConverter.createInputStream(uri); + final Properties props = new Properties(); + props.load(is); + is.close(); + emfDataStore = HbUtil.getCreateDataStore(props); + setDefinedQueries(getQueries(props)); + } catch (IOException e) { + throw new HbMapperException( + "Exception when reading properties from: " + + uri.toString(), e); + } + } + } + if (emfDataStore == null) { + throw new HbMapperException( + "No HbDataStore can be found using the uri " + + uri.toString()); + } + log.debug("Using emf data store using " + emfDataStore.getName()); + super.init(emfDataStore.getTopEntities()); + } + + /** Returns the emfdatastore */ + public HbDataStore getEMFDataStore() { + return emfDataStore; + } + + /** + * Returns the session of this resource, if no session is set yet then + * creates it using the datastore. As a default the FlushMode is set to + * Never. + * + * Deprecated, use getSessionWrapper (to support ejb3) + */ + @Deprecated + public Session getSession() { + return (Session) getSessionWrapper().getSession(); + } + + /** Return the sessionwrapper */ + public SessionWrapper getSessionWrapper() { + if (sessionWrapper == null) { + if (hasSessionController) { + sessionWrapper = sessionController.getSessionWrapper(); + } else { + // session can be null when this is an xml import! ; + sessionWrapper = emfDataStore.createSessionWrapper(); + sessionWrapper.setFlushModeManual(); + } + } + return sessionWrapper; + } + + /** + * Sets the session, overwrites current session. Deprecated use + * setSessionWrapper. + */ + @Deprecated + public void setSession(Session session) { + if (session != null) { + this.sessionWrapper = new HbSessionWrapper(emfDataStore, session); + } else { + this.sessionWrapper = null; + } + } + + /** + * Unpacks the id string and reads an object from the db, note for each read + * a transaction is opened, unless the session is controlled by the caller. + * + * @see org.eclipse.emf.ecore.resource.impl.ResourceImpl#getEObjectByID(java.lang.String) + */ + @Override + protected EObject getEObjectByID(String id) { + // try to find the different parts of the id + if (id == null) { + return super.getEObjectByID(id); + } + if (getIntrinsicIDToEObjectMap() != null) { + final EObject firstCheck = getIntrinsicIDToEObjectMap().get(id); + if (firstCheck != null) { + return firstCheck; + } + } + + if (log.isDebugEnabled()) { + log.debug("Reading eobject using urifragment " + id); + } + final String[] parts = id.split("\\" + SEPARATOR); + + if (parts.length != 2) { + if (log.isDebugEnabled()) { + log.debug("Not a valid urifragment (" + id + + ") for the hibernate resource, trying the superclass"); + } + return super.getEObjectByID(id); + } + + // build a query + final EClass eclass = emfDataStore.getEntityNameStrategy().toEClass( + parts[0]); + final int splitIndex = parts[1].indexOf("="); + if (splitIndex == -1) { + if (log.isDebugEnabled()) { + log.debug("Not a valid urifragment (" + id + + ") for the hibernate resource, trying the superclass"); + } + return super.getEObjectByID(id); + } + final String idStr = parts[1].substring(1 + splitIndex); + + // try to find the object using the id-part + final EObject eObject = super.getEObjectByID(idStr); + if (eObject != null) { + return eObject; + } + + final boolean oldLoading = isLoading(); + boolean err = true; + try { + setIsLoading(true); + if (!hasSessionController) { + getSessionWrapper().beginTransaction(); + } + + final Object result = getSessionWrapper().get( + parts[0], + (Serializable) HbUtil.stringToId(eclass, emfDataStore, + idStr)); + if (result == null) { + if (log.isDebugEnabled()) { + log.debug("Object not found in the db, trying the parent"); + } + err = false; + return super.getEObjectByID(id); + } + final InternalEObject internalEObject = (InternalEObject) result; + // only add if not yet part of a resource + if (internalEObject.eResource() == null) { + addUsingContainmentStructure((InternalEObject) result); + } + err = false; + return (EObject) result; + } finally { + setIsLoading(oldLoading); + if (!hasSessionController) { + if (err) { + getSessionWrapper().rollbackTransaction(); + getSessionWrapper().close(); + } else { + getSessionWrapper().commitTransaction(); + } + } + } + } + + /** + * Creates a unique id string from the eobject. The id string will contain a + * link to the type (eclass) and the string version of the id itself. This + * method assumes that the id can be converted from and to a string! + * + * @see org.eclipse.emf.ecore.resource.impl.ResourceImpl#getURIFragment(org.eclipse.emf.ecore.EObject) + */ + @Override + public String getURIFragment(EObject object) { + if (object == null) { + return null; + } + final String theId = HbUtil.idToString(object, emfDataStore); + if (theId == null) { + return super.getURIFragment(object); + } + final StringBuffer idStr = new StringBuffer(); + idStr.append(emfDataStore.getEntityNameStrategy().toEntityName( + object.eClass())); + idStr.append(SEPARATOR); + idStr.append("id=" + theId); + return idStr.toString(); + } + + /** + * Sets the sessionwrapper, overwrites current session. + */ + public void setSessionWrapper(SessionWrapper sessionWrapper) { + this.sessionWrapper = sessionWrapper; + } + + /** Returns the session, does nothing in this impl */ + public void returnSession(Session theSession) { + // do nothing + } + + /** + * Returns the sessionwrapper to the resource so that it can do clean up (or + * not) + */ + public void returnSessionWrapper(SessionWrapper sessionWrapper) { + + } + + /** + * Returns an array of EObjects which refer to a certain EObject, note if + * the array is of length zero then no refering EObjects where found. + */ + @Override + public Object[] getCrossReferencers(EObject referedTo) { + boolean err = true; + final SessionWrapper mySessionWrapper = getSessionWrapper(); + try { + if (!hasSessionController) { + mySessionWrapper.beginTransaction(); + } + final Object[] result = emfDataStore.getCrossReferencers( + mySessionWrapper, referedTo); + err = false; + + return result; + } catch (Exception e) { + e.printStackTrace(System.err); + throw new HbMapperException( + "Exception when doing cross reference search " + + emfDataStore.getName(), e); + } finally { + if (!hasSessionController) { + if (err) { + mySessionWrapper.rollbackTransaction(); + mySessionWrapper.close(); + } else { + mySessionWrapper.commitTransaction(); + } + } + } + } + + /** + * Saves the changed objects or removes the detached objects from this + * resource. + */ + @Override + protected void saveResource(Map<?, ?> options) { + log.debug("Saving resource with uri: " + getURI()); + + boolean err = true; + final SessionWrapper mySessionWrapper = getSessionWrapper(); + try { + if (!hasSessionController) { + mySessionWrapper.beginTransaction(); + } + + for (EObject eobject : super.getContents()) { + mySessionWrapper.saveOrUpdate(eobject); + } + + // delete all deleted objects + for (Object obj : removedEObjects) { + final InternalEObject eobj = (InternalEObject) obj; + if (eobj.eResource() != null && eobj.eResource() != this) { + continue; + } + + if (IdentifierUtil.getID(obj, + (SessionImplementor) mySessionWrapper + .getHibernateSession()) != null) // persisted + // object + { + if (eobj.eDirectResource() == null + || eobj.eDirectResource() == this) { + mySessionWrapper.delete(obj); + EMFInterceptor + .registerCollectionsForDereferencing((EObject) obj); + } + } + } + + // now flush everything + if (!hasSessionController) { + mySessionWrapper.flush(); + } + + err = false; + } catch (Exception e) { + e.printStackTrace(System.err); + throw new HbMapperException("Exception when saving resource " + + emfDataStore.getName(), e); + } finally { + if (!hasSessionController) { + if (err) { + beforeSaveRollback(); + mySessionWrapper.rollbackTransaction(); + afterSaveRollback(); + // see bugzilla 221950 + // mySessionWrapper.close(); + } else { + mySessionWrapper.commitTransaction(); + } + } + } + } + + /** + * Override point, the default implementation will check if Hibernate + * already assigned an id to an eobject. If so it is restored back to null. + * See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=331953 + */ + protected void beforeSaveRollback() { + // assigned ids + Session session = sessionWrapper.getHibernateSession(); + for (EObject eobject : super.getNewEObjects()) { + String entityName = session.getEntityName(eobject); + String identifierName = getIdentifierName(eobject, session); + Serializable id = session.getIdentifier(eobject); + Criteria exists = session.createCriteria(entityName).add( + Restrictions.eq(identifierName, id)); + if (exists.uniqueResult() == null) { + rollbackID(eobject, identifierName); + } + } + } + + /** + * Override point, default implementation is empty. + */ + protected void afterSaveRollback() { + + } + + /** + * Resets the id back to null, identifierName can be null (in that case no + * action is done, only the cached id in the identifier cache handler is + * reset back). + * + * @see IdentifierCacheHandler#setID(Object, Object) + */ + protected void rollbackID(EObject eobject, String identifierName) { + IdentifierCacheHandler.getInstance().setID(eobject, null); + if (identifierName == null) { + return; + } + EStructuralFeature identifier = eobject.eClass().getEStructuralFeature( + identifierName); + if (identifier == null) { + return; + } + eobject.eUnset(identifier); + } + + protected String getIdentifierName(EObject eobject, Session hs) { + String entityName = hs.getEntityName(eobject); + if (entityName == null) { + return null; + } + ClassMetadata entityMetaData = hs.getSessionFactory().getClassMetadata( + entityName); + if (entityMetaData == null) { + return null; + } + String identifierName = entityMetaData.getIdentifierPropertyName(); + return identifierName; + } + + /** + * Loads all the objects in the global list + */ + @Override + protected List<EObject> loadResource(Map<?, ?> options) { + log.debug("Loading resource: " + getURI().toString()); + + // first clear the old list + boolean err = true; + final SessionWrapper mySessionWrapper = getSessionWrapper(); + try { + if (!hasSessionController) { + mySessionWrapper.beginTransaction(); + } + + // note we have to a call to the super class otherwise an infinite + // loop is created + final List<EObject> storeList = loadFromStore(mySessionWrapper); + log.debug("Loaded " + storeList.size() + " objects"); + err = false; + return storeList; + } catch (Exception e) { + e.printStackTrace(System.err); + throw new HbMapperException("Exception when saving resource " + + emfDataStore.getName(), e); + } finally { + if (!hasSessionController) { + if (err) { + mySessionWrapper.rollbackTransaction(); + mySessionWrapper.close(); + } else { + mySessionWrapper.commitTransaction(); + } + } + } + } + + /** + * Rollsback the transaction if any and clears different lists to start with + * an empty resource again. + */ + @Override + protected void doUnload() { + super.doUnload(); + + if (!hasSessionController) { + if (!getSessionWrapper().isEJB3EntityManager()) { + AssertUtil.assertTrue("Session must be disconnected in unload", + !((SessionImpl) getSessionWrapper().getSession()) + .isTransactionInProgress()); + } + log.debug("Doing unload, closing and nullifying session"); + getSessionWrapper().close(); + setSessionWrapper(null); + } else { + log.debug("Doing unload, has session controller, sessioncontroller is therefor responsible for session close"); + } + } + + /** + * This method can be overridden to implement specific load behavior. Note + * that a transaction has already been started. The session is passed as a + * parameter, this is the same session which can be retrieved using the + * getSession method. The read objects should be returned in the list. Note + * that after this call the retrieved objects are put in the resource + * content. + */ + protected List<EObject> loadFromStore(SessionWrapper sess) { + if (definedQueriesPresent()) { + return loadUsingDefinedQueries(sess); + } else { + return loadUsingTopClasses(sess); + } + } + + /** Reads data based on the topclasses list */ + private ArrayList<EObject> loadUsingTopClasses(SessionWrapper sess) { + log.debug("Loading resource " + getURI() + " using top classes"); + final ArrayList<EObject> readObjects = new ArrayList<EObject>(); + for (final String topClassName : topClassNames) { + log.debug("Loading objects using hql: FROM " + topClassName); + + final List<?> qryResult; + if (sess.isEJB3EntityManager()) { + qryResult = sess.executeQuery("select o from " + topClassName + + " o"); + } else { + qryResult = sess.executeQuery("from " + topClassName); + } + final Iterator<?> it = qryResult.iterator(); + while (it.hasNext()) { + final EObject eobj = (EObject) it.next(); + // extra check on container because sometimes contained items + // are still read in + // case of multiple inheritance + if (eobj.eContainer() == null) { + readObjects.add(eobj); + } + } + } + return readObjects; + } + + /** Reads data based using defined queries */ + private ArrayList<EObject> loadUsingDefinedQueries(SessionWrapper sess) { + log.debug("Loading resource " + getURI() + " using defined queries"); + final ArrayList<EObject> readObjects = new ArrayList<EObject>(); + final String[] qrys = getDefinedQueries(); + for (String element : qrys) { + final List<?> qryResult = sess.executeQuery(element); + log.debug("Loading objects using hql: " + element); + final Iterator<?> it = qryResult.iterator(); + while (it.hasNext()) { + final Object obj = it.next(); + readObjects.add((EObject) obj); + } + } + return readObjects; + } + + /** Reads a set of objects into the resource by using a query. */ + public Object[] getObjectsByQuery(String query, boolean cache) { + log.debug("Started listing objects by query " + query + " in resource " + + getURI()); + SessionWrapper mySessionWrapper = null; + boolean err = true; + setIsLoading(true); + try { + mySessionWrapper = getSessionWrapper(); + if (!hasSessionController) { + mySessionWrapper.beginTransaction(); + } + final List<?> qryResult = mySessionWrapper.executeQuery(query, + cache); + for (Object object : qryResult) { + if (object instanceof InternalEObject) { + final InternalEObject eObject = (InternalEObject) object; + // only add if the object is not already part of this + // resource. + // if already part of this resource then it should have been + // loaded through + // a containment relation. + assert (eObject.eResource() != this + || loadedEObjectSet.contains(eObject) || newEObjects + .contains(eObject)); + addToContent(eObject); + } + } + + err = false; + log.debug("Listed " + qryResult.size() + " objects using query " + + query + " in resource " + getURI()); + return qryResult.toArray(); + } finally { + if (!hasSessionController) { + if (err) { + mySessionWrapper.rollbackTransaction(); + mySessionWrapper.close(); + } else { + mySessionWrapper.commitTransaction(); + } + } + setIsLoading(false); + log.debug("Finished getting objects by query " + query + + " in resource " + getURI()); + } + } + + /** + * @return the hasSessionController + */ + public boolean isHasSessionController() { + return hasSessionController; + } + + @Override + public boolean isLoading() { + return isLoading; + } + + /** Load additional objects into the contents using a query */ + public Object[] listByQuery(String query, boolean cache) { + log.debug("Started listing objects by query " + query + " in resource " + + getURI()); + SessionWrapper mySessionWrapper = null; + boolean err = true; + setIsLoading(true); + final Notification notification = setLoaded(true); + try { + mySessionWrapper = getSessionWrapper(); + if (!hasSessionController) { + mySessionWrapper.beginTransaction(); + } + final List<?> qryResult = mySessionWrapper.executeQuery(query, + cache); + for (Object object : qryResult) { + if (object instanceof InternalEObject) { + addToContent((InternalEObject) object); + } + } + + err = false; + log.debug("Listed " + qryResult.size() + " objects using query " + + query + " in resource " + getURI()); + return qryResult.toArray(); + } finally { + setIsLoading(false); + if (!hasSessionController) { + if (err) { + mySessionWrapper.rollbackTransaction(); + mySessionWrapper.close(); + } else { + mySessionWrapper.commitTransaction(); + } + } + if (notification != null) { + eNotify(notification); + } + log.debug("Finished listing objects by query " + query + + " in resource " + getURI()); + } + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HibernateResourceFactory.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HibernateResourceFactory.java new file mode 100755 index 000000000..76345d15f --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HibernateResourceFactory.java @@ -0,0 +1,38 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HibernateResourceFactory.java,v 1.3 2008/02/28 07:08:24 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.resource; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; + +/** + * Creates hibernate resources based on an uri. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.3 $ + */ + +public class HibernateResourceFactory implements Resource.Factory { + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.ecore.resource.Resource.Factory#createResource(org.eclipse.emf.common.util.URI) + */ + public Resource createResource(URI uri) { + return new HibernateResource(uri); + } +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HibernateXMLResource.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HibernateXMLResource.java new file mode 100755 index 000000000..c613ce24a --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HibernateXMLResource.java @@ -0,0 +1,138 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HibernateXMLResource.java,v 1.1 2008/03/12 18:36:34 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.resource; + +import java.io.IOException; +import java.io.Writer; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.xmi.DOMHandler; +import org.eclipse.emf.ecore.xmi.DOMHelper; +import org.eclipse.emf.ecore.xmi.XMLResource; +import org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl; +import org.eclipse.emf.ecore.xml.type.AnyType; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; + +/** + * Tries to add XMLResource behavior to the Hibernate Resource. Not that not all methods are + * implemented. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.1 $ + */ + +public class HibernateXMLResource extends HibernateResource implements XMLResource { + + public HibernateXMLResource(URI uri) { + super(uri); + } + + public Map<Object, Object> getDefaultLoadOptions() { + return new HashMap<Object, Object>(); + } + + public Map<Object, Object> getDefaultSaveOptions() { + return new HashMap<Object, Object>(); + } + + public DOMHelper getDOMHelper() { + return null; + } + + public String getEncoding() { + return null; + } + + public Map<EObject, AnyType> getEObjectToExtensionMap() { + return null; + } + + public Map<EObject, String> getEObjectToIDMap() { + return new HashMap<EObject, String>(); + } + + public String getID(EObject object) { + return getURIFragment(object); + } + + public Map<String, EObject> getIDToEObjectMap() { + return new HashMap<String, EObject>(); + } + + public String getPublicId() { + return null; + } + + public String getSystemId() { + return null; + } + + public String getXMLVersion() { + return null; + } + + public void load(InputSource inputSource, Map<?, ?> options) throws IOException { + final XMLResource xmlResource = new XMLResourceImpl(); + xmlResource.load(inputSource, options); + getContents().addAll(xmlResource.getContents()); + setLoaded(true); + } + + public void load(Node node, Map<?, ?> options) throws IOException { + final XMLResource xmlResource = new XMLResourceImpl(); + xmlResource.load(node, options); + getContents().addAll(xmlResource.getContents()); + setLoaded(true); + } + + public Document save(Document document, Map<?, ?> options, DOMHandler handler) { + final XMLResource xmlResource = new XMLResourceImpl(); + xmlResource.getContents().addAll(getContents()); + return xmlResource.save(document, options, handler); + } + + public void save(Writer writer, Map<?, ?> options) throws IOException { + final XMLResource xmlResource = new XMLResourceImpl(); + xmlResource.getContents().addAll(getContents()); + xmlResource.save(writer, options); + } + + public void setDoctypeInfo(String publicId, String systemId) { + } + + public void setEncoding(String encoding) { + } + + public void setID(EObject object, String id) { + } + + public void setUseZip(boolean useZip) { + } + + public void setXMLVersion(String version) { + } + + @Override + public boolean useZip() { + return false; + } +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HibernateXMLResourceFactory.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HibernateXMLResourceFactory.java new file mode 100755 index 000000000..67a6abd5a --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/HibernateXMLResourceFactory.java @@ -0,0 +1,38 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: HibernateXMLResourceFactory.java,v 1.1 2008/03/12 18:36:34 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.resource; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; + +/** + * Creates hibernate xml resources based on an uri. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.1 $ + */ + +public class HibernateXMLResourceFactory implements Resource.Factory { + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.ecore.resource.Resource.Factory#createResource(org.eclipse.emf.common.util.URI) + */ + public Resource createResource(URI uri) { + return new HibernateXMLResource(uri); + } +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/SessionController.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/SessionController.java new file mode 100755 index 000000000..296080d3d --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/resource/SessionController.java @@ -0,0 +1,108 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: SessionController.java,v 1.8 2008/06/29 14:24:25 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.resource; + +import java.util.Hashtable; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.teneo.hibernate.HbDataStore; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.SessionWrapper; +import org.hibernate.Session; + +/** + * A session controller handles one session. The session controller can be registered and retrieved + * by name. The session controller is used by resources to share one session over different + * resources. The resources get the session controller name as a parameter in the uri. + * + * This class offers the registry functionality as well as a default implementation of the session + * controller. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.8 $ + */ + +public class SessionController { + /** The logger */ + private static Log log = LogFactory.getLog(SessionController.class); + + /** The static map of session controllers */ + private static Hashtable<String, SessionController> sessionControllers = new Hashtable<String, SessionController>(); + + /** Register a session controller */ + public static synchronized void registerSessionController(String name, SessionController sc) { + if (sessionControllers.get(name) != null) { + throw new HbMapperException("There is already a session controller registered with the name: " + name); + } + log.debug("Registering session controller: " + name); + sessionControllers.put(name, sc); + } + + /** Deregisters a session controller */ + public static synchronized void deRegisterSessionController(String name) { + if (sessionControllers.get(name) == null) { + throw new HbMapperException("There is no session controller registered with the name: " + name); + } + log.debug("De-Registering session controller: " + name); + sessionControllers.remove(name); + } + + /** Returns a session controller using the name */ + public static synchronized SessionController getSessionController(String name) { + return sessionControllers.get(name); + } + + /** The local session wrapper */ + protected SessionWrapper sessionWrapper; + + /** The hb datastore from which the sessions are retrieved */ + protected HbDataStore hbDataStore; + + /** + * @return the hbDataStore + */ + public HbDataStore getHbDataStore() { + return hbDataStore; + } + + /** + * @param hbDataStore + * the hbDataStore to set + */ + public void setHbDataStore(HbDataStore hbDataStore) { + this.hbDataStore = hbDataStore; + } + + /** + * Note fails when using ejb data store. + * + * @return the session + */ + @Deprecated + public Session getSession() { + return (Session) getSessionWrapper().getSession(); + } + + /** Return the session wrapper */ + public SessionWrapper getSessionWrapper() { + if (sessionWrapper == null) { + sessionWrapper = hbDataStore.createSessionWrapper(); + } + return sessionWrapper; + } +} diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/tuplizer/EMFComponentTuplizer.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/tuplizer/EMFComponentTuplizer.java new file mode 100755 index 000000000..766fa93af --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/tuplizer/EMFComponentTuplizer.java @@ -0,0 +1,162 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EMFComponentTuplizer.java,v 1.14 2010/08/18 11:50:38 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.tuplizer; + +import java.lang.reflect.Method; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.teneo.ERuntime; +import org.eclipse.emf.teneo.hibernate.HbDataStore; +import org.eclipse.emf.teneo.hibernate.HbHelper; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.HbUtil; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.mapping.Component; +import org.hibernate.mapping.Property; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; +import org.hibernate.tuple.Instantiator; +import org.hibernate.tuple.component.AbstractComponentTuplizer; + +/** + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.14 $ + */ + +public class EMFComponentTuplizer extends AbstractComponentTuplizer { + + /** + * Generated Serial ID + */ + private static final long serialVersionUID = 6316160569897347041L; + + private EClass eClass; + + /** The logger */ + // private static Log log = LogFactory.getLog(EMFComponentTuplizer.class); + /** Constructor */ + public EMFComponentTuplizer(Component component) { + super(component); + } + + private EClass getEClass(Component component) { + if (eClass == null) { + final HbDataStore ds = HbHelper.INSTANCE.getDataStore(component); + eClass = ds.getEntityNameStrategy().toEClass(component.getComponentClassName()); + if (eClass == null) { + eClass = ERuntime.INSTANCE.getEClass(component.getComponentClass()); + } + if (eClass == null) { + eClass = HbUtil.getEClassFromMeta(component); + } + } + if (eClass == null) { + throw new HbMapperException("No eclass found for entityname: " + component.getComponentClassName()); + } + return eClass; + } + + /** Creates an EMF Instantiator */ + protected Instantiator buildInstantiator(Component component, Property property) { + return buildInstantiator(component); + } + + /** Creates an EMF Instantiator */ + @Override + protected Instantiator buildInstantiator(Component component) { + return new EMFInstantiator(getEClass(component), component); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.AbstractEntityTuplizer#buildPropertyGetter(org.hibernate.mapping.Property, + * org.hibernate.mapping.PersistentClass) + */ + @Override + protected Getter buildGetter(Component component, Property mappedProperty) { + return getPropertyAccessor(mappedProperty, component).getGetter(null, mappedProperty.getName()); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.AbstractEntityTuplizer#buildPropertySetter(org.hibernate.mapping.Property, + * org.hibernate.mapping.PersistentClass) + */ + @Override + protected Setter buildSetter(Component component, Property mappedProperty) { + return getPropertyAccessor(mappedProperty, component).getSetter(null, mappedProperty.getName()); + } + + /** Returns the correct accessor on the basis of the type of property */ + public PropertyAccessor getPropertyAccessor(Property mappedProperty, Component comp) { + final HbDataStore ds = HbHelper.INSTANCE.getDataStore(comp); + return HbUtil.getPropertyAccessor(mappedProperty, ds, comp.getComponentClassName(), getEClass(comp)); + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.Tuplizer#getMappedClass() + */ + public Class<?> getMappedClass() { + return EObject.class; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.ComponentTuplizer#getParent(java.lang.Object) + */ + @Override + public Object getParent(Object component) { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.ComponentTuplizer#hasParentProperty() + */ + @Override + public boolean hasParentProperty() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.ComponentTuplizer#isMethodOf(java.lang.reflect.Method) + */ + @Override + public boolean isMethodOf(Method method) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.ComponentTuplizer#setParent(java.lang.Object, java.lang.Object, + * org.hibernate.engine.SessionFactoryImplementor) + */ + @Override + public void setParent(Object component, Object parent, SessionFactoryImplementor factory) { + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/tuplizer/EMFEntityNameResolver.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/tuplizer/EMFEntityNameResolver.java new file mode 100755 index 000000000..6e41f508d --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/tuplizer/EMFEntityNameResolver.java @@ -0,0 +1,60 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EMFEntityNameResolver.java,v 1.1 2009/06/27 09:20:06 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.tuplizer; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.teneo.extension.ExtensionPoint; +import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy; +import org.hibernate.EntityNameResolver; + +/** + * Intercepts the getEntityName call to return the EClass name as the entity name. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.1 $ + */ + +public class EMFEntityNameResolver implements ExtensionPoint, EntityNameResolver { + + /** + * Generated Serial Version ID + */ + private static final long serialVersionUID = 1680117509182298808L; + + /** The qualify property used to compute the eclassname */ + private EntityNameStrategy qualifyStrategy; + + public EntityNameStrategy getQualifyStrategy() { + return qualifyStrategy; + } + + public void setQualifyStrategy(EntityNameStrategy qualifyStrategy) { + this.qualifyStrategy = qualifyStrategy; + } + + /* + * @see org.hibernate.EntityNameResolver#resolveEntityName(java.lang.Object) + */ + public String resolveEntityName(Object entity) { + if (entity instanceof EObject) { + // TODO handle featuremap + EObject eobj = (EObject) entity; + return qualifyStrategy.toEntityName(eobj.eClass()); + } + return null; + } +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/tuplizer/EMFInstantiator.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/tuplizer/EMFInstantiator.java new file mode 100755 index 000000000..4cddaa972 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/tuplizer/EMFInstantiator.java @@ -0,0 +1,141 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EMFInstantiator.java,v 1.11 2010/08/18 11:50:38 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.tuplizer; + +import java.io.Serializable; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.impl.DynamicEObjectImpl; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.mapping.SerializableDynamicEObjectImpl; +import org.eclipse.emf.teneo.type.PersistentStoreAdapter; +import org.eclipse.emf.teneo.util.StoreUtil; +import org.hibernate.mapping.Component; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.tuple.Instantiator; + +/** + * Instantiates eobjects using the efactory. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.11 $ + */ + +public class EMFInstantiator implements Instantiator { + + /** + * Generated Serial Version ID + */ + private static final long serialVersionUID = 6946442685247491904L; + + /** The logger */ + private static Log log = LogFactory.getLog(EMFInstantiator.class); + + /** The EClass for which we do all this */ + private final EClass eclass; + + /** The proxy interface if used */ + private final Class<?> proxyInterface; + + /** The mapped class */ + private final Class<?> mappedClass; + + private boolean isDynamicEObject = false; + + /** Constructor */ + public EMFInstantiator(EClass eclass, PersistentClass pc) { + log.debug("Creating eobject instantiator for " + pc.getEntityName() + + " and eclass " + eclass.getName()); + proxyInterface = pc.getProxyInterface(); + this.eclass = eclass; + mappedClass = eclass.getInstanceClass(); + } + + /** Constructor */ + public EMFInstantiator(EClass eclass, Component component) { + log.debug("Creating eobject instantiator for component eclass " + + eclass.getName()); + this.eclass = eclass; + mappedClass = eclass.getInstanceClass(); + proxyInterface = null; + } + + /** Instantiates using EcoreUtil.create() */ + public Object instantiate() { + EObject eobject; + if (isDynamicEObject) { + eobject = new SerializableDynamicEObjectImpl(eclass); + } else { + eobject = EcoreUtil.create(eclass); + if (eobject instanceof DynamicEObjectImpl) { + eobject = new SerializableDynamicEObjectImpl(eclass); + isDynamicEObject = true; + } + } + + final PersistentStoreAdapter adapter = StoreUtil + .getPersistentStoreAdapter(eobject); + adapter.setTargetCreatedByORM(true); + + if (eobject == null) { + throw new HbMapperException( + "The mapped " + + mappedClass.getName() + + " class can not be instantiated." + + " Possibly the class it is not an eclass or it is abstract."); + } + return eobject; + } + + /** Instantiates using EcoreUtil.create() */ + public Object instantiate(Serializable id) { + return instantiate(); + } + + /** Checks using the mapped class or the proxy interface */ + public boolean isInstance(Object object) { + if (!(object instanceof EObject)) { + return false; + } + final EObject eobject = (EObject) object; + if (eobject.eClass() == eclass) { + return true; + } + if (isSuperTypeOf(eclass, eobject.eClass())) { + return true; + } + return (proxyInterface != null && proxyInterface.isInstance(object)); + } + + /** Is eclass superclass */ + private boolean isSuperTypeOf(EClass superEClass, EClass eclass) { + for (EClass testSuperEClass : eclass.getESuperTypes()) { + if (testSuperEClass == superEClass) { + return true; + } + if (isSuperTypeOf(superEClass, testSuperEClass)) { + return true; + } + } + return false; + } + +}
\ No newline at end of file diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/tuplizer/EMFTuplizer.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/tuplizer/EMFTuplizer.java new file mode 100755 index 000000000..8b0c32a70 --- /dev/null +++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/tuplizer/EMFTuplizer.java @@ -0,0 +1,367 @@ +/** + * <copyright> + * + * Copyright (c) 2005, 2006, 2007, 2008 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 + * </copyright> + * + * $Id: EMFTuplizer.java,v 1.26 2011/02/21 05:06:13 mtaal Exp $ + */ + +package org.eclipse.emf.teneo.hibernate.tuplizer; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.impl.DynamicEObjectImpl; +import org.eclipse.emf.ecore.impl.EObjectImpl; +import org.eclipse.emf.teneo.Constants; +import org.eclipse.emf.teneo.hibernate.HbDataStore; +import org.eclipse.emf.teneo.hibernate.HbHelper; +import org.eclipse.emf.teneo.hibernate.HbMapperException; +import org.eclipse.emf.teneo.hibernate.HbStoreException; +import org.eclipse.emf.teneo.hibernate.HbUtil; +import org.eclipse.emf.teneo.hibernate.mapping.eav.EAVInstantiator; +import org.eclipse.emf.teneo.hibernate.mapping.eav.EAVPropertyHandler; +import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierCacheHandler; +import org.eclipse.emf.teneo.hibernate.mapping.internal.TeneoInternalEObject; +import org.hibernate.EntityMode; +import org.hibernate.EntityNameResolver; +import org.hibernate.HibernateException; +import org.hibernate.cfg.Environment; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; +import org.hibernate.mapping.Subclass; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.Setter; +import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.ProxyFactory; +import org.hibernate.tuple.Instantiator; +import org.hibernate.tuple.entity.AbstractEntityTuplizer; +import org.hibernate.tuple.entity.EntityMetamodel; +import org.hibernate.type.CompositeType; +import org.hibernate.util.ReflectHelper; + +/** + * Overrides the get and setidentifier methods to get the identifier from an + * internal cache instead of from the EMF object itself. The same behavior for + * the getVersion methods. Also a specific object instantiator is used to make + * use of the emf efactories. + * + * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> + * @version $Revision: 1.26 $ + */ + +public class EMFTuplizer extends AbstractEntityTuplizer { + + /** The logger */ + private static Log log = LogFactory.getLog(EMFTuplizer.class); + + /** + * The mapped class, defaults to EObject for entities and to the real impl + * class for mapped classes + */ + private Class<?> mappedClass; + + private PersistentClass persistentClass; + + /** The entitymetamodel for which this is all done */ + // private final EntityMetamodel theEntityMetamodel; + /** Constructor */ + public EMFTuplizer(EntityMetamodel entityMetamodel, + PersistentClass mappedEntity) { + super(entityMetamodel, mappedEntity); + // theEntityMetamodel = entityMetamodel; + if (mappedEntity.getMappedClass() != null) { + mappedClass = mappedEntity.getMappedClass(); + } else { + mappedClass = EObject.class; + } + persistentClass = mappedEntity; + } + + /** + * First checks the id cache and if not found uses the superclass. + */ + @Override + public Serializable getIdentifier(Object object) throws HibernateException { + Serializable id = (Serializable) IdentifierCacheHandler.getInstance() + .getID(object); + if (id != null) { + return id; + } + return super.getIdentifier(object); + } + + /* + * (non-Javadoc) + * + * @see + * org.hibernate.tuple.entity.EntityTuplizer#determineConcreteSubclassEntityName + * (java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) + */ + public String determineConcreteSubclassEntityName(Object entityInstance, + SessionFactoryImplementor factory) { + final Class<?> concreteEntityClass = entityInstance.getClass(); + if (concreteEntityClass == getMappedClass()) { + return getEntityName(); + } else { + String entityName = getEntityMetamodel() + .findEntityNameByEntityClass(concreteEntityClass); + if (entityName == null) { + throw new HibernateException( + "Unable to resolve entity name from Class [" + + concreteEntityClass.getName() + "]" + + " expected instance/subclass of [" + + getEntityName() + "]"); + } + return entityName; + } + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.entity.EntityTuplizer#getEntityNameResolvers() + */ + public EntityNameResolver[] getEntityNameResolvers() { + final HbDataStore ds = HbHelper.INSTANCE.getDataStore(persistentClass); + return new EntityNameResolver[] { ds.getEntityNameResolver() }; + } + + /** + * Uses the identifiercache to get the version. + */ + @Override + public Object getVersion(Object object) throws HibernateException { + final Object version = super.getVersion(object); + if (version != null) { + return version; + } + + return IdentifierCacheHandler.getInstance().getVersion(object); + } + + /** + * Sets the identifier in the cache. + */ + @Override + public void setIdentifier(Object object, Serializable id) + throws HibernateException { + IdentifierCacheHandler.getInstance().setID(object, id); + super.setIdentifier(object, id); + } + + /** Creates an EMF Instantiator */ + @Override + protected Instantiator buildInstantiator(PersistentClass persistentClass) { + if (persistentClass.getEntityName().equals( + Constants.EAV_EOBJECT_ENTITY_NAME)) { + return new EAVInstantiator(); + } + final HbDataStore ds = HbHelper.INSTANCE.getDataStore(persistentClass); + final EClass eclass = ds.getEntityNameStrategy().toEClass( + persistentClass.getEntityName()); + if (eclass == null) { + throw new HbMapperException("No eclass found for entityname: " + + persistentClass.getEntityName()); + } + return new EMFInstantiator(eclass, persistentClass); + } + + /* + * (non-Javadoc) + * + * @see + * org.hibernate.tuple.AbstractEntityTuplizer#buildPropertyGetter(org.hibernate + * .mapping.Property , org.hibernate.mapping.PersistentClass) + */ + @Override + protected Getter buildPropertyGetter(Property mappedProperty, + PersistentClass mappedEntity) { + if (HbUtil.isEAVMapped(mappedEntity) + && mappedProperty.getName() + .equals(Constants.EAV_EOBJECT_VALUES)) { + final HbDataStore ds = HbHelper.INSTANCE.getDataStore(mappedEntity); + final Getter getter = mappedProperty.getGetter(EObjectImpl.class); + if (getter instanceof EAVPropertyHandler) { + ((EAVPropertyHandler) getter).setHbDataStore(ds); + } + return getter; + } + return getPropertyAccessor(mappedProperty, mappedEntity).getGetter( + null, mappedProperty.getName()); + } + + /* + * (non-Javadoc) + * + * @see + * org.hibernate.tuple.AbstractEntityTuplizer#buildPropertySetter(org.hibernate + * .mapping.Property , org.hibernate.mapping.PersistentClass) + */ + @Override + protected Setter buildPropertySetter(Property mappedProperty, + PersistentClass mappedEntity) { + if (HbUtil.isEAVMapped(mappedEntity) + && mappedProperty.getName() + .equals(Constants.EAV_EOBJECT_VALUES)) { + final HbDataStore ds = HbHelper.INSTANCE.getDataStore(mappedEntity); + final Setter setter = mappedProperty.getSetter(EObjectImpl.class); + if (setter instanceof EAVPropertyHandler) { + ((EAVPropertyHandler) setter).setHbDataStore(ds); + } + return setter; + } + return getPropertyAccessor(mappedProperty, mappedEntity).getSetter( + null, mappedProperty.getName()); + } + + /* + * (non-Javadoc) + * + * @seeorg.hibernate.tuple.AbstractEntityTuplizer#buildProxyFactory(org. + * hibernate.mapping. PersistentClass, org.hibernate.property.Getter, + * org.hibernate.property.Setter) + */ + @Override + protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, + Getter idGetter, Setter idSetter) { + if (persistentClass.getProxyInterface() == null) { // an entity, no + // proxy + return null; + } + + final HbDataStore ds = HbHelper.INSTANCE.getDataStore(persistentClass); + final EClass eclass = ds.getEntityNameStrategy().toEClass( + persistentClass.getEntityName()); + if (eclass == null + && !persistentClass.getEntityName().equals( + Constants.EAV_EOBJECT_ENTITY_NAME)) { + throw new HbMapperException("No eclass found for entityname: " + + persistentClass.getEntityName()); + } + + // get all the interfaces from the main class, add the real interface + // first + final Set<Class<?>> proxyInterfaces = new LinkedHashSet<Class<?>>(); + final Class<?> pInterface = persistentClass.getProxyInterface(); + if (pInterface != null && pInterface.isInterface()) { + proxyInterfaces.add(pInterface); + } + Class<?> mappedClass = persistentClass.getMappedClass(); + if (mappedClass == null) { + mappedClass = DynamicEObjectImpl.class; + } + if (mappedClass.isInterface()) { + proxyInterfaces.add(mappedClass); + } + proxyInterfaces.add(HibernateProxy.class); + proxyInterfaces.add(TeneoInternalEObject.class); + + for (Class<?> interfaces : mappedClass.getInterfaces()) { + proxyInterfaces.add(interfaces); + } + + // iterate over all subclasses and add them also + final Iterator<?> iter = persistentClass.getSubclassIterator(); + while (iter.hasNext()) { + final Subclass subclass = (Subclass) iter.next(); + final Class<?> subclassProxy = subclass.getProxyInterface(); + final Class<?> subclassClass = subclass.getMappedClass(); + if (subclassProxy != null && subclassClass != null + && !subclassClass.equals(subclassProxy)) { + proxyInterfaces.add(subclassProxy); + } + } + + // get the idgettters/setters + final Method theIdGetterMethod = idGetter == null ? null : idGetter + .getMethod(); + final Method theIdSetterMethod = idSetter == null ? null : idSetter + .getMethod(); + + final Method proxyGetIdentifierMethod = theIdGetterMethod == null + || pInterface == null ? null : ReflectHelper.getMethod( + pInterface, theIdGetterMethod); + final Method proxySetIdentifierMethod = theIdSetterMethod == null + || pInterface == null ? null : ReflectHelper.getMethod( + pInterface, theIdSetterMethod); + + ProxyFactory pf = Environment.getBytecodeProvider() + .getProxyFactoryFactory().buildProxyFactory(); + try { + pf.postInstantiate( + getEntityName(), + mappedClass, + proxyInterfaces, + proxyGetIdentifierMethod, + proxySetIdentifierMethod, + persistentClass.hasEmbeddedIdentifier() ? (CompositeType) persistentClass + .getIdentifier().getType() : null); + } catch (HbStoreException e) { + log.warn("could not create proxy factory for:" + getEntityName(), e); + pf = null; + } + return pf; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.AbstractEntityTuplizer#getEntityMode() + */ + public EntityMode getEntityMode() { + return EntityMode.POJO; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.EntityTuplizer#getConcreteProxyClass() + */ + public Class<?> getConcreteProxyClass() { + return EObject.class; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.EntityTuplizer#isInstrumented() + */ + public boolean isInstrumented() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.tuple.Tuplizer#getMappedClass() + */ + public Class<?> getMappedClass() { + return mappedClass; + } + + /** Returns the correct accessor on the basis of the type of property */ + protected PropertyAccessor getPropertyAccessor(Property mappedProperty, + PersistentClass pc) { + final HbDataStore ds = HbHelper.INSTANCE.getDataStore(pc); + return HbUtil.getPropertyAccessor(mappedProperty, ds, + pc.getEntityName(), null); + } +}
\ No newline at end of file |