/** * <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.12 2008/03/10 21:30:18 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.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.resource.Resource; 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.mapping.elist.PersistableDelegateList; import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy; import org.eclipse.emf.teneo.resource.StoreResource; import org.eclipse.emf.teneo.util.FieldUtil; import org.hibernate.EmptyInterceptor; 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.12 $ */ 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>>(); // 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); } } } } } // 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) * * @see org.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("unchecked") public void postFlush(Iterator entities) { 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); } } /** * Returns true if the eobject belongs to the newEObject set of a hibernateResource, in all * other cases returns null. */ @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; } }