You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by mh...@apache.org on 2011/08/12 03:46:37 UTC

[Lucene.Net] svn commit: r1156935 - in /incubator/lucene.net/branches/Lucene.Net_4e: src/Lucene.Net/ src/Lucene.Net/Analysis/ src/Lucene.Net/Analysis/TokenAttributes/ src/Lucene.Net/Support/ src/Lucene.Net/Util/ test/Lucene.Net.Test/Support/

Author: mherndon
Date: Fri Aug 12 01:46:36 2011
New Revision: 1156935

URL: http://svn.apache.org/viewvc?rev=1156935&view=rev
Log:
Porting Lucene 4's AttributeSource and AttributeFactory and default attribute factory without tests at the moment. This is in order to work towards finishing up with the analysis folder.

Added:
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/ICloneableOfT.cs
      - copied, changed from r1156492, incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeFactory.cs
Modified:
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/CharTermAttribute.cs
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/FlagsAttribute.cs
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/PayloadAttribute.cs
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/TypeAttribute.cs
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenStream.cs
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Lucene.Net.csproj
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeBase.cs
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeSource.cs
    incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs

Modified: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/CharTermAttribute.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/CharTermAttribute.cs?rev=1156935&r1=1156934&r2=1156935&view=diff
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/CharTermAttribute.cs (original)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/CharTermAttribute.cs Fri Aug 12 01:46:36 2011
@@ -220,7 +220,7 @@ namespace Lucene.Net.Analysis.TokenAttri
         /// Creates a clone of the object, generally shallow.
         /// </summary>
         /// <returns>an the clone of the current instance.</returns>
-        public override object Clone()
+        public override AttributeBase Clone()
         {
             CharTermAttribute clone = (CharTermAttribute)this.MemberwiseClone();
 

Modified: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/FlagsAttribute.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/FlagsAttribute.cs?rev=1156935&r1=1156934&r2=1156935&view=diff
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/FlagsAttribute.cs (original)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/FlagsAttribute.cs Fri Aug 12 01:46:36 2011
@@ -85,7 +85,7 @@ namespace Lucene.Net.Analysis.TokenAttri
         /// Creates a clone of the object, generally shallow.
         /// </summary>
         /// <returns>an the clone of the current instance.</returns>
-        public override object Clone()
+        public override AttributeBase Clone()
         {
             return new FlagsAttribute { Flags = this.Flags };
         }

Modified: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/PayloadAttribute.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/PayloadAttribute.cs?rev=1156935&r1=1156934&r2=1156935&view=diff
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/PayloadAttribute.cs (original)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/PayloadAttribute.cs Fri Aug 12 01:46:36 2011
@@ -66,7 +66,7 @@ namespace Lucene.Net.Analysis.TokenAttri
         /// Creates a clone of the object, generally shallow.
         /// </summary>
         /// <returns>an the clone of the current instance.</returns>
-        public override object Clone()
+        public override AttributeBase Clone()
         {
             PayloadAttribute clone = (PayloadAttribute)this.MemberwiseClone();
             

Modified: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/TypeAttribute.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/TypeAttribute.cs?rev=1156935&r1=1156934&r2=1156935&view=diff
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/TypeAttribute.cs (original)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/TypeAttribute.cs Fri Aug 12 01:46:36 2011
@@ -72,7 +72,7 @@ namespace Lucene.Net.Analysis.TokenAttri
         /// Creates a clone of the object, generally shallow.
         /// </summary>
         /// <returns>an the clone of the current instance.</returns>
-        public override object Clone()
+        public override AttributeBase Clone()
         {
             return new TypeAttribute() { Type = this.Type };
         }

Modified: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenStream.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenStream.cs?rev=1156935&r1=1156934&r2=1156935&view=diff
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenStream.cs (original)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenStream.cs Fri Aug 12 01:46:36 2011
@@ -25,11 +25,12 @@ namespace Lucene.Net.Analysis
     using System.Collections.Generic;
     using System.Linq;
     using System.Text;
+    using Lucene.Net.Util;
 
     /// <summary>
     /// TODO: port
     /// </summary>
-    public class TokenStream
+    public class TokenStream : AttributeSource 
     {
     }
 }
\ No newline at end of file

Modified: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Lucene.Net.csproj
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Lucene.Net.csproj?rev=1156935&r1=1156934&r2=1156935&view=diff
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Lucene.Net.csproj (original)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Lucene.Net.csproj Fri Aug 12 01:46:36 2011
@@ -18,7 +18,7 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>..\..\build\bin\core\Debug\</OutputPath>
-    <DefineConstants>TRACE;DEBUG;SILVERLIGHT;WMP;</DefineConstants>
+    <DefineConstants>TRACE;DEBUG;SILVERLIGHT;WMP;SILVERLIGHT_4;WMP_4</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>..\..\build\bin\core\Debug\Lucene.Net.XML</DocumentationFile>
@@ -70,6 +70,7 @@
     <Compile Include="Support\BaseDictionaryOfTKeyTValue.cs" />
     <Compile Include="Support\ICloneable.cs" />
     <Compile Include="Support\DictionaryExtensions.cs" />
+    <Compile Include="Support\ICloneableOfT.cs" />
     <Compile Include="Support\ICloseable.cs" />
     <Compile Include="Support\Threading\LocalDataStoreSlot.cs" />
     <Compile Include="Support\Threading\ThreadData.cs" />
@@ -81,6 +82,7 @@
     <Compile Include="Support\WeakReferenceOfT.cs" />
     <Compile Include="Util\ArrayUtil.cs" />
     <Compile Include="Util\AttributeBase.cs" />
+    <Compile Include="Util\AttributeFactory.cs" />
     <Compile Include="Util\AttributeSource.cs" />
     <Compile Include="Util\BytesRef.cs" />
     <Compile Include="Util\IAttribute.cs" />

Copied: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/ICloneableOfT.cs (from r1156492, incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs)
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/ICloneableOfT.cs?p2=incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/ICloneableOfT.cs&p1=incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs&r1=1156492&r2=1156935&rev=1156935&view=diff
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs (original)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/ICloneableOfT.cs Fri Aug 12 01:46:36 2011
@@ -1,5 +1,5 @@
 // -----------------------------------------------------------------------
-// <copyright company="Apache" file="ICloneable.cs">
+// <copyright company="Apache" file="ICloneableOfT.cs">
 //
 //      Licensed to the Apache Software Foundation (ASF) under one or more
 //      contributor license agreements.  See the NOTICE file distributed with
@@ -27,11 +27,15 @@ namespace Lucene.Net.Support
     using System.Text;
 
     /// <summary>
-    /// 
+    /// Contract for clone an object
     /// </summary>
-    /// <typeparam name="T"></typeparam>
+    /// <typeparam name="T">The clone type</typeparam>
     public interface ICloneable<out T> : ICloneable
     {
+        /// <summary>
+        /// Clones this instance.
+        /// </summary>
+        /// <returns>returns a cloned instance of the specified type.</returns>
         new T Clone();
     }
-}
+}
\ No newline at end of file

Modified: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeBase.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeBase.cs?rev=1156935&r1=1156934&r2=1156935&view=diff
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeBase.cs (original)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeBase.cs Fri Aug 12 01:46:36 2011
@@ -49,7 +49,7 @@ namespace Lucene.Net.Util
     ///         </para>
     ///     </note>
     /// </remarks>
-    public abstract class AttributeBase : IAttribute, ICloneable
+    public abstract class AttributeBase : IAttribute, ICloneable, ICloneable<AttributeBase>
     {
         /// <summary>
         /// Clears the instance.
@@ -130,9 +130,18 @@ namespace Lucene.Net.Util
         /// Creates a clone of the object, generally shallow.
         /// </summary>
         /// <returns>an the clone of the current instance.</returns>
-        public virtual object Clone()
+        object ICloneable.Clone()
         {
-            var obj = this.MemberwiseClone();
+            return this.Clone();
+        }
+
+        /// <summary>
+        /// Creates a shallow clone of this instance by default. 
+        /// </summary>
+        /// <returns>an instance of <see cref="AttributeBase"/></returns>
+        public virtual AttributeBase Clone()
+        {
+            var obj = (AttributeBase)this.MemberwiseClone();
             return obj;
         }
     }

