All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.jdo.spi.persistence.support.sqlstore.sco.HashSet Maven / Gradle / Ivy

There is a newer version: 6.2024.6
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

/*
 * sco.HashSet.java
 */

package com.sun.jdo.spi.persistence.support.sqlstore.sco;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.ResourceBundle;

import com.sun.jdo.api.persistence.support.JDOUserException;
import com.sun.jdo.spi.persistence.support.sqlstore.PersistenceCapable;
import com.sun.jdo.spi.persistence.support.sqlstore.StateManager;
import com.sun.jdo.spi.persistence.support.sqlstore.SCOCollection;
import com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManager;
import org.glassfish.persistence.common.I18NHelper;


/**
 * A mutable 2nd class object date.
 * @author Marina Vatkina
 * @version 1.0
 * @see java.util.HashSet
 */
public class HashSet
    extends java.util.HashSet
    implements SCOCollection
{

    private transient PersistenceCapable owner;

    private transient String fieldName;

    private transient Class elementType;

    private transient boolean allowNulls;

    private transient java.util.HashSet added = new java.util.HashSet();

    private transient java.util.HashSet removed = new java.util.HashSet();

    private transient boolean isDeferred;

    /**
     * I18N message handlers
     */
    private final static ResourceBundle messages = I18NHelper.loadBundle(
                             "com.sun.jdo.spi.persistence.support.sqlstore.impl.Bundle", // NOI18N
                             HashSet.class.getClassLoader());

    private final static ResourceBundle messages1 = I18NHelper.loadBundle(
                             "com.sun.jdo.spi.persistence.support.sqlstore.Bundle", // NOI18N
                             HashSet.class.getClassLoader());


    /**
     * Creates a new empty HashSet object.
     * Assigns owning object and field name.
     *
     * @param owner the owning object
     * @param fieldName the owning field name
     * @param elementType the element types allowed
     * @param allowNulls true if nulls are allowed
     */
    public HashSet(Object owner, String fieldName, Class elementType, boolean allowNulls)
    {
        super();
    if (owner instanceof PersistenceCapable)
        {
                this.owner = (PersistenceCapable)owner;
            this.fieldName = fieldName;
        }
    this.elementType = elementType;
        this.allowNulls = allowNulls;
    }

    /**
     * Creates a new empty HashSet object that has
     * the specified initial capacity.Assigns owning object and field name.
     *
     * @param owner     the owning object
     * @param fieldName the owning field name
     * @param elementType the element types allowed
     * @param allowNulls true if nulls are allowed
     * @param      initialCapacity   the initial capacity of the hash map.
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero.
     * @see java.util.HashSet
     */
    public HashSet(Object owner, String fieldName,
                                Class elementType, boolean allowNulls,
                                int initialCapacity)
    {
    super(initialCapacity);
    if (owner instanceof PersistenceCapable)
        {
                this.owner = (PersistenceCapable)owner;
            this.fieldName = fieldName;
        }
    this.elementType = elementType;
        this.allowNulls = allowNulls;
    }

    // -------------------------Public Methods------------------

    /**
     * Adds the specified element to this set if it is not already
     * present.
     *
     * @param o element to be added to this set.
     * @return true if the set did not already contain the specified
     * element.
     * @see java.util.HashSet
     */
    public boolean add(Object o)
    {
        if (allowNulls == false && o == null)
        {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                        "sco.nulls_not_allowed")); // NOI18N
        }

        if (elementType != null && !elementType.isAssignableFrom(o.getClass()))
        {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                                     "sco.classcastexception", elementType.getName()), // NOI18N
                                       new ClassCastException(), new Object[] {o});
        }

        if (owner != null)
        {
            StateManager stateManager = owner.jdoGetStateManager();

            if (stateManager != null)
            {
                PersistenceManager pm = (PersistenceManager) stateManager.getPersistenceManagerInternal();

                pm.acquireShareLock();

                boolean modified = false;

                try
                {
                    pm.acquireFieldUpdateLock();
                    try
                    {
                       // Mark the field as dirty
                       stateManager.makeDirty(fieldName);

                       modified = super.add(o);

                       if (modified)
                       {
                           if (removed.remove(o) == false)
                           {
                               added.add(o);
                           }
                           stateManager.applyUpdates(fieldName, this);
                       }
                       return modified;
                    }
                    finally
                    {
                        pm.releaseFieldUpdateLock();
                    }

                }
                catch (JDOUserException e)
                {
                    Object[] failedObjects = e.getFailedObjectArray();

                    if (modified && (failedObjects != null))
                    {
                        //
                        // The failedObjects array may contain objects other
                        // than the one added. We iterate through it to find
                        // the one added and remove it from the collection.
                        //
                        for (int i = 0; i < failedObjects.length; i++)
                        {
                            Object failedObject = failedObjects[i];

                            if (failedObject == o)
                            {
                                super.remove(failedObject);
                                break;
                            }
                        }
                    }

                    throw e;
                }
                finally
                {
                    pm.releaseShareLock();
                }
            }
        }

        return super.add(o);
    }

    /**
     * Adds all of the elements in the specified collection to this collection
     *
     * @param c collection whose elements are to be added to this collection.
     * @return true if this collection changed as a result of the
     * call.
     * @throws UnsupportedOperationException if the addAll method is
     *            not supported by this collection.
     *
     * @see java.util.AbstractCollection
     * @see java.util.HashSet
     */
    public boolean addAll(Collection c)
    {
        if (allowNulls == false && c.contains(null))
        {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                        "sco.nulls_not_allowed")); // NOI18N
        }

        ArrayList errc = new ArrayList();

        if (elementType != null)
        {
            // iterate the collection and make a list of wrong elements.
            Iterator i = c.iterator();
            while (i.hasNext())
            {
                Object o = i.next();
                if (!elementType.isAssignableFrom(o.getClass()))
                    errc.add(o);
            }
        }

        if (errc != null && errc.size() > 0)
        {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                                     "sco.classcastexception", elementType.getName()), // NOI18N
                                       new ClassCastException(), errc.toArray());
        }

        boolean modified = false;

        if (owner != null)
        {
            StateManager stateManager = owner.jdoGetStateManager();

            if (stateManager != null)
            {
                PersistenceManager pm = (PersistenceManager) stateManager.getPersistenceManagerInternal();

                pm.acquireShareLock();

                try
                {
                    pm.acquireFieldUpdateLock();
                    try
                    {
                        // Mark the field as dirty
                        stateManager.makeDirty(fieldName);

                        for (Iterator iter = c.iterator(); iter.hasNext();)
                        {
                            Object o = iter.next();
                            if (!super.contains(o))
                            {
                                if (removed.remove(o) == false)
                                {
                                    added.add(o);
                                }

                                super.add(o);
                                modified = true;
                            }
                        }

                        // Apply updates
                        if (modified)
                        {
                            stateManager.applyUpdates(fieldName, this);
                        }
                        return modified;
                    }
                    finally
                    {
                        pm.releaseFieldUpdateLock();
                    }
                }
                catch (JDOUserException e)
                {
                    Object[] failedObjects = e.getFailedObjectArray();

                    if (modified && (failedObjects != null))
                    {
                        for (int i = 0; i < failedObjects.length; i++)
                        {
                            super.remove(failedObjects[i]);
                        }
                    }

                    throw e;
                }
                finally
                {
                    pm.releaseShareLock();
                }
            }
        }

        return super.addAll(c);
    }

    /**
     * Removes the given element from this set if it is present.
     *
     * @param o object to be removed from this set, if present.
     * @return true if the set contained the specified element.
     * @see java.util.HashSet
     */
    public boolean remove(Object o)
    {
    // Mark the field as dirty

        if (owner != null)
        {
            StateManager stateManager = owner.jdoGetStateManager();

            if (stateManager != null)
            {
                PersistenceManager pm = (PersistenceManager) stateManager.getPersistenceManagerInternal();

                pm.acquireShareLock();

                try
                {
                    pm.acquireFieldUpdateLock();
                    try
                    {
                        stateManager.makeDirty(fieldName);

                        boolean modified = super.remove(o);

                        if (modified)
                        {
                            if (added.remove(o) == false)
                            {
                                removed.add(o);
                            }

                            stateManager.applyUpdates(fieldName, this);
                        }

                        return modified;
                    }
                    finally
                    {
                        pm.releaseFieldUpdateLock();
                    }
                }
                finally
                {
                    pm.releaseShareLock();
                }
            }
        }

        return super.remove(o);
    }


    /**
     * Removes from this collection all of its elements that are contained in
     * the specified collection (optional operation). 

* * * @param c elements to be removed from this collection. * @return true if this collection changed as a result of the * call. * * @throws UnsupportedOperationException removeAll is not supported * by this collection. * * @see java.util.HashSet * @see java.util.AbstractCollection */ public boolean removeAll(Collection c) { // Mark the field as dirty if (owner != null) { StateManager stateManager = owner.jdoGetStateManager(); if (stateManager != null) { PersistenceManager pm = (PersistenceManager) stateManager.getPersistenceManagerInternal(); pm.acquireShareLock(); try { pm.acquireFieldUpdateLock(); try { stateManager.makeDirty(fieldName); for (Iterator iter = c.iterator(); iter.hasNext();) { Object o = iter.next(); if (super.contains(o)) { if (added.remove(o) == false) { removed.add(o); } } } boolean modified = super.removeAll(c); // Apply updates if (modified) { stateManager.applyUpdates(fieldName, this); } return modified; } finally { pm.releaseFieldUpdateLock(); } } finally { pm.releaseShareLock(); } } } return super.removeAll(c); } /** * Retains only the elements in this collection that are contained in the * specified collection (optional operation). * * @return true if this collection changed as a result of the * call. * * @throws UnsupportedOperationException if the retainAll method * is not supported by this collection. * * @see java.util.HashSet * @see java.util.AbstractCollection */ public boolean retainAll(Collection c) { if (owner != null) { StateManager stateManager = owner.jdoGetStateManager(); if (stateManager != null) { PersistenceManager pm = (PersistenceManager) stateManager.getPersistenceManagerInternal(); pm.acquireShareLock(); try { pm.acquireFieldUpdateLock(); try { // Mark the field as dirty stateManager.makeDirty(fieldName); for (Iterator iter = super.iterator(); iter.hasNext();) { Object o = iter.next(); if (!c.contains(o)) { if (added.remove(o) == false) { removed.add(o); } } } boolean modified = super.retainAll(c); // Apply updates if (modified) { stateManager.applyUpdates(fieldName, this); } return modified; } finally { pm.releaseFieldUpdateLock(); } } finally { pm.releaseShareLock(); } } } return super.retainAll(c); } /** * Removes all of the elements from this set. * @see java.util.HashSet */ public void clear() { if (owner != null) { StateManager stateManager = owner.jdoGetStateManager(); if (stateManager != null) { PersistenceManager pm = (PersistenceManager) stateManager.getPersistenceManagerInternal(); pm.acquireShareLock(); try { pm.acquireFieldUpdateLock(); try { // Mark the field as dirty stateManager.makeDirty(fieldName); removed.clear(); added.clear(); for (Iterator iter = super.iterator(); iter.hasNext();) { removed.add(iter.next()); } super.clear(); // Apply updates stateManager.applyUpdates(fieldName, this); return; } finally { pm.releaseFieldUpdateLock(); } } finally { pm.releaseShareLock(); } } } super.clear(); } /** * Creates and returns a copy of this object. * *

Mutable Second Class Objects are required to provide a public * clone method in order to allow for copying PersistenceCapable * objects. In contrast to Object.clone(), this method must not throw a * CloneNotSupportedException. */ public Object clone() { HashSet obj = (HashSet) super.clone(); // RESOLVE: check if added/removed should not be cleared // for a deferred collection, but applyDeferredUpdates logic // be used? obj.unsetOwner(); return obj; } /** * Returns an iterator over the elements in this set. The elements * are returned in no particular order. * * @return an Iterator over the elements in this set. * @see java.util.ConcurrentModificationException */ public Iterator iterator() { return new SCOHashIterator(super.iterator(), this); } private class SCOHashIterator implements Iterator { Iterator _iterator = null; HashSet _caller = null; Object lastReturned = null; SCOHashIterator(Iterator it, HashSet cl) { _iterator = it; _caller = cl; } public boolean hasNext() { return _iterator.hasNext(); } public Object next() { lastReturned = _iterator.next(); return lastReturned; } public void remove() { // Check if called twice. if (lastReturned == null) throw new IllegalStateException(); if (_caller.owner != null) { // Mark the field as dirty StateManager stateManager = _caller.owner.jdoGetStateManager(); if (stateManager != null) { PersistenceManager pm = (PersistenceManager) stateManager.getPersistenceManagerInternal(); pm.acquireShareLock(); try { pm.acquireFieldUpdateLock(); try { stateManager.makeDirty(_caller.fieldName); _iterator.remove(); if (added.remove(lastReturned) == false) { removed.add(lastReturned); } stateManager.applyUpdates(_caller.fieldName, _caller); } finally { pm.releaseFieldUpdateLock(); } } finally { pm.releaseShareLock(); } } } else { // No owner - regular HashSet operation. _iterator.remove(); } lastReturned = null; } } // // The following internal methods should be called under an outer lock such // as fieldUpdateLock. There is no need to synchronize them. // /** * Creates and returns a copy of this object without resetting the owner and field value. * */ public Object cloneInternal() { return super.clone(); } /** * Cleans removed and added lists */ public void reset() { // RESOLVE: do we need to synchronize this?? if (added != null) added.clear(); if (removed != null) removed.clear(); } /** * Mark this HashSet as deferred. */ public void markDeferred() { isDeferred = true; } /** * Return true is this HashSet is deferred, false otherwise. */ public boolean isDeferred() { return isDeferred; } /** * If the HashSet is deferred, we first initialize the internal collection * with c and they apply any deferred updates specified by the added and * removed lists. */ public void applyDeferredUpdates(Collection c) { if (!isDeferred) { // should throw an exception?? return; } isDeferred = false; addAllInternal(c); addAllInternal(added); removeAllInternal(removed); added.clear(); removed.clear(); } /** * Adds an object to the list without recording changes if the HashSet is * not deferred. Otherwise, add o to the added list. */ public void addInternal(Object o) { if (isDeferred) { if (removed.remove(o) == false) { added.add(o); } } else { super.add(o); } } /** * Adds a Collection to the list without recording changes if the HashSet is * not deferred. Otherwise, add o to the removed list. */ public void addAllInternal(Collection c) { if (c == null) { return; } Iterator iter = c.iterator(); while (iter.hasNext()) { addInternal(iter.next()); } } /** * @inheritDoc */ public void addToBaseCollection(Object o) { super.add(o); } /* * Remove c from the list if the HashSet is not deferred. * Otherwise, add c to the removed list. */ public void removeAllInternal(Collection c) { if (c == null) { return; } Iterator iter = c.iterator(); while (iter.hasNext()) { removeInternal(iter.next()); } } /** * Returns added collection * * @return added collection of added elements */ public Collection getAdded() { return (Collection)added; } /** * Returns removed collection * * @return removed collection of removed elements */ public Collection getRemoved() { return (Collection)removed; } /** * Clears Collection without notifing the owner */ public void clearInternal() { super.clear(); this.reset(); } /** * Removes an element without notifing the owner */ public void removeInternal(Object o) { if (isDeferred) { if (added.remove(o) == false) { removed.add(o); } } else { super.remove(o); } } /** * Nullifies references to the owner Object and Field */ public void unsetOwner() { this.owner = null; this.fieldName = null; this.elementType = null; added.clear(); removed.clear(); } /** * Returns the owner object of the SCO instance * * @return owner object */ public Object getOwner() { return this.owner; } /** * Returns the field name * * @return field name as java.lang.String */ public String getFieldName() { return this.fieldName; } /** * Marks object dirty */ public StateManager makeDirty() { StateManager stateManager = owner.jdoGetStateManager(); if (stateManager != null) { stateManager.makeDirty(fieldName); } return stateManager; } /** * Apply changes (can be a no-op) */ public void applyUpdates(StateManager sm, boolean modified) { if (modified && sm != null) { sm.applyUpdates(fieldName, this); } } /** * Set the owner if this instance is not owned. * @see SCOCollection#setOwner * @param owner the new owner. * @param fieldName the new field name. * @param elementType the new element type as Class, or null if type * is not checked or not supported. */ public void setOwner(Object owner, String fieldName, Class elementType) { if (this.owner != null) { throw new JDOUserException(I18NHelper.getMessage( messages1, "core.statemanager.anotherowner"), // NOI18N new Object[]{this.owner, this.fieldName}); } if (owner instanceof PersistenceCapable) { this.owner = (PersistenceCapable)owner; this.fieldName = fieldName; this.elementType = elementType; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy