View Javadoc

1   /*
2    * Copyright [2006] [University Corporation for Advanced Internet Development, Inc.]
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.opensaml.xml.util;
18  
19  import java.util.Collection;
20  import java.util.Collections;
21  import java.util.Map;
22  import java.util.Set;
23  
24  import javax.xml.namespace.QName;
25  
26  import net.jcip.annotations.NotThreadSafe;
27  
28  import org.opensaml.xml.Configuration;
29  import org.opensaml.xml.XMLObject;
30  
31  /**
32   * A map of attribute names and attribute values that invalidates the DOM of the attribute owning XMLObject when the
33   * attributes change.
34   * 
35   * <strong>Note:</strong> 
36   */
37  @NotThreadSafe
38  public class AttributeMap implements Map<QName, String> {
39  
40      /** XMLObject owning the attributes. */
41      private XMLObject attributeOwner;
42  
43      /** Map of attributes. */
44      private Map<QName, String> attributes;
45      
46      /** Set of attribute QNames which have been locally registered as having an ID type within this 
47       * AttributeMap instance. */
48      private Set<QName> idAttribNames;
49  
50      /**
51       * Constructor.
52       *
53       * @param newOwner the XMLObject that owns these attributes
54       * 
55       * @throws NullPointerException thrown if the given XMLObject is null
56       */
57      public AttributeMap(XMLObject newOwner) throws NullPointerException {
58          if (newOwner == null) {
59              throw new NullPointerException("Attribute owner XMLObject may not be null");
60          }
61  
62          attributeOwner = newOwner;
63          attributes = new LazyMap<QName, String>();
64          idAttribNames = new LazySet<QName>();
65      }
66  
67      /** {@inheritDoc} */
68      public String put(QName attributeName, String value) {
69          String oldValue = get(attributeName);
70          if (value != oldValue) {
71              releaseDOM();
72              attributes.put(attributeName, value);
73              if (isIDAttribute(attributeName) || Configuration.isIDAttribute(attributeName)) {
74                  attributeOwner.getIDIndex().deregisterIDMapping(oldValue);
75                  attributeOwner.getIDIndex().registerIDMapping(value, attributeOwner);
76              }
77          }
78          
79          return oldValue;
80      }
81  
82      /** {@inheritDoc} */
83      public void clear() {
84          for (QName attributeName : attributes.keySet()) {
85              remove(attributeName);
86          }
87      }
88  
89      /**
90       * Returns the set of keys.
91       * 
92       * @return unmodifiable set of keys
93       */
94      public Set<QName> keySet() {
95          return Collections.unmodifiableSet(attributes.keySet());
96      }
97  
98      /** {@inheritDoc} */
99      public int size() {
100         return attributes.size();
101     }
102 
103     /** {@inheritDoc} */
104     public boolean isEmpty() {
105         return attributes.isEmpty();
106     }
107 
108     /** {@inheritDoc} */
109     public boolean containsKey(Object key) {
110         return attributes.containsKey(key);
111     }
112 
113     /** {@inheritDoc} */
114     public boolean containsValue(Object value) {
115         return attributes.containsValue(value);
116     }
117 
118     /** {@inheritDoc} */
119     public String get(Object key) {
120         return attributes.get(key);
121     }
122 
123     /** {@inheritDoc} */
124     public String remove(Object key) {
125         String removedValue = attributes.remove(key);
126         if (removedValue != null) {
127             releaseDOM();
128             QName attributeName = (QName) key;
129             if (isIDAttribute(attributeName) || Configuration.isIDAttribute(attributeName)) {
130                 attributeOwner.getIDIndex().deregisterIDMapping(removedValue);
131             }
132         }
133 
134         return removedValue;
135     }
136 
137     /** {@inheritDoc} */
138     public void putAll(Map<? extends QName, ? extends String> t) {
139         if (t != null && t.size() > 0) {
140             for (Entry<? extends QName, ? extends String> entry : t.entrySet()) {
141                 put(entry.getKey(), entry.getValue());
142             }
143         }
144     }
145 
146     /**
147      * Returns the values in this map.
148      * 
149      * @return an unmodifiable collection of values
150      */
151     public Collection<String> values() {
152         return Collections.unmodifiableCollection(attributes.values());
153     }
154 
155     /**
156      * Returns the set of entries.
157      * 
158      * @return unmodifiable set of entries
159      */
160     public Set<Entry<QName, String>> entrySet() {
161         return Collections.unmodifiableSet(attributes.entrySet());
162     }
163     
164     /**
165      * Register an attribute as having a type of ID.
166      * 
167      * @param attributeName the QName of the ID attribute to be registered
168      */
169     public void registerID(QName attributeName) {
170         if (! idAttribNames.contains(attributeName)) {
171             idAttribNames.add(attributeName);
172         }
173         
174         // In case attribute already has a value,
175         // register the current value mapping with the XMLObject owner.
176         if (containsKey(attributeName)) {
177             attributeOwner.getIDIndex().registerIDMapping(get(attributeName), attributeOwner);
178         }
179     }
180     
181     /**
182      * Deregister an attribute as having a type of ID.
183      * 
184      * @param attributeName the QName of the ID attribute to be de-registered
185      */
186     public void deregisterID(QName attributeName) {
187         if (idAttribNames.contains(attributeName)) {
188             idAttribNames.remove(attributeName);
189         }
190         
191         // In case attribute already has a value,
192         // deregister the current value mapping with the XMLObject owner.
193         if (containsKey(attributeName)) {
194             attributeOwner.getIDIndex().deregisterIDMapping(get(attributeName));
195         }
196     }
197     
198     /**
199      * Check whether a given attribute is locally registered as having an ID type within
200      * this AttributeMap instance.
201      * 
202      * @param attributeName the QName of the attribute to be checked for ID type.
203      * @return true if attribute is registered as having an ID type.
204      */
205     public boolean isIDAttribute(QName attributeName) {
206         return idAttribNames.contains(attributeName);
207     }
208     
209     /**
210      * Releases the DOM caching associated XMLObject and its ancestors.
211      */
212     private void releaseDOM() {
213         attributeOwner.releaseDOM();
214         attributeOwner.releaseParentDOM(true);
215     }
216 }