[jboss-cvs] JBossAS SVN: r93024 - in projects/jboss-mdr/trunk: src/main/java/org/jboss/metadata/plugins/context and 3 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Mon Aug 31 08:15:16 EDT 2009


Author: smarlow at redhat.com
Date: 2009-08-31 08:15:15 -0400 (Mon, 31 Aug 2009)
New Revision: 93024

Added:
   projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/spi/scope/UnmodifiableScopeKey.java
   projects/jboss-mdr/trunk/src/test/java/org/jboss/test/metadata/scope/test/UnmodifiableScopeKeyUnitTestCase.java
Modified:
   projects/jboss-mdr/trunk/pom.xml
   projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/plugins/context/AbstractMetaDataContext.java
   projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/plugins/repository/basic/BasicMetaDataRepository.java
   projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/spi/scope/Scope.java
   projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/spi/scope/ScopeKey.java
   projects/jboss-mdr/trunk/src/test/java/org/jboss/test/metadata/scope/test/ScopeTestSuite.java
Log:
JBMDR-61 Improve ScopeKey performance.  Use UnmodifiableScopeKey for map lookup.  Improve multi-threaded use.  Added more javadoc comments.

Modified: projects/jboss-mdr/trunk/pom.xml
===================================================================
--- projects/jboss-mdr/trunk/pom.xml	2009-08-31 12:05:40 UTC (rev 93023)
+++ projects/jboss-mdr/trunk/pom.xml	2009-08-31 12:15:15 UTC (rev 93024)
@@ -18,7 +18,7 @@
   </scm>
 
   <properties>
-    <version.jboss.common.core>2.2.12.GA</version.jboss.common.core>
+    <version.jboss.common.core>2.2.13.GA</version.jboss.common.core>
     <version.jboss.logging.spi>2.0.5.GA</version.jboss.logging.spi>
     <version.jboss.logging.log4j>2.0.5.GA</version.jboss.logging.log4j>
     <version.javassist>3.10.0.GA</version.javassist>

Modified: projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/plugins/context/AbstractMetaDataContext.java
===================================================================
--- projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/plugins/context/AbstractMetaDataContext.java	2009-08-31 12:05:40 UTC (rev 93023)
+++ projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/plugins/context/AbstractMetaDataContext.java	2009-08-31 12:15:15 UTC (rev 93024)
@@ -114,7 +114,7 @@
             for (Scope scope : scopes)
                key.addScope(scope);
          }
-         scopeKey = key;
+         scopeKey = key.getOptimizedKey();
       }
       return scopeKey;
    }

Modified: projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/plugins/repository/basic/BasicMetaDataRepository.java
===================================================================
--- projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/plugins/repository/basic/BasicMetaDataRepository.java	2009-08-31 12:05:40 UTC (rev 93023)
+++ projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/plugins/repository/basic/BasicMetaDataRepository.java	2009-08-31 12:15:15 UTC (rev 93024)
@@ -108,7 +108,7 @@
    {
       if (retrieval == null)
          throw new IllegalArgumentException("Null retrieval");
-      ScopeKey key = retrieval.getScope();
+      ScopeKey key = retrieval.getScope().getOptimizedKey();
       key.freeze();
       return retrievals.put(key, retrieval);
    }

Modified: projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/spi/scope/Scope.java
===================================================================
--- projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/spi/scope/Scope.java	2009-08-31 12:05:40 UTC (rev 93023)
+++ projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/spi/scope/Scope.java	2009-08-31 12:15:15 UTC (rev 93024)
@@ -29,17 +29,19 @@
  * @author <a href="adrian at jboss.com">Adrian Brock</a>
  * @version $Revision$
  */
-public class Scope implements Serializable
+public class Scope implements Serializable,  Comparable
 {
    /** The serialVersionUID */
-   private static final long serialVersionUID = 5255750644324593361L;
+   private static final long serialVersionUID = 5255750644324593361L -1L ;
 
    /** The scope level */
    private final ScopeLevel level;
    
    /** The scope qualifier */
    private final Object qualifier;
-   
+
+   private final int hashcode;
+
    public Scope(ScopeLevel level, Object qualifier)
    {
       if (level == null)
@@ -49,6 +51,7 @@
       
       this.level = level;
       this.qualifier = qualifier;
+      this.hashcode = level.hashCode();
    }
 
    public ScopeLevel getScopeLevel()
@@ -79,9 +82,24 @@
       
       return qualifier.equals(other.qualifier);
    }
+
+   /**
+    * @param o the object to be compared.
+    * @return a negative integer, zero, or a positive integer as this object
+    *         is less than, equal to, or greater than the specified object.
+    * @throws ClassCastException if the specified object's type prevents it
+    *                            from being compared to this object.
+    */
+   public int compareTo(Object o)
+   {
+      if (o == this)
+         return 0;
+      Scope other = (Scope) o;
+      return (level.compareTo(other.getScopeLevel()));
+   }
    
    public int hashCode()
    {
-      return level.hashCode();
+      return hashcode;
    }
 }

Modified: projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/spi/scope/ScopeKey.java
===================================================================
--- projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/spi/scope/ScopeKey.java	2009-08-31 12:05:40 UTC (rev 93023)
+++ projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/spi/scope/ScopeKey.java	2009-08-31 12:15:15 UTC (rev 93024)
@@ -1,6 +1,6 @@
 /*
 * JBoss, Home of Professional Open Source
-* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* Copyright 2009, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
@@ -21,30 +21,52 @@
 */
 package org.jboss.metadata.spi.scope;
 
+import org.jboss.util.collection.ConcurrentSkipListMap;
+
 import java.io.Serializable;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
