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

org.apache.ojb.broker.util.sequence.SequenceManagerHighLowImpl Maven / Gradle / Ivy

Go to download

ObJectRelationalBridge (OJB) is an Object/Relational mapping tool that allows transparent persistence for Java Objects against relational databases.

The newest version!
package org.apache.ojb.broker.util.sequence;

/* Copyright 2002-2005 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 java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.SystemUtils;
import org.apache.ojb.broker.Identity;
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.util.ObjectModification;
import org.apache.ojb.broker.util.logging.Logger;
import org.apache.ojb.broker.util.logging.LoggerFactory;

/**
 * High/Low sequence manager implementation generates unique and continuous
 * id's (during runtime) by using sequences to avoid database access.
 * 
* *

* Implementation configuration properties: *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Property KeyProperty Values
seq.start * Set the start index of used sequences (e.g. set 100000, id generation starts with 100001). * Default start index is 1. *
grabSize * Integer entry determines the * number of IDs allocated within the * H/L sequence manager implementation. * Default was '20'. *
autoNaming * 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 sequence-name * in field-descriptor. If set 'false' OJB throws an exception * if none sequence name was found in field-descriptor. *
globalSequenceId * Deprecated! If set 'true' implementation use global unique * id's for all fields. Default was 'false'. *
globalSequenceStart * Deprecated, use property 'seq.start'. Set the start index of used global id * generation (e.g. set 100000, id generation starts with 100001) *
sequenceStart * Deprecated, use property 'seq.start'. Set the start index of used * sequences (e.g. set 100000, id generation starts with 100001). Default start index is 1. *
* *
*

* Limitations: *

    *
  • Do NOT use this implementation in managed environment or * any comparable system where any connection was associated * with the running transaction.
  • *
*

* * *
*
* * * @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 Armin Waibel * @version $Id: SequenceManagerHighLowImpl.java,v 1.1 2007-08-24 22:17:29 ewestfal 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"; protected static Map sequencesDBMap = new HashMap(); protected boolean useGlobalSequenceIdentities; protected int grabSize; protected long sequenceStart; protected int attempts; public SequenceManagerHighLowImpl(PersistenceBroker broker) { super(broker); Long start = SequenceManagerHelper.getSeqStart(getConfigurationProperties()); sequenceStart = start != null ? start.longValue() : 1; grabSize = Integer.parseInt(getConfigurationProperty(PROPERTY_GRAB_SIZE, "20")); useGlobalSequenceIdentities = Boolean.getBoolean(getConfigurationProperty(PROPERTY_GLOBAL_SEQUENCE_ID, "false")); // support for deprecated properties long globalSequenceStart = Long.parseLong(getConfigurationProperty(PROPERTY_GLOBAL_SEQUENCE_START, "1")); if(useGlobalSequenceIdentities && globalSequenceStart > sequenceStart) { sequenceStart = globalSequenceStart; } } protected long getUniqueLong(FieldDescriptor field) throws SequenceManagerException { HighLowSequence seq; String sequenceName = buildSequenceName(field); synchronized (SequenceManagerHighLowImpl.class) { // try to find sequence seq = getSequence(sequenceName); if (seq == null) { // not found, get sequence from database or create new seq = getSequence(getBrokerForClass(), field, sequenceName); addSequence(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!! addSequence(sequenceName, seq); id = seq.getNextId(); if (id == 0) { // something going wrong removeSequence(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; } } /** * Returns last used sequence object or null if no sequence * was add for given sequence name. * * @param sequenceName Name of the sequence. * @return Sequence object or null */ private HighLowSequence getSequence(String sequenceName) { HighLowSequence result = null; // now lookup the sequence map for calling DB Map mapForDB = (Map) sequencesDBMap.get(getBrokerForClass() .serviceConnectionManager().getConnectionDescriptor().getJcdAlias()); if(mapForDB != null) { result = (HighLowSequence) mapForDB.get(sequenceName); } return result; } /** * Put new sequence object for given sequence name. * @param sequenceName Name of the sequence. * @param seq The sequence object to add. */ private void addSequence(String sequenceName, HighLowSequence seq) { // lookup the sequence map for calling DB String jcdAlias = getBrokerForClass() .serviceConnectionManager().getConnectionDescriptor().getJcdAlias(); Map mapForDB = (Map) sequencesDBMap.get(jcdAlias); if(mapForDB == null) { mapForDB = new HashMap(); } mapForDB.put(sequenceName, seq); sequencesDBMap.put(jcdAlias, mapForDB); } /** * Remove the sequence for given sequence name. * * @param sequenceName Name of the sequence to remove. */ protected void removeSequence(String sequenceName) { // lookup the sequence map for calling DB Map mapForDB = (Map) sequencesDBMap.get(getBrokerForClass() .serviceConnectionManager().getConnectionDescriptor().getJcdAlias()); if(mapForDB != null) { synchronized(SequenceManagerHighLowImpl.class) { mapForDB.remove(sequenceName); } } } protected HighLowSequence getSequence(PersistenceBroker brokerForSequence, FieldDescriptor field, String sequenceName) throws 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; boolean needsInsert = false; Identity oid = broker.serviceIdentity().buildIdentity(HighLowSequence.class, seqName); // first we lookup sequence object in database newSequence = (HighLowSequence) broker.getObjectByIdentity(oid); //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; } // maybe property 'sequenceStart' was changed, so we check maxKey against // current set sequence start index if(newSequence.getMaxKey() < sequenceStart) { newSequence.setMaxKey(sequenceStart); } // 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, ObjectModification.INSERT); else broker.store(newSequence, ObjectModification.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.setName(sequenceName); seq.setGrabSize(grabSize); return seq; } protected long getMaxKeyForSequence(PersistenceBroker broker, FieldDescriptor field) { long maxKey; if (useGlobalSequenceIdentities) { maxKey = sequenceStart; } else { /* here we lookup the max key for the given field in system */ maxKey = SequenceManagerHelper.getMaxForExtent(broker, field); // check against start index maxKey = sequenceStart > maxKey ? sequenceStart : maxKey; } return maxKey; } private String buildSequenceName(FieldDescriptor field) throws SequenceManagerException { String seqName; if (useGlobalSequenceIdentities) { seqName = GLOBAL_SEQUENCE_NAME; } else { seqName = calculateSequenceName(field); } return seqName; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy