/**
* Speedo: an implementation of JDO compliant personality on top of JORM generic
* I/O sub-system.
* Copyright (C) 2001-2004 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
*
* Contact: speedo@objectweb.org
*
* Authors: S.Chassande-Barrioz.
*
*/
package org.objectweb.speedo.sequence.lib;
import org.objectweb.jorm.facility.naming.generator.LongGen;
import org.objectweb.speedo.lib.Personality;
import org.objectweb.speedo.pm.api.POManagerItf;
import org.objectweb.speedo.pm.api.POManagerFactoryItf;
import org.objectweb.speedo.sequence.api.SequenceManager;
import org.objectweb.speedo.sequence.api.SpeedoSequenceItf;
/**
* This class corresponds to the description of the tag sequence
* in the XML file.
* A sequence has :
* - a name
* - a datastore name (not mandatory)
* - a factory class (not mandatory)
* - a strategy
* - a package name
* @author Y.Bersihand
*/
public abstract class SpeedoSequence implements SpeedoSequenceItf {
private static final long serialVersionUID = -1595384241096230234L;
public final static byte NON_TRANSACTIONAL = 1;
public final static byte CONTIGUOUS = 2;
public final static byte TRANSACTIONAL = 3;
public final static String NON_TRANSACTIONAL_STRING = "nontransactional";
public final static String CONTIGUOUS_STRING = "contiguous";
public final static String TRANSACTIONAL_STRING = "transactional";
/**
* The name of the sequence
*/
public String name;
/**
* The name of the sequence in the datastore
* Can be null or ""
*/
public String datastoreName;
/**
* The name of the factory class
* Can be null or ""
*/
public String factoryClass;
/**
* The strategy of the sequence (NON_TRANSACTIONAL | CONTIGUOUS | NON_CONTIGUOUS)
*/
public byte strategy;
/**
* The name of the package in which the sequence has been defined
*/
public String packageName;
public Integer increment = new Integer(1);
public Integer start;
public Integer cache;
//the sequence manager
private SequenceManager sequenceManager = null;
private Personality personality = null;
//the long gen associated to this sequence
private LongGen longGen = null;
//used for the allocate method to avoid I/O
private int countDown = 0;
private long currentId = 0;
public LongGen getLongGen() {
return longGen;
}
public void setLongGen(LongGen longGen) {
this.longGen = longGen;
//set the increment of the longGen
this.longGen.setIncrement(this.increment.intValue());
}
/**
* Transforms a String into a Byte. The String must corresponds to local variables.
* It returns the byte associated with the variable.
* @param s String to transform.
* @return the byte associated to the String.
*/
public static byte strategyToByte(String s) {
if (s.equalsIgnoreCase(TRANSACTIONAL_STRING))
return TRANSACTIONAL;
else if (s.equalsIgnoreCase(CONTIGUOUS_STRING))
return CONTIGUOUS;
else
return NON_TRANSACTIONAL;
}
/**
* Transforms a byte into a String.
* @param b the byte to transform.
* @return the String associated to the byte.
*/
public static String strategyToString(byte b) {
if (b == TRANSACTIONAL)
return TRANSACTIONAL_STRING;
else if (b == CONTIGUOUS)
return CONTIGUOUS_STRING;
else
return NON_TRANSACTIONAL_STRING;
}
public SequenceManager getSequenceManager() {
return sequenceManager;
}
public void setSequenceManager(SequenceManager sequenceManager) {
this.sequenceManager = sequenceManager;
personality = sequenceManager.getPMF().getPersonality();
}
// IMPLEMENTATION OF THE Sequence INTERFACE //
//-------------------------------------------//
/**
* Provides a hint to the implementation that
* the application will need additional sequence
* value objects in short order.
*/
public void allocate(int additional) {
if (longGen != null) {
try {
currentId = longGen.allocateIds(additional) - (additional * increment.intValue());
countDown += additional;
} catch (Exception e) {
return;
}
}
}
/**
* Returns the current sequence value object if it is available.
*/
public Object current() {
if (longGen != null) {
if (countDown == 0) {
try {
return new Long(longGen.current());
} catch (Exception e) {
throw personality.newDataStoreRuntimeException("Problem on current() with sequence " + name
+ ": " + e.getMessage(), e);
}
} else {
return new Long(currentId);
}
}
throw personality.newDataStoreRuntimeException("Problem on current() with sequence " + name
+ ": id generator not ready.");
}
/**
* Returns the fully qualified name of the Sequence.
*/
public String getName() {
return (packageName == null)?(""):(packageName + ".") + name;
}
/**
* Returns the next sequence value object.
*/
public Object next() {
if (longGen != null) {
if (checkStrategy()) {
// if count down is not equal to zero, use the internal counter
if (countDown == 0) {
//else, make a call to the datastore
try {
return new Long(longGen.genId());
} catch (Exception e) {
throw personality.newDataStoreRuntimeException("Problem on next() with sequence " + name
+ ": " + e.getMessage(), e);
}
} else {
long res;
countDown --;
res = currentId;
currentId += increment.intValue();
return new Long(res);
}
}
}
throw personality.newDataStoreRuntimeException("Problem on next() with sequence " + name
+ ": id generator not ready.");
}
public long nextValue() {
return ((Long) next()).longValue();
}
public long currentValue() {
return ((Long) current()).longValue();
}
/**
* @return true if the operation is allowed according to the strategy
* else, false.
*/
private boolean checkStrategy() {
//at the moment, only support for transactional and nontransactional strategy
if (strategy != NON_TRANSACTIONAL) {
//get the pmf
POManagerFactoryItf pmf = sequenceManager.getPMF();
//get the pm
POManagerItf pm = pmf.lookup();
//check that a transaction is active
return (pm != null && pm.getSpeedoTransaction().isActive());
}
return true;
}
}