Package org.objectweb.speedo.mapper.lib

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

/**
* 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.jorm.api.PAccessor;
import org.objectweb.jorm.api.PBinding;
import org.objectweb.jorm.api.PException;
import org.objectweb.jorm.api.PExceptionNoDSI;
import org.objectweb.jorm.naming.api.PName;
import org.objectweb.perseus.persistence.api.ConnectionHolder;
import org.objectweb.perseus.persistence.api.NoDSIPersistenceException;
import org.objectweb.perseus.persistence.api.PersistenceException;
import org.objectweb.perseus.persistence.api.State;
import org.objectweb.perseus.persistence.api.StorageManager;
import org.objectweb.perseus.persistence.api.WorkingSet;
import org.objectweb.speedo.api.ExceptionHelper;
import org.objectweb.speedo.mapper.api.JormFactory;
import org.objectweb.speedo.mim.api.HomeItf;
import org.objectweb.speedo.mim.api.LifeCycle;
import org.objectweb.speedo.mim.api.PersistentObjectItf;
import org.objectweb.speedo.mim.api.StateItf;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;


/**
* This class is an implementation of the StorageManager interface based on
* Jorm.The single hypothesis concerns the architecture of the CacheEntry:
* - the CacheEntry implements the PBinding interface
* - the obj parameters implement StateItf and PAceessor.
*
* @author S.Chassande-Barrioz
*/
public class JormStorageManager
        implements StorageManager, BindingController {

    public final static String JORM_FACTORY_BINDING = "jorm-factory";
    public final static String LOGGER_NAME = "org.objectweb.jorm.storageManager";

    protected JormFactory jormFactory = null;

    protected Logger logger = null;

  /**
   * listes for each working set the persistent object removed in other
   * working set. When a working set want to read a persistent object from
   * the data support, a prefetch buffer can be used. But the prefetch buffer
   * can contains a removed object.
   */
  protected Map ws2removedpo = new HashMap();
 
    //IMPLEMENTATION OF THE UserBindingControler INTERFACE //
    //------------------------------------------------------//

    public String[] listFc() {
        return new String[] { JORM_FACTORY_BINDING };
    }

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

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

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


  //IMPLEMENTATION OF THE StorageManager INTERFACE //
  //-----------------------------------------------//

    public Object export(ConnectionHolder context, Object obj) throws PersistenceException {
        PBinding pb = (PBinding) obj;
        try {
            boolean flushed = false;
            if (pb.getStatus() == PBinding.LIFECYCLE_DELTOWRITE) {
                pb.write(context, (PAccessor)
                        context.getWorkingSet().lookup(pb.getPName()));
                flushed = true;
            }
            Object oid = pb.export(context);
            if (!flushed) {
                State s = context.getWorkingSet().lookup(oid);
                if (s != null) {
                    PBinding oldObj = (PBinding) s.getCacheEntry().getCeObject();
                    if (oldObj != obj) {
                        oldObj.write(context, (PAccessor) s);
                    }
                }
            }
            return oid;
        } catch (PException e) {
            throw new PersistenceException(e);
        }
    }

    public Object export(ConnectionHolder context, Object obj, Object hints) throws PersistenceException {
    PBinding pb = (PBinding) obj;
        try {
            boolean flushed = false;
            if (pb.getStatus() == PBinding.LIFECYCLE_DELTOWRITE) {
                pb.write(context, (PAccessor)
                        context.getWorkingSet().lookup(pb.getPName()));
                flushed = true;
            }
            Object oid = pb.export(context, hints);
            if (!flushed) {
                State s = context.getWorkingSet().lookup(oid);
                if (s != null) {
                    PBinding oldObj = (PBinding) s.getCacheEntry().getCeObject();
                    if (oldObj != obj) {
                        oldObj.write(context, (PAccessor) s);
                    }
                }
            }
            return oid;
        } catch (PException e) {
            throw new PersistenceException(e);
        }
    }

    public void unexport(ConnectionHolder context, Object oid) throws PersistenceException {
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG,
                    "unexport ctx=" + context + " / oid=" + oid);
        }
        try {
            ((PName) oid).unexport(context);
        } catch (PException e) {
            throw new PersistenceException(e);
        }
      registerUnexport(context.getWorkingSet(), oid);
    }

    public void unexport(ConnectionHolder context, Object oid, Object hints) throws PersistenceException {
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG,
                    "unexport(hints) ctx=" + context + " / oid=" + oid);
        }
        try {
            ((PName) oid).unexport(context, hints);
        } catch (PException e) {
            throw new PersistenceException(e);
        }
      registerUnexport(context.getWorkingSet(), oid);
    }

    public void read(ConnectionHolder context, Object oid, State obj) throws PersistenceException {
        if (logger.isLoggable(BasicLevel.DEBUG))
            logger.log(BasicLevel.DEBUG, "read ctx=" + context
                    + " / oid=" + oid
                    + " / obj.class=" + obj.getClass().getName());
        StateItf state = (StateItf) obj;
    PersistentObjectItf pb = (PersistentObjectItf) state.getSpeedoPO();
    int speedoStatus = state.speedoGetStatus();
    if (pb.getStatus() == PBinding.LIFECYCLE_DELTOWRITE
            && speedoStatus != LifeCycle.PERSISTENT_DELETED
            && speedoStatus != LifeCycle.PERSISTENT_NEW_DELETED) {
        throw new PersistenceException(
                "Concurrency problem, transaction must be rolledback");
    }
        try {
            pb.read(context, state);
            context.getWorkingSet().bind(state, oid, WorkingSet.UNKNOWN_INTENTION);
            //modified with rebind
            state.indexFieldModified(Integer.MAX_VALUE, true);
          pb.speedoGetHome().sendEvent(HomeItf.POST_LOAD, pb, null);
        } catch (PExceptionNoDSI e) {
      if (logger.isLoggable(BasicLevel.DEBUG)) {
              logger.log(BasicLevel.DEBUG, "read ==> NO DSI");
      }
      throw new NoDSIPersistenceException(e);
    } catch (PException e) {
            Exception ie = ExceptionHelper.getNested(e);
            logger.log(BasicLevel.ERROR, "read ctx=" + context
                      + " / oid=" + oid
                      + " / obj.class=" + obj.getClass().getName(), ie);
            throw new PersistenceException(ie);
        }
    }

    public void read(WorkingSet ws, Object oid, State obj, boolean forUpdate) throws PersistenceException {
        Object conn = ws.getConnectionHolder().getCHConnectionForRead();
    if (logger.isLoggable(BasicLevel.DEBUG))
            logger.log(BasicLevel.DEBUG, "read conn=" + conn
                    + " / oid=" + oid
                    + " / obj.class=" + obj.getClass().getName()
                    + " / tx=" + ws);
        StateItf state = (StateItf) obj;
    PersistentObjectItf pb = (PersistentObjectItf) state.getSpeedoPO();
    int speedoStatus = state.speedoGetStatus();
    if (pb.getStatus() == PBinding.LIFECYCLE_DELTOWRITE
            && speedoStatus != LifeCycle.PERSISTENT_DELETED
            && speedoStatus != LifeCycle.PERSISTENT_NEW_DELETED) {
        throw new PersistenceException(
                "Concurrency problem, transaction must be rolledback");
    }
    Object ctx = usePrefetchBuffer(ws, oid) ? ws : null;
        try {
            pb.read(conn, state, ctx, forUpdate);
            ws.bind(state, oid, WorkingSet.UNKNOWN_INTENTION);
            //modified with rebind
            state.indexFieldModified(Integer.MAX_VALUE, true);
          pb.speedoGetHome().sendEvent(HomeItf.POST_LOAD, pb, null);
    } catch (PExceptionNoDSI e) {
      if (logger.isLoggable(BasicLevel.DEBUG)) {
              logger.log(BasicLevel.DEBUG, "read ==> NO DSI");
      }
      throw new NoDSIPersistenceException(e);
        } catch (PException e) {
            Exception ie = ExceptionHelper.getNested(e);
            logger.log(BasicLevel.ERROR, "read conn=" + conn
                    + " / oid=" + oid
                    + " / obj.class=" + obj.getClass().getName()
                    + " / tx=" + ws, ie);
            throw new PersistenceException(ie);
        }
    }

    public void write(ConnectionHolder context, Object oid, State obj) throws PersistenceException {
    PersistentObjectItf pb = (PersistentObjectItf) obj.getCacheEntry();
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG, "write ctx=" + context
                    + " / oid=" + oid
                    + " / obj.class=" + obj.getClass().getName()
                    + " / binding.status=" + pb.getStatus());
        }
        int s = pb.getStatus();
      int preEvent = 0;
      int postEvent = 0;
      switch(s) {
      case  PBinding.LIFECYCLE_ACTIVEFORIO:
        preEvent = HomeItf.PRE_UPDATE;
        postEvent = HomeItf.POST_UPDATE;
        break;
      case  PBinding.LIFECYCLE_NEWTOWRITE:
        preEvent = HomeItf.PRE_CREATE;
        postEvent = HomeItf.POST_CREATE;
        break;
      case  PBinding.LIFECYCLE_DELTOWRITE:
        preEvent = HomeItf.PRE_DELETE;
        postEvent = HomeItf.POST_DELETE;
        break;
      }
         if (preEvent != 0 && postEvent != 0) {
          pb.speedoGetHome().sendEvent(preEvent, pb, null);
      try {
        pb.write(context, (PAccessor) obj);
      } catch (PExceptionNoDSI e) {
        throw new NoDSIPersistenceException(e);
      } catch (PException e) {
        throw new PersistenceException(e);
      }
             pb.speedoGetHome().sendEvent(postEvent, pb, null);
    }
    }

  public void beginWS(WorkingSet ws) {
    synchronized(ws2removedpo) {
      ws2removedpo.put(ws, new RemovedPOMemento(ws));
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "Begin of WS"
                        + "\n\t-ws=" + ws);
            }
    }
  }

  /**
   * forget the working set
   */
  public void endWS(WorkingSet ws) {
        final boolean debug = logger.isLoggable(BasicLevel.DEBUG);
      synchronized(ws2removedpo) {
        RemovedPOMemento mem = (RemovedPOMemento) ws2removedpo.remove(ws);
        StringBuffer sb = null;
        if (mem.removedPOFromWS != null) {
          for (Iterator it = ws2removedpo.values().iterator(); it.hasNext();) {
              RemovedPOMemento _mem = (RemovedPOMemento) it.next();
                  _mem.addRemovedPOFromOtherWS(mem.removedPOFromWS);
                  if (debug) {
                      if (sb == null) {
                          sb = new StringBuffer();
                          sb.append("Add\n\t-oids= ");
                          sb.append(mem.removedPOFromWS);
                      }
                      sb.append("\n\t-ws= " + _mem.ws);
                  }
          }               
                if (debug && sb != null) {
                    logger.log(BasicLevel.DEBUG,  sb.toString());
                }
            }
    }
  }

    private void registerUnexport(WorkingSet ws, Object oid) {
    synchronized(ws2removedpo) {
            RemovedPOMemento rpo = (RemovedPOMemento) ws2removedpo.get(ws);
            if (rpo != null) {
                rpo.registerRemovedPOFromWS(oid);
                if (logger.isLoggable(BasicLevel.DEBUG)) {
                    logger.log(BasicLevel.DEBUG, "Register the removed object:"
                            + "\n\t-oid=" + oid
                            + "\n\t-ws=" + ws);
                }
            } else {
                logger.log(BasicLevel.WARN,
                        "No POM registerd for adding the removed PO:"
                        + "\n\t-oid=" + oid
                        + "\n\t-ws=" + ws);
            }
    }
    }
   
  /**
   * check if the persistent object has not been removed in another context.
   * Indeed in case of Jorm uses prefetch buffers, the persistent object will
     * be loaded even if it has been removed from the data base.
   **/
    private boolean usePrefetchBuffer(WorkingSet ws, Object oid) {
    synchronized(ws2removedpo) {
            RemovedPOMemento rpo = (RemovedPOMemento) ws2removedpo.get(ws);
            if (rpo == null) {
                StringBuffer sb = new StringBuffer();
                sb.append("Internal Warning: No POM found for checking removed POs then Speedo does not use prefetchbuffer optimisation, and reloads data from the database");
                sb.append("\n\t-oid=").append(oid);
                sb.append("\n\t-ws=").append(ws);
                Exception e = new Exception(sb.toString());
                logger.log(BasicLevel.WARN, e.getMessage(), e);
                return false;
            } else {
                boolean res = !rpo.isRemoved(oid);
                if (logger.isLoggable(BasicLevel.DEBUG)) {
                    logger.log(BasicLevel.DEBUG,(res ? "": "NOT " ) + "USE prefetch buffer" 
                            + "\n\t-oid=" + oid
                            + "\n\t-ws= " + ws);
                }
                return res;
            }
    }       
    }
}
/**
* This structure registers the removed objects from a particular working set. 
* So an instance of this class has to be associated to a working set.
*
* @author S.Chassande-Barrioz
*/
class RemovedPOMemento {
    /**
     * contains the identifiers of persitent objects which have been removed
     * from the working set linked to this.
     * this field is used at the end of a working set to transmit the list of
     * removed object from this working set.
     */
    public HashSet removedPOFromWS = null;
   
