Package org.apache.ojb.broker.util.sequence

Source Code of org.apache.ojb.broker.util.sequence.SequenceManagerHighLowImpl

package org.apache.ojb.broker.util.sequence;

/* Copyright 2002-2004 The Apache Software Foundation
*
* 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.
*/

import org.apache.commons.lang.SystemUtils;
import org.apache.ojb.broker.OptimisticLockException;
import org.apache.ojb.broker.PersistenceBroker;
import org.apache.ojb.broker.PersistenceBrokerFactory;
import org.apache.ojb.broker.metadata.FieldDescriptor;
import org.apache.ojb.broker.query.Criteria;
import org.apache.ojb.broker.query.Query;
import org.apache.ojb.broker.query.QueryByCriteria;
import org.apache.ojb.broker.util.ObjectModificationDefaultImpl;
import org.apache.ojb.broker.util.logging.Logger;
import org.apache.ojb.broker.util.logging.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
* High/Low sequence manager implementation generates unique and continuous
* id's (during runtime) by using sequences to avoid database access.
* <br/>
*
* <p>
* Implementation configuration properties:
* </p>
*
* <table cellspacing="2" cellpadding="2" border="3" frame="box">
* <tr>
*     <td><strong>Property Key</strong></td>
*     <td><strong>Property Values</strong></td>
* </tr>
* <tr>
*     <td>grabSize</td>
*     <td>
*         Integer entry determines the
*         number of IDs allocated within the
*         H/L sequence manager implementation.
*         Default was '20'.
*    </td>
* </tr>
* <tr>
*     <td>globalSequenceId</td>
*     <td>
*         If set 'true' implementation use global unique
*         id's for all fields. Default was 'false'.
*    </td>
* </tr>
* <tr>
*     <td>globalSequenceStart</td>
*     <td>
*         Set the start index of used global id
*         generation (e.g. set 100000, id generation starts with 100001)
*    </td>
* </tr>
* <tr>
*     <td>autoNaming</td>
*     <td>
*          Default was 'true'. If set 'true' OJB try to build a
*          sequence name automatic if none found in field-descriptor
*          and set this generated name as <code>sequence-name</code>
*          in field-descriptor. If set 'false' OJB throws an exception
*          if none sequence name was found in field-descriptor.
*    </td>
* </tr>
* </table>
*
* <br/>
* <p>
* <b>Limitations:</b>
* <ul>
<li>Do NOT use this implementation in managed environment or
* any comparable system where any connection was associated
* with the running transaction.</li>
* </ul>
* </p>
*
*
* <br/>
* <br/>
*
*
* @see org.apache.ojb.broker.util.sequence.SequenceManager
* @see org.apache.ojb.broker.util.sequence.SequenceManagerFactory
* @see org.apache.ojb.broker.util.sequence.SequenceManagerHelper
*
* @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
* @version $Id: SequenceManagerHighLowImpl.java,v 1.29 2004/04/04 23:53:38 brianm Exp $
*/
public class SequenceManagerHighLowImpl extends AbstractSequenceManager
{
    private static Logger log = LoggerFactory.getLogger(SequenceManagerHighLowImpl.class);
    /**
     * sequence name used for global id generation.
     */
    private static final String GLOBAL_SEQUENCE_NAME = "global - default sequence name";
    public static final String PROPERTY_GRAB_SIZE = "grabSize";
    public static final String PROPERTY_GLOBAL_SEQUENCE_ID = "globalSequenceId";
    public static final String PROPERTY_GLOBAL_SEQUENCE_START = "globalSequenceStart";
    private static final String DEPRECATED_COLUMN = "deprecatedColumn";
    private static final String PK_FIELD = "tableName";

    protected static Map sequencesMap = new HashMap();

    protected boolean useGlobalSequenceIdentities;
    protected int grabSize;
    protected long globalSequenceStart;
    protected int attempts;

    public SequenceManagerHighLowImpl(PersistenceBroker broker)
    {
        super(broker);
        grabSize = Integer.parseInt(getConfigurationProperty(PROPERTY_GRAB_SIZE, "20"));
        useGlobalSequenceIdentities =
                Boolean.valueOf(getConfigurationProperty(PROPERTY_GLOBAL_SEQUENCE_ID, "false")).booleanValue();
        globalSequenceStart = Long.parseLong(getConfigurationProperty(PROPERTY_GLOBAL_SEQUENCE_START, "10000"));
    }

