Package org.jboss.cache.interceptors

Source Code of org.jboss.cache.interceptors.ActivationInterceptor$ActivationModificationsBuilder

/*
* JBoss, Home of Professional Open Source.
* Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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.1 of
* the License, or (at your option) any later version.
*
* This software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.cache.interceptors;

import org.jboss.cache.Fqn;
import org.jboss.cache.InternalNode;
import org.jboss.cache.InvocationContext;
import org.jboss.cache.Modification;
import org.jboss.cache.commands.AbstractVisitor;
import org.jboss.cache.commands.read.GetChildrenNamesCommand;
import org.jboss.cache.commands.read.GetKeyValueCommand;
import org.jboss.cache.commands.read.GetKeysCommand;
import org.jboss.cache.commands.read.GetNodeCommand;
import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
import org.jboss.cache.commands.tx.PrepareCommand;
import org.jboss.cache.commands.write.ClearDataCommand;
import org.jboss.cache.commands.write.MoveCommand;
import org.jboss.cache.commands.write.PutDataMapCommand;
import org.jboss.cache.commands.write.PutForExternalReadCommand;
import org.jboss.cache.commands.write.PutKeyValueCommand;
import org.jboss.cache.commands.write.RemoveKeyCommand;
import org.jboss.cache.commands.write.RemoveNodeCommand;
import org.jboss.cache.factories.annotations.Inject;
import org.jboss.cache.factories.annotations.Start;
import org.jboss.cache.jmx.annotations.ManagedAttribute;
import org.jboss.cache.jmx.annotations.ManagedOperation;
import org.jboss.cache.transaction.GlobalTransaction;
import org.jboss.cache.transaction.TransactionContext;

import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
* Loads nodes that don't exist at the time of the call into memory from the CacheLoader.
* If the nodes were evicted earlier then we remove them from the cache loader after
* their attributes have been initialized and their children have been loaded in memory.
*
* @author <a href="mailto:{hmesha@novell.com}">{Hany Mesha}</a>
* @version $Id: ActivationInterceptor.java 6776 2008-09-22 17:35:46Z manik.surtani@jboss.com $
*/
public class ActivationInterceptor extends CacheLoaderInterceptor
{

   protected TransactionManager txMgr = null;
   private long activations = 0;
   ActivationModificationsBuilder builder;

   /**
    * List<Transaction> that we have registered for
    */
   protected ConcurrentHashMap transactions = new ConcurrentHashMap(16);
   protected static final Object NULL = new Object();

   public ActivationInterceptor()
   {
      isActivation = true;
      useCacheStore = false;
   }

   @Inject
   public void injectTransactionManager(TransactionManager txMgr)
   {
      this.txMgr = txMgr;
   }

   @Start
   public void createModificationsBuilder()
   {
      builder = new ActivationModificationsBuilder();
   }

   @Override
   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
   {
      Object returnValue = super.visitClearDataCommand(ctx, command);
      if (trace)
         log.trace("This is a remove data operation; removing the data from the loader, no activation processing needed.");
      loader.removeData(command.getFqn());
      return returnValue;
   }

