[jbosscache-commits] JBoss Cache SVN: r6247 - in core/trunk/src: main/java/org/jboss/cache/config/parsing and 10 other directories.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Fri Jul 11 06:14:00 EDT 2008


Author: mircea.markus
Date: 2008-07-11 06:14:00 -0400 (Fri, 11 Jul 2008)
New Revision: 6247

Added:
   core/trunk/src/main/java/org/jboss/cache/config/parsing/element/CustomInterceptorsElementParser.java
   core/trunk/src/test/java/org/jboss/cache/config/parsing/CustomInterceptorsElementParserTest.java
   core/trunk/src/test/java/org/jboss/cache/config/parsing/custominterceptors/
   core/trunk/src/test/java/org/jboss/cache/config/parsing/custominterceptors/AaaCustomInterceptor.java
   core/trunk/src/test/java/org/jboss/cache/config/parsing/custominterceptors/BbbCustomInterceptor.java
   core/trunk/src/test/java/org/jboss/cache/config/parsing/custominterceptors/WrongCustomInterceptor.java
   core/trunk/src/test/java/org/jboss/cache/factories/CustomInterceptorConstructionTest.java
Modified:
   core/trunk/src/main/java/org/jboss/cache/config/Configuration.java
   core/trunk/src/main/java/org/jboss/cache/config/CustomInterceptorConfig.java
   core/trunk/src/main/java/org/jboss/cache/config/EvictionConfig.java
   core/trunk/src/main/java/org/jboss/cache/config/parsing/XmlConfigHelper.java
   core/trunk/src/main/java/org/jboss/cache/config/parsing/XmlConfigurationParser.java
   core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/InterceptorChain.java
   core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
   core/trunk/src/main/resources/all-elements-file-3.x.xml
   core/trunk/src/main/resources/jbosscache-config-3.0.xsd
   core/trunk/src/test/java/org/jboss/cache/config/parsing/EvictionElementParserTest.java
   core/trunk/src/test/java/org/jboss/cache/config/parsing/XmlConfigurationParserTest.java
   core/trunk/src/test/java/org/jboss/cache/invocation/InterceptorChainTest.java
   core/trunk/src/test/resources/configs/parser-test.xml
Log:
added custom interceptors support

Modified: core/trunk/src/main/java/org/jboss/cache/config/Configuration.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/config/Configuration.java	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/main/java/org/jboss/cache/config/Configuration.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -924,11 +924,19 @@
       this.muxStackName = muxStackName;
    }
 
+   /**
+    * Returns the {@link org.jboss.cache.config.CustomInterceptorConfig}, if any, associated with this configuration
+    * object. The custom interceptors will be added to the cache at startup in the sequence defined by this list.
+    * @return List of cutom interceptors, never null
+    */
    public List<CustomInterceptorConfig> getCustomInterceptors()
    {
-      return customInterceptors;
+      return customInterceptors == null ? Collections.EMPTY_LIST : customInterceptors;
    }
 
