Package org.jpox.store.rdbms.scostore

Source Code of org.jpox.store.rdbms.scostore.AbstractSetStore$SetStoreIterator

/**********************************************************************
Copyright (c) 2002 Kelly Grizzle (TJDO) 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:
2002 Mike Martin (TJDO)
2003 Andy Jefferson - coding standards
2003 Andy Jefferson - changed to use Logger
2004 Andy Jefferson - moved statements from subclasses to this class.
2005 Andy Jefferson - added embedded PC element capability
2005 Andy Jefferson - added dependent-element when removed from collection
    ...
**********************************************************************/
package org.jpox.store.rdbms.scostore;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.jpox.ClassLoaderResolver;
import org.jpox.ManagedConnection;
import org.jpox.ObjectManager;
import org.jpox.StateManager;
import org.jpox.Transaction;
import org.jpox.exceptions.JPOXDataStoreException;
import org.jpox.exceptions.JPOXException;
import org.jpox.metadata.CollectionMetaData;
import org.jpox.store.StoreManager;
import org.jpox.store.mapped.expression.QueryExpression;
import org.jpox.store.mapped.mapping.EmbeddedElementPCMapping;
import org.jpox.store.mapped.mapping.ReferenceMapping;
import org.jpox.store.mapped.mapping.SerialisedPCMapping;
import org.jpox.store.mapped.mapping.SerialisedReferenceMapping;
import org.jpox.store.query.ResultObjectFactory;
import org.jpox.store.rdbms.SQLController;
import org.jpox.store.rdbms.table.JoinTable;
import org.jpox.store.scostore.SetStore;
import org.jpox.util.JPOXLogger;

/**
* Abstract representation of the backing store for a Set.
*
* @version $Revision: 1.96 $
**/
abstract class AbstractSetStore extends AbstractCollectionStore implements SetStore
{
    protected String setName;

    /**
     * Constructor.
     * @param storeMgr Manager for the store
     */
    protected AbstractSetStore(StoreManager storeMgr, ClassLoaderResolver clr)
    {
        super(storeMgr, clr);
    }

    /**
     * Accessor for the statement for the iterator.
     * @param ownerSM the owner StateManager
     * @return The iterator Query Statement.
     **/
    protected abstract QueryExpression getIteratorStatement(StateManager ownerSM);

    /**
     * Accessor for an iterator for the set.
     * @param ownerSM State Manager for the set.
     * @return Iterator for the set.
     **/
    public Iterator iterator(StateManager ownerSM)
    {
        // Create the basic statement (without any selected columns)
        QueryExpression stmt = getIteratorStatement(ownerSM);
        if (stmt == null)
        {
            throw new JPOXException(LOCALISER.msg("056005")).setFatal();
        }

        // Add the required field selections to the statement and get a factory for extracting them
        ResultObjectFactory rof = newResultObjectFactory(ownerSM, stmt, false, true);

        ObjectManager om = ownerSM.getObjectManager();
        Transaction tx = om.getTransaction();
        boolean useUpdateLock = ((Boolean)tx.getOptions().get("transaction.serializeReadObjects")).booleanValue();
        String statement = storeMgr.getStatementTextForQuery(stmt, useUpdateLock);

        if (statement == null)
        {
            // this happens when collection is null
            throw new JPOXException(LOCALISER.msg("056005")).setFatal();
        }

        Iterator iter;
        try
        {
            ManagedConnection mconn = storeMgr.getConnection(om);
            SQLController sqlControl = storeMgr.getSQLController();
            try
            {
                PreparedStatement ps = storeMgr.getStatementForQuery(stmt, om, mconn, useUpdateLock, null, null);
                try
                {
                    ResultSet rs = sqlControl.executeStatementQuery(mconn, statement, ps);
                    try
                    {
                        iter = new SetStoreIterator(ownerSM, rs, rof);
                    }
                    finally
                    {
                        rs.close();
                    }
                }
                finally
                {
                    sqlControl.closeStatement(mconn, ps);
                }
            }
            finally
            {
                mconn.release();
            }
        }
        catch (SQLException e)
        {
            throw new JPOXDataStoreException(LOCALISER.msg("056006",statement),e);
        }

        return iter;
    }

