Lucene.Net  3.0.3
Lucene.Net is a .NET port of the Java Lucene Indexing Library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties
AttributeSource.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 using System.Collections.Generic;
20 using System.Linq;
21 using System.Reflection;
22 using Lucene.Net.Support;
23 using TokenStream = Lucene.Net.Analysis.TokenStream;
24 
25 namespace Lucene.Net.Util
26 {
27 
36  public class AttributeSource
37  {
39  public abstract class AttributeFactory
40  {
42  public abstract Attribute CreateAttributeInstance<T>() where T : IAttribute;
43 
47  public static readonly AttributeFactory DEFAULT_ATTRIBUTE_FACTORY = new DefaultAttributeFactory();
48 
49  private sealed class DefaultAttributeFactory:AttributeFactory
50  {
51  // This should be WeakDictionary<T, WeakReference<TImpl>> where typeof(T) is Attribute and TImpl is typeof(AttributeImpl)
52  private static readonly WeakDictionary<Type, WeakReference> attClassImplMap =
53  new WeakDictionary<Type, WeakReference>();
54 
55  internal DefaultAttributeFactory()
56  {
57  }
58 
59  public override Attribute CreateAttributeInstance<TAttImpl>()
60  {
61  try
62  {
63  return (Attribute)System.Activator.CreateInstance(GetClassForInterface<TAttImpl>());
64  }
65  catch (System.UnauthorizedAccessException)
66  {
67  throw new System.ArgumentException("Could not instantiate implementing class for " + typeof(TAttImpl).FullName);
68  }
69  //catch (System.Exception e)
70  //{
71  // throw new System.ArgumentException("Could not instantiate implementing class for " + typeof(TAttImpl).FullName);
72  //}
73  }
74 
75  private static System.Type GetClassForInterface<T>() where T : IAttribute
76  {
77  lock (attClassImplMap)
78  {
79  var attClass = typeof (T);
80  WeakReference refz = attClassImplMap[attClass];
81  System.Type clazz = (refz == null) ? null : ((System.Type) refz.Target);
82  if (clazz == null)
83  {
84  try
85  {
86  string name = attClass.FullName.Replace(attClass.Name, attClass.Name.Substring(1)) + ", " + attClass.Assembly.FullName;
87  attClassImplMap.Add(attClass, new WeakReference( clazz = System.Type.GetType(name, true))); //OK
88  }
89  catch (System.TypeLoadException) // was System.Exception
90  {
91  throw new System.ArgumentException("Could not find implementing class for " + attClass.FullName);
92  }
93  }
94  return clazz;
95  }
96  }
97  }
98  }
99 
100  // These two maps must always be in sync!!!
101  // So they are private, final and read-only from the outside (read-only iterators)
102  private GeneralKeyedCollection<Type, AttributeImplItem> attributes;
103  private GeneralKeyedCollection<Type, AttributeImplItem> attributeImpls;
104 
105  private State[] currentState = null;
106  private AttributeFactory factory;
107 
109  public AttributeSource():this(AttributeFactory.DEFAULT_ATTRIBUTE_FACTORY)
110  {
111  }
112 
115  {
116  if (input == null)
117  {
118  throw new System.ArgumentException("input AttributeSource must not be null");
119  }
120  this.attributes = input.attributes;
121  this.attributeImpls = input.attributeImpls;
122  this.currentState = input.currentState;
123  this.factory = input.factory;
124  }
125 
128  {
129  this.attributes = new GeneralKeyedCollection<Type, AttributeImplItem>(att => att.Key);
130  this.attributeImpls = new GeneralKeyedCollection<Type, AttributeImplItem>(att => att.Key);
131  this.currentState = new State[1];
132  this.factory = factory;
133  }
134 
136  public virtual AttributeFactory Factory
137  {
138  get { return factory; }
139  }
140 
148  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
149  public virtual IEnumerable<Type> GetAttributeTypesIterator()
150  {
151  return this.attributes.Select(item => item.Key);
152  }
153 
159  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
160  public virtual IEnumerable<Attribute> GetAttributeImplsIterator()
161  {
162  var initState = GetCurrentState();
163  while (initState != null)
164  {
165  var att = initState.attribute;
166  initState = initState.next;
167  yield return att;
168  }
169  }
170 
172  private static readonly WeakDictionary<Type, System.Collections.Generic.LinkedList<WeakReference>>
173  knownImplClasses = new WeakDictionary<Type, System.Collections.Generic.LinkedList<WeakReference>>();
174 
184  public virtual void AddAttributeImpl(Attribute att)
185  {
186  System.Type clazz = att.GetType();
187  if (attributeImpls.Contains(clazz))
188  return ;
189  System.Collections.Generic.LinkedList<WeakReference> foundInterfaces;
190  lock (knownImplClasses)
191  {
192  foundInterfaces = knownImplClasses[clazz];
193  if (foundInterfaces == null)
194  {
195  // we have a strong reference to the class instance holding all interfaces in the list (parameter "att"),
196  // so all WeakReferences are never evicted by GC
197  knownImplClasses.Add(clazz, foundInterfaces = new LinkedList<WeakReference>());
198  // find all interfaces that this attribute instance implements
199  // and that extend the Attribute interface
200  System.Type actClazz = clazz;
201  do
202  {
203  System.Type[] interfaces = actClazz.GetInterfaces();
204  for (int i = 0; i < interfaces.Length; i++)
205  {
206  System.Type curInterface = interfaces[i];
207  if (curInterface != typeof(IAttribute) && typeof(IAttribute).IsAssignableFrom(curInterface))
208  {
209  foundInterfaces.AddLast(new WeakReference(curInterface));
210  }
211  }
212  actClazz = actClazz.BaseType;
213  }
214  while (actClazz != null);
215  }
216  }
217 
218  // add all interfaces of this AttributeImpl to the maps
219  foreach(var curInterfaceRef in foundInterfaces)
220  {
221  System.Type curInterface = (System.Type) curInterfaceRef.Target;
222  System.Diagnostics.Debug.Assert(curInterface != null,
223  "We have a strong reference on the class holding the interfaces, so they should never get evicted");
224  // Attribute is a superclass of this interface
225  if (!attributes.ContainsKey(curInterface))
226  {
227  // invalidate state to force recomputation in captureState()
228  this.currentState[0] = null;
229  attributes.Add(new AttributeImplItem(curInterface, att));
230  if (!attributeImpls.ContainsKey(clazz))
231  {
232  attributeImpls.Add(new AttributeImplItem(clazz, att));
233  }
234  }
235  }
236  }
237 
243  // NOTE: Java has Class<T>, .NET has no Type<T>, this is not a perfect port
244  public virtual T AddAttribute<T>() where T : IAttribute
245  {
246  var attClass = typeof (T);
247  if (!attributes.ContainsKey(attClass))
248  {
249  if (!(attClass.IsInterface && typeof(IAttribute).IsAssignableFrom(attClass)))
250  {
251  throw new ArgumentException(
252  "AddAttribute() only accepts an interface that extends Attribute, but " +
253  attClass.FullName + " does not fulfil this contract."
254  );
255  }
256 
257  AddAttributeImpl(this.factory.CreateAttributeInstance<T>());
258  }
259 
260  return (T)(IAttribute)attributes[attClass].Value;
261  }
262 
264  public virtual bool HasAttributes
265  {
266  get { return this.attributes.Count != 0; }
267  }
268 
272  public virtual bool HasAttribute<T>() where T : IAttribute
273  {
274  return this.attributes.Contains(typeof(T));
275  }
276 
289  // NOTE: Java has Class<T>, .NET has no Type<T>, this is not a perfect port
290  public virtual T GetAttribute<T>() where T : IAttribute
291  {
292  var attClass = typeof (T);
293  if (!this.attributes.ContainsKey(attClass))
294  {
295  throw new System.ArgumentException("This AttributeSource does not have the attribute '" + attClass.FullName + "'.");
296  }
297  else
298  {
299  return (T)(IAttribute)this.attributes[attClass].Value;
300  }
301  }
302 
308  public sealed class State : System.ICloneable
309  {
310  internal /*private*/ Attribute attribute;
311  internal /*private*/ State next;
312 
313  public System.Object Clone()
314  {
315  State clone = new State();
316  clone.attribute = (Attribute) attribute.Clone();
317 
318  if (next != null)
319  {
320  clone.next = (State) next.Clone();
321  }
322 
323  return clone;
324  }
325  }
326 
327  private State GetCurrentState()
328  {
329  var s = currentState[0];
330  if (s != null || !HasAttributes)
331  {
332  return s;
333  }
334 
335  var c = s = currentState[0] = new State();
336  var it = attributeImpls.Values().GetEnumerator();
337  it.MoveNext();
338  c.attribute = it.Current.Value;
339 
340  while (it.MoveNext())
341  {
342  c.next = new State();
343  c = c.next;
344  c.attribute = it.Current.Value;
345  }
346 
347  return s;
348  }
349 
353  public virtual void ClearAttributes()
354  {
355  for (var state = GetCurrentState(); state != null; state = state.next)
356  {
357  state.attribute.Clear();
358  }
359  }
360 
364  public virtual State CaptureState()
365  {
366  var state = this.GetCurrentState();
367  return (state == null) ? null : (State) state.Clone();
368  }
369 
384  public virtual void RestoreState(State state)
385  {
386  if (state == null)
387  return ;
388 
389  do
390  {
391  if (!attributeImpls.ContainsKey(state.attribute.GetType()))
392  {
393  throw new System.ArgumentException("State contains an AttributeImpl that is not in this AttributeSource");
394  }
395  state.attribute.CopyTo(attributeImpls[state.attribute.GetType()].Value);
396  state = state.next;
397  }
398  while (state != null);
399  }
400 
401  public override int GetHashCode()
402  {
403  var code = 0;
404 
405  for (var state = GetCurrentState(); state != null; state = state.next)
406  {
407  code = code*31 + state.attribute.GetHashCode();
408  }
409 
410  return code;
411  }
412 
413  public override bool Equals(System.Object obj)
414  {
415  if (obj == this)
416  {
417  return true;
418  }
419 
420  if (obj is AttributeSource)
421  {
422  AttributeSource other = (AttributeSource) obj;
423 
424  if (HasAttributes)
425  {
426  if (!other.HasAttributes)
427  {
428  return false;
429  }
430 
431  if (this.attributeImpls.Count != other.attributeImpls.Count)
432  {
433  return false;
434  }
435 
436  // it is only equal if all attribute impls are the same in the same order
437  var thisState = this.GetCurrentState();
438  var otherState = other.GetCurrentState();
439  while (thisState != null && otherState != null)
440  {
441  if (otherState.attribute.GetType() != thisState.attribute.GetType() || !otherState.attribute.Equals(thisState.attribute))
442  {
443  return false;
444  }
445  thisState = thisState.next;
446  otherState = otherState.next;
447  }
448  return true;
449  }
450  else
451  {
452  return !other.HasAttributes;
453  }
454  }
455  else
456  return false;
457  }
458 
459  public override System.String ToString()
460  {
461  System.Text.StringBuilder sb = new System.Text.StringBuilder().Append('(');
462 
463  if (HasAttributes)
464  {
465  if (currentState[0] == null)
466  {
467  currentState[0] = GetCurrentState();
468  }
469  for (var state = currentState[0]; state != null; state = state.next)
470  {
471  if (state != currentState[0])
472  sb.Append(',');
473  sb.Append(state.attribute.ToString());
474  }
475  }
476  return sb.Append(')').ToString();
477  }
478 
483  public virtual AttributeSource CloneAttributes()
484  {
485  var clone = new AttributeSource(this.factory);
486 
487  // first clone the impls
488  if (HasAttributes)
489  {
490  for (var state = GetCurrentState(); state != null; state = state.next)
491  {
492  var impl = (Attribute) state.attribute.Clone();
493 
494  if (!clone.attributeImpls.ContainsKey(impl.GetType()))
495  {
496  clone.attributeImpls.Add(new AttributeImplItem(impl.GetType(), impl));
497  }
498  }
499  }
500 
501  // now the interfaces
502  foreach (var att in this.attributes)
503  {
504  clone.attributes.Add(new AttributeImplItem(att.Key, clone.attributeImpls[att.Value.GetType()].Value));
505  }
506 
507  return clone;
508  }
509  }
510 }