+   /**
+    * @see #getCustomInterceptors()
+    */
    public void setCustomInterceptors(List<CustomInterceptorConfig> customInterceptors)
    {
       testImmutability("customInterceptors");

Modified: core/trunk/src/main/java/org/jboss/cache/config/CustomInterceptorConfig.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/config/CustomInterceptorConfig.java	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/main/java/org/jboss/cache/config/CustomInterceptorConfig.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -1,83 +1,156 @@
 package org.jboss.cache.config;
 
 import net.jcip.annotations.Immutable;
+import org.jboss.cache.interceptors.base.CommandInterceptor;
 
-import java.io.Serializable;
-import java.util.Properties;
-import java.util.Collections;
-import java.util.Map;
-
 /**
  * Holds information about the custom interceptors defined in the configuration file.
- * todo : As a tip on your CustomInterceptorConfig, you should consider extending ConfigurationComponent which gives you a lot of the basic stuff you need. 
  *
  * @author Mircea.Markus at jboss.com
  * @since 3.0
  */
- at Immutable 
-public class CustomInterceptorConfig implements Cloneable, Serializable
+ at Immutable
+public class CustomInterceptorConfig extends ConfigurationComponent
 {
-   private String interceptorClass;
+   private CommandInterceptor interceptor;
    private boolean isFirst;
    private boolean isLast;
    private int index = -1;
    private String afterClass;
    private String beforeClass;
-   private Map properties;
 
-   public CustomInterceptorConfig(String interceptorClass, boolean first, boolean last, int index, String afterClass, String beforeClass, Properties props)
+   /**
+    * Builds a custom interceptor.
+    *
+    * @param interceptor interceptor instance, already initialized with all attributes specified in the configuration
+    * @param first true if you wan this to be the first interceptor in the chain
+    * @param last true if you wan this to be the last interceptor in the chain
+    * @param index an absolute position within the interceptor chain
+    * @param afterClass if you want this interceptor immediately after the specified class in the chain
+    * @param beforeClass immediately before the specified class in the chain
+    */
+   public CustomInterceptorConfig(CommandInterceptor interceptor, boolean first, boolean last, int index,
+                                  String afterClass, String beforeClass)
    {
-      this.interceptorClass = interceptorClass;
+      this.interceptor = interceptor;
       isFirst = first;
       isLast = last;
       this.index = index;
       this.afterClass = afterClass;
       this.beforeClass = beforeClass;
-      this.properties = Collections.unmodifiableMap(props);
    }
 
-   public String getInterceptorClass()
+   /**
+    * Constructs an interceptor config based on the supplied interceptor instance.
+    * 
+    * @param interceptor
+    */
+   public CustomInterceptorConfig(CommandInterceptor interceptor)
    {
-      return interceptorClass;
+      this.interceptor = interceptor;
    }
 
+   /**
+    * Shall this interceptor be the first one in the chain?
+    */
+   public void setFirst(boolean first)
+   {
+      testImmutability("first");
+      isFirst = first;
+   }
+
+   /**
+    * Shall this intercepto be the last one in the chain?
+    */
+   public void setLast(boolean last)
+   {
+      testImmutability("last");
+      isLast = last;
+   }
+
+   /**
+    * Put this interceptor at the specified index, after the default chain is built.
+    * If the index is not valid (negative or grater than the size of the chain)
+    * an {@link org.jboss.cache.config.ConfigurationException} is thrown at construction time.
+    */
+   public void setIndex(int index)
+   {
+      testImmutability("index");
+      this.index = index;
+   }
+
+   /**
+    * Adds the interceptor immediately after the first occurance of an interceptor having the given class.
+    * If the chain does not contain such an interceptor then this interceptor definition is ignored.
+    */
+   public void setAfterClass(String afterClass)
+   {
+      testImmutability("afterClass");
+      this.afterClass = afterClass;
+   }
+
+   /**
+    * Adds the interceptor immediately before the first occurance of an interceptor having the given class.
+    * If the chain does not contain such an interceptor then this interceptor definition is ignored.
+    */
+   public void setBeforeClass(String beforeClass)
+   {
+      testImmutability("beforeClass");
+      this.beforeClass = beforeClass;
+   }
+
+   /**
+    * Returns a the interceptor that we want to add to the chain.
+    */
+   public CommandInterceptor getInterceptor()
+   {
+      return interceptor;
+   }
+
+   /**
+    * @see #setFirst(boolean) 
+    */
    public boolean isFirst()
    {
       return isFirst;
    }
 
+   /**
+    * @see #setLast(boolean) 
+    */
    public boolean isLast()
    {
       return isLast;
    }
 
+   /**
+    * @see #getIndex() 
+    */
    public int getIndex()
    {
       return index;
    }
 
+   /**
+    * @see #getAfterClass() 
+    */
    public String getAfterClass()
    {
       return afterClass;
    }
 
+   /**
+    * @see #getBeforeClass() 
+    */
    public String getBeforeClass()
    {
       return beforeClass;
    }
 
-   /**
-    * Returns an unmodifiable map of set properties.
-    */
-   public Map getProperties()
-   {
-      return properties;
-   }
-
    public String toString()
    {
       return "CustomInterceptorConfig{" +
-            "interceptorClass='" + interceptorClass + '\'' +
+            "interceptor='" + interceptor + '\'' +
             ", isFirst=" + isFirst +
             ", isLast=" + isLast +
             ", index=" + index +
@@ -98,36 +171,32 @@
       if (isLast != that.isLast) return false;
       if (afterClass != null ? !afterClass.equals(that.afterClass) : that.afterClass != null) return false;
       if (beforeClass != null ? !beforeClass.equals(that.beforeClass) : that.beforeClass != null) return false;
-      if (interceptorClass != null ? !interceptorClass.equals(that.interceptorClass) : that.interceptorClass != null)
+      if (interceptor != null ? !interceptor.equals(that.interceptor) : that.interceptor != null)
          return false;
-      if (properties != null ? !properties.equals(that.properties) : that.properties != null) return false;
-
       return true;
    }
 
    public int hashCode()
    {
       int result;
-      result = (interceptorClass != null ? interceptorClass.hashCode() : 0);
+      result = (interceptor != null ? interceptor.hashCode() : 0);
       result = 31 * result + (isFirst ? 1 : 0);
       result = 31 * result + (isLast ? 1 : 0);
       result = 31 * result + index;
       result = 31 * result + (afterClass != null ? afterClass.hashCode() : 0);
       result = 31 * result + (beforeClass != null ? beforeClass.hashCode() : 0);
-      result = 31 * result + (properties != null ? properties.hashCode() : 0);
       return result;
    }
 
    @Override
-   protected Object clone() throws CloneNotSupportedException
+   public CustomInterceptorConfig clone() throws CloneNotSupportedException
    {
       CustomInterceptorConfig dolly = (CustomInterceptorConfig) super.clone();
-      dolly.interceptorClass = interceptorClass;
+      dolly.interceptor = interceptor;
       dolly.isFirst = isFirst;
       dolly.isLast = isLast;
       dolly.afterClass = afterClass;
       dolly.beforeClass = beforeClass;
-      dolly.properties = properties;
       return dolly;
    }
 }

Modified: core/trunk/src/main/java/org/jboss/cache/config/EvictionConfig.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/config/EvictionConfig.java	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/main/java/org/jboss/cache/config/EvictionConfig.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -178,6 +178,7 @@
 
    /**
     * Use {@link #getWakeupIntervalSeconds()}.
+    * todo mmarkus remove all the references of this method from the code
     */
    @Deprecated
    public int getWakeupIntervalSeconds()

Modified: core/trunk/src/main/java/org/jboss/cache/config/parsing/XmlConfigHelper.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/config/parsing/XmlConfigHelper.java	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/main/java/org/jboss/cache/config/parsing/XmlConfigHelper.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -155,14 +155,6 @@
    }
 
    /**
-    * Convenience method, equivalent to calling <tt>getSubElement(element, "config");</tt>
-    */
-   public static Element getConfigSubElement(Element element)
-   {
-      return getSubElement(element, CONFIG_ATTR);
-   }
-
-   /**
     * Returns a named sub-element of the current element passed in.
     * <p/>
     * None of the parameters should be null - otherwise the method may throw a NullPointerException.
@@ -471,6 +463,7 @@
             throw new ConfigurationException("Unable to invoke setter " + setter + " on " + objectClass, e);
          }
 
+         boolean setterFound = false;
          // if we get here, we could not find a String or Element setter.
          for (Method m : objectClass.getMethods())
          {
@@ -497,6 +490,7 @@
                try
                {
                   m.invoke(target, parameter);
+                  setterFound = true;
                }
                catch (Exception e)
                {
@@ -504,6 +498,7 @@
                }
             }
          }
+         if (!setterFound) throw new ConfigurationException("Couldn't find a setter method for parameter " + propName);
       }
    }
 
@@ -529,15 +524,14 @@
          if (valueStr.length() == 0)
          {
             // This may be an XML element ...
-            valueXml = getConfigSubElement(element);
+            valueXml = getSubElement(element, CONFIG_ATTR);
+            if (valueXml != null) xmlAttribs.put(name, valueXml);
          }
-
-         // add these to the maps.
-
-         if (valueStr.length() > 0) stringAttribs.put(name, valueStr);
-         if (valueXml != null) xmlAttribs.put(name, valueXml);
+         else
+         {
+            if (valueStr.length() > 0) stringAttribs.put(name, valueStr);
+         }
       }
-
       return new ParsedAttributes(stringAttribs, xmlAttribs);
    }
 }

Modified: core/trunk/src/main/java/org/jboss/cache/config/parsing/XmlConfigurationParser.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/config/parsing/XmlConfigurationParser.java	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/main/java/org/jboss/cache/config/parsing/XmlConfigurationParser.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -27,6 +27,7 @@
 import org.jboss.cache.config.parsing.element.BuddyElementParser;
 import org.jboss.cache.config.parsing.element.EvictionElementParser;
 import org.jboss.cache.config.parsing.element.LoadersElementParser;
+import org.jboss.cache.config.parsing.element.CustomInterceptorsElementParser;
 import org.jboss.cache.lock.IsolationLevel;
 import org.jboss.cache.util.FileLookup;
 import org.w3c.dom.Document;
@@ -224,29 +225,9 @@
    private void configureCustomInterceptors(Element element)
    {
       if (element == null) return; //this element might be missing
-      NodeList interceptorNodes = element.getElementsByTagName("interceptor");
-      List<CustomInterceptorConfig> interceptorConfigs = new ArrayList<CustomInterceptorConfig>(interceptorNodes.getLength());
-      for (int i = 0; i < interceptorNodes.getLength(); i++)
-      {
-         Element interceptorElement = (Element) interceptorNodes.item(i);
-         String interceptorClass = getAttributeValue(interceptorElement, "class");
-         Properties props = XmlConfigHelper.readPropertiesContents(interceptorElement, "properties");
-         Element position = getSingleElement("position", interceptorElement);
-         String firstStr = getAttributeValue(position, "first");
-         boolean first = existsAttribute(firstStr) && getBoolean(firstStr);
-         String lastStr = getAttributeValue(position, "last");
-         boolean last = existsAttribute(lastStr) && getBoolean(lastStr);
-         String indexStr = getAttributeValue(position, "index");
-         int index = existsAttribute(indexStr) ? getInt(indexStr) : -1;
-         String before = getAttributeValue(position, "before");
-         if (!existsAttribute(before)) before = null;
-         String after = getAttributeValue(position, "after");
-         if (!existsAttribute(after)) after = null;
-         CustomInterceptorConfig customInterceptorConfig = new CustomInterceptorConfig(interceptorClass, first, last,
-               index, after, before, props);
-         interceptorConfigs.add(customInterceptorConfig);
-      }
-      config.setCustomInterceptors(interceptorConfigs);
+      CustomInterceptorsElementParser parser = new CustomInterceptorsElementParser();
+      List<CustomInterceptorConfig> interceptorConfigList = parser.parseCustomInterceptors(element);
+      config.setCustomInterceptors(interceptorConfigList);
    }
 
    private void configureBuddyReplication(Element element)

Added: core/trunk/src/main/java/org/jboss/cache/config/parsing/element/CustomInterceptorsElementParser.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/config/parsing/element/CustomInterceptorsElementParser.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/config/parsing/element/CustomInterceptorsElementParser.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -0,0 +1,112 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt 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.config.parsing.element;
+
+import org.jboss.cache.config.CustomInterceptorConfig;
+import org.jboss.cache.config.ConfigurationException;
+import org.jboss.cache.config.parsing.XmlParserBase;
+import org.jboss.cache.config.parsing.ParsedAttributes;
+import org.jboss.cache.config.parsing.XmlConfigHelper;
+import org.jboss.cache.interceptors.base.CommandInterceptor;
+import org.jboss.cache.util.Util;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class for parsing 'buddy' element in the .xml configuration file.
+ * <pre>
+ * Note: class does not rely on element position in the configuration file.
+ *       It does not rely on element's name either.
+ * </pre>
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 3.0
+ */
+public class CustomInterceptorsElementParser extends XmlParserBase
+{
+   /**
+    * Iterates within the given element looking for custom interceptors.
+    *
+    * @param element should not be null
+    * @return a list which might be empty, never null
+    */
+   public List<CustomInterceptorConfig> parseCustomInterceptors(Element element)
+   {
+      NodeList interceptorNodes = element.getElementsByTagName("interceptor");
+      List<CustomInterceptorConfig> interceptorConfigs = new ArrayList<CustomInterceptorConfig>(interceptorNodes.getLength());
+      for (int i = 0; i < interceptorNodes.getLength(); i++)
+      {
+         boolean first = false;
+         boolean last = false;
+         int index = -1;
+         String after = null;
+         String before = null;
+         
+         Element interceptorElement = (Element) interceptorNodes.item(i);
+         String position = getAttributeValue(interceptorElement, "position");
+         if (existsAttribute(position) && "first".equalsIgnoreCase(position))
+         {
+            first = true;
+         }
+         if (existsAttribute(position) && "last".equalsIgnoreCase(position))
+         {
+            last = true;
+         }
+         String indexStr = getAttributeValue(interceptorElement, "index");
+         index = existsAttribute(indexStr) ? getInt(indexStr) : -1;
+
+         before = getAttributeValue(interceptorElement, "before");
+         if (!existsAttribute(before)) before = null;
+         after = getAttributeValue(interceptorElement, "after");
+         if (!existsAttribute(after)) after = null;
+
+         CommandInterceptor interceptor = buildCommandInterceptor(interceptorElement);
+         
+         CustomInterceptorConfig customInterceptorConfig = new CustomInterceptorConfig(interceptor, first, last, index, after, before);
+         interceptorConfigs.add(customInterceptorConfig);
+      }
+      return interceptorConfigs;
+   }
+
+   /**
+    * Builds the interceptor based on the interceptor class and also sets all its attributes.
+    */
+   private CommandInterceptor buildCommandInterceptor(Element element)
+   {
+      String interceptorClass = getAttributeValue(element, "class");
+      CommandInterceptor result;
+      try
+      {
+         result = (CommandInterceptor) Util.loadClass(interceptorClass).newInstance();
+      }
+      catch (Exception e)
+      {
+         throw new ConfigurationException("CommandInterceptor class is not properly loaded in classloader", e);
+      }
+      ParsedAttributes attributes = XmlConfigHelper.extractAttributes(element);
+      XmlConfigHelper.setValues(result, attributes.stringAttribs, false);
+      return result;
+   }
+}