   @Override
   public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand command) throws Throwable
   {
      Object returnValue = super.visitRemoveNodeCommand(ctx, command);
      if (trace)
         log.trace("This is a remove operation; removing the node from the loader, no activation processing needed.");
      loader.remove(command.getFqn());
      return returnValue;
   }

   @Override
   public Object visitGetChildrenNamesCommand(InvocationContext ctx, GetChildrenNamesCommand command) throws Throwable
   {
      Object returnValue = super.visitGetChildrenNamesCommand(ctx, command);
      removeNodeFromCacheLoader(command.getFqn());
      return returnValue;
   }

   @Override
   public Object visitGetKeysCommand(InvocationContext ctx, GetKeysCommand command) throws Throwable
   {
      Object returnValue = super.visitGetKeysCommand(ctx, command);
      removeNodeFromCacheLoader(command.getFqn());
      return returnValue;
   }

   @Override
   public Object visitGetNodeCommand(InvocationContext ctx, GetNodeCommand command) throws Throwable
   {
      Object returnValue = super.visitGetNodeCommand(ctx, command);
      removeNodeFromCacheLoader(command.getFqn());
      return returnValue;
   }

   @Override
   public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable
   {
      Object returnValue = super.visitGetKeyValueCommand(ctx, command);
      removeNodeFromCacheLoader(command.getFqn());
      return returnValue;
   }

   @Override
   public Object visitPutForExternalReadCommand(InvocationContext ctx, PutForExternalReadCommand command) throws Throwable
   {
      return visitPutKeyValueCommand(ctx, command);
   }

   @Override
   public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
   {
      Object returnValue = super.visitPutKeyValueCommand(ctx, command);
      removeNodeFromCacheLoader(command.getFqn());
      return returnValue;
   }

   @Override
   public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
   {
      Object returnValue = super.visitPutDataMapCommand(ctx, command);
      removeNodeFromCacheLoader(command.getFqn());
      return returnValue;
   }

   @Override
   public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable
   {
      Object returnValue = super.visitRemoveKeyCommand(ctx, command);
      removeNodeFromCacheLoader(command.getFqn());
      return returnValue;
   }

   @Override
   public Object visitMoveCommand(InvocationContext ctx, MoveCommand command) throws Throwable
   {
      Object returnValue = super.visitMoveCommand(ctx, command);
      if (trace)
         log.trace("This is a move operation; removing the FROM node from the loader, no activation processing needed.");
      loader.remove(command.getFqn());
      removeNodeFromCacheLoader(command.getFqn().getParent());
      removeNodeFromCacheLoader(command.getTo());
      return returnValue;
   }


   /**
    * Remove the node from the cache loader if it exists in memory,
    * its attributes have been initialized, its children have been loaded,
    * AND it was found in the cache loader (nodeLoaded = true).
    * Then notify the listeners that the node has been activated.
    */
   private void removeNodeFromCacheLoader(Fqn fqn) throws Throwable
   {
      if (fqn == null) return;
      InternalNode n;
      if (((n = dataContainer.peekInternalNode(fqn, true)) != null) && n.isDataLoaded() && loader.exists(fqn))
      {
         // node not null and attributes have been loaded?
         if (n.hasChildren())
         {
            boolean result = childrenLoaded(n);
            if (result)
            {
               log.debug("children all initialized");
               remove(fqn);
            }
         }
         else if (loaderNoChildren(fqn))
         {
            if (log.isDebugEnabled()) log.debug("no children " + n);
            remove(fqn);
         }
      }
   }

   private boolean childrenLoaded(InternalNode<?, ?> node)
   {
      if (!node.isChildrenLoaded())
      {
         return false;
      }
      for (InternalNode child : node.getChildren())
      {
         if (!child.isDataLoaded())
         {
            return false;
         }

         if (child.hasChildren())
         {
            if (!childrenLoaded(child))
               return false;
         }
         else if (!loaderNoChildren(child.getFqn()))
         {
            return false;
         }
      }
      return true;

   }

   @Override
   public Object visitOptimisticPrepareCommand(InvocationContext ctx, OptimisticPrepareCommand command) throws Throwable
   {
      Object retval = invokeNextInterceptor(ctx, command);
      if (inTransaction())
      {
         prepareCacheLoader(ctx);
      }
      return retval;
   }

   private boolean inTransaction() throws SystemException
   {
      return txMgr != null && txMgr.getTransaction() != null;
   }

   @Override
   public Object visitPrepareCommand(InvocationContext ctx, PrepareCommand command) throws Throwable
   {
      Object retval = invokeNextInterceptor(ctx, command);
      if (inTransaction())
      {
         prepareCacheLoader(ctx);
      }
      return retval;
   }

   private void remove(Fqn fqn) throws Exception
   {
      loader.remove(fqn);
      if (getStatisticsEnabled()) activations++;
   }

   /**
    * Returns true if the loader indicates no children for this node.
    * Return false on error.
    */
   private boolean loaderNoChildren(Fqn fqn)
   {
      try
      {
         Set childrenNames = loader.getChildrenNames(fqn);
         return (childrenNames == null);
      }
      catch (Exception e)
      {
         log.error("failed getting the children names for " + fqn + " from the cache loader", e);
         return false;
      }
   }

   private void prepareCacheLoader(InvocationContext ctx) throws Throwable
   {
      GlobalTransaction gtx = ctx.getGlobalTransaction();
      TransactionContext tCtx = ctx.getTransactionContext();
      if (tCtx == null)
      {
         throw new Exception("tCtx for transaction " + gtx + " not found in transaction table");
      }
      List<Modification> cacheLoaderModifications = new ArrayList<Modification>();

      builder.visitCollection(ctx, tCtx.getModifications());
      if (cacheLoaderModifications.size() > 0)
      {
         loader.prepare(gtx, cacheLoaderModifications, false);
      }
   }

   public class ActivationModificationsBuilder extends AbstractVisitor
   {

      private List<Modification> cacheLoaderModifications = new ArrayList<Modification>();

      private int txActs = 0;

      @Override
      public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand removeNodeCommand) throws Throwable
      {
         Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, removeNodeCommand.getFqn());
         cacheLoaderModifications.add(mod);
         return null;
      }

      @Override
      public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
      {
         Fqn fqn = command.getFqn();
         handlePutCommand(ctx, fqn);
         return null;
      }

      @Override
      public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
      {
         Fqn fqn = command.getFqn();
         handlePutCommand(ctx, fqn);
         return null;
      }

      // On the way out, remove the node from the cache loader.
      // Only remove the node if it exists in memory, its attributes have
      // been initialized, its children have been loaded
      // AND it was found in the cache loader (nodeLoaded = true).
      // Then notify the listeners that the node has been activated.
      private void handlePutCommand(InvocationContext ctx, Fqn fqn)
            throws Exception
      {
         if (fqn != null && dataContainer.exists(fqn) && loader.exists(fqn))
         {
            InternalNode n = dataContainer.peekInternalNode(fqn, true);// don't load
            // node not null and attributes have been loaded?
            if (n != null && n.isDataLoaded())
            {
               // has children?
               boolean result = childrenLoaded(n);
               if (n.hasChildren() && result)
               {
                  // children have been loaded, remove the node
                  addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getData());
                  txActs++;
               }
               // doesn't have children, check the cache loader
               else if (loaderNoChildren(fqn))
               {
                  addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getData());
                  txActs++;
               }
            }
         }
      }

      private boolean loaderNoChildren(Fqn fqn) throws Exception
      {
         return loader.getChildrenNames(fqn) != null;
      }

      private void addRemoveMod(InvocationContext ctx, List<Modification> l, Fqn fqn, Map data)
      {
         Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, fqn);
         l.add(mod);
         notifier.notifyNodeActivated(fqn, false, data, ctx);
      }

      public List<Modification> getCacheLoaderModifications()
      {
         return cacheLoaderModifications;
      }

      public int getTxActs()
      {
         return txActs;
      }

   }

   @ManagedAttribute(description = "number of cache node activations")
   public long getActivations()
   {
      return activations;
   }

   @ManagedOperation
   public void resetStatistics()
   {
      super.resetStatistics();
      activations = 0;
   }

   @ManagedOperation
   public Map<String, Object> dumpStatistics()
   {
      Map<String, Object> retval = super.dumpStatistics();
      if (retval == null)
      {
         retval = new HashMap<String, Object>();
      }
      retval.put("Activations", activations);
      return retval;
   }
}
TOP

Related Classes of org.jboss.cache.interceptors.ActivationInterceptor$ActivationModificationsBuilder

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.