Added: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeFactory.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeFactory.cs?rev=1156935&view=auto
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeFactory.cs (added)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeFactory.cs Fri Aug 12 01:46:36 2011
@@ -0,0 +1,136 @@
+// -----------------------------------------------------------------------
+// <copyright company="Apache" file="AttributeFactory.cs">
+//
+//      Licensed to the Apache Software Foundation (ASF) under one or more
+//      contributor license agreements.  See the NOTICE file distributed with
+//      this work for additional information regarding copyright ownership.
+//      The ASF licenses this file to You under the Apache License, Version 2.0
+//      (the "License"); you may not use this file except in compliance with
+//      the License.  You may obtain a copy of the License at
+// 
+//      http://www.apache.org/licenses/LICENSE-2.0
+// 
+//      Unless required by applicable law or agreed to in writing, software
+//      distributed under the License is distributed on an "AS IS" BASIS,
+//      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//      See the License for the specific language governing permissions and
+//      limitations under the License.
+//
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Lucene.Net.Util
+{
+    using System;
+    using Support;
+
+
+    /// <summary>
+    /// A contract for factories that create instances of <see cref="AttributeBase" />
+    /// that are map to interfaces that extend <see cref="IAttribute" />
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         The factory is abstract so the behavior of how interfaces that derive from
+    ///         <see cref="IAttribute"/> are mapped to concrete types that implement that 
+    ///         interface. The factory also can change how the concrete types are created.
+    ///     </para>
+    ///     <para>
+    ///         You could easily create your own factory that replaces the default 
+    ///         behavior with Dependency Injection. 
+    ///     </para>
+    /// </remarks>
+    /// <seealso cref="DefaultFactory"/>
+    public abstract class AttributeFactory
+    {
+        /// <summary>
+        /// Returns the default implementation for <see cref="AttributeFactory"/>, an instance of
+        /// <see cref="DefaultAttributeFactory"/>. 
+        /// </summary>
+        /// <remarks>
+        ///     <para>
+        ///         The default factory uses a name convention to retrieve and create instances
+        ///         of <see cref="AttributeBase" />. The convention is based on the name of 
+        ///         the interface types that are subclasses of <see cref="IAttribute"/>.
+        ///     </para>
+        ///     <para>
+        ///         The Java version appends "Impl" to each interface name. The .NET version
+        ///         removes the &quot;I&quot; from the interface name by using <c>type.Name.Substring(0)</c>.
+        ///     </para>
+        /// </remarks>
+        public static readonly AttributeFactory DefaultFactory = new DefaultAttributeFactory();
+
+        /// <summary>
+        /// Creates the <see cref="AttributeBase"/> instance based on the <typeparamref name="T"/> parameter
+        /// that must derive from both <see cref="AttributeBase"/> and <see cref="IAttribute"/>.
+        /// </summary>
+        /// <typeparam name="T">The type of interface</typeparam>
+        /// <returns>An instance of <see cref="AttributeBase"/>.</returns>
+        public abstract AttributeBase CreateAttributeInstance<T>() where T : IAttribute;
+
+        /// <summary>
+        /// Creates the <see cref="AttributeBase"/> instance based on the interface <paramref name="type"/> 
+        /// that derives from <see cref="IAttribute"/>.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns>
+        /// An instance of <see cref="AttributeBase"/>.
+        /// </returns>
+        public abstract AttributeBase CreateAttributeInstance(Type type);
+
+
+        /// <summary>
+        /// The default attribute factory implementation.
+        /// </summary>
+        private sealed class DefaultAttributeFactory : AttributeFactory
+        {
+            private static readonly WeakDictionary<Type, Type> map =
+                new WeakDictionary<Type, Type>();
+
+
+            public override AttributeBase CreateAttributeInstance<T>()
+            {
+                var implementationType = FetchClassForInterface(typeof(T));
+                return CreateAttributeInstance(typeof(T));
+            }
+
+            public override AttributeBase CreateAttributeInstance(Type type)
+            {
+                var implementationType = FetchClassForInterface(type);
+                return (AttributeBase)Activator.CreateInstance(implementationType);
+            }
+
+
+            private static Type FetchClassForInterface(Type type)
+            {
+                Type value;
+                lock (map)
+                {
+                    if (!map.TryGetValue(type, out value))
+                    {
+                        var interfaceName = type.Name;
+                        var typeName = interfaceName.Substring(1);
+
+                        try
+                        {
+                            value = Type.GetType(string.Format("{0}.{1}", type.Namespace, typeName));
+                        }
+                        catch (Exception ex)
+                        {
+                            throw new ArgumentException(
+                                string.Format(
+                                    "The implementation '{0}' could not be found for attribute interface '{1}'",
+                                    typeName,
+                                    type.FullName), 
+                                    ex);
+                        }
+
+                        map.Add(type, value);
+                    }
+                }
+
+                return value;
+            }
+        }
+    }
+}