Modified: core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -9,10 +9,13 @@
 import org.jboss.cache.config.Configuration;
 import org.jboss.cache.config.Configuration.NodeLockingScheme;
 import org.jboss.cache.config.ConfigurationException;
+import org.jboss.cache.config.CustomInterceptorConfig;
 import org.jboss.cache.factories.annotations.DefaultFactoryFor;
 import org.jboss.cache.interceptors.*;
 import org.jboss.cache.interceptors.base.CommandInterceptor;
 
+import java.util.List;
+
 /**
  * Factory class that builds an interceptor chain based on cache configuration.
  *
@@ -138,10 +141,45 @@
       if (optimistic) interceptorChain.appendIntereceptor(createInterceptor(OptimisticNodeInterceptor.class));
       CommandInterceptor callInterceptor = createInterceptor(CallInterceptor.class);
       interceptorChain.appendIntereceptor(callInterceptor);
-      if (log.isTraceEnabled()) log.trace("Finished building interceptor chain.");
+      if (log.isTraceEnabled()) log.trace("Finished building default interceptor chain.");
+      buildCustomInterceptors(interceptorChain, configuration.getCustomInterceptors());
       return interceptorChain;
    }
 
+   private void buildCustomInterceptors(InterceptorChain interceptorChain, List<CustomInterceptorConfig> customInterceptors)
+   {
+      for (CustomInterceptorConfig config : customInterceptors)
+      {
+         if (interceptorChain.containsInstance(config.getInterceptor())) continue;
+         if (config.isFirst())
+         {
+            interceptorChain.addInterceptor(config.getInterceptor(),0);
+         }
+         if (config.isLast()) interceptorChain.appendIntereceptor(config.getInterceptor());
+         if (config.getIndex() >= 0) interceptorChain.addInterceptor(config.getInterceptor(), config.getIndex());
+         if (config.getAfterClass() != null)
+         {
+            List<CommandInterceptor> withClassName = interceptorChain.getInterceptorsWithClassName(config.getAfterClass());
+            if (withClassName.isEmpty())
+            {
+               throw new ConfigurationException("Cannot add after class: " + config.getAfterClass()
+                     + " as no such iterceptor exists in the default chain");
+            }
+            interceptorChain.addAfterInterceptor(config.getInterceptor(), withClassName.get(0).getClass());
+         }
+         if (config.getBeforeClass() != null)
+         {
+            List<CommandInterceptor> withClassName = interceptorChain.getInterceptorsWithClassName(config.getBeforeClass());
+            if (withClassName.isEmpty())
+            {
+               throw new ConfigurationException("Cannot add before class: " + config.getAfterClass()
+                     + " as no such iterceptor exists in the default chain");
+            }
+            interceptorChain.addBeforeInterceptor(config.getInterceptor(), withClassName.get(0).getClass());
+         }
+      }
+   }
+
    @Override
    @SuppressWarnings("unchecked")
    protected <T> T construct(Class<T> componentType)

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/InterceptorChain.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/InterceptorChain.java	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/InterceptorChain.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -21,6 +21,8 @@
  *
  * @author Mircea.Markus at jboss.com
  * @since 2.2
+ *        todo - if you add the same interceptor instance twice, things get really dirty.
+ *        -- this should be treated as an missuse and an exception should be thrown
  */
 public class InterceptorChain
 {
@@ -175,7 +177,7 @@
     *
     * @return true if the interceptor was added; i.e. the afterInterceptor exists
     */
-   public synchronized boolean addInterceptor(CommandInterceptor toAdd, Class<? extends CommandInterceptor> afterInterceptor)
+   public synchronized boolean addAfterInterceptor(CommandInterceptor toAdd, Class<? extends CommandInterceptor> afterInterceptor)
    {
       CommandInterceptor it = firstInChain;
       while (it != null)
@@ -192,6 +194,33 @@
    }
 
    /**
+    * Adds a new interceptor in list after an interceptor of a given type.
+    *
+    * @return true if the interceptor was added; i.e. the afterInterceptor exists
+    */
+   public synchronized boolean addBeforeInterceptor(CommandInterceptor toAdd, Class<? extends CommandInterceptor> beforeInterceptor)
+   {
+      if (firstInChain.getClass().equals(beforeInterceptor))
+      {
+         toAdd.setNext(firstInChain);
+         firstInChain = toAdd;
+         return true;
+      }
+      CommandInterceptor it = firstInChain;
+      while (it.getNext() != null)
+      {
+         if (it.getNext().getClass().equals(beforeInterceptor))
+         {
+            toAdd.setNext(it.getNext());
+            it.setNext(toAdd);
+            return true;
+         }
+         it = it.getNext();
+      }
+      return false;
+   }
+
+   /**
     * Appends at the end.
     */
    public void appendIntereceptor(CommandInterceptor ci)
@@ -289,10 +318,39 @@
       return result;
    }
 
+   /**
+    * Returns all the interceptors that have the fully qualified name of their class equal with the supplied class name.
+    */
+   public List<CommandInterceptor> getInterceptorsWithClassName(String fqName)
+   {
+      CommandInterceptor iterator = firstInChain;
+      List<CommandInterceptor> result = new ArrayList<CommandInterceptor>(2);
+      while (iterator != null)
+      {
+         if (iterator.getClass().getName().equals(fqName)) result.add(iterator);
+         iterator = iterator.getNext();
+      }
+      return result;
+   }
+
    public String toString()
    {
       return "InterceptorChain{\n" +
             CachePrinter.printInterceptorChain(firstInChain) +
             "\n}";
    }
+
+   /**
+    * Checks whether the chain contains the supplied interceptor instance.
+    */
+   public boolean containsInstance(CommandInterceptor interceptor)
+   {
+      CommandInterceptor it = firstInChain;
+      while (it != null)
+      {
+         if (it == interceptor) return true;
+         it = it.getNext();
+      }
+      return false;
+   }
 }

Modified: core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -132,7 +132,7 @@
 
    public void addInterceptor(CommandInterceptor i, Class<? extends CommandInterceptor> afterInterceptor)
    {
-      invoker.addInterceptor(i, afterInterceptor);
+      invoker.addAfterInterceptor(i, afterInterceptor);
    }
 
    public List<CommandInterceptor> getInterceptorChain()

Modified: core/trunk/src/main/resources/all-elements-file-3.x.xml
===================================================================
--- core/trunk/src/main/resources/all-elements-file-3.x.xml	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/main/resources/all-elements-file-3.x.xml	2008-07-11 10:14:00 UTC (rev 6247)
@@ -17,7 +17,6 @@
    <!-- either replication or invalidation tags will be present, not both -->
    <replication>
       <sync replTimeout="15421"/>