    /**
     * contains the identifiers of persistent objects which have been removed
     * from the working set linked to this or from another working set.
     * this field is used to choose if it is possible to use a prefetch buffer
     * for a given identifier
     */
    public HashSet removedPO = null;
   
    public final WorkingSet ws;
   
    public RemovedPOMemento(WorkingSet _ws) {
        this.ws = _ws;
    }
   
    /**
     * register the unexport of a persistent object from the linked working set
     * @param oid is the identifier of the unexported persistent object
     */
    public void registerRemovedPOFromWS(Object oid) {
        if (removedPOFromWS == null) {
            removedPOFromWS = new HashSet();
        }
        removedPOFromWS.add(oid);
        if (removedPO == null) {
            removedPO = new HashSet();
        }
        removedPO.add(oid);
    }
   
    /**
     * Keeps in memory that persistent objects has been removed from another
     * working set
     * @param oids is the set of identifier of persistent object which have
     * been unexported in another working set.
     */
    public void addRemovedPOFromOtherWS(Set oids) {
        if (removedPO == null) {
            removedPO = new HashSet();
        }
        removedPO.addAll(oids);
    }
   
    /**
     * Indicates if a persistent object has been removed from the current
     * working set or another.
     * @param oid is the identifier of the persistent object  which could be
     * previously removed.
     */
    public boolean isRemoved(Object oid) {
        return removedPO != null && removedPO.contains(oid);
    }
}
TOP

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

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.