Modified: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeSource.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeSource.cs?rev=1156935&r1=1156934&r2=1156935&view=diff
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeSource.cs (original)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Util/AttributeSource.cs Fri Aug 12 01:46:36 2011
@@ -19,10 +19,15 @@
 // </copyright>
 // -----------------------------------------------------------------------
 
+
+
+
 namespace Lucene.Net.Util
 {
     using System;
     using System.Collections.Generic;
+    using Lucene.Net.Analysis;
+    using Lucene.Net.Analysis.TokenAttributes;
     using Support;
 
 
@@ -54,13 +59,75 @@ namespace Lucene.Net.Util
     ///         </para>
     ///     </note>
     /// </remarks>
-    public class AttributeSource
+    public partial class AttributeSource 
     {
         private static readonly object instanceLock = new object();
-
         private static readonly WeakDictionary<Type, LinkedList<WeakReference<Type>>> knownAttributeClasses =
             new WeakDictionary<Type, LinkedList<WeakReference<Type>>>();
 
+        private readonly Dictionary<Type, AttributeBase> interfaceMap = new Dictionary<Type, AttributeBase>();
+        private readonly Dictionary<Type, AttributeBase> attributeMap = new Dictionary<Type, AttributeBase>();
+        
+        private State[] currentState;
+
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AttributeSource"/> class. 
+        /// This constructor uses the <see cref="AttributeFactory.DefaultFactory"/>
+        /// </summary>
+        public AttributeSource()
+            : this(AttributeFactory.DefaultFactory)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AttributeSource"/> class. 
+        /// This uses another attribute source to create a new one based on the internally
+        /// store maps of <see cref="Type"/> to instances of <see cref="AttributeBase"/>
+        /// </summary>
+        /// <param name="source">The source.</param>
+        public AttributeSource(AttributeSource source)
+        {
+            this.attributeMap = source.attributeMap;
+            this.interfaceMap = source.interfaceMap;
+            this.currentState = source.currentState;
+            this.Factory = source.Factory;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AttributeSource"/> class. Creates
+        /// a new attribute source with the specified factory.
+        /// </summary>
+        /// <param name="factory">The factory.</param>
+        public AttributeSource(AttributeFactory factory)
+        {
+            this.attributeMap = new Dictionary<Type, AttributeBase>();
+            this.interfaceMap = new Dictionary<Type, AttributeBase>();
+            this.currentState = new State[1];
+
+            this.Factory = factory;
+        }
+
+
+        /// <summary>
+        /// Gets the attribute factory.
+        /// </summary>
+        /// <value>The factory.</value>
+        public AttributeFactory Factory { get; private set; }
+
+        /// <summary>
+        /// Gets a value indicating whether this instance has attributes.
+        /// </summary>
+        /// <value>
+        ///    <c>true</c> if this instance has attributes; otherwise, <c>false</c>.
+        /// </value>
+        public bool HasAttributes
+        {
+            get { return this.attributeMap.Count > 0; }
+        }
+
+        
+
         /// <summary>
         /// Gets the attribute interfaces.
         /// </summary>
@@ -92,7 +159,7 @@ namespace Lucene.Net.Util
                                 foundInterfaces.AddLast(new WeakReference<Type>(currentInterface));
                             }
                         }
-                          
+
                         activeType = activeType.BaseType;
                     } while (activeType != null);
                 }
@@ -101,13 +168,540 @@ namespace Lucene.Net.Util
             }
         }
 