-      <async useReplQueue="false" replQueueInterval="12" replQueueMaxElements="12345"/>
       <buddy enabled="true" poolName="myBuddyPoolReplicationGroup" communicationTimeout="2000">
          <dataGravitation auto="true" removeOnFind="true" searchBackupTrees="true"/>
          <locator class="org.jboss.cache.buddyreplication.NextMemberBuddyLocator">
@@ -31,10 +30,9 @@
 
    <!-- either replication or invalidation tags will be present, not both -->
    <invalidation>
-      <sync replTimeout="15421"/>
+      <async useReplQueue="false" replQueueInterval="12" replQueueMaxElements="12345"/>
    </invalidation>
 
-   <!-- todo mmarkus -->
    <stateRetrieval timeout="1524" fetchInMemoryState="true"/>
    <startup regionsInactiveOnStartup="true"/>
    <shutdown hookBehavior="REGISTER"/>
@@ -103,24 +101,16 @@
 
    <!-- this is new behavior added within 3.x only. it support configuring custom interceptors through configurations -->
    <customInterceptors>
-      <interceptor class="com.myCompany.MyInterceptor1">
-         <properties>
-            x=y
-            i=10
-         </properties>
-         <position first="true"/>
+      <interceptor position="first" class="org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor">
+         <attribute name="attrOne">value1</attribute>
+         <attribute name="attrTwo">value2</attribute>
+         <attribute name="attrThree">value3</attribute>
       </interceptor>
-      <interceptor class="com.myCompany.MyInterceptor2">
-         <position last="true"/>
-      </interceptor>
-      <interceptor class="com.myCompany.MyInterceptor3">
-         <position index="3"/>
-      </interceptor>
-      <interceptor class="com.myCompany.MyInterceptor4">
-         <position before="org.jboss.cache.interceptors.CallInterceptor"/>
-      </interceptor>
-      <interceptor class="com.myCompany.MyInterceptor5">
-         <position after="org.jboss.cache.interceptors.CallInterceptor"/>
-      </interceptor>
+      <interceptor position="last" class="org.jboss.cache.config.parsing.custominterceptors.BbbCustomInterceptor"/>
+      <interceptor index="3" class="org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor"/>
+      <interceptor before="org.jboss.cache.interceptors.CallInterceptor"
+                   class="org.jboss.cache.config.parsing.custominterceptors.BbbCustomInterceptor"/>
+      <interceptor after="org.jboss.cache.interceptors.CallInterceptor"
+                   class="org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor"/>
    </customInterceptors>
 </jbosscache>

Modified: core/trunk/src/main/resources/jbosscache-config-3.0.xsd
===================================================================
--- core/trunk/src/main/resources/jbosscache-config-3.0.xsd	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/main/resources/jbosscache-config-3.0.xsd	2008-07-11 10:14:00 UTC (rev 6247)
@@ -167,15 +167,7 @@
 
    <xs:complexType name="evictionRegionType">
       <xs:sequence>
-         <xs:element name="attribute" maxOccurs="unbounded">
-            <xs:complexType>
-               <xs:simpleContent>
-                  <xs:extension base="xs:string">
-                     <xs:attribute name="name" type="xs:string"/>
-                  </xs:extension>
-               </xs:simpleContent>
-            </xs:complexType>
-         </xs:element>
+         <xs:element name="attribute" maxOccurs="unbounded" type="attributeType"/>
       </xs:sequence>
       <xs:attribute name="name" type="xs:string"/>
       <xs:attribute name="policyClass" type="xs:string"/>
@@ -225,22 +217,32 @@
       <xs:sequence>
          <xs:element name="interceptor" maxOccurs="unbounded">
             <xs:complexType>
-               <xs:all>
-                  <xs:element name="properties" minOccurs="0" maxOccurs="1"/>
-                  <xs:element name="position" minOccurs="0" maxOccurs="1">
-                     <xs:complexType>
-                        <xs:attribute name="first" type="booleanType"/>
-                        <xs:attribute name="last" type="booleanType"/>
-                        <xs:attribute name="index" type="positiveInteger"/>
-                        <xs:attribute name="before" type="xs:string"/>
-                        <xs:attribute name="after" type="xs:string"/>
-                     </xs:complexType>
-                  </xs:element>
-               </xs:all>
+               <xs:sequence>
+                  <xs:element name="attribute" maxOccurs="unbounded" type="attributeType" minOccurs="0"/>
+               </xs:sequence>
                <xs:attribute name="class" type="xs:string"/>
+               <xs:attribute name="position">
+                  <xs:simpleType>
+                     <xs:restriction base="xs:string">
+                        <xs:enumeration value="first"/>
+                        <xs:enumeration value="last"/>
+                     </xs:restriction>
+                  </xs:simpleType>
+               </xs:attribute>
+               <xs:attribute name="before" type="xs:string"/>
+               <xs:attribute name="after" type="xs:string"/>
+               <xs:attribute name="index" type="positiveInteger"/>
             </xs:complexType>
          </xs:element>
       </xs:sequence>
    </xs:complexType>
+
+   <xs:complexType name="attributeType">
+      <xs:simpleContent>
+         <xs:extension base="xs:string">
+            <xs:attribute name="name" type="xs:string"/>
+         </xs:extension>
+      </xs:simpleContent>
+   </xs:complexType>
 </xs:schema>
 

