/**
* 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.naming.lib;
import org.objectweb.asm.Type;
import org.objectweb.jorm.api.PException;
import org.objectweb.jorm.facility.naming.basidir.BasidBinder;
import org.objectweb.jorm.facility.naming.basidir.BasidName;
import org.objectweb.jorm.metainfo.api.Class;
import org.objectweb.jorm.metainfo.api.ClassMapping;
import org.objectweb.jorm.metainfo.api.ClassRef;
import org.objectweb.jorm.metainfo.api.GenClassMapping;
import org.objectweb.jorm.metainfo.api.GenClassRef;
import org.objectweb.jorm.metainfo.api.CommonClassMapping;
import org.objectweb.jorm.metainfo.api.Manager;
import org.objectweb.jorm.metainfo.api.MetaObject;
import org.objectweb.jorm.metainfo.api.NameDef;
import org.objectweb.jorm.metainfo.api.Reference;
import org.objectweb.jorm.metainfo.api.TypedElement;
import org.objectweb.jorm.naming.api.PBinder;
import org.objectweb.jorm.naming.api.PExceptionNaming;
import org.objectweb.jorm.naming.api.PName;
import org.objectweb.jorm.naming.api.PNameCoder;
import org.objectweb.jorm.naming.lib.CTHelper;
import org.objectweb.jorm.type.api.PType;
import org.objectweb.speedo.api.SpeedoException;
import org.objectweb.speedo.api.SpeedoProperties;
import org.objectweb.speedo.generation.enhancer.pc.POVariableNames;
import org.objectweb.speedo.generation.jorm.JormMIMappingBuilder;
import org.objectweb.speedo.generation.lib.NamingRules;
import org.objectweb.speedo.mapper.api.JormFactory;
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.naming.api.MIBuilderHelper;
import org.objectweb.speedo.naming.api.NamingManager;
import org.objectweb.util.monolog.api.BasicLevel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* Is a manager of identifier naming compised of a single visible field.
*
* @author S.Chassande-Barrioz
*/
public class UserIdSingleNamingManager
extends NamingManagerHelper
implements NamingManager {
private final static String SINGLE_USER_ID = "suid";
private int getCodingType(String fn, MetaObject mo) {
TypedElement te = null;
if (mo instanceof Class) {
te = ((Class) mo).getTypedElement(fn);
} else if (mo instanceof GenClassRef) {
te = ((GenClassRef) mo).getHiddenField(fn);
} else {
return -1;
}
return CTHelper.ptc2ct(te.getType().getTypeCode());
}
protected String getName() {
return SINGLE_USER_ID;
}
// IMPLEMENTATION OF THE METHOD FROM THE NamingManager INTERFACE //
//---------------------------------------------------------------//
public Object encode(PName pn) throws PException {
if (pn instanceof BasidName) {
return pn.getPNameManager().getPType().getJormName()
+ SEP + pn.encodeString();
}
return null;
}
public PName decode(PNameCoder pnc,
Object oid,
java.lang.Class clazz,
JormFactory jf) throws PException {
if (oid instanceof String) {
String stroid = (String) oid;
int idx = stroid.indexOf(SEP);
if (pnc != null) {
if (pnc.codingSupported(PNameCoder.CTCOMPOSITE)) {
//The pnc is not a BasidBinder, then the oid cannot be managed
return null;
}
if (idx != -1) {
//The oid contains the class name
return pnc.decodeString(stroid.substring(idx + SEP.length()));
} else {
//The oid must decoded directly
return pnc.decodeString(stroid);
}
}
//No pnc specified
if (idx == -1) {
//The oid cannot be managed
return null;
}
//The oid contains the class name
String fqcn = stroid.substring(0, idx);
ClassLoader cl = jf.getClass().getClassLoader();
if (cl == null) {
cl = ClassLoader.getSystemClassLoader();
}
try {
pnc = jf.getPNamingContext(fqcn, cl);
} catch (Exception e) {
return null;
}
if (pnc == null
|| pnc.codingSupported(PNameCoder.CTCOMPOSITE)) {
return null;
}
return pnc.decodeString(stroid.substring(idx + SEP.length()));
} else if (pnc instanceof BasidBinder) {
switch (((BasidBinder) pnc).getCodingType()) {
case PNameCoder.CTCHAR:
return pnc.decodeChar(((Character) oid).charValue());
case PNameCoder.CTBYTE:
return pnc.decodeByte(((Byte) oid).byteValue());
case PNameCoder.CTSHORT:
return pnc.decodeShort(((Short) oid).shortValue());
case PNameCoder.CTINT:
return pnc.decodeInt(((Integer) oid).intValue());
case PNameCoder.CTLONG:
return pnc.decodeLong(((Long) oid).longValue());
case PNameCoder.CTOCHAR:
return pnc.decodeOchar((Character) oid);
case PNameCoder.CTOBYTE:
return pnc.decodeObyte((Byte) oid);
case PNameCoder.CTOSHORT:
return pnc.decodeOshort((Short) oid);
case PNameCoder.CTOINT:
return pnc.decodeOint((Integer) oid);
case PNameCoder.CTOLONG:
return pnc.decodeOlong((Long) oid);
case PNameCoder.CTSTRING:
return pnc.decodeString((String) oid);
case PNameCoder.CTDATE:
return pnc.decodeDate((Date) oid);
case PNameCoder.CTCHARARRAY:
return pnc.decodeCharArray((char[]) oid);
case PNameCoder.CTBYTEARRAY:
return pnc.decode((byte[]) oid);
default:
throw new PExceptionNaming("Unmanaged coding type: "
+ ((BasidBinder) pnc).getCodingType());
}
} else {
//oid
return null;
}
}
public boolean canManage(SpeedoClass sc) {
if (sc.identity.strategy == SpeedoIdentity.USER_ID) {
String objectidClass = sc.identity.objectidClass;
if (sc.generateObjectId()) {
objectidClass = NamingRules.generatedObjectIdName(sc.getFQName());
}
return objectidClass == null || objectidClass.length() == 0;
}
return false;
}
public boolean canProvidePBinder(Object hints, ClassLoader classLoader) {
if(!super.canProvidePBinder(hints, classLoader)) {
return false;
}
String ctStr = getBinderClassNameFromHints(hints, SINGLE_USER_ID);
if (ctStr == null) {
return false;
}
try {
Short.parseShort(ctStr);
return true;
} catch (NumberFormatException e) {
return false;
}
}
public boolean canProvidePNamingContext(Object hints, ClassLoader classLoader) {
return getPNCClassNameFromHints(hints, SINGLE_USER_ID) != null;
}
public PBinder getPBinder(String className, String hints, ClassLoader cl, byte mappingStructureRule, Map cn2binder, Map cn2pnc) {
String ctStr = getBinderClassNameFromHints(hints, SINGLE_USER_ID);
return new BasidBinder(Short.parseShort(ctStr));
}
/**
* sud,coding type, pnc class name, class name
*/
public void getJormNamingConfig(NameDef nd,
SpeedoClass targetClass,
MetaObject sourceMO,
String key,
Properties result) throws SpeedoException {
StringBuffer sb = new StringBuffer();
sb.append(SINGLE_USER_ID);
sb.append(HINTS_SEP);
int ct = getCodingType(nd.getFieldName(), sourceMO);
sb.append(ct);
sb.append(HINTS_SEP);
String className = targetClass.getFQName();
SpeedoClass ancestor = targetClass.getAncestor();
if (sourceMO instanceof GenClassRef //For a Genclass ref or identifier
|| (ancestor == null //No inheritance
&& targetClass.jormclass.getSubClasses().isEmpty())) {
sb.append(ct);
} else {
if (ancestor == null) {
ancestor = targetClass;
}
try {
if (targetClass.jormclass.getSubClasses().isEmpty()) {
sb.append(ct);
} else if (targetClass.jormclass.detectFilterElementNotInPK(targetClass.jormclass.getInheritanceFilter(nd), nd)) {
//if has child(ren)
//and one of the fields of the filter is not in the primary key,
//use a PolymorphicPNC
sb.append(POLYMORPHIC_PNC);
} else {
//use a kfpnc
sb.append(NamingRules.kfpncName(ancestor.getFQName()));
}
} catch (Exception e) {
logger.log(BasicLevel.ERROR, "Error while retrieving the inheritance filter of the namedef:" + nd.toString());
throw new SpeedoException("Error while retrieving the inheritance filter of the namedef:" + nd.toString(), e);
}
className = ancestor.getFQName();
}
sb.append(HINTS_SEP);
sb.append(className);
result.setProperty(key, sb.toString());
}
public Object[] getPNameHints2(SpeedoClass sc, NameDef nd) {
String fn = nd.getFieldName();
return new Object[]{PNH_PFIELD, fn, sc.jormclass.getTypedElement(fn).getType()};
}
public String getPNameHints(SpeedoClass sc, NameDef nd) {
String fn = nd.getFieldName();
//provide the field value as Object format
int tc = sc.jormclass.getTypedElement(fn).getType().getTypeCode();
fn = POVariableNames.REFSTATE_FIELD_NAME + "." + fn;
switch (tc) {
case PType.TYPECODE_CHAR:
return "new Character(" + fn + ")";
case PType.TYPECODE_BYTE:
return "new Byte(" + fn + ")";
case PType.TYPECODE_SHORT:
return "new Short(" + fn + ")";
case PType.TYPECODE_INT:
return "new Integer(" + fn + ")";
case PType.TYPECODE_LONG:
return "new Long(" + fn + ")";
default:
return fn;
}
}
public String getGCPNameHints(SpeedoClass sc, NameDef nd) {
return "speedoPO.getPName()";
}
public void defineClassIdentifierNameDef(NameDef nd,
Class jc,
SpeedoClass sc,
ClassMapping cm,
MIBuilderHelper mibh,
JormMIMappingBuilder mb,
Collection createdMOs) throws SpeedoException, PException {
SpeedoClass clazz = sc.getAncestor();
if (clazz == null) {
clazz = sc;
}
SpeedoField pkField = clazz.getUniquePKField();
nd.setFieldName(pkField.name);
}
public boolean needInheritanceDiscriminator(SpeedoClass sc)
throws SpeedoException {
return true;
}
/**
* This internal method defines a NameDef based on on the PK fields of the
* Referenced class. This method manages ClassRef owned by a class or by
* a generic class. But this method does not mapped the fields (ex:
* no rdb mapping)
* @param nd is the namedef to fill
* @param cr is the JORM meta object representing the reference. This
* ClassRef can be owned by a Class or a GenClassRef.
* @param sf is the Speedo MetaObject representing the persistent field
* linked to this ClassRef. If the owner of the ClassRef is a simple class
* then this parameter represents the classRef too. If the owner of the
* ClassRef is a generic class, then this parameter represents the reference
* to the generic class (Collection, Map, ...).
* @param mibh is a helper for the management of the JORM meta info
* @param prefix is a prefix for the name of the field composing the
* identifier
*/
private void defineClassReferenceNamedDef(NameDef nd,
SpeedoField sf,
ClassRef cr,
MIBuilderHelper mibh,
String prefix) throws SpeedoException, PException {
SpeedoClass referencedClass = sf.moClass.getSpeedoClassFromContext(cr.getMOClass().getFQName());
SpeedoField pkField = (SpeedoField) referencedClass.getUniquePKField();
String fn = prefix + pkField.name;
int size = PType.NOSIZE;
int scale = PType.NOSIZE;
if (pkField.columns != null && pkField.columns.length == 1) {
if (pkField.columns[0].length != -1) {
size = pkField.columns[0].length;
}
if (pkField.columns[0].scale != -1) {
scale = pkField.columns[0].scale;
}
}
PType type = mibh.getPrimitivePType(Type.getType(pkField.type));
mibh.createNameDefField(cr.getParent(), fn, type, size, scale);
nd.setFieldName(fn);
}
public void defineClassReferenceNameDef(NameDef nd,
ClassRef cr,
SpeedoField sf,
SpeedoClass currentClass,
ClassMapping cm,
MIBuilderHelper mibh,
JormMIMappingBuilder mb) throws SpeedoException, PException {
String prefix = mibh.getNameDefFieldPrefix(cr, false, false, sf);
defineClassReferenceNamedDef(nd, sf, cr, mibh, prefix);
mb.createClassRefNameDefMapping(cm, nd, sf);
}
public void defineClassReferenceNameDef(NameDef nd,
ClassRef cr,
SpeedoField sf,
SpeedoClass currentClass,
GenClassMapping gcm,
MIBuilderHelper mibh,
JormMIMappingBuilder mb) throws SpeedoException, PException {
String prefix = mibh.getNameDefFieldPrefix(cr, false, false, sf);
defineClassReferenceNamedDef(nd, sf, cr, mibh, prefix);
mb.createClassRefNameDefMapping(gcm, nd, sf);
}
private void defineGenClassNameDef(NameDef nd,
GenClassRef gcr,
SpeedoField sf,
MIBuilderHelper mibh,
boolean isGCId) throws SpeedoException, PException {
SpeedoField pkField = sf.moClass.getUniquePKField();
String prefix = mibh.getNameDefFieldPrefix(gcr, isGCId, isGCId, sf);
String fn = prefix + pkField.name;
if (isGCId) {
int size = PType.NOSIZE;
int scale = PType.NOSIZE;
if (pkField.columns != null && pkField.columns.length == 1) {
if (pkField.columns[0].length != -1) {
size = pkField.columns[0].length;
}
if (pkField.columns[0].scale != -1) {
scale = pkField.columns[0].scale;
}
}
PType type = mibh.getPrimitivePType(Type.getType(pkField.type));
mibh.createNameDefField(gcr, fn, type, size, scale);
}
nd.setFieldName(fn);
}
public void defineGenClassIdentifierNameDef(NameDef nd,
GenClassRef gcr,
SpeedoField sf,
SpeedoClass currentClass,
GenClassMapping gcm,
MIBuilderHelper mibh,
JormMIMappingBuilder mb)throws SpeedoException, PException {
defineGenClassNameDef(nd, gcr, sf, mibh, true);
mb.createGenClassIdentifierNameDefMapping(gcm, nd, sf, mibh);
}
public void defineGenClassReferenceNameDef(NameDef nd,
GenClassRef gcr,
SpeedoField sf,
SpeedoClass currentClass,
ClassMapping cm,
MIBuilderHelper mibh,
JormMIMappingBuilder mb) throws SpeedoException, PException {
defineGenClassNameDef(nd, gcr, sf, mibh, false);
}
}