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.17 2001/11/20 14:10:36 cursu Exp $
14   */
15  
16  package gate.util;
17  
18  import java.util.*;
19  import gate.*;
20  import gate.event.*;
21  
22  /** Simple case of features.
23    */
24  //>>> DAM: was (derived from HashMap)
25  /*
26  public class SimpleFeatureMapImpl  extends HashMap implements FeatureMap
27  */
28  //=== DAM: FeatArray optimization, now derived from SimpleMapImpl
29  public class SimpleFeatureMapImpl
30      extends SimpleMapImpl
31  //    extends HashMap
32      implements FeatureMap, java.io.Serializable, java.lang.Cloneable
33  //>>> DAM: end
34  {
35    /** Debug flag */
36    private static final boolean DEBUG = false;
37  
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.m_size; i++) {
58        key = sfm.m_keys[i];
59        keyValueFromAFeatureMap = sfm.m_values[i];
60        keyValueFromThis = get(key);
61  
62        if  ( (keyValueFromThis == null && keyValueFromAFeatureMap != null) ||
63              (keyValueFromThis != null && keyValueFromAFeatureMap == null)
64            ) return false;
65  
66        if ((keyValueFromThis != null) && (keyValueFromAFeatureMap != null))
67          if (!keyValueFromThis.equals(keyValueFromAFeatureMap)) return false;
68      } // for
69  
70      return true;
71    }//subsumes()
72  
73    /** Tests if <b>this</b> featureMap object includes aFeatureMap but only
74      * for the those features present in the aFeatureNamesSet.
75      * @param aFeatureMap which will be included or not in <b>this</b>
76      * FeatureMap obj.If this param is null then it will return true.
77      * @param aFeatureNamesSet is a set of strings representing the names of the
78      * features that would be considered for subsumes. If aFeatureNamesSet is
79      * <b>null</b> then subsumes(FeatureMap) will be called.
80      * @return <code>true</code> if all features present in the aFeaturesNameSet
81      * from aFeatureMap are included in <b>this</b> obj, or <code>false</code>
82      * otherwise.
83      */
84    public boolean subsumes(FeatureMap aFeatureMap, Set aFeatureNamesSet){
85      // This means that all features are taken into consideration.
86      if (aFeatureNamesSet == null) return this.subsumes(aFeatureMap);
87      // null is included in everything
88      if (aFeatureMap == null) return true;
89      // This means that subsumes is supressed.
90      if (aFeatureNamesSet.isEmpty()) return true;
91  
92      SimpleFeatureMapImpl sfm = (SimpleFeatureMapImpl)aFeatureMap;
93  
94      Object key;
95      Object keyValueFromAFeatureMap;
96      Object keyValueFromThis;
97  
98      for (int i=0; i<sfm.m_size; i++) {
99        key = sfm.m_keys[i];
100 
101       if (!aFeatureNamesSet.contains(key))
102         continue;
103 
104       keyValueFromAFeatureMap = sfm.m_values[i];
105         keyValueFromThis = get(key);
106 
107       if  ( (keyValueFromThis == null && keyValueFromAFeatureMap != null) ||
108             (keyValueFromThis != null && keyValueFromAFeatureMap == null)
109           ) return false;
110 
111       if ((keyValueFromThis != null) && (keyValueFromAFeatureMap != null))
112         if (!keyValueFromThis.equals(keyValueFromAFeatureMap)) return false;
113     } // for
114 
115     return true;
116   }// subsumes()
117 
118 
119   /**
120    * Overriden to fire events, so that the persistent objects
121    *  can keep track of what's updated
122    */
123   public Object put(Object key, Object value) {
124     Object result = super.put(key, value);
125     this.fireMapUpdatedEvent();
126     return result;
127   } // put
128 
129   /**
130    * Overriden to fire events, so that the persistent objects
131    *  can keep track of what's updated
132    */
133   public Object remove(Object key) {
134     Object result = super.remove(key);
135     this.fireMapUpdatedEvent();
136     return result;
137   } // remove
138 
139   public void clear() {
140     super.clear();
141     //tell the world if they're listening
142     this.fireMapUpdatedEvent();
143   } // clear
144 
145   // Views
146     public Object clone() {
147           return super.clone();
148     }
149 
150   public boolean equals(Object o) {
151     return super.equals(o);
152   }
153 
154 
155 //////////////////THE EVENT HANDLING CODE//////////////
156 //Needed so an annotation can listen to its features//
157 //and update correctly the database//////////////////
158   private transient Vector mapListeners;
159   /**
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   }
170   /**
171    *
172    * Adds a gate listener
173    */
174    public synchronized void addFeatureMapListener(FeatureMapListener l) {
175      Vector v = mapListeners == null ? new Vector(2) : (Vector)mapListeners.clone();
176     if (!v.contains(l)) {
177       v.addElement(l);
178       mapListeners = v;
179     }
180   }
181   /**
182    *
183    * @param e
184    */
185    protected void fireMapUpdatedEvent () {
186      if (mapListeners != null) {
187        Vector listeners = mapListeners;
188       int count = listeners.size();
189       if (count == 0) return;
190       for (int i = 0; i < count; i++)
191         ((FeatureMapListener) listeners.elementAt(i)).featureMapUpdated();
192     }
193   }//fireAnnotationUpdated
194 
195 
196  /** Freeze the serialization UID. */
197   static final long serialVersionUID = -2747241616127229116L;
198 } // class SimpleFeatureMapImpl
199 
200