Added: core/trunk/src/test/java/org/jboss/cache/config/parsing/CustomInterceptorsElementParserTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/config/parsing/CustomInterceptorsElementParserTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/config/parsing/CustomInterceptorsElementParserTest.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -0,0 +1,139 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt 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.config.parsing;
+
+import org.jboss.cache.config.ConfigurationException;
+import org.jboss.cache.config.CustomInterceptorConfig;
+import org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor;
+import org.jboss.cache.config.parsing.custominterceptors.BbbCustomInterceptor;
+import org.jboss.cache.config.parsing.element.CustomInterceptorsElementParser;
+import org.testng.annotations.Test;
+import org.w3c.dom.Element;
+
+import java.util.List;
+
+/**
+ * Tester class for {@link CustomInterceptorsElementParser}.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 3.0
+ */
+ at Test (groups = "unit")
+public class CustomInterceptorsElementParserTest
+{
+   CustomInterceptorsElementParser parser = new CustomInterceptorsElementParser();
+
+   /**
+    * Tests a correct configuration having all possible elements/attributes.
+    * @throws Exception
+    */
+   public void testFullConfiguration() throws Exception
+   {
+      String xml =
+               "   <customInterceptors>\n" +
+               "      <interceptor position=\"first\" class=\"org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor\">\n" +
+               "         <attribute name=\"attrOne\">value1</attribute>\n" +
+               "         <attribute name=\"attrTwo\">value2</attribute>\n" +
+               "         <attribute name=\"attrThree\">value3</attribute>\n" +
+               "      </interceptor>\n" +
+               "      <interceptor position=\"last\" class=\"org.jboss.cache.config.parsing.custominterceptors.BbbCustomInterceptor\"/>\n" +
+               "      <interceptor index=\"3\" class=\"org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor\"/>\n" +
+               "      <interceptor before=\"org.jboss.cache.interceptors.CallInterceptor\"\n" +
+               "                   class=\"org.jboss.cache.config.parsing.custominterceptors.BbbCustomInterceptor\"/>\n" +
+               "      <interceptor after=\"org.jboss.cache.interceptors.CallInterceptor\"\n" +
+               "                   class=\"org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor\"/>\n" +
+               "   </customInterceptors>";
+      Element element = XmlConfigHelper.stringToElement(xml);
+      List<CustomInterceptorConfig> configs = parser.parseCustomInterceptors(element);
+      assert configs.size() == 5;
+      CustomInterceptorConfig one = configs.get(0);
+      assert one.isFirst();
+      assert one.getInterceptor() instanceof AaaCustomInterceptor;
+      assert ((AaaCustomInterceptor)one.getInterceptor()).getAttrOne().equals("value1");
+      assert ((AaaCustomInterceptor)one.getInterceptor()).getAttrTwo().equals("value2");
+      assert ((AaaCustomInterceptor)one.getInterceptor()).getAttrThree().equals("value3");
+
+      CustomInterceptorConfig two = configs.get(1);
+      assert !two.isFirst();
+      assert two.isLast();
+      assert two.getInterceptor() instanceof BbbCustomInterceptor;
+
+      CustomInterceptorConfig three = configs.get(2);
+      assert !three.isFirst();
+      assert !three.isLast();
+      assert three.getIndex() == 3;
+
+      CustomInterceptorConfig four = configs.get(3);
+      assert !four.isFirst();
+      assert !four.isLast();
+      assert four.getBeforeClass().equals("org.jboss.cache.interceptors.CallInterceptor");
+
+      CustomInterceptorConfig five = configs.get(4);
+      assert !five.isFirst();
+      assert !five.isLast();
+      assert five.getAfterClass().equals("org.jboss.cache.interceptors.CallInterceptor");
+   }
+
+   /**
+    * trying to specify an attribute that does not exist on the interceptor class.
+    */
+   public void testWrongAttribute() throws Exception
+   {
+      String xml =
+            "   <customInterceptors>\n" +
+            "      <interceptor position=\"first\" class=\"org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor\">\n" +
+            "         <attribute name=\"nonexistenAttribute\">value3</attribute>\n" +
+            "      </interceptor>\n" +
+            "   </customInterceptors>";
+      Element el = XmlConfigHelper.stringToElement(xml);
+      try
+      {
+         parser.parseCustomInterceptors(el);
+         assert false: "exception expected";  
+      } catch (ConfigurationException e)
+      {
+         //expected
+      }
+   }
+
+   /**
+    * If the interceptor class is incorrect (e.g. does not extend the CommandInterceptor base class) then parser should fail.
+    */
+   public void testBadInterceptorClass() throws Exception
+   {
+      String xml =
+                  "   <customInterceptors>\n" +
+                  "      <interceptor position=\"first\" class=\"org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor\">\n" +
+                  "         <attribute name=\"notExists\">value1</attribute>\n" +
+                  "      </interceptor>\n" +
+                  "   </customInterceptors>";
+      Element el = XmlConfigHelper.stringToElement(xml);
+      try
+      {
+         parser.parseCustomInterceptors(el);
+         assert false: "exception expected";
+      } catch (ConfigurationException e)
+      {
+         //expected
+      }
+   }
+}

Modified: core/trunk/src/test/java/org/jboss/cache/config/parsing/EvictionElementParserTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/config/parsing/EvictionElementParserTest.java	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/test/java/org/jboss/cache/config/parsing/EvictionElementParserTest.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -112,7 +112,6 @@
                   "      </region>\n" +
                   "      <region name=\"/lfu\">\n" +
                   "         <attribute name=\"maxNodes\">5000</attribute>\n" +
-                  "         <attribute name=\"minNodes\">4000</attribute>\n" +
                   "         <attribute name=\"timeToLive\">1000000</attribute>\n" +
                   "      </region>\n" +
                   "   </eviction>";

Modified: core/trunk/src/test/java/org/jboss/cache/config/parsing/XmlConfigurationParserTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/config/parsing/XmlConfigurationParserTest.java	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/test/java/org/jboss/cache/config/parsing/XmlConfigurationParserTest.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -1,6 +1,8 @@
 package org.jboss.cache.config.parsing;
 
 import org.jboss.cache.config.*;
+import org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor;
+import org.jboss.cache.config.parsing.custominterceptors.BbbCustomInterceptor;
 import org.jboss.cache.eviction.LRUConfiguration;
 import org.jboss.cache.eviction.MRUConfiguration;
 import org.jboss.cache.lock.IsolationLevel;
