1   /*
2    *  SimpleFeatureMapImpl.java
3    *
4    *  Copyright (c) 1998-2001, The University of Sheffield.
5    *
6    *  This file is part of GATE (see http://gate.ac.uk/), and is free
7    *  software, licenced under the GNU Library General Public License,
8    *  Version 2, June 1991 (in the distribution as file licence.html,
9    *  and also available at http://gate.ac.uk/gate/licence.html).
10   *
11   *  Hamish Cunningham, 7/Feb/2000
12   *
13   *  $Id: SimpleFeatureMapImpl.java,v 1.20 2002/01/14 13:44:34 nasso Exp $
14   */
15  
16  package gate.util;
17  
18  import java.util.*;
19  import gate.*;
20  import gate.event.*;
21  /** Simple case of features. */
22  //>>> DAM: was (derived from HashMap)
23  /*
24  public class SimpleFeatureMapImpl  extends HashMap implements FeatureMap
25  */
26  //=== DAM: FeatArray optimization, now derived from SimpleMapImpl
27  public class SimpleFeatureMapImpl
28      extends SimpleMapImpl
29  //    extends HashMap
30      implements FeatureMap, java.io.Serializable, java.lang.Cloneable
31  //>>> DAM: end
32  {
33    /** Debug flag */
34    private static final boolean DEBUG = false;
35  
36   /** Freeze the serialization UID. */
37    static final long serialVersionUID = -2747241616127229116L;
38  
39    /** Test if <b>this</b> featureMap includes all features from aFeatureMap
40      * @param aFeatureMap object which will be included or not in
41      * <b>this</b> FeatureMap obj.If this param is null then it will return true.
42      * @return <code>true</code> if aFeatureMap is incuded in <b>this</b> obj.
43      * and <code>false</code> if not.
44      */
45    public boolean subsumes(FeatureMap aFeatureMap){
46      // null is included in everything
47      if (aFeatureMap == null) return true;
48  
49      if (this.size() < aFeatureMap.size()) return false;
50  
51      SimpleFeatureMapImpl sfm = (SimpleFeatureMapImpl)aFeatureMap;
52  
53      Object key;
54      Object keyValueFromAFeatureMap;
55      Object keyValueFromThis;
56  
57      for (int i = 0; i < sfm.count; i++) {
58        key = sfm.theKeys[i];
59        keyValueFromAFeatureMap = sfm.theValues[i];
60        int v = super.getSubsumeKey(key);
61        if (v < 0) return false;
62        keyValueFromThis = theValues[v];//was: get(key);
63  
64        if  ( (keyValueFromThis == null && keyValueFromAFeatureMap != null) ||
65              (keyValueFromThis != null && keyValueFromAFeatureMap == null)
66            ) return false;
67  
68        if ((keyValueFromThis != null) && (keyValueFromAFeatureMap != null))
69          if (!keyValueFromThis.equals(keyValueFromAFeatureMap)) return false;
70      } // for
71  
72      return true;
73    }//subsumes()
74  
75    /** Tests if <b>this</b> featureMap object includes aFeatureMap but only
76      * for the those features present in the aFeatureNamesSet.
77      * @param aFeatureMap which will be included or not in <b>this</b>
78      * FeatureMap obj.If this param is null then it will return true.
79      * @param aFeatureNamesSet is a set of strings representing the names of the
80      * features that would be considered for subsumes. If aFeatureNamesSet is
81      * <b>null</b> then subsumes(FeatureMap) will be called.
82      * @return <code>true</code> if all features present in the aFeaturesNameSet
83      * from aFeatureMap are included in <b>this</b> obj, or <code>false</code>
84      * otherwise.
85      */
86    public boolean subsumes(FeatureMap aFeatureMap, Set aFeatureNamesSet){
87      // This means that all features are taken into consideration.
88      if (aFeatureNamesSet == null) return this.subsumes(aFeatureMap);
89      // null is included in everything
90      if (aFeatureMap == null) return true;
91      // This means that subsumes is supressed.
92      if (aFeatureNamesSet.isEmpty()) return true;
93  
94      SimpleFeatureMapImpl sfm = (SimpleFeatureMapImpl)aFeatureMap;
95  
96      Object key;
97      Object keyValueFromAFeatureMap;
98      Object keyValueFromThis;
99  
100     for (int i = 0; i < sfm.count; i++) {
101       key = sfm.theKeys[i];
102 
103       if (!aFeatureNamesSet.contains(key))
104         continue;
105 
106       keyValueFromAFeatureMap = sfm.theValues[i];
107         keyValueFromThis = get(key);
108 
109       if  ( (keyValueFromThis == null && keyValueFromAFeatureMap != null) ||
110             (keyValueFromThis != null && keyValueFromAFeatureMap == null)
111           ) return false;
112 
113       if ((keyValueFromThis != null) && (keyValueFromAFeatureMap != null))
114         if (!keyValueFromThis.equals(keyValueFromAFeatureMap)) return false;
115     } // for
116 
117     return true;
118   }// subsumes()
119 
120 
121   /**
122    * Overriden to fire events, so that the persistent objects
123    *  can keep track of what's updated
124    */
125   public Object put(Object key, Object value) {
126     Object result = super.put(key, value);
127     this.fireMapUpdatedEvent();
128     return result;
129   } // put
130 
131   /**
132    * Overriden to fire events, so that the persistent objects
133    *  can keep track of what's updated
134    */
135   public Object remove(Object key) {
136     Object result = super.remove(key);
137     this.fireMapUpdatedEvent();
138     return result;
139   } // remove
140 
141   public void clear() {
142     super.clear();
143     //tell the world if they're listening
144     this.fireMapUpdatedEvent();
145   } // clear
146 
147   // Views
148   public Object clone() {
149     return super.clone();
150   } //clone
151 
152   public boolean equals(Object o) {
153     return super.equals(o);
154   } // equals
155 
156 //////////////////THE EVENT HANDLING CODE//////////////
157 //Needed so an annotation can listen to its features//
158 //and update correctly the database//////////////////
159   private transient Vector mapListeners;
160   /**
161    * Removes a gate listener
162    */
163   public synchronized void removeFeatureMapListener(FeatureMapListener l) {
164     if (mapListeners != null && mapListeners.contains(l)) {
165       Vector v = (Vector) mapListeners.clone();
166       v.removeElement(l);
167       mapListeners = v;
168     }
169   } //removeFeatureMapListener
170   /**
171    * Adds a gate listener
172    */
173   public synchronized void addFeatureMapListener(FeatureMapListener l) {
174     Vector v = mapListeners == null ? new Vector(2) : (Vector)mapListeners.clone();
175     if (!v.contains(l)) {
176       v.addElement(l);
177       mapListeners = v;
178     }
179   } //addFeatureMapListener
180   /**
181    *
182    * @param e
183    */
184   protected void fireMapUpdatedEvent () {
185     if (mapListeners != null) {
186       Vector listeners = mapListeners;
187       int count = listeners.size();
188       if (count == 0) return;
189       for (int i = 0; i < count; i++)
190         ((FeatureMapListener) listeners.elementAt(i)).featureMapUpdated();
191     }
192   }//fireMapUpdatedEvent
193 } // class SimpleFeatureMapImpl
194 
195