/**
* 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.mapper.lib;
import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.fractal.api.control.IllegalLifeCycleException;
import org.objectweb.fractal.api.control.LifeCycleController;
import org.objectweb.jorm.api.PClassMapping;
import org.objectweb.jorm.api.PClassMappingCtrl;
import org.objectweb.jorm.api.PException;
import org.objectweb.jorm.api.PMapCluster;
import org.objectweb.jorm.api.PMapper;
import org.objectweb.jorm.lib.JormPathHelper;
import org.objectweb.jorm.metainfo.api.Package;
import org.objectweb.jorm.metainfo.lib.BasicClass;
import org.objectweb.jorm.metainfo.lib.BasicCompositeName;
import org.objectweb.jorm.metainfo.lib.JormManager;
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.api.PNameManager;
import org.objectweb.jorm.naming.api.PNamingContext;
import org.objectweb.jorm.naming.lib.KFPNCManager;
import org.objectweb.jorm.type.api.PType;
import org.objectweb.perseus.cache.api.CacheManager;
import org.objectweb.perseus.persistence.api.ConnectionHolder;
import org.objectweb.perseus.persistence.api.TransactionalPersistenceManager;
import org.objectweb.speedo.api.SpeedoRuntimeException;
import org.objectweb.speedo.genclass.AbstractGenClassHome;
import org.objectweb.speedo.generation.lib.NamingRules;
import org.objectweb.speedo.lib.Personality;
import org.objectweb.speedo.mapper.api.JormFactory;
import org.objectweb.speedo.mapper.api.JormFactoryAttributes;
import org.objectweb.speedo.metadata.SpeedoIndex;
import org.objectweb.speedo.mim.api.HomeItf;
import org.objectweb.speedo.naming.api.NamingManager;
import org.objectweb.speedo.naming.api.NamingManagerFactoryItf;
import org.objectweb.speedo.naming.lib.NamingManagerHelper;
import org.objectweb.speedo.pm.api.POManagerFactoryItf;
import org.objectweb.speedo.sequence.api.SpeedoSequenceItf;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.LoggerFactory;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* This class manages the initialization and the naming, of persistent class.
* The type of naming supported depends on the NamingManager registered into
* the NamingManagerFactory
*
* @see org.objectweb.speedo.naming.api.NamingManager
* @author S.Chassande-Barrioz
*/
public class BasicJormFactory
implements JormFactory,
PNameCoder,
BindingController,
LifeCycleController,
JormFactoryAttributes {
/**
* fractal binding name to the mapper
*/
public final static String MAPPER_BINDING = "mapper";
/**
* fractal binding name to the cache manager
*/
public final static String CACHE_MANAGER_BINDING = "cache-manager";
public final static String TPM_BINDING = "transactional-persistence-manager";
public final static String PMF_BINDING = "po-manager-factory";
public final static String NMF_BINDING = "naming-manager-factory";
protected TransactionalPersistenceManager tpm;
protected POManagerFactoryItf pmf;
/**
* The mapper is used to map and find the Jorm classes.
*/
protected PMapper mapper = null;
/**
* The cache to assign to the binders
*/
protected CacheManager cache = null;
/**
* key = String class name
* value = PBinder binder of the class
*/
protected Map binders = null;
/**
* key = String class name
* value = PNamingContext pnc of the class
*/
protected Map pnamingContexts = null;
/**
* temporaly variable use in the recursive algorithm
*/
protected Map cn2pcm = null;
/**
* The manager of NamingManager available.
*/
private NamingManagerFactoryItf nmf;
/**
* The rule concerning the data structure (jorm property of the mapper)
*/
private byte mappingStructuresRule = JormFactoryAttributes.CREATE_IF_REQUIRED;
protected Logger logger = null;
private KFPNCManager kfpncManager;
ClassPropertiesManager cpm;
Personality personality;
/**
* builds the BasicJormFactory
* and the hosting structure for the binder list.
*/
public BasicJormFactory() {
pnamingContexts = new HashMap();
binders = new HashMap();
cn2pcm = new HashMap();
kfpncManager = new KFPNCManager(pnamingContexts);
cpm = new ClassPropertiesManager();
}
// IMPLEMENTATION OF THE JormFactoryAttributes INTERFACE //
//-------------------------------------------------------//
public byte getMappingStructureRule() {
return mappingStructuresRule;
}
public void setMappingStructureRule(byte rule) {
mappingStructuresRule = rule;
}
public Personality getPersonality() {
return personality;
}
public void setPersonality(Personality p) {
this.personality = p;
}
// IMPLEMENTATION OF THE UserBindingController INTERFACE //
//-------------------------------------------------------//
public String[] listFc() {
return new String[]{
MAPPER_BINDING,
CACHE_MANAGER_BINDING,
TPM_BINDING,
PMF_BINDING,
NMF_BINDING
};
}
public Object lookupFc(String s) {
if (MAPPER_BINDING.equals(s))
return mapper;
else if (CACHE_MANAGER_BINDING.equals(s))
return cache;
else if (TPM_BINDING.equals(s))
return tpm;
else if (PMF_BINDING.equals(s))
return pmf;
else if (NMF_BINDING.equals(s))
return nmf;
else
return null;
}
public void bindFc(String s, Object o) {
if ("logger".equals(s)) {
logger = (Logger) o;
} else if ("monolog-factory".equals(s)) {
LoggerFactory lf = (LoggerFactory) o;
kfpncManager.setLogger(lf.getLogger(logger.getName() + ".kfpncmanager"));
cpm.logger = lf.getLogger(logger.getName() + ".class-properties");
} else if (MAPPER_BINDING.equals(s)) {
mapper = (PMapper) o;
cpm.mapper = mapper;
} else if (CACHE_MANAGER_BINDING.equals(s)) {
cache = (CacheManager) o;
} else if (TPM_BINDING.equals(s)) {
tpm = (TransactionalPersistenceManager) o;
} else if (PMF_BINDING.equals(s)) {
pmf = (POManagerFactoryItf) o;
} else if (NMF_BINDING.equals(s)) {
nmf = (NamingManagerFactoryItf) o;
}
}
public void unbindFc(String s) {
if (MAPPER_BINDING.equals(s)) {
mapper = null;
} else if (CACHE_MANAGER_BINDING.equals(s)) {
cache = null;
} else if (TPM_BINDING.equals(s)) {
tpm = null;
} else if (PMF_BINDING.equals(s)) {
pmf = null;
} else if (NMF_BINDING.equals(s)) {
nmf = null;
}
}
private boolean started = false;
public String getFcState() {
return started ? STARTED : STOPPED;
}
public void startFc() throws IllegalLifeCycleException {
if (!started) {
mapper.addMapperEventListener(kfpncManager);
started = true;
}
}
public void stopFc() throws IllegalLifeCycleException {
if (started) {
mapper.removeMapperEventListener(kfpncManager);
started = false;
}
}
// IMPLEMENTATION OF THE JormFactory INTERFACE //
//---------------------------------------------//
public PBinder getPBinder(Class clazz) throws PException {
String clName = clazz.getName();
PClassMapping pcm = mapper.lookup(clName);
if (pcm != null)
return pcm.getPBinder();
return getPClassMapping(clazz).getPBinder();
}
public PBinder getPBinder(String classname, ClassLoader cl) throws PException {
PClassMapping pcm = mapper.lookup(classname);
if (pcm != null)
return pcm.getPBinder();
return getPClassMapping(getClass(classname, cl)).getPBinder();
}
public ClassLoader getClassLoader(String className) {
Object o = mapper.lookup(className);
if (o == null) {
return null;
}
return getClassLoader(o.getClass());
}
public PClassMapping getGenClassMapping(String path) {
return JormPathHelper.getPClassMapping(path, mapper);
}
public PClassMapping getPClassMapping(Class clazz) throws PException {
PClassMapping pcm = mapper.lookup(clazz.getName());
if (pcm == null) {
pcm = getPClassMapping(clazz.getName(),
clazz.getClassLoader());
}
return pcm;
}
/**
* This Method is a shortcut to the getPNamingContext(PersistentObjectItf) method.
* It only does the instanciation of the classname
* (Class.ForName(classsName).newInstance()) and call the
* getPNamingContext(PersistentObjectItf) method with the created instance. Then if
* an instance is availlable it is better to use the other method.
* @param classname the Jorm class name managed by the wanted PNamingContext
* @return the PNamingContext instance to use for the given jorm class name
* @throws org.objectweb.jorm.api.PException
*/
public PNamingContext getPNamingContext(String classname, ClassLoader cl) throws PException {
return getPNamingContext(getClass(classname, cl));
}
public PNamingContext getPNamingContext(Class clazz) throws PException {
PClassMapping pcm = getPClassMapping(clazz);
String className = clazz.getName();
String path = JormPathHelper.getPath(className);
Properties classProperties = getClassProperties(clazz);
String jormConf = classProperties.getProperty(path);
if (jormConf != null) {
return (PNamingContext) findPNameManager(
className, clazz.getClassLoader(), pcm, jormConf);
} else {
throw new PException(
"Impossible to find the PNamingContext for the class "
+ className);
}
}
public Properties getSpeedoProperties() {
return cpm.getProperties();
}
public void setSpeedoProperties(Properties p) {
cpm.addProperties(p);
pmf.getProperties().putAll(p);
}
public void setSpeedoProperty(String[] name_n_value) {
cpm.addProperty(name_n_value[0], name_n_value[1]);
if (name_n_value[1].length() == 0) {
pmf.getProperties().remove(name_n_value[0]);
} else {
pmf.getProperties().setProperty(name_n_value[0], name_n_value[1]);
}
}
public void clean() throws PException {
//clear the binders
binders.clear();
//clear the pnaming contexts
pnamingContexts.clear();
//clear the map
cn2pcm.clear();
//clean the mapper
mapper.clean();
//clean the kfpnc manager
kfpncManager.clean();
//clean the nmf
nmf.clean();
}
// IMPLEMENTATION OF THE PNameCoder INTERFACE //
//--------------------------------------------//
public boolean codingSupported(int codingtype) {
return (codingtype & CTCOMPOSITE) != 0;
}
public PName decode(byte[] en) throws PExceptionNaming {
return null;
}
public PName decodeAbstract(Object oid, Object context)
throws PExceptionNaming, UnsupportedOperationException {
Class clazz = null;
ConnectionHolder conn = null;
if (context != null) {
if (!(context instanceof ConnectionHolder)) {
clazz = (Class) context;
} else {
conn = (ConnectionHolder) context;
}
}
if (oid instanceof PName) {
try {
return ((PName) oid).resolve(conn);
} catch (PException e) {
throw personality.newUserRuntimeException("Impossible to decode the identifier "
+ oid + (clazz == null
? "" : " of the class " + clazz.getName()), e);
}
}
PBinder binder = null;
PName pn = null;
try {
if (clazz != null) {
binder = getPBinder(clazz);
}
pn = nmf.decode(binder, oid, clazz, this);
} catch (PException e) {
throw personality.newUserRuntimeException("Impossible to decode the identifier "
+ oid + (clazz == null
? "" : " of the class " + clazz.getName()), e);
}
if (pn != null) {
return pn;
}
if (binder != null) {
return binder.decodeAbstract(oid, null);
}
throw personality.newUserRuntimeException("Impossible to decode the identifier "
+ oid + (clazz == null
? "" : " of the class " + clazz.getName()));
}
public PName decodeByte(byte en) throws PExceptionNaming, UnsupportedOperationException {
return decodeAbstract(new Byte(en), null);
}
public PName decodeObyte(Byte en) throws PExceptionNaming, UnsupportedOperationException {
return decodeAbstract(en, null);
}
public PName decodeChar(char en) throws PExceptionNaming, UnsupportedOperationException {
return decodeAbstract(new Character(en), null);
}
public PName decodeOchar(Character en) throws PExceptionNaming, UnsupportedOperationException {
return decodeAbstract(en, null);
}
public PName decodeInt(int en) throws PExceptionNaming, UnsupportedOperationException {
return decodeAbstract(new Integer(en), null);
}
public PName decodeOint(Integer en) throws PExceptionNaming, UnsupportedOperationException {
return decodeAbstract(en, null);
}
public PName decodeLong(long en) throws PExceptionNaming, UnsupportedOperationException {
return decodeAbstract(new Long(en), null);
}
public PName decodeOlong(Long en) throws PExceptionNaming, UnsupportedOperationException {
return decodeAbstract(en, null);
}
public PName decodeShort(short en) throws PExceptionNaming, UnsupportedOperationException {
return decodeAbstract(new Short(en), null);
}
public PName decodeOshort(Short en) throws PExceptionNaming, UnsupportedOperationException {
return decodeAbstract(en, null);
}
public PName decodeString(String en) throws PExceptionNaming {
return decodeAbstract(en, null);
}
public PName decodeCharArray(char[] en) throws PExceptionNaming {
return decodeAbstract(en, null);
}
public PName decodeDate(Date en) throws PExceptionNaming {
return decodeAbstract(en, null);
}
public PName decodeBigInteger(BigInteger en) throws PExceptionNaming {
return decodeAbstract(en, null);
}
public PName decodeBigDecimal(BigDecimal en) throws PExceptionNaming {
return decodeAbstract(en, null);
}
public byte[] encode(PName pn) throws PExceptionNaming {
return pn.encode();
}
public Object encodeAbstract(PName pn) throws PExceptionNaming, UnsupportedOperationException {
try {
return nmf.encode(pn);
} catch (PException e) {
throw new SpeedoRuntimeException(
"Impossible to encode the identifier :" + pn);
}
}
public byte encodeByte(PName pn) throws PExceptionNaming, UnsupportedOperationException {
throw new UnsupportedOperationException("Impossible to encode to a byte");
}
public Byte encodeObyte(PName pn) throws PExceptionNaming, UnsupportedOperationException {
throw new UnsupportedOperationException("Impossible to encode to a Byte");
}
public char encodeChar(PName pn) throws PExceptionNaming, UnsupportedOperationException {
throw new UnsupportedOperationException("Impossible to encode to a char");
}
public Character encodeOchar(PName pn) throws PExceptionNaming, UnsupportedOperationException {
throw new UnsupportedOperationException("Impossible to encode to a Character");
}
public int encodeInt(PName pn) throws PExceptionNaming, UnsupportedOperationException {
throw new UnsupportedOperationException("Impossible to encode to a int");
}
public Integer encodeOint(PName pn) throws PExceptionNaming, UnsupportedOperationException {
throw new UnsupportedOperationException("Impossible to encode to a Integer");
}
public long encodeLong(PName pn) throws PExceptionNaming, UnsupportedOperationException {
throw new UnsupportedOperationException("Impossible to encode to a long");
}
public Long encodeOlong(PName pn) throws PExceptionNaming, UnsupportedOperationException {
throw new UnsupportedOperationException("Impossible to encode to a Long");
}
public short encodeShort(PName pn) throws PExceptionNaming, UnsupportedOperationException {
throw new UnsupportedOperationException("Impossible to encode to a short");
}
public Short encodeOshort(PName pn) throws PExceptionNaming, UnsupportedOperationException {
throw new UnsupportedOperationException("Impossible to encode to a Short");
}
public String encodeString(PName pn) throws PExceptionNaming {
throw new UnsupportedOperationException("Impossible to encode to a String");
}
public char[] encodeCharArray(PName pn) throws PExceptionNaming {
throw new UnsupportedOperationException("Impossible to encode to a char[]");
}
public Date encodeDate(PName pn) throws PExceptionNaming {
throw new UnsupportedOperationException("Impossible to encode to a Date");
}
public BigInteger encodeBigInteger(PName pn) throws PExceptionNaming {
throw new UnsupportedOperationException("Impossible to encode to a BigInteger");
}
public BigDecimal encodeBigDecimal(PName pn) throws PExceptionNaming {
throw new UnsupportedOperationException("Impossible to encode to a BigDecimal");
}
public PName getNull() {
return null;
}
public void setNullPName(Object o) throws PException {
}
public boolean supportDynamicComposite() {
return false;
}
public boolean supportCompositeField(String fn, PType ft) {
return false;
}
public boolean supportStaticComposite() {
return false;
}
public PType getPType() {
return null;
}
public void setPType(PType pt) {
}
// PRIVATE METHODS //
//-----------------//
/**
* Fetch the configuration properties of a persistent class. The current
* speedo implementation make available the properties throught the
* method getClassProperties() of the home class.
* The method implementation of this method invokes the method.
* @param clazz is the java.lang.Class of a persistent class
* @return the java.util.Properties instance describing the configuration
* properties of the given persistent class.
* @throws PException if an error occurs during the method invocation.
*/
private Properties getClassProperties(Class clazz) throws PException {
PClassMapping pcm = getPClassMapping(
clazz.getName(), clazz.getClassLoader());
return ((HomeItf) pcm).getClassProperties();
}
/**
* This method is the real implementation of the getPClassMapping methods
* from the JormFactory interface. It instanciates and configure a
* persistent class. That represents
* - the instanciation of the PClassMapping
* - its configuration: fetching PNamingContext instances for each reference
* and allocating GenClassMapping for each gen class reference (collection).
* - the mapping of class (map operation on the mapper)
* - the management of data strucutre for the cluster (creation table)
*
* @param className is the class name of the persistent class which the
* PClasMapping is asked
* @param classLoader is the classloader for the persistent class. It
* assumes that the classloader contains the Speedo/Jorm classes about the
* persistent class (PClassMapping, PAccessor, PName, PBinder, PNG, ...)
* @return The PClassMapping of the persistent class
* @throws PException
*/
public synchronized PClassMapping getPClassMapping(String className,
ClassLoader classLoader)
throws PException {
boolean debug = logger.isLoggable(BasicLevel.DEBUG);
HomeItf pcm = (HomeItf) cn2pcm.get(className);
if (pcm != null) {
if (debug)
logger.log(BasicLevel.DEBUG, "PClassMapping for class " + className
+ " is being configured:" + pcm);
return pcm;
}
pcm = (HomeItf) mapper.lookup(className);
if (pcm != null) {
if (debug)
logger.log(BasicLevel.DEBUG, "PClassMapping for class " + className
+ " already exist:" + pcm);
return pcm;
}
// Creates the PClassMapping, its PBinder and the PNC
if (debug) {
logger.log(BasicLevel.DEBUG,
"Looking for the PClassMapping of the class " + className);
}
String pcmcn = NamingRules.fqMappingName(className);
try {
pcm = (HomeItf) classLoader.loadClass(pcmcn).newInstance();
} catch (Exception e) {
throw new PException(e,
"Impossible to instanciate the PClassMapping of the class "
+ className + ": " + pcmcn);
}
pcm.setTransactionalPersistenceManager(tpm);
pcm.setPOManagerFactory(pmf);
Properties classProperties = pcm.getClassProperties();
if (debug) {
logger.log(BasicLevel.DEBUG, "Jorm config:" + classProperties);
}
//Load the Jorm Meta information
loadJormSpeedoMI(className, classProperties, classLoader);
// Fetch the Binder
PBinder binder = findPBinder(className, classLoader,
classProperties.getProperty(JormPathHelper.getPath(className)));
pcm.setPBinder(binder);
binder.setPClassMapping(pcm);
// Fetch the PNC of the class
PNameCoder classPnc = findPNameManager(
className, classLoader, pcm, classProperties.getProperty(JormPathHelper.getPath(className))
);
((PClassMappingCtrl) pcm).setClassPNameCoder(classPnc);
//Configure references (PNameCoder and GenClassMappping)
RefConfig refConfig = new RefConfig(classProperties, classLoader);
cn2pcm.put(className, pcm);//register the pcm in order to avoid double configuration
pcm.configureRefFields(refConfig);
cn2pcm.remove(className);
if (debug) {
logger.log(BasicLevel.DEBUG, "PClassMapping/PBinder/PNC created for the class " + className);
logger.log(BasicLevel.DEBUG, "- pcm: " + pcm);
logger.log(BasicLevel.DEBUG, "- binder: " + binder);
logger.log(BasicLevel.DEBUG, "-pnc: " + classPnc);
}
// Maps the class
mapper.map(null, pcm);
pcm.configureRefFields(new GCMHomeConfig(pcm));
cpm.applyProperties(pcm);
logger.log(BasicLevel.DEBUG, "Class " + className + " mapped");
//Manage the cluster of classes
PMapCluster cluster = mapper.getPMappingStructuresManager().getPMapCluster(className);
if (cluster.isDefined()) { //cluster is full (all classes are mapped)
if (mappingStructuresRule >= CREATE_IF_REQUIRED) {
if (mappingStructuresRule == FORCE_CREATE) {
cluster.deleteMappingStructures();
}
cluster.createMappingStructures(
mappingStructuresRule == FORCE_CREATE);
if (mappingStructuresRule == DELETE_DATA) {
cluster.deleteData();
}
}
if (logger.isLoggable(BasicLevel.INFO)) {
String msr=null;
switch(mappingStructuresRule){
case CREATE_IF_REQUIRED: msr = "CREATE_IF_REQUIRED"; break;
case FORCE_CREATE: msr = "FORCE_CREATE"; break;
case DELETE_DATA: msr = "DELETE_DATA"; break;
case DO_NOTHING: msr = "DO_NOTHING"; break;
}
logger.log(BasicLevel.INFO, "Classes "
+ cluster.getClusterClasses()
+ " initialized (" + msr + ").");
}
} else { // some classes are not already mapped
//ask the mapping of the next
getPClassMapping((String) cluster
.getUnResolvedDependencies().iterator().next(),
classLoader);
}
return pcm;
}
/**
* Load a class from a given classLoader
* @param classname is the name of the class to load
* (non null value is required).
* @param cl is the classloader contains the class
* (non null value is required).
* @return the Class object (never null)
*/
private Class getClass(String classname, ClassLoader cl) throws PException {
if (cl == null) {
throw new PException("Impossible to load the class "
+ classname + " without a classLoader(" + cl + ")");
}
try {
return cl.loadClass(classname);
} catch (Exception e) {
throw new PException(e, "Impossible to load the class '"
+ classname + "' with the class loader :" + cl);
}
}
/**
* Retrieves a PBinder managing a given persistent class.
* This implementation delegates the PBinder allocation to NamingManager.
* @see org.objectweb.speedo.naming.api.NamingManager
*
* @param className is the name of the persistent class which the asked
* PBinder must managed
* @param classLoader is the classloader for the persistent class. It
* assumes that the classloader contains the Speedo/Jorm classes about the
* persistent class (PClassMapping, PAccessor, PName, PBinder, PNG, ...)
* @param hints is a string data permitting to allocate and to configure
* the PBinder.
* @return the PBinder managing the given persistent class.
*/
public synchronized PBinder findPBinder(String className,
ClassLoader classLoader,
String hints) throws PException {
if (hints == null || hints.length() == 0)
throw new PException(
"Impossible to get the PNamingContext of the class " + className
+ ": Specified binder class is not valid: " + hints);
PBinder binder = (PBinder) binders.get(className);
if (binder != null)
return binder;
binder = nmf.getNamingManager(hints, classLoader)
.getPBinder(className, hints, classLoader,
mappingStructuresRule, binders, pnamingContexts);
//binder.setCacheManager(cache);
binders.put(className, binder);
return binder;
}
/**
* Retrieves a PNameManager managing a given persistent class and its sub
* classes. This implementation delegates the PNameManager allocation to
* NamingManager.
* @see org.objectweb.speedo.naming.api.NamingManager
*
* @param className is the name of the persistent class which the asked
* PNameManager must managed (non null value is required)
* @param classLoader is the classloader for the persistent class. It
* assumes that the classloader contains the Speedo/Jorm classes about the
* persistent class (PClassMapping, PAccessor, PName, PBinder, PNG, ...)
* (non null value is required)
* @param hints is a string data permitting to allocate and to configure
* the PNameManager. (non null value is required)
* @return the PNameManager managing the given persistent class and its
* sub classes.
*/
protected synchronized PNameManager findPNameManager(String className,
ClassLoader classLoader,
PClassMapping pcm,
String hints
) throws PException {
if (hints == null || hints.length() == 0)
throw new SpeedoRuntimeException(
"Impossible to get the PNamingContext of the class " + className
+ ": Specified PNameManager class is not valid: " + hints);
PNameManager pnm = (PNameManager) pnamingContexts.get(className);
if (pnm != null && (hints.indexOf(NamingManagerHelper.POLYMORPHIC_PNC) == -1))
return pnm;
NamingManager nm = nmf.getNamingManager(hints, classLoader);
if (nm.supportPNamingcontext()) {
pnm = nm.getPNamingContext(className, hints, classLoader,
mappingStructuresRule, binders, pnamingContexts,
mapper.getMetaInfoManager(), pcm);
} else {
pnm = findPBinder(className, classLoader, hints);
}
pnamingContexts.put(className, pnm);
return pnm;
}
/**
* Is defines a PClassMapping.ReferenceConfigurator permitting to configure
* the reference of a persistent class.
*/
private class RefConfig implements PClassMapping.ReferenceConfigurator {
/**
* The properties of the persistent class. This properties contains the
* information permitting to allowing the naming manager for the class
* and its references.
*/
private Map classProperties = null;
/**
* is the classloader for the persistent class. It assumes that the
* classloader contains the Speedo/Jorm classes about the persistent
* class (PClassMapping, PAccessor, PName, PBinder, PNG, ...)
* (non null value is required).
*/
private ClassLoader classLoader = null;
public RefConfig(Map _classProperties,
ClassLoader cl) {
this.classProperties = _classProperties;
this.classLoader = cl;
}
// IMPLEMENTATION OF THE PClassMapping.PNCGetter INTERFACE //
//---------------------------------------------------------//
public PNameCoder getPNameCoder(String sourceclassName,
String refFieldName,
String destclassName) {
try {
PNamingContext pnc = getPNamingContext(destclassName, classLoader);
if (logger.isLoggable(BasicLevel.DEBUG))
logger.log(BasicLevel.DEBUG,
"Assign the PNamingContext for the field " + sourceclassName
+ "." + refFieldName + " which references the class "
+ destclassName + ": " + pnc);
logger.log(BasicLevel.DEBUG,
"getPNameManager(" + destclassName + ") ==>" + pnc);
return pnc;
} catch (PException e) {
throw new SpeedoRuntimeException(
"ERROR during the assignation of the PNameManager of the reference "
+ refFieldName + " of the class " + sourceclassName, e);
}
}
public PNameCoder getPNameCoder(String sourceclassName,
String refFieldName,
String[] genClassNames) {
String path = JormPathHelper.getPath(
sourceclassName, refFieldName, genClassNames);
String hints = (String) classProperties.get(path);
try {
PNamingContext pnc = (PNamingContext) findPNameManager(path, classLoader, null, hints);
logger.log(BasicLevel.DEBUG,
"getPNameManager(" + path + ") ==>" + pnc);
return pnc;
} catch (PException e) {
throw new SpeedoRuntimeException(e.getMessage(), e);
}
}
public PClassMapping getGenClassMapping(String sourceclassName,
String refFieldName,
String[] genClassNames) {
String cn = JormPathHelper.getPath(
sourceclassName, refFieldName, genClassNames);
String hints = (String) classProperties.get(cn);
logger.log(BasicLevel.DEBUG, "getGenClassMapping(" + cn + ")");
logger.log(BasicLevel.DEBUG, "\thints=" + hints);
try {
PClassMapping gcm = (PClassMapping)
Class.forName(getGCMClassName(mapper.getMapperName())).newInstance();
logger.log(BasicLevel.DEBUG, "\tgcm=" + gcm);
PBinder pb = findPBinder(cn, classLoader,hints);
logger.log(BasicLevel.DEBUG, "\tbinder=" + pb);
gcm.setPBinder(pb);
pb.setPClassMapping(gcm);
return gcm;
} catch (Exception e) {
throw new SpeedoRuntimeException(e.getMessage(), e);
}
}
public PClassMapping getGenClassMapping(String sourceclassName,
String refFieldName,
String[] genClassNames,
String destclassName) {
String cn = JormPathHelper.getPath(
sourceclassName, refFieldName, genClassNames);
String hints = (String) classProperties.get(cn);
try {
PClassMapping gcm = (PClassMapping)
Class.forName(getGCMClassName(mapper.getMapperName())).newInstance();
logger.log(BasicLevel.DEBUG, "getGenClassMapping(" + cn + ")");
logger.log(BasicLevel.DEBUG, "\tgcm=" + gcm);
PBinder pb = findPBinder(cn, classLoader, hints);
logger.log(BasicLevel.DEBUG, "\tbinder=" + pb);
gcm.setPBinder(pb);
pb.setPClassMapping(gcm);
PNamingContext pnc = getPNamingContext(destclassName, classLoader);
logger.log(BasicLevel.DEBUG, "\tpnc=" + pnc);
((PClassMappingCtrl) gcm).setPNameCoder(pnc);
return gcm;
} catch (Exception e) {
throw new SpeedoRuntimeException(e.getMessage(), e);
}
}
}
private class GCMHomeConfig implements PClassMapping.ReferenceConfigurator {
PClassMapping pcm;
GCMHomeConfig(PClassMapping _pcm) {
this.pcm = _pcm;
}
public PNameCoder getPNameCoder(String sourceclassName,
String refFieldName,
String destclassName) {
return pcm.getPNameCoder(refFieldName);
}
public PNameCoder getPNameCoder(String sourceclassName,
String refFieldName,
String[] genClassNames) {
return pcm.getPNameCoder(refFieldName);
}
public PClassMapping getGenClassMapping(String sourceclassName,
String refFieldName,
String[] genClassNames) {
PClassMapping gcm = pcm.getGenClassMapping(refFieldName);
gcm = newGenClassHome(gcm, tpm, pmf,
sourceclassName + "#" + refFieldName);
gcm.getPBinder().setPClassMapping(gcm);
logger.log(BasicLevel.DEBUG, "Insert the home=" + gcm);
cpm.applyProperties((HomeItf) gcm);
return gcm;
}
public PClassMapping getGenClassMapping(String sourceclassName,
String refFieldName,
String[] genClassNames,
String destclassName) {
PClassMapping gcm = pcm.getGenClassMapping(refFieldName);
gcm = newGenClassHome(gcm, tpm, pmf,
sourceclassName + "#" + refFieldName);
gcm.getPBinder().setPClassMapping(gcm);
logger.log(BasicLevel.DEBUG, "Insert the home=" + gcm);
try {
HomeItf refHome = (HomeItf) getPClassMapping(
destclassName, pcm.getClass().getClassLoader());
cpm.applyProperties((HomeItf) gcm, refHome);
} catch (PException e) {
logger.log(BasicLevel.WARN,
"Impossible to fetch the Home of the class '"
+ destclassName + "'.", e);
}
return gcm;
}
}
/**
* Instanciates a new home for a generic class. The used class depends
* on the Personality.
* @param _pcm is the real pcm to link to the home
* @param _tpm is the transactional persistence manager to link to the home
* @param _pmf is the PO manager factory to link to the home
* @param path is the path identifing the genclass.
* @return a new instance of HomeItf managing a genclass
*/
HomeItf newGenClassHome(PClassMapping _pcm,
TransactionalPersistenceManager _tpm,
POManagerFactoryItf _pmf,
String path) {
String cn = pmf.getPersonality().getPersonalityClassName(
"org.objectweb.speedo.genclass", "GenClassHome");
try {
AbstractGenClassHome gcHome = (AbstractGenClassHome)
Class.forName(cn).newInstance();
gcHome.init(_pcm, _tpm, _pmf, path);
return gcHome;
} catch (Exception e) {
throw new SpeedoRuntimeException(e);
}
}
/**
* Load the jorm/speedo meta information for a persistent class.
*
* @param className is the name of class which the Jorm meta information
* has to be loaded.
* @param classProperties is the properties of the persistent class. This
* properties contains the information about file name containing the JMI.
* @param classLoader is the classloader for the persistent class. It
* assumes that the classloader contains the Speedo/Jorm classes about the
* persistent class (PClassMapping, PAccessor, PName, PBinder, PNG, ...)
* (non null value is required)
*/
private void loadJormSpeedoMI(String className,
Properties classProperties,
ClassLoader classLoader) {
JormManager m = (JormManager) mapper.getMetaInfoManager();
synchronized (m) {
if (m.getClass(className) != null) {
return;
}
//deserialize the JMI from the file
Set mos = null;
String fn = classProperties.getProperty(Object2StringSerializer.DESC_FILE_NAME_PROP);
try {
mos = (Set) Object2StringSerializer.deserialize(fn, classLoader, logger);
} catch (Exception e) {
throw personality.newRuntimeException("Impossible to load the jorm meta " +
"information for the class '" + className + "' from the file '"
+ fn + "' (You must use the same Speedo version for the"
+ " enhancement and for the runtime): ", e);
}
//insert the Jorm meta object into the Jorm MI mamager
for (Iterator it = mos.iterator(); it.hasNext();) {
Object o = it.next();
if (o instanceof BasicClass) {
BasicClass c = (BasicClass) o;
Package s = m.createPackage(((Package) c.getParent()).getName());
s.addClass(c);
c.setParent(s);
c.setLogger(m.getLogger());
logger.log(BasicLevel.DEBUG,
"Jorm Meta Object Class " + c.getFQName() + " loaded");
} else if (o instanceof BasicCompositeName) {
BasicCompositeName cn = (BasicCompositeName) o;
Package s = m.createPackage(((Package) cn.getParent()).getName());
s.addCompositeName(cn);
cn.setLogger(m.getLogger());
logger.log(BasicLevel.DEBUG,
"Jorm Meta Object CompositeName " + cn.getFQName() + " loaded");
} else if (o instanceof SpeedoSequenceItf) {
//add the sequence to the sequence manager of the pmf
pmf.getSequenceManager().addSequence(o);
logger.log(BasicLevel.DEBUG,
"Speedo Meta Object Sequence " + o + " loaded");
} else if (o instanceof SpeedoIndex) {
//SpeedoIndex si = (SpeedoIndex) o;
//TODO handle speedo index
} else
throw new SpeedoRuntimeException("Umanaged Jorm/Speedo Meta Object " + o);
}
if (m.getClass(className) == null) {
throw new SpeedoRuntimeException(
"Internal ERROR: No meta information found about the persistent class '"
+ className + "' in the file '" + fn + "'.");
}
}
}
/**
* Retrieves the class name of the PClassMapping implementation for the
* generic class for a given mapper name.
* @param mapperName is a name of a Jorm Mapper (rdb, rdb.postgres, fos, ..)
*/
protected String getGCMClassName(String mapperName) {
if (mapperName.startsWith("rdb")) {
return "org.objectweb.jorm.mapper.rdb.genclass.RdbGenClassMapping";
} else {
throw new SpeedoRuntimeException("Umanaged mapper: " + mapperName);
}
}
/**
* Find the class loader of a java class. This is a tool method managing the
* fact that the clazz.getClassCloader() method could return null. In this
* case the Speedo class loader is returned.
*
* @param clazz is a java.lang.Class object
*/
private ClassLoader getClassLoader(Class clazz) {
ClassLoader cl = clazz.getClassLoader();
if (cl == null) {
cl = this.getClass().getClassLoader();
if (cl == null) {
cl = ClassLoader.getSystemClassLoader();
logger.log(BasicLevel.DEBUG,
"Use the system class loader for the class '"
+ clazz.getName() + "': " + cl);
} else {
logger.log(BasicLevel.DEBUG,
"Use the Speedo class loader for the class '"
+ clazz.getName() + "': " + cl);
}
} else {
logger.log(BasicLevel.DEBUG,
"Use the Application class loader for the class '"
+ clazz.getName() + "': " + cl);
}
return cl;
}
}