@@ -224,15 +226,13 @@
    {
       List<CustomInterceptorConfig> interceptorConfigs = config.getCustomInterceptors();
       assert interceptorConfigs.size() == 5;
-      assert interceptorConfigs.get(0).getInterceptorClass().equals("com.myCompany.MyInterceptor1");
-      assert interceptorConfigs.get(1).getInterceptorClass().equals("com.myCompany.MyInterceptor2");
-      assert interceptorConfigs.get(2).getInterceptorClass().equals("com.myCompany.MyInterceptor3");
-      assert interceptorConfigs.get(3).getInterceptorClass().equals("com.myCompany.MyInterceptor4");
-      assert interceptorConfigs.get(4).getInterceptorClass().equals("com.myCompany.MyInterceptor5");
+      assert interceptorConfigs.get(0).getInterceptor() instanceof AaaCustomInterceptor;
+      assert interceptorConfigs.get(1).getInterceptor() instanceof BbbCustomInterceptor;
+      assert interceptorConfigs.get(2).getInterceptor() instanceof AaaCustomInterceptor;
+      assert interceptorConfigs.get(3).getInterceptor() instanceof BbbCustomInterceptor;
+      assert interceptorConfigs.get(4).getInterceptor() instanceof AaaCustomInterceptor;
       assert interceptorConfigs.get(0).isFirst();
       assert !interceptorConfigs.get(0).isLast();
-      assert interceptorConfigs.get(0).getProperties().get("x").equals("y");
-      assert interceptorConfigs.get(0).getProperties().get("i").equals("10");
       assert interceptorConfigs.get(1).isLast();
       assert interceptorConfigs.get(2).getIndex() == 3;
       assert interceptorConfigs.get(3).getBeforeClass().equals("org.jboss.cache.interceptors.CallInterceptor");

Added: core/trunk/src/test/java/org/jboss/cache/config/parsing/custominterceptors/AaaCustomInterceptor.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/config/parsing/custominterceptors/AaaCustomInterceptor.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/config/parsing/custominterceptors/AaaCustomInterceptor.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -0,0 +1,68 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt 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.config.parsing.custominterceptors;
+
+import org.jboss.cache.interceptors.base.CommandInterceptor;
+
+/**
+ * Used for testing custom interceptors construction.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 3.0
+ */
+public class AaaCustomInterceptor extends CommandInterceptor
+{
+   private String attrOne;
+   private String attrTwo;
+   private String attrThree;
+
+   public String getAttrOne()
+   {
+      return attrOne;
+   }
+
+   public String getAttrTwo()
+   {
+      return attrTwo;
+   }
+
+   public String getAttrThree()
+   {
+      return attrThree;
+   }
+
+   public void setAttrOne(String attrOne)
+   {
+      this.attrOne = attrOne;
+   }
+
+   public void setAttrTwo(String attrTwo)
+   {
+      this.attrTwo = attrTwo;
+   }
+
+   public void setAttrThree(String attrThree)
+   {
+      this.attrThree = attrThree;
+   }
+}
+

Added: core/trunk/src/test/java/org/jboss/cache/config/parsing/custominterceptors/BbbCustomInterceptor.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/config/parsing/custominterceptors/BbbCustomInterceptor.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/config/parsing/custominterceptors/BbbCustomInterceptor.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -0,0 +1,34 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt 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.config.parsing.custominterceptors;
+
+import org.jboss.cache.interceptors.base.CommandInterceptor;
+
+/**
+ * Used for testing custom interceptors construction.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 3.0
+ */
+public class BbbCustomInterceptor extends CommandInterceptor
+{
+}

Added: core/trunk/src/test/java/org/jboss/cache/config/parsing/custominterceptors/WrongCustomInterceptor.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/config/parsing/custominterceptors/WrongCustomInterceptor.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/config/parsing/custominterceptors/WrongCustomInterceptor.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -0,0 +1,33 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt 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.config.parsing.custominterceptors;
+
+/**
+ * Used for testing custom interceptors construction.
+ * This is a incorrect interceptor implementation as it does not extend CommandInterceptor.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 3.0
+ */
+public class WrongCustomInterceptor
+{
+}

Added: core/trunk/src/test/java/org/jboss/cache/factories/CustomInterceptorConstructionTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/factories/CustomInterceptorConstructionTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/factories/CustomInterceptorConstructionTest.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -0,0 +1,168 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt 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.factories;
+
+import org.jboss.cache.CacheFactory;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.CustomInterceptorConfig;
+import org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor;
+import org.jboss.cache.interceptors.MVCCLockingInterceptor;
+import org.jboss.cache.interceptors.base.CommandInterceptor;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Tests how custom interceptor construction is handled.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 3.0
+ */
+ at Test(groups = "functional")
+public class CustomInterceptorConstructionTest
+{
+   CacheSPI cache;
+   int defaultInterceptroCount;
+
+   @AfterMethod 
+   public void tearDown()
+   {
+      if (cache != null)
+      {
+         cache.stop();
+      }
+      cache = null;
+   }
+
+   public void testAddFirst()
+   {
+      AaaCustomInterceptor interceptor = new AaaCustomInterceptor();
+      CustomInterceptorConfig config = new CustomInterceptorConfig(interceptor);
+      config.setFirst(true);
+      buildCache(config);
+      assert cache.getInterceptorChain().get(0).equals(interceptor);
+      assert cache.getInterceptorChain().size() == defaultInterceptroCount + 1;
+   }
+
+   public void testAddLast()
+   {
+      AaaCustomInterceptor interceptor = new AaaCustomInterceptor();
+      CustomInterceptorConfig config = new CustomInterceptorConfig(interceptor);
+      config.setLast(true);
+      buildCache(config);
+      List chain = cache.getInterceptorChain();
+      assert chain.get(chain.size() - 1).equals(interceptor);
+      assert cache.getInterceptorChain().size() == defaultInterceptroCount + 1;
+   }
+
+   public void testAddAfter()
+   {
+      AaaCustomInterceptor interceptor = new AaaCustomInterceptor();
+      CustomInterceptorConfig config = new CustomInterceptorConfig(interceptor);
+      config.setAfterClass(MVCCLockingInterceptor.class.getName());
+      buildCache(config);
+      List<CommandInterceptor> chain = cache.getInterceptorChain();
+      int occurenceCount = 0;
+      for (CommandInterceptor ci : chain)
+      {
+         if (ci instanceof MVCCLockingInterceptor)
+         {
+            assert ci.getNext().equals(interceptor);
+            occurenceCount++;
+         }
+      }
+      assert occurenceCount == 1;
+      assert cache.getInterceptorChain().size() == defaultInterceptroCount + 1;
+   }
+
+   public void testAddBefore()
+   {
+      AaaCustomInterceptor interceptor = new AaaCustomInterceptor();
+      CustomInterceptorConfig config = new CustomInterceptorConfig(interceptor);
+      config.setBeforeClass(MVCCLockingInterceptor.class.getName());
+      buildCache(config);
+      List<CommandInterceptor> chain = cache.getInterceptorChain();
+      int occurenceCount = 0;
+      for (CommandInterceptor ci : chain)
+      {
+         if (ci instanceof AaaCustomInterceptor)
+         {
+            assert ci.getNext() instanceof MVCCLockingInterceptor;
+            occurenceCount++;
+         }
+      }
+      assert occurenceCount == 1;
+      assert cache.getInterceptorChain().size() == defaultInterceptroCount + 1;
+   }
+
+   @Test (enabled = true)
+   public void testAddAtIndex()
+   {
+      AaaCustomInterceptor interceptor = new AaaCustomInterceptor();
+      CustomInterceptorConfig config = new CustomInterceptorConfig(interceptor);
+      config.setIndex(1);
+      buildCache(config);
+      List<CommandInterceptor> chain = cache.getInterceptorChain();
+      assert chain.get(1).equals(interceptor);
+      assert cache.getInterceptorChain().size() == defaultInterceptroCount + 1;
+   }
+
+   public void testAddAtInvalidIndex()
+   {
+      AaaCustomInterceptor interceptor = new AaaCustomInterceptor();
+      CustomInterceptorConfig config = new CustomInterceptorConfig(interceptor);
+      config.setIndex(1000);
+      try
+      {
+         buildCache(config);
+         assert false : "exception expected here";
+      } catch (Exception e)
+      {
+         //expected
+      }
+   }
+
+   private void buildCache(CustomInterceptorConfig interceptorConfig)
+   {
+      buildCache(Collections.singletonList(interceptorConfig));
+   }
+
+   private void buildCache(List<CustomInterceptorConfig> interceptorConfig)
+   {
+      Configuration config = new Configuration();
+      config.setCacheMode(Configuration.CacheMode.LOCAL);
+      config.setNodeLockingScheme(Configuration.NodeLockingScheme.MVCC);
+      CacheFactory cacheFactory2 = new DefaultCacheFactory();
+      CacheSPI tmpCacheSPI = (CacheSPI) cacheFactory2.createCache(config);
+      defaultInterceptroCount = tmpCacheSPI.getInterceptorChain().size();
+      tmpCacheSPI.stop();
+
+      CacheFactory cacheFactory = new DefaultCacheFactory();
+      config.setCustomInterceptors(interceptorConfig);
+      cache = (CacheSPI) cacheFactory.createCache(config, true);
+   }
+}
+

Modified: core/trunk/src/test/java/org/jboss/cache/invocation/InterceptorChainTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/invocation/InterceptorChainTest.java	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/test/java/org/jboss/cache/invocation/InterceptorChainTest.java	2008-07-11 10:14:00 UTC (rev 6247)
@@ -138,7 +138,7 @@
       assert result.size() == chain.asList().size();
    }
 
