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

org.datanucleus.state.ReferentialStateManagerImpl Maven / Gradle / Ivy

Go to download

DataNucleus Core provides the primary components of a heterogenous Java persistence solution. It supports persistence API's being layered on top of the core functionality.

There is a newer version: 6.0.9
Show newest version
/**********************************************************************
Copyright (c) 2013 Andy Jefferson 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:
    ...
 **********************************************************************/
package org.datanucleus.state;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.datanucleus.ExecutionContext;
import org.datanucleus.identity.IdentityUtils;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.util.ClassUtils;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;
import org.datanucleus.util.StringUtils;

/**
 * Implementation of a StateManager for use where insertion ordering is important (such as RDBMS).
 * Adds on simple handling to be run after an object is inserted.
 */
public class ReferentialStateManagerImpl extends StateManagerImpl
{
    /** List of StateManagers that we must notify when we have completed inserting our record. */
    private List insertionNotifyList = null;

    /** Fields of this object that we must update when notified of the insertion of the related objects. */
    private Map fieldsToBeUpdatedAfterObjectInsertion = null;

    /**
     * Constructor for object of specified type managed by the provided ExecutionContext.
     * @param ec ExecutionContext
     * @param cmd the metadata for the class.
     */
    public ReferentialStateManagerImpl(ExecutionContext ec, AbstractClassMetaData cmd)
    {
        super(ec, cmd);
    }

    @Override
    public void connect(ExecutionContext ec, AbstractClassMetaData cmd)
    {
        super.connect(ec, cmd);
        fieldsToBeUpdatedAfterObjectInsertion = null;
        insertionNotifyList = null;
    }

    @Override
    public void disconnect()
    {
        this.fieldsToBeUpdatedAfterObjectInsertion = null;
        this.insertionNotifyList = null;
        super.disconnect();
    }

    /**
     * Override the superclass that simply sets the INSERTING_CALLBACKS flag, and call insertion notify list.
     */
    @Override
    public void setInsertingCallbacks()
    {
        super.setInsertingCallbacks();
        if (insertionNotifyList != null)
        {
            // Full insertion has just completed so notify all interested parties
            synchronized (insertionNotifyList)
            {
                Iterator notifyIter = insertionNotifyList.iterator();
                while (notifyIter.hasNext())
                {
                    ReferentialStateManagerImpl notifySM = notifyIter.next();
                    notifySM.insertionCompleted(this);
                }
            }
            insertionNotifyList.clear();
            insertionNotifyList = null;
        }
    }

    /**
     * Marks the given field as being required to be updated when the specified object has been inserted.
     * @param pc The Persistable object
     * @param fieldNumber Number of the field.
     */
    @Override
    public void updateFieldAfterInsert(Object pc, int fieldNumber)
    {
        ReferentialStateManagerImpl otherSM = (ReferentialStateManagerImpl) myEC.findStateManager(pc);

        // Register the other SM to update us when it is inserted
        if (otherSM.insertionNotifyList == null)
        {
            otherSM.insertionNotifyList = Collections.synchronizedList(new ArrayList<>(1));
        }
        otherSM.insertionNotifyList.add(this);

        // Register that we should update this field when the other SM informs us
        if (fieldsToBeUpdatedAfterObjectInsertion == null)
        {
            fieldsToBeUpdatedAfterObjectInsertion = new HashMap<>(1);
        }
        FieldContainer cont = fieldsToBeUpdatedAfterObjectInsertion.get(otherSM);
        if (cont == null)
        {
            cont = new FieldContainer(fieldNumber);
        }
        else
        {
            cont.set(fieldNumber);
        }
        fieldsToBeUpdatedAfterObjectInsertion.put(otherSM, cont);

        if (NucleusLogger.PERSISTENCE.isDebugEnabled())
        {
            NucleusLogger.PERSISTENCE.debug(Localiser.msg("026021", 
                cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber).getFullFieldName(), 
                StringUtils.toJVMIDString(myPC), StringUtils.toJVMIDString(pc)));
        }
    }

    /**
     * Method called by another StateManager when this object has registered that it needs to know
     * when the other object has been inserted.
     * @param op StateManager of the other object that has just been inserted
     */
    void insertionCompleted(ReferentialStateManagerImpl op)
    {
        if (fieldsToBeUpdatedAfterObjectInsertion == null)
        {
            return;
        }

        // Go through our insertion update list and mark all required fields as dirty
        FieldContainer fldCont = fieldsToBeUpdatedAfterObjectInsertion.get(op);
        if (fldCont != null)
        {
            dirty = true;
            int[] fieldsToUpdate = fldCont.getFields();
            for (int i=0;i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy