diff options
Diffstat (limited to 'hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbDataStore.java')
-rwxr-xr-x | hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/HbDataStore.java | 1866 |
1 files changed, 1866 insertions, 0 deletions
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 |