+
+        /// <summary>
+        /// Adds the attribute.
+        /// </summary>
+        /// <param name="attribute">The attribute.</param>
+        public void AddAttribute(AttributeBase attribute)
+        {
+            if (attribute == null)
+                throw new ArgumentNullException("attribute");
+
+            Type type = attribute.GetType();
+            if (this.attributeMap.ContainsKey(type))
+                return;
+
+            var foundInterfaces = GetAttributeInterfaces(type);
+            foreach (var interfaceTypeRef in foundInterfaces)
+            {
+                var interfaceType = interfaceTypeRef.Target;
+
+#if DEBUG
+                System.Diagnostics.Debug.Assert(interfaceType != null, "We have a strong reference on the class holding the interfaces, so they should never get evicted");
+#endif
+                
+                if (!this.interfaceMap.ContainsKey(interfaceType))
+                {
+                    this.currentState[0] = null;
+                    this.attributeMap.Add(type, attribute);
+                    this.interfaceMap.Add(interfaceType, attribute);
+                }
+            }
+        }
+
         /// <summary>
         /// Adds an attribute.
         /// </summary>
         /// <param name="attributeType">The type of attribute that is to be added.</param>
-        public void AddAttribute(Type attributeType)
+        /// <exception cref="ArgumentNullException">
+        ///         Thrown when <paramref name="attributeType"/> is null.
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///     Thrown when <paramref name="attributeType"/> is not a type of interface
+        ///     that inherits from <see cref="IAttribute"/>.
+        /// </exception>
+        /// <returns>
+        /// The instance of <see cref="AttributeBase"/> that was created.
+        /// </returns>
+        public AttributeBase AddAttribute(Type attributeType)
         {
-            throw new NotImplementedException();
+            if (attributeType == null)
+                throw new ArgumentNullException("attributeType");
+
+            AttributeBase instance;
+
+            if (this.attributeMap.TryGetValue(attributeType, out instance))
+            {
+                if (!attributeType.IsInterface)
+                    throw new ArgumentException("The type must be an interface.");
+
+                if (!attributeType.IsSubclassOf(typeof(IAttribute)))
+                    throw new ArgumentException(
+                        string.Format(
+                            "The interface type '{0}' is not a subclass of IAttribute.",
+                            attributeType.FullName));
+
+                this.AddAttribute(instance = this.Factory.CreateAttributeInstance(attributeType));
+            }
+
+            return instance;
+        }
+
+        /// <summary>
+        /// Adds the attribute.
+        /// </summary>
+        /// <typeparam name="T">The type of AttributeBase that is to be added.</typeparam>
+        /// <returns>An instance of <typeparamref name="T"/>.</returns>
+        public T AddAttribute<T>() where T : AttributeBase, IAttribute
+        {
+            return (T)this.AddAttribute(typeof(T));
+        }
+
+        /// <summary>
+        /// Captures the state.
+        /// </summary>
+        /// <returns>An instance of <see cref="State"/>.</returns>
+        public State CaptureState()
+        {
+            State state = this.GetCurrentState();
+            return state == null ? null : state.Clone();
+        }
+
+
+
+        /// <summary>
+        /// Clears the attributes.
+        /// </summary>
+        public void ClearAttributes()
+        {
+            for (var state = this.GetCurrentState(); state != null; state = state.Next)
+                state.Attribute.Clear();
+        }
+
+        /// <summary>
+        /// Clones the current <see cref="AttributeSource"/> and injects clones of all of 
+        /// the stored <see cref="AttributeBase"/> instances into the <see cref="AttributeSource"/> clone.
+        /// </summary>
+        /// <remarks>
+        ///     <para>
+        ///     This method can be use to create another <see cref="Lucene.Net.Analysis.TokenStream"/>
+        ///     with exactly the same attributes. You can also use this method as a non-performant 
+        ///     replacement for <see cref="CaptureState"/> for times you wish to modify or peek at 
+        ///     the captured state.
+        ///     </para>
+        /// </remarks>
+        /// <returns>
+        /// A new instance of <see cref="AttributeSource"/> with cloned attributes.
+        /// </returns>
+        public AttributeSource CloneAttributes()
+        {
+            var clone = new AttributeSource(this.Factory);
+
+            if (this.HasAttributes)
+            {
+                this.ForEachState((state) => {
+                    clone.attributeMap.Add(state.Attribute.GetType(), state.Attribute.Clone());
+                });
+
+                foreach (var pair in this.interfaceMap)
+                    clone.interfaceMap.Add(pair.Key, pair.Value.Clone());
+            }
+
+            return clone;
+        }
+
+        /// <summary>
+        /// Determines whether the specified type contains attribute.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns>
+        ///     <c>true</c> if the specified type contains attribute; otherwise, <c>false</c>.
+        /// </returns>
+        public bool ContainsAttribute(Type type)
+        {
+            if (type.IsInterface)
+                return this.interfaceMap.ContainsKey(type);
+            else
+                return this.attributeMap.ContainsKey(type);
+        }
+
+        /// <summary>
+        /// Copies the contents of this <see cref="AttributeSource"/> to the specified 
+        /// <see cref="AttributeSource"/> <paramref name="source"/>.
+        /// </summary>
+        /// <remarks>
+        ///     <para>
+        ///     The <paramref name="source"/> has to provide all <see cref="IAttribute"/>s this instance contains. 
+        ///     The actual attribute implementations must be identical in both <see cref="AttributeSource"/> instances;
+        ///     ideally both <see cref="AttributeSource"/> instances should use the same <see cref="AttributeFactory"/>.
+        ///     You can use this method as a replacement for <see cref="RestoreState"/>, if you use
+        ///     <see cref="CloneAttributes"/> instead of <see cref="CaptureState"/>.
+        ///     </para>
+        /// </remarks>
+        /// <param name="source">The source.</param>
+        /// <exception cref="ArgumentException">
+        ///     Thrown when the <paramref name="source"/> contains an instance
+        ///     of <see cref="IAttribute"/> that current <see cref="AttributeSource"/>
+        ///     object does not contain.
+        /// </exception>
+        public void CopyTo(AttributeSource source)
+        {
+            this.ForEachState((state) => {
+                var attribute = this.attributeMap[state.Attribute.GetType()];
+                if (attribute == null)
+                    throw new ArgumentException(this.CreateStateExceptionMessage(state));
+
+                state.Attribute.CopyTo(attribute);
+            });
+        }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
+        /// </summary>
+        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
+        /// <returns>
+        ///     <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
+        /// </returns>
+        public override bool Equals(object obj)
+        {
+            if (obj == this)
+                return true;
+
+            AttributeSource compare = (AttributeSource)obj;
+
+            if (compare == null)
+                return false;
+
+            if (!this.HasAttributes)
+                return !compare.HasAttributes;
+
+            if (!compare.HasAttributes ||
+                (compare.attributeMap.Count != this.attributeMap.Count))
+                return false;
+
+            var localState = this.GetCurrentState();
+            var compareState = compare.GetCurrentState();
+
+            while (localState != null && compareState != null)
+            {
+                // this differs from java-lucene-core: 
+                // .NET's attributes will return false if the types mismatch.  
+                if (!localState.Attribute.Equals(compareState.Attribute))
+                    return false;
+
+                localState = localState.Next;
+                compareState = compareState.Next;
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// Finds the specified attribute based on the <typeparamref name="T"/> which must
+        /// a type that implements <see cref="AttributeBase"/> and <see cref="IAttribute"/>.
+        /// </summary>
+        /// <typeparam name="T">The type that </typeparam>
+        /// <returns>An instance of <typeparamref name="T"/>.</returns>
+        /// <exception cref="ArgumentException">
+        ///     Thrown when the type of <typeparamref name="T"/> could not be found in this instance.
+        /// </exception>
+        public T FindAttribute<T>() where T : IAttribute
+        {
+            AttributeBase value;
+            if (!this.interfaceMap.TryGetValue(typeof(T), out value))
+                throw new ArgumentException(
+                    string.Format(
+                    "The specified type '{0}' could not be found, try using " +
+                    "ContainsAttribute(Type) first.",
+                    typeof(T).FullName));
+      
+            object unbox = value;
+            return (T)unbox;
+        }
+
+        /// <summary>
+        /// Finds the specified attribute based on the <paramref name="type"/> which must
+        /// be a <see cref="Type"/> that implements <see cref="AttributeBase"/> 
+        /// and <see cref="IAttribute"/>.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns>
+        /// An instance of <see cref="AttributeBase"/>.
+        /// </returns>
+        public AttributeBase FindAttribute(Type type)
+        {
+            AttributeBase value;
+
+            if (type.IsInterface)
+            {
+                if (!this.interfaceMap.TryGetValue(type, out value))
+                    throw new ArgumentException(
+                        string.Format(
+                        "The specified type '{0}' could not be found, try using " +
+                        "ContainsAttribute(Type) first.",
+                        type.FullName));
+            } 
+            else
+            {
+                if (!this.attributeMap.TryGetValue(type, out value))
+                    throw new ArgumentException(
+                        string.Format(
+                        "The specified type '{0}' could not be found, try using " +
+                        "ContainsAttribute(Type) first.",
+                        type.FullName));
+            }
+
+           
+            return value;
+        }
+
+        /// <summary>
+        /// Returns the enumerator for stored interface types in the same order
+        /// they were stored int.
+        /// </summary>
+        /// <returns>
+        /// An instance of <see cref="IEnumerator{Type}"/>.
+        /// </returns>
+        public IEnumerator<Type> GetAttributeTypesEnumerator()
+        {
+            return this.interfaceMap.Keys.GetEnumerator();
+        }
+
+        /// <summary>
+        /// Creates and returns an <see cref="AttributeEnumerator"/> that will enumerate
+        /// throw all available instances of <see cref="AttributeBase"/>. The enumerator
+        /// may contain less instances than <see cref="GetAttributeTypesEnumerator"/>.
+        /// </summary>
+        /// <returns>
+        /// An instance of <see cref="IEnumerator{AttributeBase}"/>.
+        /// </returns>
+        public IEnumerator<AttributeBase> GetAttributeEnumerator()
+        {
+            return new AttributeEnumerator(this);
+        }
+
+        /// <summary>
+        /// Returns a hash code for this instance.
+        /// </summary>
+        /// <returns>
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
+        /// </returns>
+        public override int GetHashCode()
+        {
+            int code = 0;
+            for (var state = this.GetCurrentState(); state != null; state = state.Next)
+                code = (code * 31) + state.Attribute.GetHashCode();
+
+            return code;
+        }
+
+        /// <summary>
+        /// Restores the attribute source state by copying the values of all
+        /// attribute instances that the state contains into the target stream.
+        /// </summary>
+        /// <remarks>
+        ///     <para>
+        ///         The target stream must contain a corresponding instance for 
+        ///         each argument contained in this state. It is not possible 
+        ///         to restore the state of an <see cref="AttributeSource"/>
+        ///         containing a <c>TermAttribute</c> into an <see cref="AttributeSource"/>
+        ///         using a <see cref="Token"/> instance.
+        ///     </para>
+        ///     <note>
+        ///         This method does not affect attributes of the target stream
+        ///         that are not contained in this state. If the target stream
+        ///         contains an <see cref="OffsetAttribute"/>, but this <paramref name="state"/> 
+        ///         does not, then the value of the <see cref="OffsetAttribute"/> 
+        ///         remains unchanged.
+        ///     </note>
+        ///     <para>
+        ///         It might be desirable to reset its value to the default. 
+        ///         The caller should first call <see cref="ClearAttributes"/> on 
+        ///         the target stream in order to reset its value.
+        ///     </para>
+        /// </remarks>
+        /// <param name="state">The state.</param>
+        /// <exception cref="ArgumentException">
+        ///     Thrown when a state contains ain attribute that is not found
+        ///     within the current instance of <see cref="AttributeSource"/>
+        /// </exception>
+        public void RestoreState(State state)
+        {
+            if (state == null)
+                return;
+            do
+            {
+                var attribute = this.attributeMap[state.Attribute.GetType()];
+
+                if (attribute == null)
+                    throw new ArgumentException(this.CreateStateExceptionMessage(state));
+
+                state.Attribute.CopyTo(attribute);
+                state = state.Next;
+            } 
+            while (state != null);
+        }
+
+        /// <summary>
+        /// Enumerates over the stored states in the <see cref="AttributeSource"/>
+        /// </summary>
+        /// <param name="invoke">The action to invoke on each state.</param>
+        protected void ForEachState(Action<State> invoke)
+        {
+            for (var state = this.GetCurrentState(); state != null; state = state.Next)
+                invoke(state);
+        }
+
+        private State GetCurrentState()
+        {
+            State state = this.currentState[0];
+
+            if (state != null || !this.HasAttributes)
+                return state;
+
+            State current = state = this.currentState[0] = new State();
+
+            var enumerator = this.attributeMap.Values.GetEnumerator();
+            enumerator.MoveNext();
+            current.Attribute = enumerator.Current;
+
+            while (enumerator.MoveNext())
+            {
+                current = current.Next = new State();
+                current.Attribute = enumerator.Current;
+            }
+
+            return state;
+        }
+
+        private string CreateStateExceptionMessage(State state)
+        {
+            return string.Format(
+                "The state contains an attribute of type '{0}' " +
+                "that is currently not found within this instance of '{1}#{2}'. ",
+                state.Attribute.GetType(), 
+                this.GetType().Name, 
+                this.GetHashCode());
+        }
+
+        /// <summary>
+        /// The enumerator for <see cref="AttributeBase"/> instances stored inside
+        /// of an <see cref="AttributeSource"/> instance.
+        /// </summary>
+        public sealed class AttributeEnumerator : IEnumerator<AttributeBase>
+        {
+            private State state;
+            private AttributeSource source;
+
+            /// <summary>
+            /// Initializes a new instance of the <see cref="AttributeEnumerator"/> class.
+            /// </summary>
+            /// <param name="source">The source.</param>
+            internal AttributeEnumerator(AttributeSource source)
+            {
+                this.source = source;
+                this.state = source.GetCurrentState();
+            }
+
+            /// <summary>
+            /// Gets the current <see cref="AttributeBase"/> at this position.
+            /// </summary>
+            /// <value>The current.</value>
+            /// <exception cref="ObjectDisposedException">
+            ///     Thrown when <see cref="Dispose"/> has already been called on the object.
+            /// </exception>
+            public AttributeBase Current
+            {
+                get
+                {
+                    if (this.source == null)
+                        throw new ObjectDisposedException(this.GetType().Name);
+
+                    return this.state.Attribute;
+                }
+            }
+
+            object System.Collections.IEnumerator.Current
+            {
+                get { return this.Current; }
+            }
+
+
+            /// <summary>
+            /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+            /// </summary>
+            public void Dispose()
+            {
+                this.state = null;
+                this.source = null;
+            }
+
+           
+
+
+
+            /// <summary>
+            /// Advances the enumerator to the next element of the collection.
+            /// </summary>
+            /// <returns>
+            /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
+            /// </returns>
+            /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception>
+            /// <exception cref="ObjectDisposedException">
+            ///     Thrown when <see cref="Dispose"/> has already been called on the object.
+            /// </exception>
+            public bool MoveNext()
+            {
+                if (this.source == null)
+                    throw new ObjectDisposedException(this.GetType().Name);
+
+                this.state = this.state.Next;
+                return this.state != null;
+            }
+
+            /// <summary>
+            /// Sets the enumerator to its initial position, which is before the first element in the collection.
+            /// </summary>
+            /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception>
+            /// <exception cref="ObjectDisposedException">
+            ///     Thrown when <see cref="Dispose"/> has already been called on the object.
+            /// </exception>
+            public void Reset()
+            {
+                if (this.source == null)
+                    throw new ObjectDisposedException(this.GetType().Name);
+
+                this.state = this.source.GetCurrentState();
+            }
+        }
+
+       
+        /// <summary>
+        /// The state of an attribute source.
+        /// </summary>
+        public sealed class State : ICloneable, ICloneable<State>
+        {
+            /// <summary>
+            /// Gets or sets the attribute.
+            /// </summary>
+            /// <value>The attribute.</value>
+            public AttributeBase Attribute { get; set; }
+            
+            /// <summary>
+            /// Gets or sets the next state.
+            /// </summary>
+            /// <value>The next.</value>
+            public State Next { get; set; }
+
+            /// <summary>
+            /// Fully clones this instance.
+            /// </summary>
+            /// <returns>an instance of the cloned <see cref="State"/>.</returns>
+            public State Clone()
+            {
+                State state = new State { Attribute = this.Attribute.Clone() };
+               
+                if (this.Next != null)
+                    state.Next = this.Next.Clone();
+
+                return state;
+            }
+
+            object ICloneable.Clone()
+            {
+                return this.Clone();
+            }
         }
     }
 }

Modified: incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs?rev=1156935&r1=1156934&r2=1156935&view=diff
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs (original)
+++ incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs Fri Aug 12 01:46:36 2011
@@ -25,6 +25,7 @@ namespace Lucene.Net.Support
     using System.Collections.Generic;
     using System.Linq;
     using System.Text;
+    using System.Collections.Concurrent;
 
     /// <summary>
     ///