org.eclipse.emf.teneo.hibernate.mapping.elist.MapHibernatePersistableEMap.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.teneo.hibernate.mapping.elist.MapHibernatePersistableEMap.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: MapHibernatePersistableEMap.java,v 1.9 2010/02/04 10:53:08 mtaal Exp $
 */

package org.eclipse.emf.teneo.hibernate.mapping.elist;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.common.util.BasicEMap;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.teneo.extension.ExtensionPoint;
import org.eclipse.emf.teneo.hibernate.SessionWrapper;
import org.eclipse.emf.teneo.hibernate.resource.HbResource;
import org.eclipse.emf.teneo.mapping.elist.MapPersistableEMap;
import org.eclipse.emf.teneo.resource.StoreResource;
import org.hibernate.Session;
import org.hibernate.collection.AbstractPersistentCollection;
import org.hibernate.collection.PersistentMap;

/**
 * Implements the hibernate persistable emap using a real map mapping (instead of the previous list
 * mapping).
 * 
 * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
 * @author <a href="mailto:jdboudreault@gmail.com">Jean-Denis Boudreault</a>
 * @version $Revision: 1.9 $
 */

public class MapHibernatePersistableEMap<K, V> extends MapPersistableEMap<K, V> implements ExtensionPoint {
    /**
     * Serial Version ID
     */
    private static final long serialVersionUID = -4553160393592497834L;

    /** The logger */
    private static Log log = LogFactory.getLog(MapHibernatePersistableEMap.class);

    private Long cachedSize = null;

    /**
     * Constructor: this version will take a natural map as input (probided by hibernate) and
     * transform the entries into the EMF keyToValue format
     * 
     * 
     */
    public MapHibernatePersistableEMap(InternalEObject owner, EReference eref, Map<K, V> map) {
        super(eref.getEReferenceType(), owner, eref, map);
    }

    /**
     * This constructor is usually called when the list is created and filled by the user first.
     * when called by a hibernate load, the other overload with a map input is used instead.
     * 
     */
    public MapHibernatePersistableEMap(InternalEObject owner, EReference eref, List<BasicEMap.Entry<K, V>> list) {
        super(eref.getEReferenceType(), owner, eref, list);
    }

    /** If the delegate has been initialized */
    public boolean isInitialized() {
        return isORMMapDelegateLoaded();
    }

    /**
     * Override isLoaded to check if the delegate lists was not already loaded by hibernate behind
     * the scenes, this happens with eagerly loaded lists.
     */
    @Override
    public boolean isLoaded() {
        // if the lazyload delegate is null, then this map is already loaded
        if (ormMapDelegate == null) {
            return true;
        }

        // if the delegated map was loaded under the hood and this
        // HibernatePersistableEMap did
        // not yet notice it then do the local load behavior.
        // delegate is loaded in case of subselect or eager loading
        if (!super.isLoaded() && !isLoading() && isORMMapDelegateLoaded()) {
            if (log.isDebugEnabled()) {
                log.debug("Persistentlist already initialized, probably eagerly loaded: " + getLogString());
            }
            try {
                this.setLoading(true);
                // do load to load the resource
                doLoad();
                this.setLoading(true);
            } finally {
                this.setLoading(false);
            }
        }
        return super.isLoaded();
    }

    /**
     * Overridden because of access to size attribute. This version will try to read the collection
     * size without lading it if it is lazy loaded
     */
    @Override
    public int size() {
        if (size != 0) {
            return size;
        }

        // if we are not loaded yet, we return the size of the buffered lazy
        // load delegate
        if (!isMapValueIsEAttribute() && this.getORMMapDelegate() != null) {
            if (!this.isORMMapDelegateLoaded()
                    && (this.getORMMapDelegate() instanceof AbstractPersistentCollection)) {
                if (cachedSize != null) {
                    return cachedSize.intValue();
                }
                try {
                    // here is a neat trick. we use reflection to get the
                    // session of the persistanMap.
                    Field field = AbstractPersistentCollection.class.getDeclaredField("session");
                    field.setAccessible(true);
                    Session s = (Session) field.get(this.getORMMapDelegate());

                    // now that we have the session, we can query the size of
                    // the list without loading it
                    cachedSize = ((Long) s.createFilter(this.getORMMapDelegate(), "select count(*)").list().get(0));
                    size = cachedSize.intValue();
                    return size;
                } catch (Throwable t) {
                    // ignore on purpose, let the call to super handle it
                }
            }
        }

        // didnt work, so we simply call the parent version
        return super.size();
    }