    protected long getUniqueLong(FieldDescriptor field) throws SequenceManagerException
    {
        HighLowSequence seq;
        String sequenceName = buildSequenceName(field);
        synchronized (sequencesMap)
        {
            // try to find sequence in map
            seq = (HighLowSequence) sequencesMap.get(sequenceName);

            if (seq == null)
            {
                // not found, get sequence from database or create new
                seq = getSequence(getBrokerForClass(), field, sequenceName);
                sequencesMap.put(sequenceName, seq);
            }

            // now we have a sequence
            long id = seq.getNextId();
            // seq does not have reserved IDs => catch new block of keys
            if (id == 0)
            {
                seq = getSequence(getBrokerForClass(), field, sequenceName);
                // replace old sequence!!
                sequencesMap.put(sequenceName, seq);
                id = seq.getNextId();
                if (id == 0)
                {
                    // something going wrong
                    sequencesMap.remove(sequenceName);
                    throw new SequenceManagerException("Sequence generation failed: " +
                            SystemUtils.LINE_SEPARATOR + "Sequence: " + seq +
                            ". Unable to build new ID, id was always 0." +
                            SystemUtils.LINE_SEPARATOR + "Thread: " + Thread.currentThread() +
                            SystemUtils.LINE_SEPARATOR + "PB: " + getBrokerForClass());
                }
            }
            return id;
        }
    }

    protected HighLowSequence getSequence(PersistenceBroker brokerForSequence,
                                        FieldDescriptor field,
                                        String sequenceNamethrows SequenceManagerException
    {
        HighLowSequence newSequence = null;
        PersistenceBroker internBroker = null;
        try
        {
            /*
            arminw:
            we use a new internBroker instance, because we run into problems
            when current internBroker was rollback, then we have new sequence
            in memory, but not in database and a concurrent thread will
            get the same sequence.
            Thus we use a new internBroker instance (with new connection) to
            avoid this problem.
            */
            internBroker = PersistenceBrokerFactory.createPersistenceBroker(brokerForSequence.getPBKey());
            internBroker.beginTransaction();

            newSequence = lookupStoreSequence(internBroker, field, sequenceName);

            internBroker.commitTransaction();

            if (log.isDebugEnabled()) log.debug("new sequence was " + newSequence);
        }
        catch(Exception e)
        {
            log.error("Can't lookup new HighLowSequence for field "
                    + (field != null ? field.getAttributeName() : null)
                    + " using sequence name " + sequenceName, e);
            if(internBroker != null && internBroker.isInTransaction()) internBroker.abortTransaction();
            throw new SequenceManagerException("Can't build new sequence", e);
        }
        finally
        {
            attempts = 0;
            if (internBroker != null) internBroker.close();
        }
        return newSequence;
    }

    protected HighLowSequence lookupStoreSequence(PersistenceBroker broker, FieldDescriptor field, String seqName)
    {
        HighLowSequence newSequence = null;
        boolean needsInsert = false;

        Criteria c = new Criteria();
        c.addEqualTo(PK_FIELD, seqName);
        Query q = new QueryByCriteria(HighLowSequence.class, c);

        // first we lookup sequence object in database
        newSequence = (HighLowSequence) broker.getObjectByQuery(q);

        //not in db --> we have to store a new sequence
        if (newSequence == null)
        {
            if (log.isDebugEnabled())
            {
                log.debug("sequence for field " + field + " not found in db, store new HighLowSequence");
            }
            /*
            here we lookup the max key for the given field in system
            */
            // !!! here we use current broker instance to avoid deadlock !!!
            long maxKey = getMaxKeyForSequence(getBrokerForClass(), field);

            newSequence = newSequenceObject(seqName, field);
            newSequence.setMaxKey(maxKey);
            needsInsert = true;
        }
        // set current grab size
        newSequence.setGrabSize(grabSize);

        //grab the next key scope
        newSequence.grabNextKeySet();

        //store the sequence to db
        try
        {
            if(needsInsert) broker.store(newSequence, ObjectModificationDefaultImpl.INSERT);
            else broker.store(newSequence, ObjectModificationDefaultImpl.UPDATE);
        }
        catch (OptimisticLockException e)
        {
            // we try five times to get a new sequence
            if(attempts < 5)
            {
                log.info("OptimisticLockException was thrown, will try again to store sequence. Sequence was "+newSequence);
                attempts++;
                newSequence = lookupStoreSequence(broker, field, seqName);
            }
            else throw e;
        }
        return newSequence;
    }

    protected HighLowSequence newSequenceObject(String sequenceName,
                                              FieldDescriptor field)
    {
        HighLowSequence seq = new HighLowSequence();
        seq.setTableName(sequenceName);
        seq.setFieldName(DEPRECATED_COLUMN);
        seq.setGrabSize(grabSize);
        return seq;
    }

    protected long getMaxKeyForSequence(PersistenceBroker broker,
                                        FieldDescriptor field)
    {
        long maxKey = 0;
        if (useGlobalSequenceIdentities)
        {
            maxKey = globalSequenceStart;
        }
        else
        {
            /*
            here we lookup the max key for the given field in system
            */
            maxKey = SequenceManagerHelper.getMaxForExtent(broker, field);
        }
        return maxKey;
    }

    private String buildSequenceName(FieldDescriptor field) throws SequenceManagerException
    {
        String seqName = null;
        if (useGlobalSequenceIdentities)
        {
            seqName = GLOBAL_SEQUENCE_NAME;
        }
        else
        {
            seqName = calculateSequenceName(field);
        }
        return seqName;
    }
}
TOP

Related Classes of org.apache.ojb.broker.util.sequence.SequenceManagerHighLowImpl

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.