Package org.objectweb.speedo.mim.lib

Source Code of org.objectweb.speedo.mim.lib.MemoryInstanceManagerImpl

/**
* 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.mim.lib;

import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.jorm.api.PClassMapping;
import org.objectweb.jorm.api.PException;
import org.objectweb.jorm.lib.JormPathHelper;
import org.objectweb.jorm.naming.api.PBinder;
import org.objectweb.jorm.naming.api.PName;
import org.objectweb.jorm.naming.api.PNameManager;
import org.objectweb.jorm.type.api.PType;
import org.objectweb.jorm.util.api.Loggable;
import org.objectweb.perseus.cache.api.CacheEntry;
import org.objectweb.perseus.cache.api.CacheEntryFactory;
import org.objectweb.perseus.cache.api.CacheEvent;
import org.objectweb.perseus.cache.api.FixableCacheEntry;
import org.objectweb.perseus.persistence.api.ConnectionHolder;
import org.objectweb.perseus.persistence.api.MemoryInstanceManager;
import org.objectweb.perseus.persistence.api.PersistenceException;
import org.objectweb.perseus.persistence.api.State;
import org.objectweb.perseus.persistence.api.StateManager;
import org.objectweb.speedo.api.ExceptionHelper;
import org.objectweb.speedo.api.SpeedoRuntimeException;
import org.objectweb.speedo.genclass.AbstractGenClassHome;
import org.objectweb.speedo.genclass.SupportedGenClass;
import org.objectweb.speedo.genclass.api.SpeedoGenClassPO;
import org.objectweb.speedo.lib.Personality;
import org.objectweb.speedo.mapper.api.JormFactory;
import org.objectweb.speedo.mim.api.LifeCycle;
import org.objectweb.speedo.mim.api.MemoryInstanceManagerAttribute;
import org.objectweb.speedo.mim.api.StateItf;
import org.objectweb.speedo.mim.api.HomeItf;
import org.objectweb.speedo.mim.api.PersistentObjectItf;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;

import javax.jdo.listener.InstanceLifecycleEvent;

/**
* This class is an implementation of the MemoryInstanceManager provided by the
* persistence framwork availlable in perseus. This implementation depends on
* the identifier used, and the way to instanciate user objects. This
* implementation supports only the jorm object identifier: PName.
* This implementation supports also the instanciation of the Jorm generic
* class. To do this it is needed to specify for each jorm generic class used
* the name of the class which must be instanciated. This configuration is done
* via the GenClassNames attribute.
* This implementation does not used a pool, then the instance are created at
* each newInstance call.
*
* @author S.Chassande-Barrioz
*/
public class MemoryInstanceManagerImpl
    implements MemoryInstanceManager,
    MemoryInstanceManagerAttribute,
    StateManager,
    CacheEntryFactory,
    BindingController {

  public final static String JORM_FACTORY_BINDING = "jorm-factory";

  /**
   * This fields maintains the association between the name of the Jorm
   * generic class and the class name which must be implemented.
   */
  private Map name2gcimpl = null;

  protected JormFactory jf = null;
 
  protected Personality personality;

  protected Logger logger = null;

  public MemoryInstanceManagerImpl() {
    name2gcimpl = Collections.EMPTY_MAP;
  }

  private String getGCClassName(String cn) {
    String res = (String) name2gcimpl.get(cn);
    if (res != null) {
      return res;
    }
    for (int i = 0; i < SupportedGenClass.GC_IMPL.length; i++) {
      if (SupportedGenClass.GC_IMPL[i][0].equals(cn)) {
        return personality.getGenClassName(
            SupportedGenClass.GC_IMPL[i][1]);
      }
    }
    return null;
  }

  /**
   * Active a persistent object :
   * - assign the PClassMapping
   * - assign a Pbinding for the SpeedoGenClassPO
   *
   * @param sp is PersistentObjectItf or a SpeedoGenClassPO instance, the
   * persistent object
   * @param pn the identifier of the object
   */
  private void activePO(PersistentObjectItf sp, PName pn) {
    //fetch the PClassMapping
    PClassMapping pcm = null;
    if (pn != null && (pn.getPNameManager() instanceof PBinder)) {
      pcm = ((PBinder) pn.getPNameManager()).getBinderClassMapping();
    }
    if (sp instanceof SpeedoGenClassPO) {
      if (((SpeedoGenClassPO) sp).speedoGetPBinding() == null) {
        if (pcm == null)  {
          pcm = jf.getGenClassMapping(
              ((SpeedoGenClassPO) sp).speedoGetGenClassId());
        }
        //Assign the PBinding
        try {
          ((SpeedoGenClassPO) sp).speedoSetPBinding(pcm.createPBinding());
        } catch (PException e) {
          throw personality.newRuntimeException("Impossible to initialize the delegate PBinding of the genclass", e);
        }
        if (sp instanceof Loggable) {
          ((Loggable) sp).setLogger(logger);
        }
      }
    } else {
      if (pcm == null)  {
        try {
          pcm = jf.getPClassMapping(sp.getClass());
        } catch (PException e) {
          throw personality.newRuntimeException("Impossible to initialize a class", e);
        }
      }
      if (sp.getPClassMapping() == null) {
        //Assign the PClassMapping
        try {
          sp.init(pcm);
        } catch (PException e) {
          Exception ie = ExceptionHelper.getNested(e);
          if (logger != null)
            logger.log(BasicLevel.ERROR,
                "Impossible to init the persistent class: "
                + sp.getClass().getName(), ie);
          throw personality.newRuntimeException("Impossible to init the persistent class:" +
              ie.getMessage());
        }
      }
    }
    //Mark as active
    sp.speedoIsActive(true);
    if (logger != null && logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, "PO activated: " + sp.getClass().getName());
  }

  private HomeItf getHome(Object o) {
    if (o == null) {
      logger.log(BasicLevel.WARN, "Impossible to find the home: null object");
      return null;
    } else if (o instanceof PersistentObjectItf) {
            PersistentObjectItf po =(PersistentObjectItf) o;
      HomeItf h = po.speedoGetHome();
      if (h == null) {
                if (o instanceof SpeedoGenClassPO) {
                    PName pn = po.getPName();
                    if (pn == null) {
                        h = (HomeItf) ((PBinder) pn.getPNameManager()).getBinderClassMapping();
                    } else {
                        h = (HomeItf) jf.getGenClassMapping(
                                ((SpeedoGenClassPO) po).speedoGetGenClassId());
                    }
                } else {
            try {
              h = (HomeItf) jf.getPClassMapping(o.getClass());
            } catch (PException e) {
              throw new SpeedoRuntimeException(e);
                    }
        }
      }
            if (h == null) {
                logger.log(BasicLevel.WARN, "Impossible to find the home");
            }
      return h;
    } else if (o instanceof PName) {
            PName pn = (PName) o;
            PNameManager pnm = pn.getPNameManager();
            while (!(pnm instanceof PBinder)) {
                PName npn;
                try {
                    npn = pn.resolve(null);
                } catch (PException e) {
                    logger.log(BasicLevel.WARN, "Impossible to find the home from the PName " + pn, e);
                    return null;
                }
                if (npn == pn) {
                    logger.log(BasicLevel.WARN, "Impossible to find the home from the PName " + pn +" : cycle");
                    return null;
                } else {
                    pnm = pn.getPNameManager();
                }
            }
      return (HomeItf) ((PBinder) pnm).getBinderClassMapping();
    } else {
      logger.log(BasicLevel.WARN, "No home found with this object: " + o.getClass());
      return null;
    }
  }
 
  // IMPLEMENTATION OF THE MemoryInstanceManagerAttribute INTERFACE //
  //----------------------------------------------------------------------//
  public String[] listFc() {
    return new String[]{JORM_FACTORY_BINDING};
  }

  public Object lookupFc(String s) {
    if (JORM_FACTORY_BINDING.equals(s)) {
      return jf;
    } else {
      return null;
    }
  }

  public void bindFc(String s, Object o) {
    if (JORM_FACTORY_BINDING.equals(s)) {
      jf = (JormFactory) o;
    } else if ("logger".equals(s)) {
      logger = (Logger) o;
    }
  }

  public void unbindFc(String s) {
    if (JORM_FACTORY_BINDING.equals(s)) {
      jf = null;
    }
  }


  // IMPLEMENTATION OF THE MemoryInstanceManagerAttribute INTERFACE //
  //----------------------------------------------------------------------//

  /**
   * @return a String describing the genclass names with the following format:
   * "(jorm_name,java_name),(jorm_name,java_name),(jorm_name,java_name)}"
   */
  public String getGenClassNames() {
    if (name2gcimpl == null || name2gcimpl.size() == 0)
      return "{}";
    StringBuffer res = new StringBuffer("");
    boolean first = true;
    for (Iterator it = name2gcimpl.entrySet().iterator(); it.hasNext();) {
      if (first) {
        res.append("{");
        first = false;
      } else
        res.append(",");
      res.append("(");
      Map.Entry me = (Map.Entry) it.next();
      res.append(me.getKey());
      res.append(",");
      res.append(me.getValue());
      res.append(")");
    }
    res.append("}");
    return res.toString();
  }

  /**
   * It assignes a description of the gen class names.
   * @param gcname is the desciption which must follow this format:
   * "(jorm_name,java_name),(jorm_name,java_name),(jorm_name,java_name)}"
   */
  public void setGenClassNames(String gcname) {
    if (gcname == null || gcname.length() == 0)
      name2gcimpl = Collections.EMPTY_MAP;
    name2gcimpl = new HashMap(5);
    StringTokenizer st = new StringTokenizer(gcname, "{,()}:;[]", false);
    String key = null;
    while (st.hasMoreTokens()) {
      if (key == null) {
        key = st.nextToken().trim();
      } else {
        name2gcimpl.put(key, st.nextToken().trim());
      }
    }
  }

  public Personality getPersonality() {
    return personality;
  }

  public void setPersonality(Personality p) {
    this.personality = p;
  }

  // IMPLEMENTATION OF THE MemoryInstanceManager INTERFACE //
  //-------------------------------------------------------//

  /**
   * It creates an instance since an identifier
   * @param oid is the identifier of the futur object
   * @return a memory instance
   */
  public Object newInstance(Object oid, ConnectionHolder context) throws PersistenceException {
    if (!(oid instanceof PName))
      throw new PersistenceException("Unmanaged object identifier: " + oid);
    PName pn = (PName) oid;
    String className = null;
    try {
      pn = pn.resolve(context);
      if (logger.isLoggable(BasicLevel.DEBUG)) {
        logger.log(BasicLevel.DEBUG, "newInstance(" + oid + "): pn.resolve=" + pn);
        logger.log(BasicLevel.DEBUG, "newInstance(" + oid + "): pn.type=" + pn.getPType());
      }
      PType type = pn.getPType();
      if (type == null) {
        //Error detected by Roland Hedayat
        throw new PersistenceException("newInstance() "
          + "\n\toid=" + oid
          + "\n\tpn=" + pn
          + "\n\tpn.pnc=" + (pn.getPNameManager() != null ? pn.getPNameManager() : null));
      }
      className = type.getJormName();
      int idx = className.indexOf(JormPathHelper.SEP);
      PClassMapping pcm = ((PBinder) pn.getPNameManager())
          .getBinderClassMapping();
      PersistentObjectItf sp = null;
      if ((pcm instanceof AbstractGenClassHome) && idx != -1) {
        // This is a Generic class
        className = getGCClassName(className.substring(0, idx));
        sp = (PersistentObjectItf) Class.forName(className).newInstance();
      } else {
        if (pcm != null) {
          className = pcm.getClassName();
        }
        ClassLoader cl = jf.getClassLoader(className);
        if (cl == null) {
          cl = oid.getClass().getClassLoader();
          if (cl == null) {
            cl = ClassLoader.getSystemClassLoader();
          }
        }
        sp = (PersistentObjectItf)
            cl.loadClass(className).newInstance();
      }
            sp.speedoSetReferenceState(null);
      return sp;
    } catch (PException e) {
      throw new PersistenceException(
          "Impossible to analyze the object identifier" + oid, e);
    } catch (Exception e) {
      throw new PersistenceException(
          "Impossible to instanciate the class " + className
          + "Be careful to the generic class (Collection, ...), oid class:"
          + oid.getClass(), e);
    }
  }


  public boolean isObjectSharing(Object o) {
    HomeItf home = getHome(o);
    return home == null || home.isShareable();
  }

  // IMPLEMENTATION OF THE StateManager INTERFACE //
  //----------------------------------------------//
  public State createState(CacheEntry ce) {
    return ((PersistentObjectItf) ce).speedoCreateState();
  }

  public State createState(State s) {
    PersistentObjectItf sp = (PersistentObjectItf) s.getCacheEntry();
    StateItf sa = sp.speedoCreateState();
    sp.speedoCopyState(((StateItf) s), sa);
    return sa;
  }

  public State getReferenceState(CacheEntry ce) {
    return ((PersistentObjectItf) ce).speedoGetReferenceState();
  }

  public void destroyState(State state) {
    //nothing to do
  }

  public void makeUnexported(State state) {
    ((StateItf) state).speedoChangeStatus(LifeCycle.ACTION_DELETEPERSISTENT);
  }

  public boolean isUnexported(State state) {
    return LifeCycle.isDeleted(((StateItf) state).speedoGetStatus());
  }

  public void makeExported(State state) {
    ((StateItf) state).speedoChangeStatus(LifeCycle.ACTION_MAKEPERSISTENT);
  }

  public boolean isExported(State state) {
    return LifeCycle.isNew(((StateItf) state).speedoGetStatus());
  }

  public void makeDirty(State state) {
    ((StateItf) state).speedoChangeStatus(LifeCycle.ACTION_WRITEFIELD_ACTIVEDATASTORETRANSACTION);
    ((StateItf) state).setFlushed(false);
  }

  public boolean isDirty(State state) {
    return LifeCycle.isDirty(((StateItf) state).speedoGetStatus());
  }

  public void setReferenceState(CacheEntry ce, State state) {
    if (state == ((PersistentObjectItf) ce).speedoGetReferenceState()) {
      return;
    }
    PersistentObjectItf sp = (PersistentObjectItf) ce;
    if (sp.speedoIsActive() && state == null) {
        sp.speedoGetHome().sendEvent(HomeItf.PRE_CLEAR, sp, null);
    }
      sp.speedoSetReferenceState((StateItf) state);
    if (sp.speedoIsActive() && state == null) {
        sp.speedoGetHome().sendEvent(HomeItf.POST_CLEAR, sp, null);
    }
  }

  public void makeClean(State state) {
        StateItf sa = (StateItf) state;
    sa.speedoSetStatus(LifeCycle.PERSISTENT_CLEAN);
  }

  public void makeFlushed(State state) {
    ((StateItf) state).setFlushed(true);
  }

  public boolean isFlushed(State state) {
    return ((StateItf) state).hasBeenFlush();
  }

  public void makeUnbound(CacheEntry ce) {
    PersistentObjectItf sp = (PersistentObjectItf) ce;
    sp.speedoIsActive(false);
    try {
            sp.init(null);
        } catch (PException e) {
            logger.log(BasicLevel.WARN, "Error during the unbinding: ", e);
        }
  }

  public void makeBound(CacheEntry ce, Object oid) {
    PName pname = (PName) oid;
    PersistentObjectItf sp = (PersistentObjectItf) ce;
    try {
            sp.bind(pname);
        } catch (PException e) {
            logger.log(BasicLevel.WARN, "Error during the binding: ", e);
        }
  }
 
  public boolean isBound(CacheEntry ce) {
    return ((PersistentObjectItf) ce).speedoIsActive();
  }

    public boolean isToMerge(State state) {
        return ((StateItf) state).isToMerge();
    }
    public void makeToMerge(State state, Object thinLock) {
        ((StateItf) state).makeToMerge(thinLock);
    }
    public State merge(State oldState, State newState) {
        return ((StateItf) newState).merge(oldState);
    }

    public void stateNoMoreUsed(State state) {
        ((StateItf) state).unSwizzle();
    }
   
    // IMPLEMENTATION OF THE CacheEventListener INTERFACE //
  //----------------------------------------------------//

  /**
   * @param event
   */
  public void entryBound(CacheEvent event) {
  }

  /**
   * @param event
   */
  public void entryUnbound(CacheEvent event) {
      if (logger.isLoggable(BasicLevel.DEBUG)) {
          logger.log(BasicLevel.DEBUG, "Entry unbound from the cache: \n\tid: "
              + event.getCeIdentifier());
      }
      PName pn = (PName) event.getCeIdentifier();
      HomeItf sh = (HomeItf)
              ((PBinder) pn.getPNameManager()).getBinderClassMapping();
      sh.userCacheEntryUnbound(pn);
  }
 
  // IMPLEMENTATION OF THE CacheEntryFactory INTERFACE //
  //---------------------------------------------------//

  public int getCachingStrategy(Object o) {
    HomeItf home = getHome(o);
    if (home == null) {
      return CACHING_STRATEGY_CACHED;
    } else {
      return home.isCacheable()
        ? CACHING_STRATEGY_CACHED
        : CACHING_STRATEGY_NO_CACHE;
    }
  }

  /**
   * binds the PersistentObjectItf to its identifier (PName) if it does not have
   * already one.
   * @param id is the PName of the PersistentObjectItf
   * @param obj is the PersistentObjectItf instance added into the cache
   * @return the PersistentObjectItf instance
   */
  public FixableCacheEntry create(Object id, Object obj) {
    PersistentObjectItf sp =  (PersistentObjectItf) obj;
    PName pn = (PName) id;
    activePO(sp, pn);
    if (sp.getPName() == null || sp.getPName().isNull()) {
      try {
        pn.resolve(null);
        sp.bind(pn);
      } catch (PException e) {
        throw personality.newRuntimeException(
            "Impossible to bind the po to its persistent name: ", e);
      }
    }
    /**
     * else the entry is a new persistent object, the export created an
     * identifier
     */
    return (FixableCacheEntry) obj;
  }
}
TOP

Related Classes of org.objectweb.speedo.mim.lib.MemoryInstanceManagerImpl

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.