-   public void removeInterceptorWithtType()
+   public void testRemoveInterceptorWithtType()
    {
       chain.addInterceptor(txInterceptor, 1);
       chain.addInterceptor(invalidationInterceptor, 2);
@@ -158,16 +158,29 @@
       assert pessimisticInterceptor.getNext() == null;
    }
 
-   public void addInterceptorWithType()
+   public void testAddInterceptorWithType()
    {
-      assert chain.addInterceptor(invalidationInterceptor, icInterceptor.getClass());
+      assert chain.addAfterInterceptor(invalidationInterceptor, icInterceptor.getClass());
       assert icInterceptor.getNext().equals(invalidationInterceptor);
 
-      chain.addInterceptor(txInterceptor, icInterceptor.getClass());
+      chain.addAfterInterceptor(txInterceptor, icInterceptor.getClass());
       assert icInterceptor.getNext().equals(txInterceptor);
       assert txInterceptor.getNext().equals(invalidationInterceptor);
    }
 
+   public void testGetInterceptorsWithClassName()
+   {
+      chain.appendIntereceptor(invalidationInterceptor);
+      chain.appendIntereceptor(callInterceptor);
+      chain.appendIntereceptor(pessimisticInterceptor);
+      chain.appendIntereceptor(create(CallInterceptor.class));
+      assert chain.getInterceptorsWithClassName(InvocationContextInterceptor.class.getName()).size() == 1;
+      assert chain.getInterceptorsWithClassName(InvalidationInterceptor.class.getName()).size() == 1;
+      assert chain.getInterceptorsWithClassName(PessimisticLockInterceptor.class.getName()).size() == 1;
+      assert chain.getInterceptorsWithClassName(CallInterceptor.class.getName()).size() == 2;
+      assert chain.getInterceptorsWithClassName(CommandInterceptor.class.getName()).size() == 0;
+   }
+
    private CommandInterceptor create(Class<? extends CommandInterceptor> toInstantiate)
    {
       try

Modified: core/trunk/src/test/resources/configs/parser-test.xml
===================================================================
--- core/trunk/src/test/resources/configs/parser-test.xml	2008-07-11 01:33:09 UTC (rev 6246)
+++ core/trunk/src/test/resources/configs/parser-test.xml	2008-07-11 10:14:00 UTC (rev 6247)
@@ -99,24 +99,16 @@
 
    <!-- this is new behavior added within 3.x only. it support configuring custom interceptors through configurations -->
    <customInterceptors>
-      <interceptor class="com.myCompany.MyInterceptor1">
-         <properties>
-            x=y
-            i=10
-         </properties>
-         <position first="true"/>
+      <interceptor position="first" class="org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor">
+         <attribute name="attrOne">value1</attribute>
+         <attribute name="attrTwo">value2</attribute>
+         <attribute name="attrThree">value3</attribute>
       </interceptor>
-      <interceptor class="com.myCompany.MyInterceptor2">
-         <position last="true"/>
-      </interceptor>
-      <interceptor class="com.myCompany.MyInterceptor3">
-         <position index="3"/>
-      </interceptor>
-      <interceptor class="com.myCompany.MyInterceptor4">
-         <position before="org.jboss.cache.interceptors.CallInterceptor"/>
-      </interceptor>
-      <interceptor class="com.myCompany.MyInterceptor5">
-         <position after="org.jboss.cache.interceptors.CallInterceptor"/>
-      </interceptor>
+      <interceptor position="last" class="org.jboss.cache.config.parsing.custominterceptors.BbbCustomInterceptor"/>
+      <interceptor index="3" class="org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor"/>
+      <interceptor before="org.jboss.cache.interceptors.CallInterceptor"
+                   class="org.jboss.cache.config.parsing.custominterceptors.BbbCustomInterceptor"/>
+      <interceptor after="org.jboss.cache.interceptors.CallInterceptor"
+                   class="org.jboss.cache.config.parsing.custominterceptors.AaaCustomInterceptor"/>
    </customInterceptors>
 </jbosscache>




More information about the jbosscache-commits mailing list