    /**
     * Inner class representing an iterator of the Set.
     **/
    private class SetStoreIterator implements Iterator
    {
        private final StateManager sm;
        private final ObjectManager om;
        private final Iterator delegate;
        private Object lastElement = null;

        /**
         * Constructor
         * @param sm the StateManager
         * @param rs the ResultSet
         * @param rof the Query.ResultObjectFactory
         * @throws SQLException
         */
        public SetStoreIterator(StateManager sm, ResultSet rs, ResultObjectFactory rof)
        throws SQLException
        {
            this.sm = sm;
            this.om = sm.getObjectManager();

            ArrayList results = new ArrayList();
            if (rs != null)
            {
                while (rs.next())
                {
                    Object nextElement;
                    if (elementsAreEmbedded || elementsAreSerialised)
                    {
                        int param[] = new int[elementMapping.getNumberOfDatastoreFields()];
                        for (int i = 0; i < param.length; ++i)
                        {
                            param[i] = i + 1;
                        }

                        if (elementMapping instanceof SerialisedPCMapping ||
                            elementMapping instanceof SerialisedReferenceMapping ||
                            elementMapping instanceof EmbeddedElementPCMapping)
                        {
                            // Element = Serialised
                            int ownerFieldNumber = -1;
                            if (containerTable != null)
                            {
                                ownerFieldNumber = ((JoinTable)containerTable).getOwnerFieldMetaData().getAbsoluteFieldNumber();
                            }
                            nextElement = elementMapping.getObject(om, rs, param, sm, ownerFieldNumber);
                        }
                        else
                        {
                            // Element = Non-PC
                            nextElement = elementMapping.getObject(om, rs, param);
                        }
                    }
                    else if (elementMapping instanceof ReferenceMapping)
                    {
                        // Element = Reference (Interface/Object)
                        int param[] = new int[elementMapping.getNumberOfDatastoreFields()];
                        for (int i = 0; i < param.length; ++i)
                        {
                            param[i] = i + 1;
                        }
                        nextElement = elementMapping.getObject(om, rs, param);
                    }
                    else
                    {
                        // Element = PC
                        nextElement = rof.getObject(om, rs);
                    }
                    results.add(nextElement);
                }
            }
            delegate = results.iterator();
        }

        public boolean hasNext()
        {
            return delegate.hasNext();
        }

        public Object next()
        {
            lastElement = delegate.next();

            return lastElement;
        }

        public synchronized void remove()
        {
            if (lastElement == null)
            {
                throw new IllegalStateException("No entry to remove");
            }

            AbstractSetStore.this.remove(sm, lastElement, -1, true);
            delegate.remove();

            lastElement = null;
        }
    }

    /**
     * Adds one element to the association owner vs elements
     * @param sm State Manager for the container
     * @param element The element to add
     * @return Whether it was successful
     */
    public boolean add(StateManager sm, Object element, int size)
    {
        validateElementForWriting(sm, element, null);

        boolean modified = false;
        ObjectManager om = sm.getObjectManager();

        try
        {
            ManagedConnection mconn = storeMgr.getConnection(om);
            try
            {
                int[] num = internalAdd(sm, mconn, false, element, true);
                if (num[0] > 0)
                {
                    modified = true;
                }
            }
            finally
            {
                mconn.release();
            }
        }
        catch (SQLException e)
        {
            JPOXLogger.DATASTORE.error(e);
            String msg = LOCALISER.msg("056009", getAddStmt());
            JPOXLogger.DATASTORE.error(msg);
            throw new JPOXDataStoreException(msg, e);
        }

        return modified;
    }
   
