Package org.datanucleus.store.mapped.scostore

Source Code of org.datanucleus.store.mapped.scostore.AbstractListStore

/**********************************************************************
Copyright (c) 2003 David Jencks and others. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Contributors:
2003 Andy Jefferson - coding standards
2003 Andy Jefferson - updated to support inherited objects
2003 Andy Jefferson - revised logging
2004 Andy Jefferson - merged IteratorStmt and GetStmt into GetRangeStmt
2005 Andy Jefferson - added embedded PC element capability
2005 Andy Jefferson - added dependent-element when removed from collection
    ...
**********************************************************************/
package org.datanucleus.store.mapped.scostore;

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

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.ObjectManager;
import org.datanucleus.StateManager;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.metadata.CollectionMetaData;
import org.datanucleus.store.StoreManager;
import org.datanucleus.store.scostore.ListStore;

/**
* Abstract representation of a backing store for a List.
*/
public abstract class AbstractListStore extends AbstractCollectionStore implements ListStore
{
    /** Whether the list is indexed (like with JDO). If false then it will have no orderMapping (like with JPA). */
    protected boolean indexedList = true;

    /**
     * Constructor. Protected to prevent instantiation.
     * @param storeMgr Manager for the store
     * @param clr ClassLoader resolver
     * @param specialization the datastore-specific specialization
     */
    protected AbstractListStore(StoreManager storeMgr, ClassLoaderResolver clr, AbstractListStoreSpecialization specialization)
    {
        super(storeMgr, clr, specialization);
    }

    private AbstractListStoreSpecialization getSpecialization()
    {
        return (AbstractListStoreSpecialization) specialization;
    }

    // -------------------------- List Method implementations ------------------

    /**
     * Accessor for an iterator through the list elements.
     * @param sm State Manager for the container.
     * @return The Iterator
     */
    public Iterator iterator(StateManager sm)
    {
        return listIterator(sm);
    }

    /**
     * Accessor for an iterator through the list elements.
     * @param sm State Manager for the container.
     * @return The List Iterator
     */
    public ListIterator listIterator(StateManager sm)
    {
        return listIterator(sm, -1, -1);
    }

    /**
     * Accessor for an iterator through the list elements.
     * @param ownerSM State Manager for the container.
     * @param startIdx The start point in the list (only for indexed lists).
     * @param endIdx The end point in the list (only for indexed lists).
     * @return The List Iterator
     */
    protected abstract ListIterator listIterator(StateManager ownerSM, int startIdx, int endIdx);

    /**
     * Method to add an element to the List.
     * @param sm The state manager
     * @param element The element to remove
     * @param size Size of the current list (if known, -1 if not)
     * @return Whether it was added successfully.
     */
    public boolean add(StateManager sm, Object element, int size)
    {
        return internalAdd(sm, 0, true, Collections.singleton(element), size);
    }

    /**
     * Method to add an element to the List.
     * @param element The element to add.
     * @param index The location to add at
     * @param sm The state manager.
     */
    public void add(StateManager sm, Object element, int index, int size)
    {
        internalAdd(sm, index, false, Collections.singleton(element), size);
    }

    /**
     * Method to add a collection of elements to the List.
     * @param sm The state manager
     * @param elements The elements to remove
     * @param size Current size of the list (if known). -1 if not known
     * @return Whether they were added successfully.
     */
    public boolean addAll(StateManager sm, Collection elements, int size)
    {
        return internalAdd(sm, 0, true, elements, size);
    }

    /**
     * Method to add all elements from a Collection to the List.
     * @param sm The state manager
     * @param elements The collection
     * @param index The location to add at
     * @param size Current size of the list (if known). -1 if not known
     * @return Whether it was successful
     */
    public boolean addAll(StateManager sm, Collection elements, int index, int size)
    {
        return internalAdd(sm, index, false, elements, size);
    }

    /**
     * Internal method for adding an item to the List.
     * @param sm The state manager
     * @param startAt The start position
     * @param atEnd Whether to add at the end
     * @param elements The Collection of elements to add.
     * @param size Current size of List (if known). -1 if not known
     * @return Whether it was successful
     */
    protected abstract boolean internalAdd(StateManager sm, int startAt, boolean atEnd, Collection elements, int size);

    /**
     * Method to retrieve an element from the List.
     * @param sm The state manager
     * @param index The index of the element required.
     * @return The object
     */
    public Object get(StateManager sm, int index)
    {
        ListIterator iter = listIterator(sm, index, index);
        if (iter == null || !iter.hasNext())
        {
            return null;
        }
        if (!indexedList)
        {
            // Restrict to the actual element since can't be done in the query
            Object obj = null;
            int position = 0;
            while (iter.hasNext())
            {
                obj = iter.next();
                if (position == index)
                {
                    return obj;
                }
                position++;
            }
        }

        return iter.next();
    }

    /**
     * Accessor for the indexOf an object in the List.
     * @param sm The state manager
     * @param element The element.
     * @return The index
     */
    public int indexOf(StateManager sm, Object element)
    {
        validateElementForReading(sm, element);
        return getSpecialization().indexOf(sm, element, this);
    }

    /**
     * Method to retrieve the last index of an object in the list.
     * @param sm The state manager.
     * @param element The object
     * @return The last index
     */
    public int lastIndexOf(StateManager sm, Object element)
    {
        validateElementForReading(sm, element);
        return getSpecialization().lastIndexOf(sm, element, this);
    }

