Package org.objectweb.speedo.mapper.lib

Source Code of org.objectweb.speedo.mapper.lib.BasicJormFactory

/**
* 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;
  }
 
}
TOP

Related Classes of org.objectweb.speedo.mapper.lib.BasicJormFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.