    /**
     * Adds all elements from a collection to the association owner vs elements
     * @param sm State Manager for the container
     * @param elements The elements to add
     * @param size Current size of set (if known). Not used by sets
     * @return Whether it was successful
     */
    public boolean addAll(StateManager sm, Collection elements, int size)
    {
        if (elements == null || elements.size() == 0)
        {
            return false;
        }

        boolean modified = false;
        List exceptions = new ArrayList();
        boolean batched = (elements.size() > 1);

        // Validate all elements for writing
        Iterator iter = elements.iterator();
        while (iter.hasNext())
        {
            validateElementForWriting(sm, iter.next(), null);
        }

        ObjectManager om = sm.getObjectManager();
        ManagedConnection mconn = storeMgr.getConnection(om);
        try
        {
            // Loop through all elements to be added
            iter = elements.iterator();
            Object element = null;
            int[] returnCode = null;
            while (iter.hasNext())
            {
                element = iter.next();

                try
                {
                    returnCode = internalAdd(sm, mconn, batched, element, !batched || (batched && !iter.hasNext()));
                }
                catch (SQLException sqe)
                {
                    exceptions.add(sqe);
                    JPOXLogger.DATASTORE.error(sqe);
                }
            }

            if (exceptions.size() == 0)
            {
                if (returnCode == null)
                {
                    modified = false;
                }
                else
                {
                    for (int i=0;i<returnCode.length;i++)
                    {
                        if (returnCode[i] > 0)
                        {
                            modified = true;
                        }
                    }
                }
            }
        }
        finally
        {
            mconn.release();
        }

        if (!exceptions.isEmpty())
        {
            // Throw all exceptions received as the cause of a JPOXDataStoreException so the user can see which record(s) didn't persist
            String msg = LOCALISER.msg("056009", getAddStmt());
            JPOXLogger.DATASTORE.error(msg);
            throw new JPOXDataStoreException(msg, (Throwable[])exceptions.toArray(new Throwable[exceptions.size()]), sm.getObject());
        }

        return modified;
    }

    /**
     * Method to process an "add" statement.
     * @param ownerSM StateManager for the owner
     * @param conn The connection
     * @param batched Whether we are batching it
     * @param element The element
     * @return Number of datastore records changed (always 0 if batch since nothing yet changed)
     * @throws SQLException Thrown if an error occurs
     */
    protected int[] internalAdd(StateManager ownerSM, ManagedConnection conn, boolean batched, Object element, boolean processNow)
    throws SQLException
    {
        ObjectManager om = ownerSM.getObjectManager();
        SQLController sqlControl = storeMgr.getSQLController();
        String addStmt = getAddStmt();
        PreparedStatement ps = sqlControl.getStatementForUpdate(conn, addStmt, batched);
        try
        {
            int jdbcPosition = 1;
            jdbcPosition = populateOwnerInStatement(ownerSM, om, ps, jdbcPosition);
            jdbcPosition = populateElementInStatement(om, ps, element, jdbcPosition);
            if (relationDiscriminatorMapping != null)
            {
                jdbcPosition = populateRelationDiscriminatorInStatement(om, ps, jdbcPosition);
            }

            // Execute the statement
            return sqlControl.executeStatementUpdate(conn, addStmt, ps, processNow);
        }
        finally
        {
            sqlControl.closeStatement(conn, ps);
        }
    }

    /**
     * Removes the association to one element
     * @param sm State Manager for the container
     * @param element Element to remove
     * @param size Current size
     * @param allowDependentField Whether to allow any cascade deletes caused by this removal
     * @return Whether it was successful
     */
    public boolean remove(StateManager sm, Object element, int size, boolean allowDependentField)
    {
        if (!validateElementForReading(sm, element))
        {
            JPOXLogger.DATASTORE.debug("AbstractSetStore::remove element=" + element + " doesn't exist in this Set.");
            return false;
        }

        boolean modified = false;
        ObjectManager om = sm.getObjectManager();

        String removeStmt = getRemoveStmt();
        try
        {
            ManagedConnection mconn = storeMgr.getConnection(om);
            SQLController sqlControl = storeMgr.getSQLController();
            try
            {
                PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, removeStmt, false);
                try
                {
                    int jdbcPosition = 1;
                    jdbcPosition = populateOwnerInStatement(sm, om, ps, jdbcPosition);
                    jdbcPosition = populateElementInStatement(om, ps, element, jdbcPosition);
                    if (relationDiscriminatorMapping != null)
                    {
                        jdbcPosition = populateRelationDiscriminatorInStatement(om, ps, jdbcPosition);
                    }

                    int[] rowsDeleted = sqlControl.executeStatementUpdate(mconn, removeStmt, ps, true);
                    modified = (rowsDeleted[0] == 1);
                }
                finally
                {
                    sqlControl.closeStatement(mconn, ps);
                }
            }
            finally
            {
                mconn.release();
            }
        }
        catch (SQLException e)
        {
            JPOXLogger.DATASTORE.error(e);
            String msg = LOCALISER.msg("056012",removeStmt);
            JPOXLogger.DATASTORE.error(msg);
            throw new JPOXDataStoreException(msg, e);
        }