    /**
     * this method is used to determine if the underlying hibernate map collection has been eagerly
     * loaded
     * 
     * @return true if is laoded, false if not
     */
    @Override
    protected boolean isORMMapDelegateLoaded() {
        if (this.getORMMapDelegate() == null) {
            return false;
        }

        return ((this.ormMapDelegate instanceof PersistentMap)
                && (((PersistentMap) ormMapDelegate).wasInitialized()));
    }

    /**
     * Do the actual load and wrapping. can be overridden
     */
    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected void doLoad() {
        SessionWrapper sessionWrapper = null;
        boolean controlsTransaction = false;
        boolean err = true;
        Resource res = null;
        final Map<K, V> delegate = getORMMapDelegate();

        try {
            res = getEObject().eResource();
            if (res != null && res instanceof HbResource) {
                sessionWrapper = ((HbResource) res).getSessionWrapper();
                if (res.isLoaded()) // resource is loaded reopen transaction
                {
                    // if the delegate is already loaded then no transaction is
                    // required
                    final boolean isDelegateLoaded = delegate instanceof AbstractPersistentCollection
                            && ((AbstractPersistentCollection) delegate).wasInitialized();
                    if (!isDelegateLoaded && !sessionWrapper.isTransactionActive()) {
                        if (log.isDebugEnabled()) {
                            log.debug("Reconnecting session to read a lazy collection, elist: " + logString);
                        }
                        controlsTransaction = true;
                        sessionWrapper.beginTransaction();
                        sessionWrapper.setFlushModeManual();
                    } else if (log.isDebugEnabled()) {
                        log.debug("Delegate loaded or resource session is still active, using it");
                    }
                } else if (log.isDebugEnabled()) {
                    log.debug("EMap uses session from resource, " + logString);
                }
            } else if (log.isDebugEnabled()) {
                log.debug("EMap is not loaded in session context");
            }

            if (controlsTransaction) {
                assert (res instanceof HbResource);
                ((StoreResource) res).setIsLoading(true);
            }

            try {
                // set all entries in ourselves by wrapping the hibernate map.
                // this also forces the load
                for (Object o : this.getORMMapDelegate().entrySet()) {
                    final Map.Entry entry = (Map.Entry) o;
                    put((K) entry.getKey(), (V) entry.getValue());
                }

                // add the new objects to the resource so they are tracked
                if (res != null && res instanceof StoreResource) {
                    // attach the new contained objects so that they are adapted
                    // when required
                    for (Object o : entrySet()) {
                        if (o instanceof EObject) {
                            ((StoreResource) res).addToContentOrAttach((InternalEObject) o,
                                    (EReference) getEStructuralFeature());
                        }
                    }
                }
                if (log.isDebugEnabled()) {
                    log.debug("Loaded " + delegate.size() + " from backend store for " + logString);
                }
            } finally {
                if (controlsTransaction) {
                    ((StoreResource) res).setIsLoading(false);
                }
            }
            err = false;
        } finally {
            if (controlsTransaction) {
                if (err) {
                    sessionWrapper.rollbackTransaction();
                    sessionWrapper.restorePreviousFlushMode();
                } else {
                    // a bit rough but delete from the persitence context
                    // otherwise
                    // hibernate will think that this collection is not attached
                    // to anything and
                    // will delete me
                    // getSession().getPersistenceContext().getCollectionEntries().remove(this);
                    sessionWrapper.commitTransaction();
                    sessionWrapper.restorePreviousFlushMode();
                }
                ((HbResource) res).returnSessionWrapper(sessionWrapper);
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("Finished loading emap " + logString);
        }
    }

    /** Return the hibernate map */
    @Override
    public Object getDelegate() {
        return getORMMapDelegate();
    }
}