/**
* 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
*/
package org.objectweb.speedo.generation.mivisitor;
import org.objectweb.speedo.api.SpeedoException;
import org.objectweb.speedo.api.SpeedoProperties;
import org.objectweb.speedo.lib.Personality;
import org.objectweb.speedo.metadata.SpeedoClass;
import org.objectweb.speedo.metadata.SpeedoExtension;
import org.objectweb.speedo.metadata.SpeedoField;
import org.objectweb.speedo.metadata.SpeedoIdentity;
import org.objectweb.speedo.metadata.SpeedoPackage;
import org.objectweb.speedo.sequence.jdo.JDOSequence;
import org.objectweb.speedo.sequence.lib.SpeedoSequence;
import org.objectweb.util.monolog.api.BasicLevel;
/**
* This SMI visitor manages the datastore identifier strategy. In particular, it
* converts old extensions (ID, SEQ*) in the right datastore strategy.
* A SpeedoSequence is also created each time the old extension about sequence
* are used. Finally the sequence are registered as meta object to serialized.
*
* @author S.Chassande-Barrioz
* @author Y.Bersihand
*/
public final class DataStoreId
extends AbstractMetaInfoVisitor
implements SpeedoProperties {
public DataStoreId(Personality p) {
super(p);
}
/**
* Register the sequence as serialized meta objects (.jmi file).
*/
public final void visitSequence(final SpeedoSequence ss, SpeedoPackage sp) throws SpeedoException {
sp.xmlDescriptor.mos.add(ss);
super.visitSequence(ss, sp);
}
/**
* Treats the datastore identifier of the class
*/
public final void visitClass(final SpeedoClass sc) throws SpeedoException {
if (sc.identity.isDataStore()) {
translateIDExtension(sc);
treatDataStoreSequence(sc);
treatDataStoreLong(sc);
}
super.visitClass(sc);
}
public void visitField(SpeedoField sf) throws SpeedoException {
super.visitField(sf);
//change identity.strategy to DATASTORE_SEQUENCE
//and assign the sequence to the class as an id
//only if field is pk
if (sf.primaryKey && sf.valueStrategy != null
&& sf.valueStrategy.equals("sequence") && sf.sequence != null) {
sf.moClass.identity.strategy = SpeedoIdentity.DATASTORE_SEQUENCE;
sf.moClass.identity.sequenceName = sf.sequence;
}
}
protected String getLoggerName() {
return super.getLoggerName() + ".datastoreid";
}
/**
* translates the ID extension in a identity strategy
*/
private final void translateIDExtension(final SpeedoClass sc) throws SpeedoException {
final String idExt = sc.getExtensionValueByKey(ID);
if (idExt != null) {
if (ID_LONG.equals(idExt)) {
sc.identity.strategy = SpeedoIdentity.DATASTORE_LONG;
} else if (ID_OLONG.equals(idExt)) {
sc.identity.strategy = SpeedoIdentity.DATASTORE_OLONG;
} else if (ID_SEQUENCE.equals(idExt)) {
sc.identity.strategy = SpeedoIdentity.DATASTORE_SEQUENCE;
} else if (ID_POLYMORPH_2L.equals(idExt)) {
sc.identity.strategy = SpeedoIdentity.DATASTORE_POLYMORPHID;
} else {
logger.log(BasicLevel.WARN, "Extension " + idExt +
" unknown => use the default (class="
+ sc.getFQName() + ").");
}
logger.log(BasicLevel.DEBUG, "Set the strategy "
+ sc.identity.getStrategyName()
+ " to the identity of the class " + sc.getFQName()
+ " from the extension " + ID + "/" + idExt );
}
}
/**
* , and create
* SpeedoSequence for old extention.
* if sequence name specified, set the identity of the class
*/
private final void treatDataStoreSequence(final SpeedoClass sc) throws SpeedoException {
final String seqName = sc.getExtensionValueByKey(SQL_SEQ_NAME);
if (seqName != null) {
logger.log(BasicLevel.DEBUG, "Set the sequence name: " + seqName
+ " to the identity of the class '" + sc.getFQName() + "'.");
sc.identity.setDatastoreIdSequenceName(seqName);
}
if (sc.identity.strategy == SpeedoIdentity.DATASTORE_SEQUENCE) {
if (sc.identity.sequenceName == null
|| sc.moPackage.sequences.get(sc.identity.sequenceName) == null) {
// No sequence name is defined or no SpeedoSequence exists to
// the specified name
createSpeedoSequenceFromExtension(sc);
}
}
}
/**
* Creates a new SpeedoSequence, register it into class's package and
* configures it from old extensions.
* @param sc a class requiring a sequence for the identifier.
*/
private SpeedoSequence createSpeedoSequenceFromExtension(final SpeedoClass sc) {
if (sc.identity.sequenceName == null) {
//compute the name of the sequence
SpeedoExtension se = sc.getExtensionByKey(SQL_SEQ_NAME);
if (se == null) { //no extension for the name of the sequence
if (sc.mainTable != null) {
if (debug) {
logger.log(BasicLevel.DEBUG, "Sequence name computed from the table name.");
}
//use the name of table
sc.identity.sequenceName = sc.mainTable.name + "_SEQ";
} else {
if (debug) {
logger.log(BasicLevel.DEBUG, "Sequence name computed from the class name.");
}
//use the name of class (without package name)
sc.identity.sequenceName = sc.name.toUpperCase() + "_SEQ";
}
} else {
if (debug) {
logger.log(BasicLevel.DEBUG, "Sequence name specified by the extension " + SQL_SEQ_NAME);
}
sc.identity.sequenceName = se.value;
}
}
//Create the sequence and register it
SpeedoSequence seq = new JDOSequence();
seq.name = sc.identity.sequenceName;
seq.packageName = sc.moPackage.name;
sc.moPackage.addSequence(seq);
seq.datastoreName = sc.identity.sequenceName;
seq.strategy = SpeedoSequence.NON_TRANSACTIONAL;
sc.moPackage.xmlDescriptor.mos.add(seq);
if (debug) {
logger.log(BasicLevel.DEBUG, "Create the sequence '" + seq.name
+ "' into the package '" + seq.packageName);
}
//Configure the sequence from the extensions
//increment
String v = sc.getExtensionValueByKey(SQL_SEQ_INC);
if (v != null) {
seq.increment = new Integer(v);
if (debug) {
logger.log(BasicLevel.DEBUG, "\t- Sequence increment: " + seq.increment);
}
}
//start
v = sc.getExtensionValueByKey(SQL_SEQ_START);
if (v != null) {
seq.start = new Integer(v);
if (debug) {
logger.log(BasicLevel.DEBUG, "\t- Sequence start: " + seq.start);
}
}
//cache
v = sc.getExtensionValueByKey(SQL_SEQ_CACHE);
if (v != null) {
seq.cache = new Integer(v);
if (debug) {
logger.log(BasicLevel.DEBUG, "\t- Sequence cache: " + seq.cache);
}
}
//allocator
v = sc.getExtensionValueByKey(SQL_SEQ_ALLOCATOR);
if (v != null) {
seq.factoryClass = v;
if (debug) {
logger.log(BasicLevel.DEBUG, "\t- Sequence allocator: " + seq.factoryClass);
}
}
return seq;
}
/**
* If strategy is the default one (SpeedoIdentity.DATASTORE_NATIVE) then we
* have to check the type of field (if there is one). Maybe it is a
* java.lang.Long instead of a long. In this case the strategy is
* SpeedoIdentity.DATASTORE_OLONG.
*/
private final void treatDataStoreLong(final SpeedoClass sc) throws SpeedoException {
if (sc.identity.strategy == SpeedoIdentity.DATASTORE_NATIVE) {
SpeedoField sf = sc.getUniquePKField();
if (sf != null && "Ljava/lang/Long;".equals(sf.type)) {
sc.identity.strategy = SpeedoIdentity.DATASTORE_OLONG;
}
}
}
}