    /**
     * Remove all elements from a collection from the association owner vs elements.
     * TODO : Change the query to do all in one go for efficiency. Currently
     * removes an element and shuffles the indexes, then removes an element
     * and shuffles the indexes, then removes an element and shuffles the
     * indexes etc ... a bit inefficient !!!
     * @param sm State Manager for the container
     * @param elements Collection of elements to remove
     * @return Whether the database was updated
     */
    public boolean removeAll(StateManager sm, Collection elements, int size)
    {
        if (elements == null || elements.size() == 0)
        {
            return false;
        }

        boolean modified = false;
        if (indexedList)
        {
            // Get the indices of the elements to remove in reverse order (highest first)
            int[] indices = getIndicesOf(sm,elements);

            // Remove each element in turn, doing the shifting of indexes each time
            // TODO : Change this to remove all in one go and then shift once
            for (int i=0;i<indices.length;i++)
            {
                removeAt(sm, indices[i], -1);
                modified = true;
            }
        }
        else
        {
            // Ordered List
            // TODO Remove the list item
            throw new NucleusException("Not yet implemented AbstractListStore.remove for ordered lists");
        }

        if (ownerMemberMetaData.getCollection().isDependentElement())
        {
            // "delete-dependent" : delete elements if the collection is marked as dependent
            // TODO What if the collection contains elements that are not in the List ? should not delete them
            sm.getObjectManager().deleteObjects(elements.toArray());
        }

        return modified;
    }

    /**
     * Method to remove the specified element from the List.
     * @param sm The state manager
     * @param element The element to remove.
     * @param size Current size of list if known. -1 if not known
     * @param allowDependentField Whether to allow any cascade deletes caused by this removal
     * @return Whether it was removed successfully.
     */
    public boolean remove(StateManager sm, Object element, int size, boolean allowDependentField)
    {
        if (!validateElementForReading(sm, element))
        {
            return false;
        }

        Object elementToRemove = element;
        ObjectManager om = sm.getObjectManager();
        if (om.getApiAdapter().isDetached(element))
        {
            // Element passed in is detached so find attached version (DON'T attach this object)
            elementToRemove = om.findObject(om.getApiAdapter().getIdForObject(element), true, false,
                element.getClass().getName());
        }

        boolean modified = internalRemove(sm, elementToRemove, size);

        CollectionMetaData collmd = ownerMemberMetaData.getCollection();
        if (allowDependentField && collmd.isDependentElement() && !collmd.isEmbeddedElement())
        {
            // Delete the element if it is dependent
            sm.getObjectManager().deleteObjectInternal(elementToRemove);
        }

        return modified;
    }

    /**
     * Convenience method to remove the specified element from the List.
     * @param sm StateManager of the owner
     * @param element The element
     * @param size Current size of list if known. -1 if not known
     * @return Whether the List was modified
     */
    protected abstract boolean internalRemove(StateManager sm, Object element, int size);

    /**
     * Method to remove an object at an index in the List.
     * If the list is ordered, will remove the element completely since no index positions exist.
     * @param index The location
     * @param sm The state manager
     * @param size Current size of the list (if known). -1 if not known
     * @return The object that was removed
     */
    public Object remove(StateManager sm, int index, int size)
    {
        Object element = get(sm, index);
        if (indexedList)
        {
            // Remove the element at this position
            removeAt(sm, index, size);
        }
        else
        {
            // Ordered list doesn't allow indexed removal so just remove the element
            internalRemove(sm, element, size);
        }

        CollectionMetaData collmd = ownerMemberMetaData.getCollection();
        if (collmd.isDependentElement() && !collmd.isEmbeddedElement())
        {
            if (!contains(sm, element))
            {
                // Delete the element if it is dependent and doesn't have a duplicate entry in the list
                sm.getObjectManager().deleteObjectInternal(element);
            }
        }

        return element;
    }

    /**
     * Internal method to remove an object at a location from the List.
     * @param sm The state manager
     * @param index The index of the element to remove
     * @param size Current list size (if known). -1 if not known
     */
    protected abstract void removeAt(StateManager sm, int index, int size);

    /**
     * Method to retrieve a list of elements in a range.
     * @param sm The state manager.
     * @param startIdx From index (inclusive).
     * @param endIdx To index (exclusive)
     * @return Sub List of elements in this range.
     */
    public java.util.List subList(StateManager sm, int startIdx, int endIdx)
    {
        ListIterator iter = listIterator(sm, startIdx, endIdx);
        java.util.List list = new ArrayList();
        while (iter.hasNext())
        {
            list.add(iter.next());
        }
        if (!indexedList)
        {
            if (list.size() > (endIdx-startIdx))
            {
                // Iterator hasn't restricted what is returned so do the index range restriction here
                return list.subList(startIdx, endIdx);
            }
        }
        return list;
    }

    /**
     * Utility to find the indices of a collection of elements.
     * The returned list are in reverse order (highest index first).
     * @param sm The state manager.
     * @param elements The elements
     * @return The indices of the elements in the List.
     */
    protected int[] getIndicesOf(StateManager sm, Collection elements)
    {
        if (elements == null || elements.size() == 0)
        {
            return null;
        }

        Iterator iter = elements.iterator();
        while (iter.hasNext())
        {
            validateElementForReading(sm, iter.next());
        }

        return getSpecialization().getIndicesOf(sm, elements, this);
    }
}
TOP

Related Classes of org.datanucleus.store.mapped.scostore.AbstractListStore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.