        CollectionMetaData collmd = ownerMemberMetaData.getCollection();
        if (allowDependentField && collmd.isDependentElement() && !collmd.isEmbeddedElement())
        {
            // TODO Could this element be stored as a duplicate in this set ?
            // Delete the element if it is dependent
            om.deleteObjectInternal(element);
        }

        return modified;
    }

    /**
     * Remove all elements from a collection from the association owner vs
     * elements. This implementation iterates around the remove() method doing
     * each element 1 at a time. Please refer to the JoinSetStore and
     * FKSetStore for the variations used there. This is used for Map key and value
     * stores.
     * @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;
        List exceptions = new ArrayList();
        boolean batched = (elements.size() > 1);

        // Validate all elements exist
        Iterator iter = elements.iterator();
        while (iter.hasNext())
        {
            Object element = iter.next();
            if (!validateElementForReading(sm, element))
            {
                JPOXLogger.DATASTORE.debug("AbstractSetStore::removeAll element=" + element + " doesn't exist in this Set.");
                return false;
            }
        }

        try
        {
            ObjectManager om = sm.getObjectManager();
            ManagedConnection mconn = storeMgr.getConnection(om);
            try
            {
                Object element = null;
                iter = elements.iterator();
                SQLController sqlControl = storeMgr.getSQLController();
                sqlControl.processStatementsForConnection(mconn); // Process all waiting batched statements before we start our work

                while (iter.hasNext())
                {
                    element = iter.next();
                    try
                    {
                        // Process the remove
                        int[] rc = internalRemove(sm, mconn, batched, element, !batched || (batched && !iter.hasNext()));
                        if (rc != null)
                        {
                            for (int i=0;i<rc.length;i++)
                            {
                                if (rc[i] > 0)
                                {
                                    // At least one record was inserted
                                    modified = true;
                                }
                            }
                        }
                    }
                    catch (SQLException sqe)
                    {
                        sqe.printStackTrace();
                        exceptions.add(sqe);
                        JPOXLogger.DATASTORE.error(sqe);
                    }
                }
            }
            finally
            {
                mconn.release();
            }
        }
        catch (SQLException e)
        {
            e.printStackTrace();
            exceptions.add(e);
            JPOXLogger.DATASTORE.error(e);
        }

        if (!exceptions.isEmpty())
        {
            // Throw all exceptions received as the cause of a JPOXDataStoreException so the user can see which record(s) didn't remove
            String msg = LOCALISER.msg("056012", getRemoveStmt());
            JPOXLogger.DATASTORE.error(msg);
            throw new JPOXDataStoreException(msg, (Throwable[])exceptions.toArray(new Throwable[exceptions.size()]), sm.getObject());
        }

        return modified;
    }

    /**
     * Method to process a "remove" statement.
     * @param ownerSM StateManager for the owner
     * @param conn The connection
     * @param batched Whether we are batching it
     * @param element The element
     * @param executeNow Whether to execute the statement rather than allow batching til later
     * @return Number of records changed (0 if batch since nothing yet changed)
     * @throws SQLException Thrown if an error occurs
     */
    protected int[] internalRemove(StateManager ownerSM, ManagedConnection conn, boolean batched, Object element, boolean executeNow)
    throws SQLException
    {
        ObjectManager om = ownerSM.getObjectManager();
        SQLController sqlControl = storeMgr.getSQLController();
        String removeStmt = getRemoveStmt();
        PreparedStatement ps = sqlControl.getStatementForUpdate(conn, removeStmt, batched);
        try
        {
            int jdbcPosition = 1;
            jdbcPosition = populateOwnerInStatement(ownerSM, om, ps, jdbcPosition);
            jdbcPosition = populateElementInStatement(om, ps, element, jdbcPosition);
            if (relationDiscriminatorMapping != null)
            {
                jdbcPosition = populateRelationDiscriminatorInStatement(om, ps, jdbcPosition);
            }

            // Execute the statement
            return sqlControl.executeStatementUpdate(conn, removeStmt, ps, executeNow);
        }
        finally
        {
            sqlControl.closeStatement(conn, ps);
        }
    }
}
TOP

Related Classes of org.jpox.store.rdbms.scostore.AbstractSetStore$SetStoreIterator

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.