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

org.babyfish.hibernate.collection.PersistentMANavigableSet Maven / Gradle / Ivy

The newest version!
/*
 * BabyFish, Object Model Framework for Java and JPA.
 * https://github.com/babyfish-ct/babyfish
 *
 * Copyright (c) 2008-2015, Tao Chen
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * Please visit "http://opensource.org/licenses/LGPL-3.0" to know more.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 */
package org.babyfish.hibernate.collection;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;

import org.babyfish.association.AssociatedEndpoint;
import org.babyfish.collection.MANavigableSet;
import org.babyfish.collection.MASet;
import org.babyfish.collection.UnifiedComparator;
import org.babyfish.collection.XCollection;
import org.babyfish.collection.XMap;
import org.babyfish.collection.event.ElementEvent;
import org.babyfish.collection.spi.laziness.AbstractLazyMANavigableSet;
import org.babyfish.collection.spi.laziness.DummyReadingResultRef;
import org.babyfish.collection.spi.laziness.LazyBehaviorProcessor;
import org.babyfish.collection.spi.laziness.QueuedOperationType;
import org.babyfish.collection.spi.wrapper.WrapperAware;
import org.babyfish.hibernate.collection.spi.PersistentCollection;
import org.babyfish.hibernate.collection.spi.persistence.SetBasePersistence;
import org.babyfish.hibernate.model.metadata.HibernateMetadatas;
import org.babyfish.lang.Ref;
import org.babyfish.persistence.model.metadata.JPAAssociationProperty;
import org.babyfish.persistence.model.metadata.LazyBehavior;
import org.babyfish.util.LazyResource;
import org.hibernate.HibernateException;
import org.hibernate.LazyInitializationException;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.type.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Tao Chen
 */
