blob: 259680382fdb255c3c109233af97a87f988103d5 [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2005, 2006, 2007 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.14.2.3 2007/05/04 04:59:41 mtaal Exp $
*/
package org.eclipse.emf.teneo.hibernate;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
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.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
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.teneo.ERuntime;
import org.eclipse.emf.teneo.PersistenceOptions;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel;
import org.eclipse.emf.teneo.classloader.StoreClassLoadException;
import org.eclipse.emf.teneo.ecore.EClassNameStrategy;
import org.eclipse.emf.teneo.hibernate.hbannotation.util.MappingBuilder;
import org.eclipse.emf.teneo.hibernate.mapper.HbMapperConstants;
import org.eclipse.emf.teneo.hibernate.mapper.HibernateMappingGenerator;
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.EContainerUserType;
import org.eclipse.emf.teneo.hibernate.mapping.elist.HibernateFeatureMapEntry;
import org.eclipse.emf.teneo.hibernate.resource.HibernateResource;
import org.eclipse.emf.teneo.hibernate.resource.HibernateResourceFactory;
import org.eclipse.emf.teneo.util.StoreUtil;
import org.hibernate.EntityMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cache.HashtableCacheProvider;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.CascadeStyle;
import org.hibernate.mapping.Bag;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.List;
import org.hibernate.mapping.ManyToOne;
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;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
/**
* 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.14.2.3 $
*/
public class HbDataStore {
/** 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.getExtensionToFactoryMap().put("hibernate", new HibernateResourceFactory());
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("ehb", new HibernateResourceFactory());
}
/** The name under which it is registered */
private String name;
/** The list of epackages stored in the datastore */
private EPackage[] ePackages;
/** The persistency manager factory */
private SessionFactory sessionFactory;
/** The used Hibernate configuration */
private Configuration hbConfiguration;
/** HashMap with referers */
private HashMap referers;
/**
* The used mapping if not passed through a hbm file, can be retrieved for debugging purposes
*/
private String mappingXML = null;
/** The properties used to create the hibernate configuration object */
private PersistenceOptions persistenceOptions;
private Properties hibernateProperties;
/** Is the store initialized */
private boolean initialized = false;
/** The array with entities (eclasses) which are not contained */
private String[] topEntities;
/** Update the schema option */
// private boolean updateSchema = true;
/** The hb context */
private HbContext hbContext = new HbContextImpl();
/** The pamodel, is set after initialization */
private PAnnotatedModel paModel;
/** Initializes this Data Store */
public void initialize() {
// check a few things
if (getEPackages() == null)
throw new HbMapperException("EPackages are not set");
// if (getName() == null)
// throw new HbStoreException("Name is not set");
log.debug(">>>>> Creating HB Configuration");
hbConfiguration = getHbContext().createConfiguration();
mapModel();
setPropertiesInConfiguration();
setInterceptor();
log.debug("Determine referers for each class");
referers = computeReferers();
topEntities = computeTopEntities();
// now add the econtainer mappings to the contained types, only for
// unidirectional container relations
addContainerMappings();
// buildmappings has to be done before setting the tuplizers because
// buildMappings will ensure that the element
// is set in the List properties.
hbConfiguration.buildMappings();
setTuplizer();
// set the event listeners
setEventListeners();
updateDatabaseSchema();
log.debug("Registering datastore with persistent classes");
HbHelper.INSTANCE.registerDataStoreByPC(this);
// wait for the session factory until the database is (re)created
if (sessionFactory != null && !sessionFactory.isClosed())
sessionFactory.close();
sessionFactory = buildSessionFactory();
initialized = true;
}
/**
* Gets the initialized state.
*/
public boolean isInitialized() {
return initialized;
}
/** Sets the tuplizer */
protected void setTuplizer() {
final Configuration cfg = getConfiguration();
for (Iterator pcs = cfg.getClassMappings(); pcs.hasNext();) {
final PersistentClass pc = (PersistentClass) pcs.next();
if (pc.getMetaAttribute(HbMapperConstants.ECLASS_META) != null
|| pc.getMetaAttribute(HbMapperConstants.FEATUREMAP_META) != null) { // featuremap
// entry
pc.addTuplizer(EntityMode.MAP, getHbContext().getFeatureMapEntryTuplizer(cfg).getName());
} else {
// final EClass eclass =
// StoreUtil.getEClassFromURI(pc.getEntityName(),
// getEPackages());
// pc.setClassName(eclass.getInstanceClassName());
pc.addTuplizer(EntityMode.MAP, getHbContext().getEMFTuplizerClass(cfg).getName());
pc.addTuplizer(EntityMode.POJO, getHbContext().getEMFTuplizerClass(cfg).getName());
}
// also set the tuplizer for the components, and register for the
// component
// Build a list of all properties.
java.util.List properties = new ArrayList();
final Property identifierProperty = pc.getIdentifierProperty();
if (identifierProperty != null) {
properties.add(identifierProperty);
}
for (Iterator it = pc.getPropertyIterator(); it.hasNext();) {
properties.add(it.next());
}
// Now set component tuplizers where necessary.
for (Iterator it = properties.iterator(); it.hasNext();) {
Property prop = (Property) it.next();
if (prop.getName().compareTo("_identifierMapper") == 0) {
continue; // ignore this one
}
final Value value = prop.getValue();
if (value instanceof Component) {
setComponentTuplizer((Component) value, cfg);
} else if (value instanceof Collection && ((Collection) value).getElement() instanceof Component) {
setComponentTuplizer((Component) ((Collection) value).getElement(), cfg);
}
}
}
}
/** 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
*/
private void setComponentTuplizer(Component component, Configuration cfg) {
// check if the eclass exists
try {
EClass eClass = getPersistenceOptions().getEClassNameStrategy().toEClass(component.getComponentClassName(),
getEPackages());
if (eClass != null) {
log.debug("Found " + eClass.getName() + " as a component");
}
} catch (IllegalArgumentException e) {
return; // not a valud eclass;
}
// is a
// valid
// eclass
component.addTuplizer(EntityMode.MAP, getHbContext().getEMFComponentTuplizerClass(cfg).getName());
HbHelper.INSTANCE.registerDataStoreByComponent(this, component);
}
/** Compute the top eclasses */
protected String[] computeTopEntities() {
ArrayList result = new ArrayList();
for (Iterator pcs = getConfiguration().getClassMappings(); pcs.hasNext();) {
final PersistentClass pc = (PersistentClass) pcs.next();
ArrayList refs = (ArrayList) referers.get(pc.getEntityName());
boolean topEntity = true;
if (refs != null) {
for (Iterator it = refs.iterator(); it.hasNext();) {
ReferenceTo rt = (ReferenceTo) it.next();
if (rt.isContainer) {
topEntity = false;
break;
}
}
}
if (topEntity)
result.add(pc.getEntityName());
}
return (String[]) result.toArray(new String[result.size()]);
}
/** Adds a econtainer mapping to the class mapping */
protected void addContainerMappings() {
if (getPersistenceOptions().isDisableEContainerMapping()) {
log.debug("EContainer mapping disabled.");
return;
}
for (Iterator pcs = getConfiguration().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);
}
}
/** Returns true if the pc is contained */
private boolean isContained(PersistentClass pc) {
ArrayList refs = (ArrayList) referers.get(pc.getEntityName());
if (refs == null)
return false;
for (Iterator it = refs.iterator(); it.hasNext();) {
ReferenceTo rt = (ReferenceTo) it.next();
if (rt.isContainer) {
return true;
}
}
return false;
}
/** Sets the properties in the Hibernate Configuration. */
protected void setPropertiesInConfiguration() {
Properties properties = getHibernateProperties();
if (properties != null) {
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());
}
log.debug("Setting properties in Hibernate Configuration:");
logProperties(properties);
getConfiguration().setProperties(properties);
}
}
/** Sets the interceptor */
protected void setInterceptor() {
hbConfiguration.setInterceptor(getHbContext().createInterceptor(getConfiguration(), getPersistenceOptions()));
}
/**
* 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()) {
// register otherwise the getFileList will not work
ERuntime.INSTANCE.register(getEPackages());
log.debug("Searching hbm files in class paths of epackages");
final String[] fileList = StoreUtil.getFileList(HbConstants.HBM_FILE_NAME, null);
for (int i = 0; i < fileList.length; i++) {
log.debug("Adding file " + fileList[i] + " to Hibernate Configuration");
getConfiguration().addInputStream(this.getClass().getResourceAsStream(fileList[i]));
}
} else {
mappingXML = mapEPackages();
getConfiguration().addXML(mappingXML);
}
}
/** 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();
paModel = MappingBuilder.INSTANCE.buildMapping(getEPackages(), po);
HibernateMappingGenerator hmg = new HibernateMappingGenerator(po);
return hmg.generateToString(paModel);
}
/**
* 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());
}
if (!isContained(pc))
return;
if (hasEContainerProp(pc))
return;
log.debug("Adding container mapping for " + pc.getEntityName());
// check if there are not alreadyecontai ner features for the eclass
final EClass eclass = getPersistenceOptions().getEClassNameStrategy().toEClass(pc.getEntityName(),
getEPackages());
// 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 (Iterator it = eclass.getEAllReferences().iterator(); it.hasNext();) {
EReference eref = (EReference) it.next();
if (eref.isContainer()) {
log
.debug("There are container ereferences present, assuming that no separate econtainer columns are required.");
return;
}
}
log.debug("Adding eContainer and econtainerfeatureid properties to " + pc.getClassName());
final Property eContainer = new Property();
eContainer.setName(HbConstants.PROPERTY_ECONTAINER);
eContainer.setMetaAttributes(new HashMap());
eContainer.setNodeName(eContainer.getName());
eContainer.setPropertyAccessorName(EContainerAccessor.class.getName());
final SimpleValue sv = new SimpleValue(pc.getTable());
sv.setTypeName(EContainerUserType.class.getName());
final Column eccColumn = new Column(HbConstants.COLUMN_ECONTAINER_CLASS);
sv.addColumn(checkColumnExists(pc.getTable(), eccColumn));
final Column ecColumn = new Column(HbConstants.COLUMN_ECONTAINER);
sv.addColumn(checkColumnExists(pc.getTable(), ecColumn));
eContainer.setValue(sv);
pc.addProperty(eContainer);
final Property ecFID = new Property();
ecFID.setName(HbConstants.PROPERTY_ECONTAINER_FEATURE_ID);
ecFID.setMetaAttributes(new HashMap());
ecFID.setNodeName(ecFID.getName());
ecFID.setPropertyAccessorName(EContainerFeatureIDAccessor.class.getName());
final SimpleValue svfid = new SimpleValue(pc.getTable());
svfid.setTypeName("integer");
final Column ecfColumn = new Column(HbConstants.COLUMN_ECONTAINER_FEATUREID);
svfid.addColumn(checkColumnExists(pc.getTable(), ecfColumn));
ecFID.setValue(svfid);
pc.addProperty(ecFID);
}
/** 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 */
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(getConfiguration()).execute(false, true);
log.debug(">>> Update of schema finished");
}
/** Build the session factory */
protected SessionFactory buildSessionFactory() {
return getConfiguration().buildSessionFactory();
}
/** Checks if a certain column already exists in a class */
private Column checkColumnExists(Table table, Column searchCol) {
final Column foundCol = table.getColumn(searchCol);
if (foundCol != null) {
return foundCol;
}
table.addColumn(searchCol);
return searchCol;
}
/** Dump properties in the log */
private 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));
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.teneo.jpox.emf.IEMFDataStore#close()
*/
public void close() {
if (!getSessionFactory().isClosed()) {
getSessionFactory().close();
}
}
/**
* 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
final ArrayList theReferers = (ArrayList) referers.get(obj.getClass());
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("." + 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 options = new HashMap();
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);
}
}
/**
* 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 result = getCrossReferencers(session, referedTo, false);
return (Object[]) 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 getCrossReferencers(Session session, Object referedTo, boolean onlyContainers) {
assert (referedTo != null);
String targetEntityName = null;
if (referedTo instanceof EObject) {
final EObject eReferedTo = (EObject) referedTo;
targetEntityName = getPersistenceOptions().getEClassNameStrategy().toUniqueName(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 ArrayList refersList = (ArrayList) referers.get(targetEntityName);
if (refersList == null || refersList.size() == 0)
return new ArrayList();
final ArrayList result = new ArrayList();
for (int i = 0; i < refersList.size(); i++) {
final ReferenceTo refersTo = (ReferenceTo) refersList.get(i);
// if we only check containment relations then skip this
if (onlyContainers && !refersTo.isContainer())
continue;
final Query qry = session.createQuery(refersTo.getQueryStr());
qry.setEntity("to", referedTo);
final java.util.List list = qry.list();
for (int j = 0; j < list.size(); j++) {
Object obj = list.get(j);
if (obj instanceof HibernateFeatureMapEntry) {
// search then again with the
final ArrayList fms = getCrossReferencers(session, 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;
}
/**
* Computes the referers, handles the lazy for containment
*/
protected HashMap computeReferers() {
final HashMap result = new HashMap();
Iterator it = hbConfiguration.getClassMappings();
it = hbConfiguration.getClassMappings();
ArrayList fmes = new ArrayList();
while (it.hasNext()) {
final PersistentClass pc = (PersistentClass) it.next();
// keep track which are the feature map entries
if (pc.getMetaAttribute(HbMapperConstants.ECLASS_META) != null
|| pc.getMetaAttribute(HbMapperConstants.FEATUREMAP_META) != null)
fmes.add(pc.getEntityName());
// everyone should have a list otherwise the copying of referers to
// super types to
// this type does not work
if (result.get(pc.getEntityName()) == null) {
result.put(pc.getEntityName(), new ArrayList());
}
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;
try{
eClass = getPersistenceOptions().getEClassNameStrategy().toEClass(pc.getEntityName(), getEPackages());
} catch (IllegalArgumentException e) {
// ignoring exception on purpose
eClass = null;
}
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 List || prop.getValue() instanceof Bag) {
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 {
throw new HbMapperException("Type "
+ ((Collection) prop.getValue()).getElement().getClass().getName()
+ " not supported");
}
} 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;
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 = getPersistenceOptions().getEClassNameStrategy().toUniqueName(
((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 = getPersistenceOptions().getEClassNameStrategy().toUniqueName((EClass) ef.getEType());
}
// filter out non eobjects
else {
continue;
}
}
} else {
continue;
}
ArrayList list = (ArrayList) result.get(toEntity);
if (list == null) {
list = new ArrayList();
result.put(toEntity, list);
}
list.add(new ReferenceTo(pc.getEntityName(), prop, isContainer, isMany));
} 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 Iterator keyIt = result.keySet().iterator();
final ArrayList classDone = new ArrayList();
while (keyIt.hasNext()) {
final String em = (String) keyIt.next();
// only do this if not a fme
if (!fmes.contains(em))
setRefersToOfSupers(em, result, classDone);
}
return result;
}
/**
* Add the refersto for each superclass/interface to the subclass refersto list. As a convenience returns the set
* list
*/
private ArrayList setRefersToOfSupers(String eClassUri, HashMap refersTo, ArrayList classDone) {
final EClassNameStrategy ens = getPersistenceOptions().getEClassNameStrategy();
EClass eclass = ens.toEClass(eClassUri, getEPackages());
if (eclass == null)
return new ArrayList();
if (classDone.contains(eclass)) {
return (ArrayList) refersTo.get(eclass);
}
final ArrayList thisList = (ArrayList) refersTo.get(ens.toUniqueName(eclass));
if (thisList == null) {
return new ArrayList();
}
for (Iterator it = eclass.getESuperTypes().iterator(); it.hasNext();) {
String eclassUri = ens.toUniqueName((EClass) it.next());
addUnique(thisList, setRefersToOfSupers(eclassUri, refersTo, classDone));
}
classDone.add(eclass);
return thisList;
}
/** Adds list 2 to list 1 without duplicates */
private void addUnique(ArrayList l1, ArrayList l2) {
if (l2 == null)
return; // this is a valid situation so do nothing
final Iterator it = l2.iterator();
while (it.hasNext()) {
final Object obj = it.next();
if (!l1.contains(obj))
l1.add(obj);
}
}
/**
* @return the mappingXML
*/
public String getMappingXML() {
return mappingXML;
}
/**
* @return the dsName
*/
public String getName() {
return name;
}
/**
* @return the epackages
*/
public EPackage[] getEPackages() {
return ePackages;
}
/**
* @param epackages
* the epackages to set
*/
public void setEPackages(EPackage[] epackages) {
this.ePackages = epackages;
}
/**
* 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 = new PersistenceOptions(props);
}
return persistenceOptions;
}
/**
* Sets the persistence options.
*/
public void setPersistenceProperties(Properties persistenceOptions) {
this.persistenceOptions = new PersistenceOptions(persistenceOptions);
}
public Properties getHibernateProperties() {
return hibernateProperties;
}
public void setHibernateProperties(Properties hibernateProperties) {
this.hibernateProperties = hibernateProperties;
}
/**
* @param name
* the name to set
*/
public void setName(String name) {
this.name = name;
}
/** Get the session factory */
public SessionFactory getSessionFactory() {
if (!isInitialized()) {
initialize();
}
assert (sessionFactory != null);
return sessionFactory;
}
/**
* @return the hbConfiguration
*/
public Configuration getConfiguration() {
return hbConfiguration;
}
/**
* The entities (eclasses) which are not contained in another eclass.
*
* @return the topEntities
*/
public String[] getTopEntities() {
return topEntities;
}
/** Contains the reference to a class which refers to another reference */
public 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) {
this.isContainer = isContainer;
if (isMany) {
qryStr = "SELECT ref FROM " + fromEntity + " as ref WHERE :to 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 hbContext
*/
public HbContext getHbContext() {
return hbContext;
}
/**
* @param hbContext
* the hbContext to set
*/
public void setHbContext(HbContext hbContext) {
this.hbContext = hbContext;
}
/**
* @return the referers
*/
public HashMap getReferers() {
return referers;
}
/**
* @return the paModel
*/
public PAnnotatedModel getPaModel() {
return paModel;
}
}