-import java.util.SortedMap;
-import java.util.TreeMap;
 
 /**
- * ScopeKey.
- * 
+ * The ScopeKey represents a path which is made up of the path entries.  Elements may be added dynamically
+ * until the ScopeKey is frozen.  If you want to add more elements to a frozen ScopeKey, clone it
+ * (cloned objects are not frozen).
+ *
+ * To use the ScopeKey as a key object, use the UnmodifiableScopeKey returned from getOptimizedKey().
+ * UnmodifiableScopeKey's are immutable and suitable for use as a key (also thread-safe with no object lock contention). 
+ *
+ * The ScopeKey (Server=Bob,Deployment=Foo.war,Class=Bar)
+ * is the child of (Server=Bob,Deployment=Foo.war),
+ * which is the child of (Server=Bob).  Think about this statement in terms of
+ * a path relationship.  The server (Bob) contains a deployment (Foo.war) and
+ * the deployment contains a class (Bar).
+ *
+ * See historical design notes
+ * http://www.jboss.org/index.html?module=bb&op=viewtopic&p=3972233#3972233
+ * http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4013747#4013747
+ *
+ * Thread Safety:  This class is thread safe.
+ *
+ * Warning:  This class is (delicately) extended by UnmodifiableScopeKey.
+ * Since there is no common interface class between the two classes, there are risks to be
+ * aware of.  If a new method is added to ScopeKey and not to UnmodifiableScopeKey, undesireable
+ * behavior will occur when that UnmodifiableScopeKey.method is invoked (ScopeKey's member variables will be null). 
+ *
  * @author <a href="adrian at jboss.com">Adrian Brock</a>
  * @version $Revision$
  */
 public class ScopeKey implements Serializable, Cloneable
 {
    /** The serialVersionUID */
-   private static final long serialVersionUID = -496238095349593371L;
+   private static final long serialVersionUID = -496238095349593371L + 1L;
 
    /** The default scope */
-   public static ScopeKey DEFAULT_SCOPE = new ScopeKey(new Scope(CommonLevels.JVM, "THIS"));
+   public static final ScopeKey DEFAULT_SCOPE = new ScopeKey(new Scope(CommonLevels.JVM, "THIS"));
    
-   /** The scopes */
-   private SortedMap<ScopeLevel, Scope> scopes = Collections.synchronizedSortedMap(new TreeMap<ScopeLevel, Scope>());
-   
+   /** The scopes () */
+   private ConcurrentSkipListMap<ScopeLevel, Scope> scopes = new ConcurrentSkipListMap<ScopeLevel, Scope>();
+
    /** The scope level for this key */
    private ScopeLevel maxScopeLevel;
    
@@ -87,7 +109,8 @@
    /**
     * Create a new ScopeKey.
     * 
-    * @param scopes the scopes
+    * @param scopes is a collection of Scope instances that make up the represented path
+    * @throws IllegalArgumentException if parameter scopes is null
     */
    public ScopeKey(Collection<Scope> scopes)
    {
@@ -100,7 +123,8 @@
    /**
     * Create a new ScopeKey.
     * 
-    * @param scopes the scopes
+    * @param scopes is zero or more Scope instances that make up the represented path
+    * @throws IllegalArgumentException if parameter scopes is null
     */
    public ScopeKey(Scope[] scopes)
    {
@@ -122,6 +146,7 @@
 
    /**
     * Set to frozen.
+    * @throws IllegalArgumentException if there are no Scope entries added.
     */
    public void freeze()
    {
@@ -131,9 +156,18 @@
    }
    
    /**
-    * Get the scopes
+    * The returned ScopeKey is immutable and optimized for use at runtime.
+    * @return Optimized immutable ScopeKey
+    */
+   public ScopeKey getOptimizedKey()
+   {
+      return new UnmodifiableScopeKey(this);
+   }
+
+   /**
+    * Get the scopes 
     * 
-    * @return the scopes
+    * @return the scopes in expected path order
     */
    public Collection<Scope> getScopes()
    {
@@ -145,6 +179,7 @@
     * 
     * @param level the scope level
     * @return the scope
+    * @throws IllegalArgumentException if level is null.
     */
    public Scope getScope(ScopeLevel level)
    {
@@ -166,7 +201,8 @@
    /**
     * Get the parent scope key
     * 
-    * @return the parent or null if there is no parent
+    * @return the parent or null if there is no parent (meaning that we
+    * are at the top most element in the path)
     */
    public ScopeKey getParent()
    {
@@ -188,22 +224,24 @@
     *
     * @param key the key parameter
     * @return true if this is direct parent of key param
+    * @throws IllegalArgumentException if parameter key is null
     */
    public boolean isParent(ScopeKey key)
    {
       if (key == null)
          throw new IllegalArgumentException("Null key");
+      Collection keyValues = key.getScopesCollection();
 
       // The passed key doesn't have a parent
-      if (key.scopes.size() < 2)
+      if (keyValues.size() < 2)
          return false;
       
       // If it is a child, it will have one more scope
-      if (scopes.size() != key.scopes.size() - 1)
+      if (scopes.size() != keyValues.size() - 1)
          return false;
 
       Iterator<Scope> thisScopes = scopes.values().iterator();
-      Iterator<Scope> keyScopes = key.scopes.values().iterator();
+      Iterator<Scope> keyScopes = keyValues.iterator();
       
       while (thisScopes.hasNext())
       {
@@ -221,6 +259,8 @@
     * 
     * @param scope the scope
     * @return the previous value or null if there wasn't one
+    * @throws IllegalArgumentException if scope is null.
+    * @throws IllegalStateException if frozen
     */
    public Scope addScope(Scope scope)
    {
@@ -228,7 +268,7 @@
          throw new IllegalArgumentException("Null scope");
       if (frozen)
          throw new IllegalStateException("The scope key is frozen");
-      
+
       ScopeLevel level = scope.getScopeLevel();
       Scope result = scopes.put(level, scope);
       if (maxScopeLevel == null || level.compareTo(maxScopeLevel) >= 0)
@@ -268,6 +308,7 @@
     * 
     * @param scopeLevel the scope level
     * @return the scope or null if there is no such level
+    * @throws IllegalArgumentException if parameter key is null    
     */
    public Scope getScopeLevel(ScopeLevel scopeLevel)
    {
@@ -311,22 +352,29 @@
          return true;
       if (object == null || object instanceof ScopeKey == false)
          return false;
-      
       ScopeKey other = (ScopeKey) object;
-      return scopes.equals(other.scopes);
+      if (other instanceof UnmodifiableScopeKey)
+         return other.equals(this);
+      else
+         return scopes.equals(other.scopes);
    }
-   
+
    public int hashCode()
    {
-      return scopes.hashCode();
+      return computeHashCode(scopes.values());  
    }
 
+   /**
+    * Clone a ScopeKey instance.
+    *
+    * @Return an unfrozen instance (even if the current instance is frozen).
+    */
    public ScopeKey clone()
    {
       try
       {
          ScopeKey result = (ScopeKey) super.clone();
-         result.scopes = Collections.synchronizedSortedMap(new TreeMap<ScopeLevel, Scope>(scopes));
+         result.scopes = new ConcurrentSkipListMap<ScopeLevel, Scope>(scopes);
          result.frozen = false;
          return result;
       }
@@ -335,4 +383,32 @@
          throw new Error(e);
       }
    }
+
+   protected Scope[] getArray()
+   {
+      Collection<Scope> scopes = getScopes();
+      return scopes.toArray(new Scope[0]);
+   }
+
+   protected Collection<Scope> getScopesCollection()
+   {
+      return scopes.values();
+   }
+   
+   protected static int computeHashCode(Scope[] scopeArray) 
+   {
+      int hashCode = 0;
+      for (Scope scope : scopeArray)
+         hashCode += scope.getScopeLevel().hashCode();
+      return hashCode;
+   }
+
+   protected static int computeHashCode(Collection<Scope> scopeCollection) 
+   {
+      int hashCode = 0;
+      for (Scope scope : scopeCollection)
+         hashCode += scope.getScopeLevel().hashCode();
+      return hashCode;
+   }
+  
 }

Added: projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/spi/scope/UnmodifiableScopeKey.java
===================================================================
--- projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/spi/scope/UnmodifiableScopeKey.java	                        (rev 0)
+++ projects/jboss-mdr/trunk/src/main/java/org/jboss/metadata/spi/scope/UnmodifiableScopeKey.java	2009-08-31 12:15:15 UTC (rev 93024)
@@ -0,0 +1,376 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, JBoss Inc., and individual contributors as indicated
+* 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.metadata.spi.scope;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * The UnmodifiableScopeKey represents a path which is made up of the path entries.
+ *
+ * The UnmodifiableScopeKey (Server=Bob,Deployment=Foo.war,Class=Bar)
+ * is the child of (Server=Bob,Deployment=Foo.war),
+ * which is the child of (Server=Bob).  Think about this statement in terms of
+ * a path relationship.  The server (Bob) contains a deployment (Foo.war) and
+ * the deployment contains a class (Bar).
+ *
+ * See historical design notes
+ * http://www.jboss.org/index.html?module=bb&op=viewtopic&p=3972233#3972233
+ * http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4013747#4013747
+ *
+ * Thread Safety:  This class is immutable and therefore thread safe.
+ *
+ * Note: this class requires that class Scope implement Comparable, so that it
+ * can correctly sort the array of Scopes.  Note that is not needed for 
+ * UnmodifiableScopeKey(ScopeKey), which is already sorted.
+ *
+ * Warning:  This class (delicately) extends ScopeKey and overides all ScopeKey methods.
+ * Since there is no common interface class between the two classes, there are risks to be
+ * aware of.  If a new method is added to ScopeKey and not to UnmodifiableScopeKey, undesireable
+ * behavior will occur when that new method is invoked (ScopeKey's member variables will be null). 
+ *
+ * @author <a href="smarlow at redhat.com">Scott Marlow</a>
+ * @version $Revision: 75678 $
+ */
+
+public final class UnmodifiableScopeKey extends ScopeKey implements Serializable, Cloneable
+{
+
+   /** The serialVersionUID */
+   private static final long serialVersionUID = -442157853443439820L;
+
+   // the entries in this array are always sorted by (int) Scope.level.level
+   // Therefore, the maxScopeLevel is always found at the last element.
+   private final Scope theScopes[];
+
+   // Scopes in collection form
+   private final Collection<Scope> theScopesCollection;
+
+   // The cached hashCode that is calculated only once by the constructor
+   private final int hashcode;
+
+   public UnmodifiableScopeKey( ScopeKey key)
+   {
+      theScopes = new Scope[key.getScopes().size()];
+      key.getScopes().toArray(theScopes);
+      // sort(theScopes);  // already sorted
+      hashcode = ScopeKey.computeHashCode(theScopes);
+      theScopesCollection = Collections.unmodifiableCollection(Arrays.asList(theScopes));
+   }
+
+   /**
+    * Create a new ScopeKey.
+    *
+    * @param level the scope level
+    * @param qualifier the scope qualifier
+    */
+   public UnmodifiableScopeKey(ScopeLevel level, Object qualifier)
+   {
+      this( new Scope(level, qualifier));
+   }
+
+   /**
+    * Create a new ScopeKey.
+    *
+    * @param scopes is a collection of Scope instances that make up the represented path
+    * @throws IllegalArgumentException if parameter scopes is null
+    */
+   public UnmodifiableScopeKey(Collection<Scope> scopes)
+   {
+      if (scopes == null)
+         throw new IllegalArgumentException("Null scopes");
+      theScopes = new Scope[scopes.size()];
+      scopes.toArray(theScopes);
+      sort(theScopes);
+      hashcode = ScopeKey.computeHashCode(theScopes);
+      theScopesCollection = Collections.unmodifiableCollection(Arrays.asList(theScopes));
+   }
+
+   /**
+    * Create a new ScopeKey.
+    *
+    * @param scopes is zero or more Scope instances that make up the represented path
+    * @throws IllegalArgumentException if parameter scopes is null
+    */
+   public UnmodifiableScopeKey(Scope... scopes)
+   {
+      if (scopes == null)
+         throw new IllegalArgumentException("Null scopes");
+      theScopes = setup(scopes.length, scopes);
+      hashcode = ScopeKey.computeHashCode(theScopes);
+      theScopesCollection = Collections.unmodifiableCollection(Arrays.asList(theScopes));
+   }
+
+   /**
+    * Create a new ScopeKey.
+    *
+    * @param max number of passed Scope instances to use
+    * @param scopes is zero or more Scope instances that make up the represented path
+    * @throws IllegalArgumentException if parameter scopes is null
+    */
+   public UnmodifiableScopeKey(int max, Scope... scopes)
+   {
+      if (scopes == null)
+         throw new IllegalArgumentException("Null scopes");
+      theScopes = setup(max, scopes);
+      hashcode = ScopeKey.computeHashCode(theScopes);
+      theScopesCollection = Collections.unmodifiableCollection(Arrays.asList(theScopes));
+   }
+
+   public ScopeKey getOptimizedKey()
+   {
+      return this;
+   }
+
+   /**
+    * Get the scopes
+    *
+    * @return the unmodifiable collection of the scopes in expected path order
+    */
+   public Collection<Scope> getScopes()
+   {
+      return theScopesCollection;
+   }
+
+   
+
+   /**
+    * Get a scope
+    *
+    * @param level the scope level
+    * @return the scope
+    * @throws IllegalArgumentException if level is null.
+    */
+   public Scope getScope(ScopeLevel level)
+   {
+      if (level == null)
+         throw new IllegalArgumentException("Null level");
+      // Note that the following search succeeds because we know that the qualifier (empty string)
+      // is ignored during the search.
+      int idx = Arrays.binarySearch(theScopes, new Scope(level,""));
+      if(idx >= 0)
+         return theScopes[idx];
+      return null;   // not found
+   }
+
+   /**
+    * Get the maximum scope level
+    *
+    * @return the largest scope level
+    */
+   public ScopeLevel getMaxScopeLevel()
+   {
+      // the maximum scope level is always the last entry (since we are sorted by scopelevel)
+      if (theScopes.length > 0)
+         return theScopes[theScopes.length - 1].getScopeLevel();
+      else
+         return null;
+   }
+
+   /**
+    * Get the parent scope key
+    *
+    * @return the parent or null if there is no parent (meaning that we
+    * are at the top most element in the path)
+    */
+   public ScopeKey getParent()
+   {
+    if (theScopes.length < 2)
+         return null;
+    ScopeKey result = new UnmodifiableScopeKey(theScopes.length - 1, theScopes);
+    return result;
+   }
+
+   /**
+    * Is this parent of key parameter.
+    *
+    * @param key the key parameter
+    * @return true if this is direct parent of key param
+    * @throws IllegalArgumentException if parameter key is null
+    */
+   public boolean isParent(ScopeKey key)
+   {
+      if (key == null)
+         throw new IllegalArgumentException("Null key");
+
+      Scope[] keyArray = key.getArray();
+
+      // The passed key doesn't have a parent
+      if (keyArray.length < 2)
+         return false;
+
+      // If it is a child, it will have one more scope
+      if (theScopes.length != keyArray.length - 1)
+         return false;
+
+      for (int looper = 0; looper < keyArray.length - 1; looper ++)
+      {
+         if(keyArray[looper].equals(theScopes[looper]) == false)
+            return false;
+      }
+      return true;
+   }
+
+
+   /**
+    * Get scope for the specified scopeLevel
+    *
+    * @param scopeLevel the scope level
+    * @return the scope or null if there is no such level
+    * @throws IllegalArgumentException if parameter scopeLevel is null
+    */
+   public Scope getScopeLevel(ScopeLevel scopeLevel)
+   {
+      if (scopeLevel == null)
+         throw new IllegalArgumentException("Null scope level");
+      return getScope(scopeLevel);
+   }
+
+
+   public String toString()
+   {
+      return getScopes().toString();
+   }
+
+   public boolean equals(Object object)
+   {
+      if (object == this)
+         return true;
+      if (object == null || object instanceof ScopeKey == false)
+         return false;
+      ScopeKey other = (ScopeKey) object;
+      Scope[] otherArray = other.getArray();
+      return Arrays.equals(theScopes, otherArray);
+   }
+
+   public int hashCode()
+   {
+      return hashcode;
+   }
+
+   /**
+    * Get the frozen.
+    *
+    * @return true as UnmodifiableScopeKey is always frozen
+    */
+   public boolean isFrozen()
+   {
+      return true;
+   }
+
+   /**
+    * This method is ignored as UnmodifiableScopeKey is always frozen
+    */
+   public void freeze()
+   {
+   }   
+
+   /**
+    * Scope cannot be added to an UnmodifiableScopeKey (instead construct a new UnmodifiableScopeKey).  
+    * Calling addScope will always fail.
+    * 
+    * @param scope the scope
+    * @throws IllegalArgumentException if scope is null.
+    * @throws IllegalStateException because UnmodifiableScopeKey is always frozen
+    */
+   public Scope addScope(Scope scope)
+   {
+      if (scope == null)
+         throw new IllegalArgumentException("Null scope");
+      throw new IllegalStateException("The scope key is frozen");
+   }
+
+    /**
+    * Scope cannot be added to an UnmodifiableScopeKey (instead construct a new UnmodifiableScopeKey).  
+    * Calling addScope will always fail.
+    *
+    * @param level the scope level
+    * @param qualifier the scope qualifier
+    * @throws IllegalStateException because UnmodifiableScopeKey is always frozen
+    */
+   public Scope addScope(ScopeLevel level, Object qualifier)
+   {
+      throw new IllegalStateException("The scope key is frozen"); 
+   }
+
+   /**
+    * Scope cannot be removed from an UnmodifiableScopeKey (instead construct a new UnmodifiableScopeKey).  
+    * Calling removeScope will always fail.
+    *
+    * @param scope the scope
+    * @throws IllegalStateException because UnmodifiableScopeKey is always frozen
+    */
+   public Scope removeScope(Scope scope)
+   {
+      throw new IllegalStateException("The scope key is frozen");
+   }
+
+   /**
+    * ScopeLevel cannot be removed from an UnmodifiableScopeKey (instead construct a new UnmodifiableScopeKey).  
+    * Calling removeScope will always fail.
+    *
+    * @param scopeLevel the scopeLevel
+    * @throws IllegalStateException because UnmodifiableScopeKey is always frozen
+    */
+   public Scope removeScopeLevel(ScopeLevel scopeLevel)
+   {
+      throw new IllegalStateException("The scope key is frozen");
+   }
+
+   
+   /**
+    * clone will always return a frozen copy of the UnmodifiableScopeKey.  
+    * This is different then ScopeKey.clone(), which returns an unfrozen ScopeKey.
+    */
+   public ScopeKey clone()
+   {
+      ScopeKey result = super.clone();
+      return result;
+   }
+
+   private static Scope[] setup(int max, Scope... scopes)
+   {
+      if (max > scopes.length)
+         max = scopes.length;
+      Scope createdScopes[] = new Scope[max];
+      for (int looper = 0; looper < max; looper++)
+         createdScopes[looper] = scopes[looper];
+      sort(createdScopes);
+      return createdScopes;
+   }
+
+   private static void sort(Scope scopes[])
+   {
+      Arrays.sort(scopes);
+   }
+
+   protected Scope[] getArray()
+   {
+      return theScopes;
+   }
+
+   protected Collection<Scope> getScopesCollection()
+   {
+      return theScopesCollection;
+   }
+
+}

Modified: projects/jboss-mdr/trunk/src/test/java/org/jboss/test/metadata/scope/test/ScopeTestSuite.java
===================================================================
--- projects/jboss-mdr/trunk/src/test/java/org/jboss/test/metadata/scope/test/ScopeTestSuite.java	2009-08-31 12:05:40 UTC (rev 93023)
+++ projects/jboss-mdr/trunk/src/test/java/org/jboss/test/metadata/scope/test/ScopeTestSuite.java	2009-08-31 12:15:15 UTC (rev 93024)
@@ -46,6 +46,7 @@
       suite.addTest(new TestSuite(CommonLevelsUnitTestCase.class));
       suite.addTest(new TestSuite(ScopeUnitTestCase.class));
       suite.addTest(new TestSuite(ScopeKeyUnitTestCase.class));
+      suite.addTest(new TestSuite(UnmodifiableScopeKeyUnitTestCase.class));
       
       return suite;
    }

Added: projects/jboss-mdr/trunk/src/test/java/org/jboss/test/metadata/scope/test/UnmodifiableScopeKeyUnitTestCase.java
===================================================================
--- projects/jboss-mdr/trunk/src/test/java/org/jboss/test/metadata/scope/test/UnmodifiableScopeKeyUnitTestCase.java	                        (rev 0)
+++ projects/jboss-mdr/trunk/src/test/java/org/jboss/test/metadata/scope/test/UnmodifiableScopeKeyUnitTestCase.java	2009-08-31 12:15:15 UTC (rev 93024)
@@ -0,0 +1,769 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, JBoss Inc., and individual contributors as indicated
+* 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.test.metadata.scope.test;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Arrays;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.jboss.metadata.spi.scope.Scope;
+import org.jboss.metadata.spi.scope.ScopeKey;
+import org.jboss.metadata.spi.scope.ScopeLevel;
+import org.jboss.test.metadata.AbstractMetaDataTest;
+
+/**
+ * UnmodifiableScopeKeyUnitTestCase is derived from ScopeKeyUnitTestCase.
+ *
+ * @author <a href="smarlow at redhat.com">Scott Marlow</a>
+ * @version $Revision: 46146 $
+ */
+public class UnmodifiableScopeKeyUnitTestCase extends AbstractMetaDataTest
+{
+   private static ScopeLevel testLevel1 = new ScopeLevel(1, "ONE");
+   private static ScopeLevel testLevel2 = new ScopeLevel(2, "TWO");
+   private static ScopeLevel testLevel3 = new ScopeLevel(3, "THREE");
+   private static ScopeLevel testLevel4 = new ScopeLevel(4, "FOUR");
+   private static ScopeLevel testLevel5 = new ScopeLevel(5, "FIVE");
+
+   private static String testQualifier1 = "qualifier1";
+   private static String testQualifier1Different = "qualifier1Different";
+   private static String testQualifier2 = "qualifier2";
+   private static String testQualifier3 = "qualifier3";
+   private static String testQualifier3Different = "qualifier3Different";
+   private static String testQualifier4 = "qualifier4";
+   private static String testQualifier5 = "qualifier5";
+
+   private static Scope testScope1 = new Scope(testLevel1, testQualifier1);
+   private static Scope testScope1Different = new Scope(testLevel1, testQualifier1Different);
+   private static Scope testScope2 = new Scope(testLevel2, testQualifier2);
+   private static Scope testScope3 = new Scope(testLevel3, testQualifier3);
+   private static Scope testScope3Different = new Scope(testLevel3, testQualifier3Different);
+   private static Scope testScope4 = new Scope(testLevel4, testQualifier4);
+   private static Scope testScope5 = new Scope(testLevel5, testQualifier5);
+
+   public UnmodifiableScopeKeyUnitTestCase(String name)
+   {
+      super(name);
+   }
+
+   public void testBasicScopeKeyConstructor() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      Scope[] expected = new Scope[0];
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertNull(key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testSingleScopeKeyConstructor() throws Exception
+   {
+      ScopeKey key = new ScopeKey(testScope1);
+      Scope[] expected = new Scope[] { testScope1 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testLevelQualifierScopeKeyConstructor() throws Exception
+   {
+      ScopeKey key = new ScopeKey(testLevel1, testQualifier1);
+      Scope[] expected = new Scope[] { testScope1 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testCollectionScopeKeyConstructor() throws Exception
+   {
+      Scope[] expected = new Scope[] {};
+      HashSet<Scope> set = new HashSet<Scope>();
+      ScopeKey key = new ScopeKey(set);
+      assertScopeKey(expected, key.getOptimizedKey());
+
+      expected = new Scope[] { testScope1 };
+      set = new HashSet<Scope>();
+      for (Scope scope : expected)
+         set.add(scope);
+      key = new ScopeKey(set);
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      expected = new Scope[] { testScope1, testScope2, testScope3, testScope4, testScope5 };
+      set = new HashSet<Scope>();
+      for (Scope scope : expected)
+         set.add(scope);
+      key = new ScopeKey(set);
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope5.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testCollectionScopeKeyConstructorSorts() throws Exception
+   {
+      Scope[] expected = new Scope[] { testScope1, testScope2, testScope3, testScope4, testScope5 };
+      HashSet<Scope> set = new HashSet<Scope>();
+      set.add(testScope2);
+      set.add(testScope4);
+      set.add(testScope5);
+      set.add(testScope3);
+      set.add(testScope1);
+      ScopeKey key = new ScopeKey(set);
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope5.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testArrayScopeKeyConstructor() throws Exception
+   {
+      Scope[] expected = new Scope[] {};
+      ScopeKey key = new ScopeKey(expected);
+      assertScopeKey(expected, key.getOptimizedKey());
+
+      expected = new Scope[] { testScope1 };
+      key = new ScopeKey(expected);
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      expected = new Scope[] { testScope1, testScope2, testScope3, testScope4, testScope5 };
+      key = new ScopeKey(expected);
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope5.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testArrayScopeKeyConstructorSorts() throws Exception
+   {
+      Scope[] expected = new Scope[] { testScope1, testScope2, testScope3, testScope4, testScope5 };
+      Scope[] array = new Scope[] { testScope5, testScope3, testScope1, testScope2, testScope4 };
+      ScopeKey key = new ScopeKey(array);
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope5.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testAddScope() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testScope1, null);
+      Scope[] expected = new Scope[] { testScope1 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      assertAddScope(key, testScope2, null);
+      expected = new Scope[] { testScope1, testScope2 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope2.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testAddScopeDuplicate() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testScope1, null);
+      Scope[] expected = new Scope[] { testScope1 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      assertAddScope(key, testScope1, testScope1);
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testAddScopeSorts() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testScope1, null);
+      assertAddScope(key, testScope3, null);
+      assertAddScope(key, testScope5, null);
+      assertAddScope(key, testScope2, null);
+      assertAddScope(key, testScope4, null);
+      Scope[] expected = new Scope[] { testScope1, testScope2, testScope3, testScope4, testScope5 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope5.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testAddScopeChange() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testScope1, null);
+      Scope[] expected = new Scope[] { testScope1 };
+      assertScopeKey(expected, key);
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      assertAddScope(key, testScope1Different, testScope1);
+      expected = new Scope[] { testScope1Different };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1Different.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testAddScopeChangeSorts() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testScope1, null);
+      assertAddScope(key, testScope2, null);
+      assertAddScope(key, testScope3, null);
+      assertAddScope(key, testScope4, null);
+      assertAddScope(key, testScope5, null);
+      Scope[] expected = new Scope[] { testScope1, testScope2, testScope3, testScope4, testScope5 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope5.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      assertAddScope(key, testScope3Different, testScope3);
+      expected = new Scope[] { testScope1, testScope2, testScope3Different, testScope4, testScope5 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope5.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testAddScopeLevelQualifier() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testLevel1, testQualifier1, null);
+      Scope[] expected = new Scope[] { testScope1 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      assertAddScope(key, testLevel2, testQualifier2, null);
+      expected = new Scope[] { testScope1, testScope2 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope2.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testAddScopeLevelQualifierDuplicate() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testLevel1, testQualifier1, null);
+      Scope[] expected = new Scope[] { testScope1 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      assertAddScope(key, testLevel1, testQualifier1, testScope1);
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testAddScopeLevelQualifierSorts() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testLevel4, testQualifier4, null);
+      assertAddScope(key, testLevel2, testQualifier2, null);
+      assertAddScope(key, testLevel1, testQualifier1, null);
+      assertAddScope(key, testLevel3, testQualifier3, null);
+      assertAddScope(key, testLevel5, testQualifier5, null);
+      Scope[] expected = new Scope[] { testScope1, testScope2, testScope3, testScope4, testScope5 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope5.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testAddScopeLevelChange() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testLevel1, testQualifier1, null);
+      Scope[] expected = new Scope[] { testScope1 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      assertAddScope(key, testLevel1, testQualifier1Different, testScope1);
+      expected = new Scope[] { testScope1Different };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1Different.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+ }
+
+   public void testAddScopeLevelChangeSorts() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testLevel1, testQualifier1, null);
+      assertAddScope(key, testLevel2, testQualifier2, null);
+      assertAddScope(key, testLevel3, testQualifier3, null);
+      assertAddScope(key, testLevel4, testQualifier4, null);
+      assertAddScope(key, testLevel5, testQualifier5, null);
+      Scope[] expected = new Scope[] { testScope1, testScope2, testScope3, testScope4, testScope5 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope5.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      assertAddScope(key, testLevel3, testQualifier3Different, testScope3);
+      expected = new Scope[] { testScope1, testScope2, testScope3Different, testScope4, testScope5 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope5.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testRemoveScope() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testScope1, null);
+      Scope[] expected = new Scope[] { testScope1 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      assertRemoveScope(key, testScope1, testScope1);
+      expected = new Scope[0];
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertNull(key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testRemoveScopeSorts() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testScope1, null);
+      assertAddScope(key, testScope2, null);
+      assertAddScope(key, testScope3, null);
+      Scope[] expected = new Scope[] { testScope1, testScope2, testScope3 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope3.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      assertRemoveScope(key, testScope2, testScope2);
+      expected = new Scope[] { testScope1, testScope3 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope3.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testRemoveScopeLevel() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testLevel1, testQualifier1, null);
+      Scope[] expected = new Scope[] { testScope1 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope1.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      assertRemoveScope(key, testLevel1, testScope1);
+      expected = new Scope[0];
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertNull(key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testRemoveScopeLevelSorts() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      assertAddScope(key, testLevel1, testQualifier1, null);
+      assertAddScope(key, testLevel2, testQualifier2, null);
+      assertAddScope(key, testLevel3, testQualifier3, null);
+      Scope[] expected = new Scope[] { testScope1, testScope2, testScope3 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope3.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      assertRemoveScope(key, testLevel2, testScope2);
+      expected = new Scope[] { testScope1, testScope3 };
+      assertScopeKey(expected, key.getOptimizedKey());
+      assertEquals(testScope3.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+   }
+
+   public void testFreeze() throws Exception
+   {
+      ScopeKey key = new ScopeKey(testScope1).getOptimizedKey();
+      // key.freeze();
+      try
+      {
+         key.addScope(testScope1);
+         fail("Should not be here!");
+      }
+      catch (IllegalStateException expected)
+      {
+      }
+      try
+      {
+         key.addScope(testLevel1, testQualifier1);
+         fail("Should not be here!");
+      }
+      catch (IllegalStateException expected)
+      {
+      }
+      try
+      {
+         key.removeScope(testScope1);
+         fail("Should not be here!");
+      }
+      catch (IllegalStateException expected)
+      {
+      }
+      try
+      {
+         key.removeScopeLevel(testLevel1);
+         fail("Should not be here!");
+      }
+      catch (IllegalStateException expected)
+      {
+      }
+   }
+
+   public void testNoParentEmpty() throws Exception
+   {
+      ScopeKey key = new ScopeKey().getOptimizedKey();
+      ScopeKey parent = key.getParent();
+      assertNull(parent);
+   }
+
+   public void testNoParentSingleScope() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      key.addScope(testScope1);
+      ScopeKey parent = key.getOptimizedKey().getParent();
+      assertNull(parent);
+   }
+
+   public void testSimpleParent() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      key.addScope(testScope1);
+      key.addScope(testScope2);
+      ScopeKey parent = key.getOptimizedKey().getParent();
+      assertNotNull(parent);
+
+      ScopeKey expected = new ScopeKey();
+      expected.addScope(testScope1);
+      assertEquals(expected, parent);
+      assertEquals(testScope1.getScopeLevel(), parent.getMaxScopeLevel());
+   }
+
+   public void testComplexParent() throws Exception
+   {
+      ScopeKey key = new ScopeKey();
+      key.addScope(testScope1);
+      key.addScope(testScope2);
+      key.addScope(testScope3);
+      key.addScope(testScope4);
+      key.addScope(testScope5);
+      assertEquals(testScope5.getScopeLevel(), key.getOptimizedKey().getMaxScopeLevel());
+
+      ScopeKey parent = key.getOptimizedKey().getParent();
+      assertNotNull(parent);
+      ScopeKey expected = new ScopeKey();
+      expected.addScope(testScope1);
+      expected.addScope(testScope2);
+      expected.addScope(testScope3);
+      expected.addScope(testScope4);
+      assertEquals(expected, parent);
+      assertEquals(expected.getOptimizedKey(), parent);
+      assertEquals(testScope4.getScopeLevel(), parent.getMaxScopeLevel());
+
+      parent = parent.getParent();
+      assertNotNull(parent);
+      expected = new ScopeKey();
+      expected.addScope(testScope1);
+      expected.addScope(testScope2);
+      expected.addScope(testScope3);
+      assertEquals(expected, parent);
+      assertEquals(expected.getOptimizedKey(), parent);
+      assertEquals(testScope3.getScopeLevel(), parent.getMaxScopeLevel());
+
+      parent = parent.getParent();
+      assertNotNull(parent);
+      expected = new ScopeKey();
+      expected.addScope(testScope1);
+      expected.addScope(testScope2);
+      assertEquals(expected, parent);
+      assertEquals(expected.getOptimizedKey(), parent);
+      assertEquals(testScope2.getScopeLevel(), parent.getMaxScopeLevel());
+
+      parent = parent.getParent();
+      assertNotNull(parent);
+      expected = new ScopeKey();
+      expected.addScope(testScope1);
+      assertEquals(expected, parent);
+      assertEquals(expected.getOptimizedKey(), parent);
+      assertEquals(testScope1.getScopeLevel(), parent.getMaxScopeLevel());
+
+      parent = parent.getParent();
+      assertNull(parent);
+   }
+
+   public void testIsParentNoScopes() throws Exception
+   {
+      ScopeKey parent = new ScopeKey(testScope1).getOptimizedKey();
+      ScopeKey test = new ScopeKey();
+      assertFalse(parent.isParent(test));
+      assertFalse(parent.isParent(test.getOptimizedKey()));
+   }
+
+   public void testIsParentSameScope() throws Exception
+   {
+      ScopeKey parent = new ScopeKey(testScope1).getOptimizedKey();
+      assertFalse(parent.isParent(parent));
+
+      ScopeKey test = new ScopeKey(testScope1).getOptimizedKey();
+      assertFalse(parent.isParent(test));
+   }
+
+   public void testIsParentDifferentLevel() throws Exception
+   {
+      ScopeKey parent = new ScopeKey(testScope1).getOptimizedKey();
+      ScopeKey test = new ScopeKey(testScope2).getOptimizedKey();
+      assertFalse(parent.isParent(test));
+   }
+
+   public void testIsParentDifferentQualifier() throws Exception
+   {
+      ScopeKey parent = new ScopeKey(testScope1).getOptimizedKey();
+      ScopeKey test = new ScopeKey(testScope1Different).getOptimizedKey();
+      assertFalse(parent.isParent(test));
+   }
+
+   public void testIsParent() throws Exception
+   {
+      ScopeKey parent = new ScopeKey(testScope1).getOptimizedKey();
+      ScopeKey test = new ScopeKey();
+      test.addScope(testScope1);
+      test.addScope(testScope2);
+      assertTrue(parent.isParent(test));
+      assertTrue(parent.isParent(test.getOptimizedKey()));
+      test = new ScopeKey();
+      test.addScope(testScope1);
+      test.addScope(testScope3);
+      assertTrue(parent.isParent(test));
+      assertTrue(parent.isParent(test.getOptimizedKey()));
+   }
+
+   public void testIsParentNotDirectly() throws Exception
+   {
+      ScopeKey parent = new ScopeKey(testScope1).getOptimizedKey();
+      ScopeKey test = new ScopeKey();
+      test.addScope(testScope1);
+      test.addScope(testScope2);
+      test.addScope(testScope3);
+      assertFalse(parent.isParent(test));
+      assertFalse(parent.isParent(test.getOptimizedKey()));
+   }
+
+   public void testIsParentNotChild() throws Exception
+   {
+      ScopeKey parent = new ScopeKey();
+      parent.addScope(testScope1);
+      parent.addScope(testScope2);
+
+      ScopeKey test = new ScopeKey();
+      test.addScope(testScope1);
+      assertFalse(parent.isParent(test.getOptimizedKey()));
+      assertFalse(parent.getOptimizedKey().isParent(test.getOptimizedKey()));
+      assertFalse(parent.getOptimizedKey().isParent(test));
+      
+   }
+
+   public void testIsParentComplicated() throws Exception
+   {
+      ScopeKey parent = new ScopeKey();
+      parent.addScope(testScope1);
+      parent.addScope(testScope2);
+      parent.addScope(testScope3);
+      parent.addScope(testScope4);
+
+      ScopeKey test = new ScopeKey();
+      test.addScope(testScope1);
+      test.addScope(testScope2);
+      test.addScope(testScope3);
+      test.addScope(testScope4);
+      test.addScope(testScope5);
+      assertTrue(parent.isParent(test.getOptimizedKey()));
+      assertTrue(parent.getOptimizedKey().isParent(test.getOptimizedKey()));
+      assertTrue(parent.getOptimizedKey().isParent(test));
+   }
+
+   public void testEqualsEmpty() throws Exception
+   {
+      ScopeKey key1 = new ScopeKey();
+      ScopeKey key2 = new ScopeKey();
+      assertEquals(key1.getOptimizedKey(), key2);
+      assertEquals(key1.getOptimizedKey(), key2.getOptimizedKey());
+      assertEquals(key1, key2.getOptimizedKey());
+   }
+
+   public void testEqualsAfterAdd() throws Exception
+   {
+      ScopeKey key1 = new ScopeKey();
+      ScopeKey key2 = new ScopeKey();
+      assertAddScope(key1, testScope1, null);
+      assertAddScope(key2, testScope1, null);
+      assertAddScope(key1, testScope2, null);
+      assertAddScope(key2, testScope2, null);
+      assertAddScope(key1, testScope3, null);
+      assertAddScope(key2, testScope3, null);
+      assertEquals(key1.getOptimizedKey(), key2);
+      assertEquals(key1.getOptimizedKey(), key2.getOptimizedKey());
+      assertEquals(key1, key2.getOptimizedKey());
+
+   }
+
+   public void testEqualsAfterRemove() throws Exception
+   {
+      ScopeKey key1 = new ScopeKey();
+      ScopeKey key2 = new ScopeKey();
+      assertAddScope(key1, testScope1, null);
+      assertAddScope(key2, testScope1, null);
+      assertAddScope(key1, testScope2, null);
+      assertAddScope(key2, testScope2, null);
+      assertAddScope(key1, testScope3, null);
+      assertAddScope(key2, testScope3, null);
+      assertRemoveScope(key1, testScope2, testScope2);
+      assertRemoveScope(key2, testScope2, testScope2);
+      assertEquals(key1.getOptimizedKey(), key2);
+      assertEquals(key1.getOptimizedKey(), key2.getOptimizedKey());
+      assertEquals(key1, key2.getOptimizedKey());
+   }
+
+   public void testEqualsAfterReplace() throws Exception
+   {
+      ScopeKey key1 = new ScopeKey();
+      ScopeKey key2 = new ScopeKey();
+      assertAddScope(key1, testScope1, null);
+      assertAddScope(key2, testScope1, null);
+      assertAddScope(key1, testScope2, null);
+      assertAddScope(key2, testScope2, null);
+      assertAddScope(key1, testScope3, null);
+      assertAddScope(key2, testScope3, null);
+      assertAddScope(key1, testScope3Different, testScope3);
+      assertAddScope(key2, testScope3Different, testScope3);
+      assertEquals(key1.getOptimizedKey(), key2);
+      assertEquals(key1.getOptimizedKey(), key2.getOptimizedKey());
+      assertEquals(key1, key2.getOptimizedKey());
+   }
+
+   public void testNotEqualsAfterAdd() throws Exception
+   {
+      ScopeKey key1 = new ScopeKey();
+      ScopeKey key2 = new ScopeKey();
+      assertAddScope(key1, testScope1, null);
+      assertAddScope(key2, testScope1, null);
+      assertAddScope(key1, testScope2, null);
+      assertAddScope(key2, testScope2, null);
+      assertEquals(key1.getOptimizedKey(), key2);
+      assertEquals(key1.getOptimizedKey(), key2.getOptimizedKey());
+      assertEquals(key1, key2.getOptimizedKey());
+      assertAddScope(key1, testScope3, null);
+      assertFalse(key1.getOptimizedKey().equals(key2));
+      assertFalse(key1.getOptimizedKey().equals(key2.getOptimizedKey()));
+      assertFalse(key1.equals(key2.getOptimizedKey()));
+   }
+
+   public void testNotEqualsAfterRemove() throws Exception
+   {
+      ScopeKey key1 = new ScopeKey();
+      ScopeKey key2 = new ScopeKey();
+      assertAddScope(key1, testScope1, null);
+      assertAddScope(key2, testScope1, null);
+      assertAddScope(key1, testScope2, null);
+      assertAddScope(key2, testScope2, null);
+      assertAddScope(key1, testScope3, null);
+      assertAddScope(key2, testScope3, null);
+      assertEquals(key1.getOptimizedKey(), key2);
+      assertEquals(key1.getOptimizedKey(), key2.getOptimizedKey());
+      assertEquals(key1, key2.getOptimizedKey());
+      assertRemoveScope(key1, testScope2, testScope2);
+      assertFalse(key1.getOptimizedKey().equals(key2));
+      assertFalse(key1.getOptimizedKey().equals(key2.getOptimizedKey()));
+      assertFalse(key1.equals(key2.getOptimizedKey()));
+   }
+
+   public void testNotEqualsAfterReplace() throws Exception
+   {
+      ScopeKey key1 = new ScopeKey();
+      ScopeKey key2 = new ScopeKey();
+      assertAddScope(key1, testScope1, null);
+      assertAddScope(key2, testScope1, null);
+      assertAddScope(key1, testScope2, null);
+      assertAddScope(key2, testScope2, null);
+      assertAddScope(key1, testScope3, null);
+      assertAddScope(key2, testScope3, null);
+      assertEquals(key1.getOptimizedKey(), key2);
+      assertEquals(key1.getOptimizedKey(), key2.getOptimizedKey());
+      assertEquals(key1, key2.getOptimizedKey());
+      assertAddScope(key1, testScope3Different, testScope3);
+      assertFalse(key1.getOptimizedKey().equals(key2));
+      assertFalse(key1.getOptimizedKey().equals(key2.getOptimizedKey()));
+      assertFalse(key1.equals(key2.getOptimizedKey()));
+   }
+
+   public void testScopeKeyClassMethodsAreCovered() throws Exception
+   {
+      ScopeKey scopeKey = new ScopeKey();
+      ScopeKey unmodifiableScopeKey = scopeKey.getOptimizedKey();
+
+      Method scopeKeyMethods[] =  scopeKey.getClass().getDeclaredMethods();
+      Method unmodifiableScopeKeyMethods[] =  unmodifiableScopeKey.getClass().getDeclaredMethods();
+
+      // every public (non-constructor) method in scopeKeyMethods, needs to be in unmodifiableScopeKeyMethods
+      for( Method scopeKeyMethod : scopeKeyMethods)
+      {
+         int modifiers = scopeKeyMethod.getModifiers();
+
+         if (Modifier.isPublic(modifiers))   // only check public methods which could be part of the ScopeKey api
+         {
+            boolean matched = false;
+            for (Method unmodifiableScopeKeyMethod : unmodifiableScopeKeyMethods)
+               if (match(scopeKeyMethod, unmodifiableScopeKeyMethod))
+                  matched = true;
+            assertTrue("ScopeKey method " + scopeKeyMethod +
+               " not found in UnmodifiableScopeKey class.  UnmodifiableScopeKey methods="+
+               showMethods(unmodifiableScopeKeyMethods),
+               matched);
+         }
+      }
+      
+   }
+
+   private boolean match(Method m1, Method m2)
+   {
+      Class<?> m1Types[] = m1.getParameterTypes();
+      Class<?> m2Types[] = m2.getParameterTypes();
+
+      boolean result = m1.getName().equals(m2.getName()) &&
+         Arrays.equals(m1Types, m2Types);   
+      return result;
+   }
+
+   private String showMethods(Method methods[])
+   {
+      String result = "";
+      for (Method method : methods)
+      {
+         result += "Method: " + method.toString() +", ";
+      }
+      return result;
+   }
+
+   protected void assertScopeKey(Scope[] scopes, ScopeKey key) throws Exception
+   {
+      assertNotNull(scopes);
+      assertNotNull(key);
+
+      Collection<Scope> result = key.getOptimizedKey().getScopes();
+      assertEquals(scopes.length, result.size());
+
+      int index = 0;
+      for (Scope scope : result)
+         assertEquals(scopes[index++], scope);
+   }
+
+   protected void assertAddScope(ScopeKey key, Scope add, Scope expected) throws Exception
+   {
+      Scope previous = key.addScope(add);
+      assertEquals(expected, previous);
+   }
+
+   protected void assertRemoveScope(ScopeKey key, Scope remove, Scope expected) throws Exception
+   {
+      Scope previous = key.removeScope(remove);
+      assertEquals(expected, previous);
+   }
+
+   protected void assertAddScope(ScopeKey key, ScopeLevel level, String qualifier, Scope expected) throws Exception
+   {
+      Scope previous = key.addScope(level, qualifier);
+      assertEquals(expected, previous);
+   }
+
+   protected void assertRemoveScope(ScopeKey key, ScopeLevel level, Scope expected) throws Exception
+   {
+      Scope previous = key.removeScopeLevel(level);
+      assertEquals(expected, previous);
+   }
+}
\ No newline at end of file




More information about the jboss-cvs-commits mailing list