public class PersistentMANavigableSet 
extends AbstractLazyMANavigableSet
implements PersistentCollection, Serializable {

    private static final long serialVersionUID = 7581444734901489840L;
    
    private static final LazyResource LAZY_COMMON_RESOURCE = 
            LazyResource.of(CommonResource.class);

    private static final Logger LOGGER = LoggerFactory.getLogger(PersistentMANavigableSet.class);
    
    private transient AssociatedEndpoint wrapperEndpoint;
    
    public PersistentMANavigableSet(String role, SessionImplementor session, MANavigableSet base) {
        super(null);
        RootData rootData = this.>getRootData();
        SetBasePersistence basePersistence = rootData.basePersistence;
        basePersistence.setSnapshot(null, role, null);
        basePersistence.setCurrentSession(session);
        this.replace(base);
        rootData.setDirectlyAccessible();
    }

    @Override
    protected RootData createRootData() {
        return new RootData();
    }

    @Override
    protected void onModified(ElementEvent e) throws Throwable {
        this.dirty();
    }
    
    protected final AssociatedEndpoint getWrapperEndpoint() {
        return this.wrapperEndpoint;
    }
    
    @SuppressWarnings("unchecked")
    @WrapperAware
    void setWrapper(XCollection wrapper) {
        AssociatedEndpoint oldWrapper = this.wrapperEndpoint;
        if (oldWrapper != wrapper) {
            if (wrapper instanceof AssociatedEndpoint) {
                this.wrapperEndpoint = (AssociatedEndpoint)wrapper; 
            } else {
                this.wrapperEndpoint = null;
            }
        }
    }
    
    @Override
    public E getElement(Object entry) {
        return this.>getRootData().basePersistence.getElement(entry);
    }

    @Override
    public Iterator entries(CollectionPersister persister) {
        return this.>getRootData().basePersistence.entries(persister);
    }

    @Override
    public E readFrom(ResultSet rs, CollectionPersister persister,
            CollectionAliases descriptor, Object owner)
            throws HibernateException, SQLException {
        return this.>getRootData().basePersistence.readFrom(rs, persister, descriptor, owner);
    }

    @Override
    public Iterator getDeletes(CollectionPersister persister,
            boolean indexIsFormula) throws HibernateException {
        return this.>getRootData().basePersistence.getDeletes(persister, indexIsFormula);
    }

    @Override
    public Collection getOrphans(Serializable snapshot, String entityName)
            throws HibernateException {
        return this.>getRootData().basePersistence.getOrphans(snapshot, entityName);
    }

    @Override
    public Iterator queuedAdditionIterator() {
        return this.>getRootData().basePersistence.queuedAdditionIterator();
    }

    @Override
    public Collection getQueuedOrphans(String entityName) {
        return this.>getRootData().basePersistence.getQueuedOrphans(entityName);
    }

    @Override
    public Object getOwner() {
        return this.>getRootData().basePersistence.getOwner();
    }

    @Override
    public void setOwner(Object entity) {
        this.>getRootData().basePersistence.setOwner(entity);
    }

    @Override
    public boolean empty() {
        return this.>getRootData().basePersistence.empty();
    }

    @Override
    public void setSnapshot(Serializable key, String role, Serializable snapshot) {
        this.>getRootData().basePersistence.setSnapshot(key, role, snapshot);
    }

    @Override
    public void postAction() {
        this.>getRootData().basePersistence.postAction();
    }

    @Override
    public Object getValue() {
        return this;
    }

    @Override
    public void beginRead() {
        this.>getRootData().basePersistence.beginRead();
    }

    @Override
    public boolean endRead() {
        return this.>getRootData().basePersistence.endRead();
    }

    @Override
    public boolean afterInitialize() {
        return this.>getRootData().basePersistence.afterInitialize();
    }

    @Override
    public boolean isDirectlyAccessible() {
        return this.>getRootData().basePersistence.isDirectlyAccessible();
    }

    @Override
    public boolean unsetSession(SessionImplementor currentSession) {
        return this.>getRootData().basePersistence.unsetSession(currentSession);
    }

    @Override
    public boolean setCurrentSession(SessionImplementor session)
            throws HibernateException {
        return this.>getRootData().basePersistence.setCurrentSession(session);
    }

    @Override
    public void initializeFromCache(CollectionPersister persister,
            Serializable disassembled, Object owner) throws HibernateException {
        this.>getRootData().basePersistence.initializeFromCache(persister, disassembled, owner);
    }

    @Override
    public Object getIdentifier(Object entry, int i) {
        return this.>getRootData().basePersistence.getIdentifier(entry, i);
    }

    @Override
    public Object getIndex(Object entry, int i, CollectionPersister persister) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Object getSnapshotElement(Object entry, int i) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void beforeInitialize(CollectionPersister persister,
            int anticipatedSize) {
        this.>getRootData().basePersistence.beforeInitialize(persister, anticipatedSize);
    }

    @Override
    public boolean equalsSnapshot(CollectionPersister persister)
            throws HibernateException {
        return this.>getRootData().basePersistence.equalsSnapshot(persister);
    }

    @Override
    public boolean isSnapshotEmpty(Serializable snapshot) {
        return this.>getRootData().basePersistence.isSnapshotEmpty(snapshot);
    }

    @Override
    public Serializable disassemble(CollectionPersister persister)
            throws HibernateException {
        return this.>getRootData().basePersistence.disassemble(persister);
    }

    @Override
    public boolean needsRecreate(CollectionPersister persister) {
        return this.>getRootData().basePersistence.needsRecreate(persister);
    }

    @Override
    public Serializable getSnapshot(CollectionPersister persister)
            throws HibernateException {
        return this.>getRootData().basePersistence.getSnapshot(persister);
    }

    @Override
    public void forceInitialization() throws HibernateException {
        this.>getRootData().basePersistence.forceInitialization();
    }

    @Override
    public boolean entryExists(Object entry, int i) {
        return this.>getRootData().basePersistence.entryExists(entry, i);
    }

    @Override
    public boolean needsInserting(Object entry, int i, Type elemType)
            throws HibernateException {
        return this.>getRootData().basePersistence.needsInserting(entry, i, elemType);
    }

    @Override
    public boolean needsUpdating(Object entry, int i, Type elemType)
            throws HibernateException {
        return this.>getRootData().basePersistence.needsUpdating(entry, i, elemType);
    }

    @Override
    public boolean isRowUpdatePossible() {
        return this.>getRootData().basePersistence.isRowUpdatePossible();
    }

    @Override
    public boolean isWrapper(Object collection) {
        return this.>getRootData().basePersistence.isWrapper(collection);
    }

    @Override
    public boolean wasInitialized() {
        return this.>getRootData().basePersistence.wasInitialized();
    }

    @Override
    public boolean hasQueuedOperations() {
        return this.>getRootData().basePersistence.hasQueuedOperations();
    }

    @Override
    public Serializable getKey() {
        return this.>getRootData().basePersistence.getKey();
    }

    @Override
    public String getRole() {
        return this.>getRootData().basePersistence.getRole();
    }
    
    @Override
    public String getNonNullRole() {
        return this.>getRootData().basePersistence.getNonNullRole();
    }

    @Override
    public boolean isUnreferenced() {
        return this.>getRootData().basePersistence.isUnreferenced();
    }

    @Override
    public boolean isDirty() {
        return this.>getRootData().basePersistence.isDirty();
    }

    @Override
    public void clearDirty() {
        this.>getRootData().basePersistence.clearDirty();
    }

    @Override
    public Serializable getStoredSnapshot() {
        return this.>getRootData().basePersistence.getStoredSnapshot();
    }

    @Override
    public void dirty() {
        this.>getRootData().basePersistence.dirty();
    }

    @Override
    public void preInsert(CollectionPersister persister)
            throws HibernateException {
        this.>getRootData().basePersistence.preInsert(persister);
    }

    @Override
    public void afterRowInsert(CollectionPersister persister, Object entry,
            int i) throws HibernateException {
        this.>getRootData().basePersistence.afterRowInsert(persister, entry, i);
    }
    
    private void writeObject(ObjectOutputStream out) throws IOException {
        this.writeState(out);
    }
    
    private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
        this.readState(in);
    }
    
    protected static class RootData extends AbstractLazyMANavigableSet.RootData {
        
        private static final long serialVersionUID = 2354897796778495334L;

        private boolean loaded;
        
        private SetBasePersistence basePersistence;
        
        private transient boolean loading;
        
        private transient SessionImplementor session;
        
        private transient JPAAssociationProperty jpaAssociationProperty;
        
        private transient boolean directlyAccessible;
        
        public RootData() {
            
        }
        
        protected void onInitialize() {
            this.basePersistence = new SetBasePersistence() {
                
                private static final long serialVersionUID = 8607658837550099941L;

                @Override
                public void forceInitialization() throws HibernateException {
                    RootData.this.load();
                }

                @Override
                protected void setBase(MASet base) {
                    RootData.this.setBase((MANavigableSet)base);
                }

                @Override
                protected MANavigableSet getBase() {
                    return RootData.this.getBase();
                }

                @Override
                protected UnifiedComparator unifiedComparator() {
                    return RootData.this.unifiedComparator();
                }

                @Override
                public boolean hasQueuedOperations() {
                    return RootData.this.hasQueuedOperations();
                }

                @Override
                protected XMap getQueuedOperations() {
                    return RootData.this.getQueuedOperations();
                }

                @Override
                protected void performQueuedOperations() {
                    RootData.this.performQueuedOperations();
                }

                @Override
                protected PersistentCollection onGetWrapperPersistentCollection() {
                    return RootData.this.>getRootWrapper();
                }

                @Override
                public boolean isDirectlyAccessible() {
                    return RootData.this.directlyAccessible;
                }

                @Override
                public boolean wasInitialized() {
                    return RootData.this.loaded;
                }

                @Override
                protected void setInitialized(boolean initialized) {
                    RootData.this.loaded = initialized;
                }

                @Override
                protected void setInitializing(boolean initializing) {
                    RootData.this.loading = initializing;
                }

                @Override
                protected SessionImplementor getSession() {
                    return RootData.this.session;
                }

                @Override
                protected void setSession(SessionImplementor session) {
                    RootData.this.session = session;
                }
            };
        }
        
        public final SetBasePersistence getBasePersistence() {
            return this.basePersistence;
        }
        
        public final JPAAssociationProperty getJPAAssociationProperty() {
            JPAAssociationProperty jpaAssociationProperty = this.jpaAssociationProperty;
            if (jpaAssociationProperty == null) {
                String role = this.basePersistence.getNonNullRole();
                this.jpaAssociationProperty = jpaAssociationProperty = HibernateMetadatas.ofRole(role);
            }
            return jpaAssociationProperty;
        }

        @Override
        public final boolean isLoaded() {
            return this.loaded;
        }

        @Override
        public final boolean isLoading() {
            return this.loading;
        }

        @Override
        public final boolean isLoadable() {
            return this.basePersistence.isConnectedToSession();
        }

        @Override
        protected final void setLoaded(boolean loaded) {
            this.loaded = loaded;
        }

        @Override
        protected final void setLoading(boolean loading) {
            this.loading = loading;
        }

        protected final void setDirectlyAccessible() {
            MANavigableSet base = this.getBase(true);
            if (base != null) {
                this.directlyAccessible = true;
                this.loading = false;
                this.loaded = true;
            }
        }

        @Override
        protected void onLoad() {
            SessionImplementor session = this.session;
            if (session==null) {
                throw new LazyInitializationException(
                        LAZY_COMMON_RESOURCE.get().rootTypeRetainNoSession(this.getClass(), SessionImplementor.class)
                );
            }
            if (!session.isConnected()) {
                throw new LazyInitializationException(
                        LAZY_COMMON_RESOURCE.get().rootTypeRetainDisconnectedSession(this.getClass(), SessionImplementor.class)
                );
            }
            session.initializeCollection(this.>getRootWrapper(), false);
        }
        
        @SuppressWarnings("unchecked")
        @Override
        protected UnifiedComparator getDefaultUnifiedComparator() {
            return this.basePersistence.getRole() == null ?
                    null :
                    (UnifiedComparator)
                    this.getJPAAssociationProperty().getCollectionUnifiedComparator();
        }

        @Override
        protected boolean onGetVisionallyReadable(QueuedOperationType nullOrOperationType) {
            if (nullOrOperationType != null) {
                return this.jpaAssociationProperty.isInverse();
            }
            return super.onGetVisionallyReadable(nullOrOperationType);
        }

        @Override
        protected int onGetVisionalSize() {
            SessionImplementor session = this.session;
            CollectionEntry ce = 
                    session
                    .getPersistenceContext()
                    .getCollectionEntry(this.>getRootWrapper());
            CollectionPersister persister = ce.getLoadedPersister();
            if (!persister.isInverse()) {
                return -1;
            }
            if (session != null && this.hasQueuedOperations()) {
                session.flush();
            }
            return persister.getSize(ce.getLoadedKey(), session);
        }
        
        @Override
        protected Ref onVisionallyRead(E element, QueuedOperationType nullOrQueuedOperationType) {
            if (nullOrQueuedOperationType != null) {
                AssociatedEndpoint endpoint = 
                        this
                        .>getRootWrapper()
                        .getWrapperEndpoint();
                if (endpoint != null) {
                    AssociatedEndpoint oppositeEndpoint = endpoint.getOppositeEndpoint(element);
                    if (oppositeEndpoint.isSuspended()) {
                        LOGGER.info(
                                "The visioanllyRead(" +
                                QueuedOperationType.class.getSimpleName() + 
                                '.' +
                                nullOrQueuedOperationType.name() +
                                ") of the collection whose role is \"" +
                                this.>getRootWrapper().getRole() +
                                "\" return a dummy value immediately without the real data checking " +
                                "because the opposite endpoint wrapper is supspended(" +
                                "the current endpoint is not modified by the programer).");
                        return new DummyReadingResultRef(nullOrQueuedOperationType == QueuedOperationType.ATTACH ? null : element);
                    }
                }
            }
            SessionImplementor session = this.session;
            if (session != null && this.hasQueuedOperations()) {
                session.flush();
            }
            return this.basePersistence.visionallyRead(element);
        }

        @Override
        protected LazyBehaviorProcessor createLazyBehaviorProcessor() {
            LazyBehavior lazyBehavior = this.getJPAAssociationProperty().getLazyBehavior();
            if (lazyBehavior == null) {
                return LazyBehaviorProcessor.of(16, 2);
            }
            return LazyBehaviorProcessor.of(lazyBehavior.rowLimit(), lazyBehavior.countLimit());
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy