org.eclipse.emf.teneo.mapping.elist.PersistableFeatureMap.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.teneo.mapping.elist.PersistableFeatureMap.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 - Initial API and implementation
 *
 * </copyright>
 *
 * $Id: PersistableFeatureMap.java,v 1.15 2010/02/04 11:03:00 mtaal Exp $
 */

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

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.util.DelegatingFeatureMap;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.teneo.TeneoException;
import org.eclipse.emf.teneo.type.FeatureMapEntry;
import org.eclipse.emf.teneo.util.AssertUtil;

/**
 * A persistable elist which can be used by different or mappers. This persistable elist works around the idea that the
 * persisted list (e.g. PersistentList in Hibernate) is the delegate for this elist.
 * 
 * Note the delegate**() methods are overridden to force a load before anything else happens with the delegated list.
 * The addUnique. addSet methods are overridden to ensure that the featuremap entries of the right type are passed to
 * the persistent store.
 * 
 * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
 * @version $Revision: 1.15 $
 */

public abstract class PersistableFeatureMap extends DelegatingFeatureMap
        implements PersistableDelegateList<FeatureMap.Entry> {

    private static final long serialVersionUID = 1L;

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

    /**
     * The actual list, must never be an elist as notifications etc. are done by this list
     */
    protected List<FeatureMap.Entry> delegate;

    /** Is loaded from backend */
    private boolean isLoaded = false;

    /** Is being loaded from backend */
    private boolean isLoading = false;

    /** The string used for logging */
    protected final String logString;

    /** The type of the elements in this list */
    private final Class<? extends FeatureMap.Entry> elementType;

    /** Constructor */
    public PersistableFeatureMap(InternalEObject owner, EStructuralFeature feature, List<FeatureMap.Entry> list) {
        super(owner, feature);
        elementType = determineElementType();

        if (list == null) {
            delegate = new ArrayList<FeatureMap.Entry>();
            isLoaded = true;
        } else if (list instanceof EList<?>) {
            AssertUtil.assertTrue("The passed elist is not a featuremap but a : " + list.getClass().getName()
                    + ". Error in featureMap: " + getLogString(), list instanceof FeatureMap);

            delegate = replaceEntryAll(list);
            isLoaded = true;
        } else {
            delegate = list;
            isLoaded = list.size() > 0;
        }

        logString = "FeatureMap of member " + getEStructuralFeature().getName() + " owned by "
                + owner.getClass().getName() + " with delegate list " + delegate.getClass().getName();

        if (log.isDebugEnabled()) {
            log.debug("Created persistable featuremap " + logString);
        }
    }

    /** Returns the element type to be used */
    protected abstract Class<? extends FeatureMap.Entry> determineElementType();

    /** Returns the element type */
    public Class<? extends FeatureMap.Entry> getElementType() {
        return elementType;
    }

    /** Shortcut to replace entries */
    protected FeatureMap.Entry replaceEntry(FeatureMap.Entry entry) {
        if (entry instanceof FeatureMapEntry && ((FeatureMapEntry) entry).belongsToFeatureMap(this)) {
            return entry;
        }

        final FeatureMap.Entry emfEntry = entry;
        return createEntry(emfEntry.getEStructuralFeature(), emfEntry.getValue());
    }

    /** Convenience to replace all */
    private List<FeatureMap.Entry> replaceEntryAll(Collection<? extends FeatureMap.Entry> coll) {
        final ArrayList<FeatureMap.Entry> result = new ArrayList<FeatureMap.Entry>();
        for (FeatureMap.Entry fe : coll) {
            result.add(replaceEntry(fe));
        }
        return result;
    }

    /** Creates an exception with the logID added, without a cause */
    protected TeneoException createException(String msg) {
        return new TeneoException(msg + "\n" + getLogString());
    }

    /** Creates an exception with the logID added, without a cause */
    protected TeneoException createException(String msg, Throwable t) {
        return new TeneoException(msg + "\n" + getLogString(), t);
    }

    /** Return the delegate list without doing a load */
    public List<FeatureMap.Entry> getDelegate() {
        return delegate;
    }

    /** Returns the underlying elist */
    @Override
    protected List<FeatureMap.Entry> delegateList() {
        load();

        return delegate;
    }

    /** Replace the delegating list */
    public void replaceDelegate(List<FeatureMap.Entry> newDelegate) {
        AssertUtil.assertTrue("This featuremap " + logString + " already wraps an or specific featuremap",
                !isPersistencyWrapped());

        delegate = newDelegate;
        isLoaded = false;
    }

    /** Returns a string which can be used to log for this elist */
    public String getLogString() {
        return logString;
    }

    /**
     * Performs the load action if not yet loaded and sends out the load notification
     */
    protected void load() {
        if (isLoaded) {
            return;
        }

        // When we are loading we should not be reloaded!
        // this can happen in the jpox fm impl. when detaching
        if (isLoading) {
            return;
        }

        isLoading = true;
        doLoad();
        isLoaded = true;
        isLoading = false;
        // StoreUtil.dispatchEListLoadNotification(owner, this,
        // getEStructuralFeature());
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.ecore.util.EcoreEList#isNotificationRequired()
     */
    @Override
    protected boolean isNotificationRequired() {
        if (!isLoaded() || isLoading()) {
            return false; // not yet loaded so no notifications, prevents
            // infinite looping
        }
        return super.isNotificationRequired();
    }

    /** Is loaded */
    public boolean isLoaded() {
        return isLoaded;
    }

    /** Is loaded */
    public void setIsLoaded(boolean isLoaded) {
        this.isLoaded = isLoaded;
    }

    /** Is loading */
    public void setIsLoading(boolean isLoading) {
        this.isLoading = isLoading;
    }

    /** Returns true if the load action is running and false otherwise */
    public boolean isLoading() {
        return isLoading;
    }

    /**
     * The load method which should be overridden by the subclass to add lazyloading
     */
    protected abstract void doLoad();

    /** Returns true if the wrapped list is a persistency layer specific list */
    public abstract boolean isPersistencyWrapped();

    /** Override the didadd to enable opposite setting */
    // MT not necessary anymore in new EMF versions
    // @Override
    // protected void didAdd(int index, FeatureMap.Entry obj) {
    // final NotificationChain nc = inverseAdd(obj, null);
    // if (nc != null && isNotificationRequired()) {
    // nc.dispatch();
    // }
    // super.didAdd(index, obj);
    // }
    /* Override the didremove to enable opposite setting */
    // @Override
    // protected void didRemove(int index, FeatureMap.Entry obj) {
    // final NotificationChain nc = inverseRemove(obj, null);
    // if (nc != null && isNotificationRequired()) {
    // nc.dispatch();
    // }
    // super.didRemove(index, obj);
    // }
    // ---------------------------- Overloaded delegate methods
    // --------------------------
    // These methods have been overridden to a load action before the backing
    // list is
    // accessed.
    /** OVerridden to create the correct featuremap entry */
    @Override
    protected abstract FeatureMap.Entry createEntry(EStructuralFeature eStructuralFeature, Object value);

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateAdd(int, java.lang.Object)
     */
    @Override
    protected void delegateAdd(int index, FeatureMap.Entry object) {
        load();
        super.delegateAdd(index, object);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateAdd(java.lang.Object)
     */
    @Override
    protected void delegateAdd(FeatureMap.Entry object) {
        load();
        super.delegateAdd(object);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.notify.impl.DelegatingNotifyingListImpl#addAllUnique (java.util.Collection )
     */
    @Override
    public boolean addAllUnique(Collection<? extends FeatureMap.Entry> collection) {
        return super.addAllUnique(replaceEntryAll(collection));
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.notify.impl.DelegatingNotifyingListImpl#addAllUnique (int, java.util.Collection)
     */
    @Override
    public boolean addAllUnique(int index, Collection<? extends FeatureMap.Entry> collection) {
        return super.addAllUnique(index, replaceEntryAll(collection));
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.notify.impl.DelegatingNotifyingListImpl#addUnique (int, java.lang.Object)
     */
    @Override
    public void addUnique(int index, FeatureMap.Entry object) {
        super.addUnique(index, replaceEntry(object));
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.notify.impl.DelegatingNotifyingListImpl#addUnique (java.lang.Object)
     */
    @Override
    public void addUnique(FeatureMap.Entry object) {
        super.addUnique(replaceEntry(object));
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.notify.impl.DelegatingNotifyingListImpl#setUnique (int, java.lang.Object)
     */
    @Override
    public FeatureMap.Entry setUnique(int index, FeatureMap.Entry object) {
        return super.setUnique(index, replaceEntry(object));
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateBasicList()
     */
    @Override
    protected List<FeatureMap.Entry> delegateBasicList() {
        load();
        return super.delegateBasicList();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateClear()
     */
    @Override
    protected void delegateClear() {
        load();
        super.delegateClear();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateContains(java.lang .Object)
     */
    @Override
    protected boolean delegateContains(Object object) {
        load();
        return super.delegateContains(object);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateContainsAll(java. util.Collection)
     */
    @Override
    protected boolean delegateContainsAll(Collection<?> collection) {
        load();
        return super.delegateContainsAll(collection);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateEquals(java.lang. Object)
     */
    @Override
    protected boolean delegateEquals(Object object) {
        load();
        return super.delegateEquals(object);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateGet(int)
     */
    @Override
    protected FeatureMap.Entry delegateGet(int index) {
        load();
        return super.delegateGet(index);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateHashCode()
     */
    @Override
    protected int delegateHashCode() {
        load();
        return super.delegateHashCode();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateIndexOf(java.lang .Object)
     */
    @Override
    protected int delegateIndexOf(Object object) {
        load();
        return super.delegateIndexOf(object);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateIsEmpty()
     */
    @Override
    protected boolean delegateIsEmpty() {
        load();
        return super.delegateIsEmpty();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateIterator()
     */
    @Override
    protected Iterator<FeatureMap.Entry> delegateIterator() {
        load();
        return super.delegateIterator();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateLastIndexOf(java. lang.Object)
     */
    @Override
    protected int delegateLastIndexOf(Object object) {
        load();
        return super.delegateLastIndexOf(object);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateListIterator()
     */
    @Override
    protected ListIterator<FeatureMap.Entry> delegateListIterator() {
        // TODO Auto-generated method stub
        return super.delegateListIterator();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateRemove(int)
     */
    @Override
    protected FeatureMap.Entry delegateRemove(int index) {
        load();
        return super.delegateRemove(index);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateSet(int, java.lang.Object)
     */
    @Override
    protected FeatureMap.Entry delegateSet(int index, FeatureMap.Entry object) {
        load();
        // do the delegate set in two steps so that cascade delete works
        // for featuremap as a component
        final FeatureMap.Entry old = delegateRemove(index);
        delegateAdd(index, object);
        return old;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateSize()
     */
    @Override
    protected int delegateSize() {
        load();
        return super.delegateSize();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateToArray()
     */
    @Override
    protected Object[] delegateToArray() {
        load();
        return super.delegateToArray();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateToArray(java.lang .Object[])
     */
    @Override
    protected <T> T[] delegateToArray(T[] array) {
        load();
        return super.delegateToArray(array);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateToString()
     */
    @Override
    protected String delegateToString() {
        load();
        return super.delegateToString();
    }

    /**
     * Is overridden because it can't use delegates for equality because the delegate (a hibernate or jpox list) will
     * try to be equal with this persistable elist.
     * 
     * This method does jvm instance equality because doing a full-fledge equal would result in a load of the list.
     */
    @Override
    public boolean equals(Object object) {
        return this == object;
    }
}