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

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.teneo.mapping.elist.PersistableEList.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: PersistableEList.java,v 1.26 2010/02/06 20:51:42 mtaal Exp $
 */

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

import java.io.IOException;
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.notify.Notification;
import org.eclipse.emf.common.notify.NotifyingList;
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.DelegatingEcoreEList;
import org.eclipse.emf.teneo.util.StoreUtil;

/**
 * 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.
 * 
 * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
 * @version $Revision: 1.26 $
 */

public abstract class PersistableEList<E> extends DelegatingEcoreEList<E> implements PersistableDelegateList<E> {
    private static final long serialVersionUID = 1L;

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

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

    /** The structural feature modeled by this list */
    private EStructuralFeature estructuralFeature;

    /** The unique path to the efeature, used to support serializaion */
    private String eFeaturePath = "";

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

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

    /** The string used for logging */
    protected String logString = "";

    protected Boolean isThisListWrapped;

    /** Constructor */
    public PersistableEList(InternalEObject owner, EStructuralFeature feature, List<E> list) {
        super(owner);
        estructuralFeature = feature;
        if (list == null) {
            delegate = new ArrayList<E>();
            isLoaded = true;
        } else if (list instanceof EList<?>) {
            delegate = new ArrayList<E>(list);
            isLoaded = true;
        } else if (list instanceof ArrayList<?>) { // already loaded lists are
            // packaged in an elist
            delegate = list;
            isLoaded = list.size() > 0;
        } else {
            delegate = list;
        }

        if (log.isDebugEnabled()) {
            logString = "EList of type: " + this.getClass().getName() + " of member " + estructuralFeature.getName()
                    + " owned by " + owner.getClass().getName() + " with delegate list "
                    + delegate.getClass().getName();

            log.debug("Created persistable list " + logString);
        }
    }

    /** Takes care of serializing the efeature */
    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
        EStructuralFeature estructuralFeatureOld = estructuralFeature;
        eFeaturePath = StoreUtil.structuralFeatureToString(estructuralFeature);
        // Commented to fix the bug due to which the attribute structuralFeature
        // was getting chnaged to null
        estructuralFeature = null;
        additionalWriteObject();
        out.defaultWriteObject();
        estructuralFeature = estructuralFeatureOld;
    }

    /** Do your subclass thing for serialization */
    protected void additionalWriteObject() {
    }

    /** Takes care of deserializing the efeature */
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        estructuralFeature = StoreUtil.stringToStructureFeature(eFeaturePath);
    }

    /*
     * Get the underlying efeature
     * 
     * @see org.eclipse.emf.ecore.util.DelegatingEcoreEList#getEStructuralFeature()
     */
    @Override
    public EStructuralFeature getEStructuralFeature() {
        return estructuralFeature;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.ecore.util.DelegatingEcoreEList#getFeature()
     */
    @Override
    public Object getFeature() {
        return estructuralFeature;
    }

    /** Return the isunique value of the efeature */
    @Override
    public boolean isUnique() {
        return estructuralFeature.isUnique();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.ecore.util.DelegatingEcoreEList#getFeatureID()
     */
    @Override
    // todo: get rid of the override when the issue with the
    // delegatingecorelist.getFeatureId is
    // solved.
    public int getFeatureID() {
        return owner.eClass().getFeatureID(estructuralFeature);
    }

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

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

        return delegate;
    }

    /**
     * If this instance is again wrapped by a NotifyingList then assume that the wrapper will be smart enough to do all
     * the inverse things.... Note that the check if a list is wrapped is done once and then the result is cached. So
     * this assumes that a list will not be re-wrapped.
     * 
     * @return false if the list is wrapped, otherwise the super hasInverse is called.
     */
    @Override
    protected boolean hasInverse() {
        if (isWrapped()) {
            return false;
        }

        return super.hasInverse();
    }

    @Override
    protected void dispatchNotification(Notification notification) {
        // don't notify anyone as the wrapper should do that
        if (isWrapped()) {
            return;
        }
        super.dispatchNotification(notification);
    }

    private boolean isWrapped() {
        if (isThisListWrapped == null) {
            final Object value = getEObject().eGet(getEStructuralFeature());
            isThisListWrapped = value != this && value instanceof NotifyingList<?>;
        }
        return isThisListWrapped;
    }

    /** Replace the delegating list and set isLoaded = false */
    public void replaceDelegate(List<E> newDelegate) {
        // disabled this assertion because in case of a session refresh it is
        // possible
        // that the list is replaced by a persistent list
        // AssertUtil.assertTrue("This elist " + logString +
        // " already wraps an or specific list",
        // !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 oaded 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 elist impl. when detaching
        if (isLoading) {
            return;
        }

        isLoading = true;
        if (log.isDebugEnabled()) {
            log.debug("Loading " + getLogString());
        }

        // prevent notifications to be sent out
        boolean eDeliver = owner.eDeliver();
        boolean setDeliver = false;
        try {
            // only set to false if it was true
            if (eDeliver) {
                if (log.isDebugEnabled()) {
                    log.debug("Owner " + owner.getClass() + " set eDeliver to false");
                }
                owner.eSetDeliver(false);
                setDeliver = true;
            }
        } catch (UnsupportedOperationException e) {
            // in this case the eSetDeliver was not overridden from the
            // baseclass
            // ignore
        }
        try {
            doLoad();
        } finally {
            isLoaded = true;
            isLoading = false;
            if (setDeliver) {
                owner.eSetDeliver(eDeliver);
            }
        }
        // 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();

    // ---------------------------- Overloaded delegate methods
    // --------------------------
    // These methods have been overridden to a load action before the backing
    // list is
    // accessed.

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

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

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.util.DelegatingEList#delegateBasicList()
     */
    @Override
    protected List<E> 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 E 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<E> 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<E> delegateListIterator() {
        return super.delegateListIterator();
    }

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

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

    /*
     * (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();
    }

    /** If not loaded then basicIterator will always return a false for hasNext */
    @SuppressWarnings("deprecation")
    @Override
    public Iterator<E> basicIterator() {
        if (!isLoaded()) {
            return new NonResolvingEIterator<E>() {
                /** Always returns false */
                @Override
                public boolean hasNext() {
                    return false;
                }
            };
        }

        return super.basicIterator();
    }

    /**
     * If not loaded then basicIterator will always return a false for hasNext/hasPrevious
     */
    @Override
    @SuppressWarnings("deprecation")
    public ListIterator<E> basicListIterator() {
        if (!isLoaded()) {
            return new NonResolvingEListIterator<E>() {
                /** Always returns false */
                @Override
                public boolean hasNext() {
                    return false;
                }

                /** Always returns false */
                @Override
                public boolean hasPrevious() {
                    return false;
                }
            };
        }

        return super.basicListIterator();
    }

    /**
     * If not loaded then basicIterator will always return a false for hasNext/hasPrevious
     */
    @Override
    @SuppressWarnings("deprecation")
    public ListIterator<E> basicListIterator(int index) {
        if (!isLoaded()) {
            // note no size check on index as this would load this thing
            return new NonResolvingEListIterator<E>() {
                /** Always returns false */
                @Override
                public boolean hasNext() {
                    return false;
                }

                /** Always returns false */
                @Override
                public boolean hasPrevious() {
                    return false;
                }
            };
        }

        return super.basicListIterator(index);
    }

    /**
     * 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;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#clone()
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}