org.eclipse.emf.teneo.hibernate.EMFInterceptor.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.teneo.hibernate.EMFInterceptor.java

Source

/**
 * <copyright>
 *
 * Copyright (c) 2005, 2006, 2007, 2008 Springsite BV (The Netherlands) and others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Martin Taal
 * </copyright>
 *
 * $Id: EMFInterceptor.java,v 1.15 2010/02/04 10:53:08 mtaal Exp $
 */

package org.eclipse.emf.teneo.hibernate;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.teneo.extension.ExtensionInitializable;
import org.eclipse.emf.teneo.extension.ExtensionManager;
import org.eclipse.emf.teneo.extension.ExtensionManagerAware;
import org.eclipse.emf.teneo.extension.ExtensionPoint;
import org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierCacheHandler;
import org.eclipse.emf.teneo.mapping.elist.PersistableDelegateList;
import org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy;
import org.eclipse.emf.teneo.type.PersistentStoreAdapter;
import org.eclipse.emf.teneo.util.FieldUtil;
import org.hibernate.EmptyInterceptor;
import org.hibernate.Transaction;
import org.hibernate.collection.AbstractPersistentCollection;

/**
 * Intercepts the getEntityName call to return the EClass name as the entity name.
 * 
 * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
 * @version $Revision: 1.15 $
 */

public class EMFInterceptor extends EmptyInterceptor
        implements ExtensionPoint, ExtensionManagerAware, ExtensionInitializable {

    // is kept to do dereferencing of collections, see the description in the deReferenceCollections
    // method
    // clear all session instances in the persistentcollection to solve
    // this issue which still occured with Teneo in hibernate 3.2.5
    // http://forum.hibernate.org/viewtopic.php?t=934961&highlight=two+representations+same+collection
    // http://opensource.atlassian.com/projects/hibernate/browse/HHH-511
    // this issue occured when doing the following using a resource:
    // create a new object with a isMany feature, save the resource,
    // delete the just saved object, save the resource
    // undo the delete (possible in the editor) and then
    // save the resource a 'Found two representations of same collection:'
    // exception occurs
    private static ThreadLocal<List<AbstractPersistentCollection>> persistentCollections = new ThreadLocal<List<AbstractPersistentCollection>>();
    private static ThreadLocal<List<EObject>> deletedEObjects = new ThreadLocal<List<EObject>>();

    // note is also used for non-deleted objects in HbResource
    public static void registerCollectionsForDereferencing(EObject eObject) {
        for (EReference eReference : eObject.eClass().getEAllReferences()) {
            if (eReference.isMany()) {
                final Object refValue = eObject.eGet(eReference);
                if (refValue instanceof PersistableDelegateList<?>) {
                    final Object delegate = ((PersistableDelegateList<?>) refValue).getDelegate();
                    if (delegate instanceof AbstractPersistentCollection) {
                        if (persistentCollections.get() == null) {
                            persistentCollections.set(new ArrayList<AbstractPersistentCollection>());
                        }
                        final List<AbstractPersistentCollection> list = persistentCollections.get();
                        list.add((AbstractPersistentCollection) delegate);
                    }
                }
            }
        }
        if (deletedEObjects.get() == null) {
            deletedEObjects.set(new ArrayList<EObject>());
        }
        deletedEObjects.get().add(eObject);
    }

    // is used to unset a session in a collection. Note that it would be better to use the
    // AbstractPersistentCollection.unsetSession/getSession method but these give me a
    // java.lang.AccessError
    private static final Field sessionField = FieldUtil.getField(AbstractPersistentCollection.class, "session");

    /**
     * Generated Serial Version ID
     */
    private static final long serialVersionUID = 1680117509182298808L;

    /** The qualify property used to compute the eclassname */
    private EntityNameStrategy qualifyStrategy;

    private ExtensionManager extensionManager;

    /*
     * (non-Javadoc)
     * 
     * @seeorg.eclipse.emf.teneo.extension.ExtensionManagerAware#setExtensionManager(org.eclipse.emf.teneo.extension.
     * ExtensionManager)
     */
    public void setExtensionManager(ExtensionManager extensionManager) {
        this.extensionManager = extensionManager;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.teneo.extension.ExtensionInitializable#initializeExtension()
     */
    public void initializeExtension() {
        qualifyStrategy = extensionManager.getExtension(EntityNameStrategy.class);
    }

    /**
     * Is overridden to return the eclass uri as the entity name.
     * 
     * @see org.hibernate.EmptyInterceptor#getEntityName(java.lang.Object)
     */
    @Override
    public String getEntityName(Object object) {
        if (object instanceof EObject) {
            // TODO handle featuremap
            EObject eobj = (EObject) object;
            return qualifyStrategy.toEntityName(eobj.eClass());
        }

        return super.getEntityName(object);
    }

    @Override
    @SuppressWarnings("rawtypes")
    public void postFlush(Iterator entities) {
        // TODO: consider to move this to after commit
        final List<AbstractPersistentCollection> list = persistentCollections.get();
        if (list == null) {
            return;
        }
        try {
            for (AbstractPersistentCollection apc : list) {
                try {
                    sessionField.set(apc, null);
                } catch (Exception e) {
                    throw new HbStoreException(e);
                }
            }
        } finally {
            persistentCollections.set(null);
        }
    }

    @Override
    public void afterTransactionCompletion(Transaction tx) {
        if (tx.wasCommitted()) {
            if (deletedEObjects.get() != null) {
                try {
                    for (EObject eObject : deletedEObjects.get()) {
                        // remove the PersistentStoreAdapter
                        PersistentStoreAdapter toRemoveAdapter = null;
                        for (Adapter adapter : eObject.eAdapters()) {
                            if (adapter instanceof PersistentStoreAdapter) {
                                toRemoveAdapter = (PersistentStoreAdapter) adapter;
                            }
                        }
                        if (toRemoveAdapter != null) {
                            eObject.eAdapters().remove(toRemoveAdapter);
                        }
                        IdentifierCacheHandler.getInstance().setVersion(eObject, null);
                        IdentifierCacheHandler.getInstance().setID(eObject, null);

                    }
                } finally {
                    deletedEObjects.set(null);
                }
            }
        }
        super.afterTransactionCompletion(tx);
    }

    /**
     * Returns true if the eobject belongs to the newEObject set of a hibernateResource, in all other cases returns
     * null.
     */
    // Disabled this method because an object can be new to a resource but already
    // exist in the database.
    // See bugzilla 280355 and the related testcase
    // @Override
    // public Boolean isTransient(Object entity) {
    // if (!(entity instanceof EObject)) {
    // return null;
    // }
    //
    // final EObject eObject = (EObject) entity;
    // final Resource res = eObject.eResource();
    // if (res == null || !(res instanceof StoreResource)) {
    // return null;
    // }
    //
    // final StoreResource storeResource = (StoreResource) res;
    // if (storeResource.getNewEObjectSet().contains(entity)) {
    // return true;
    // }
    // // in all other cases let hibernate do it
    // return null;
    // }
}