Change from string reference comparison to equals() for clarity.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / aa / AAAttribute.java
1 /* 
2  * The Shibboleth License, Version 1. 
3  * Copyright (c) 2002 
4  * University Corporation for Advanced Internet Development, Inc. 
5  * All rights reserved
6  * 
7  * 
8  * Redistribution and use in source and binary forms, with or without 
9  * modification, are permitted provided that the following conditions are met:
10  * 
11  * Redistributions of source code must retain the above copyright notice, this 
12  * list of conditions and the following disclaimer.
13  * 
14  * Redistributions in binary form must reproduce the above copyright notice, 
15  * this list of conditions and the following disclaimer in the documentation 
16  * and/or other materials provided with the distribution, if any, must include 
17  * the following acknowledgment: "This product includes software developed by 
18  * the University Corporation for Advanced Internet Development 
19  * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement 
20  * may appear in the software itself, if and wherever such third-party 
21  * acknowledgments normally appear.
22  * 
23  * Neither the name of Shibboleth nor the names of its contributors, nor 
24  * Internet2, nor the University Corporation for Advanced Internet Development, 
25  * Inc., nor UCAID may be used to endorse or promote products derived from this 
26  * software without specific prior written permission. For written permission, 
27  * please contact shibboleth@shibboleth.org
28  * 
29  * Products derived from this software may not be called Shibboleth, Internet2, 
30  * UCAID, or the University Corporation for Advanced Internet Development, nor 
31  * may Shibboleth appear in their name, without prior written permission of the 
32  * University Corporation for Advanced Internet Development.
33  * 
34  * 
35  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
36  * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
37  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
38  * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK 
39  * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. 
40  * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY 
41  * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, 
42  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
43  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
47  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49  
50 package edu.internet2.middleware.shibboleth.aa;
51
52
53 import java.util.ArrayList;
54 import java.util.Arrays;
55 import java.util.Collection;
56 import java.util.Iterator;
57 import java.util.List;
58
59 import org.apache.log4j.Logger;
60 import org.opensaml.QName;
61 import org.opensaml.SAMLAttribute;
62 import org.opensaml.SAMLException;
63 import org.opensaml.XML;
64 import org.w3c.dom.Document;
65 import org.w3c.dom.Element;
66 import org.w3c.dom.Node;
67
68 import edu.internet2.middleware.shibboleth.aa.arp.ArpAttribute;
69 import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolverAttribute;
70 import edu.internet2.middleware.shibboleth.aa.attrresolv.provider.ValueHandler;
71 import edu.internet2.middleware.shibboleth.aa.attrresolv.provider.ValueHandlerException;
72
73 /**
74  * An attribute for which the Shibboleth Attribute Authority has been asked
75  * to provide an assertion.
76  * 
77  * @author Walter Hoehn (wassa@columbia.edu)
78  */
79 public class AAAttribute extends SAMLAttribute implements ResolverAttribute, ArpAttribute {
80
81         private static Logger log = Logger.getLogger(AAAttribute.class.getName());
82         private boolean resolved = false;
83         
84         public final static String SHIB_ATTRIBUTE_NAMESPACE_URI = "urn:mace:shibboleth:1.0:attributeNamespace:uri";
85         
86         /** Default lifetime, in seconds **/
87         private static long defaultLifetime = 1800; // 30 minutes
88         private ValueHandler valueHandler = new StringValueHandler();
89
90         public AAAttribute(String name) throws SAMLException {
91                 super(
92                         name,
93                         SHIB_ATTRIBUTE_NAMESPACE_URI,
94                         new QName("urn:mace:shibboleth:1.0", "AttributeValueType"),
95                         defaultLifetime,
96                         null);
97         }
98
99         public AAAttribute(String name, Object[] values) throws SAMLException {
100                 this(name);
101                 setValues(values);
102         }
103         
104         public AAAttribute(String name, Object[] values, ValueHandler handler) throws SAMLException {
105                         this(name);
106                         setValues(values);
107                         registerValueHandler(handler);
108                 }
109
110         public boolean hasValues() {
111                 if (values.isEmpty()) {
112                         return false;
113                 }
114                 return true;
115         }
116
117         public Iterator getValues() {
118                 return valueHandler.getValues(values);
119         }
120
121         public void setValues(Object[] values) {
122                 if (!this.values.isEmpty()) {
123                         this.values.clear();
124                 }
125                 List newList = Arrays.asList(values);
126                 if (newList.contains(null)) {
127                         newList.remove(null);
128                 }
129                 this.values.addAll(newList);
130         }
131
132         /**
133         * @see java.lang.Object#hashCode()
134         */
135         public int hashCode() {
136                 int code = 0;
137                 if (values != null) {
138                         Iterator iterator = values.iterator();
139                         while (iterator.hasNext()) {
140                                 code += iterator.next().hashCode();
141                         }
142                 }
143                 return name.hashCode() + code;
144         }
145
146         /**
147          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#resolved()
148          */
149         public boolean resolved() {
150                 return resolved;
151         }
152
153         /**
154          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#setResolved()
155          */
156         public void setResolved() {
157                 resolved = true;
158         }
159
160         /**
161          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#resolveFromCached(edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute)
162          */
163         public void resolveFromCached(ResolverAttribute attribute) {
164                 resolved = true;
165                 setLifetime(attribute.getLifetime());
166
167                 if (!this.values.isEmpty()) {
168                         this.values.clear();
169                 }
170                 for (Iterator iterator = attribute.getValues(); iterator.hasNext();) {
171                         values.add(iterator.next());
172                 }
173
174                 registerValueHandler(attribute.getRegisteredValueHandler());
175         }
176
177         public void setLifetime(long lifetime) {
178                 this.lifetime = lifetime;
179
180         }
181
182         public void addValue(Object value) {
183                 if (value != null) {
184                         values.add(value);
185                 }
186         }
187
188         /**
189          * @see org.opensaml.SAMLObject#toDOM(org.w3c.dom.Document)
190          */
191         public Node toDOM(Document doc, boolean xmlns) {
192
193                 Element attributeElement = doc.createElementNS(XML.SAML_NS, "Attribute");
194                 attributeElement.setAttributeNS(null, "AttributeName", name);
195                 attributeElement.setAttributeNS(null, "AttributeNamespace", namespace);
196
197                 for (int i = 0; i < values.size(); i++) {
198
199                         if (type != null) {
200                                 attributeElement.setAttributeNS(XML.XMLNS_NS, "xmlns:typens", type.getNamespaceURI());
201                         }
202                         Element valueElement = doc.createElementNS(XML.SAML_NS, "AttributeValue");
203                         if (type != null) {
204                                 valueElement.setAttributeNS(XML.XSI_NS, "xsi:type", "typens:" + type.getLocalName());
205                         }
206                         
207                         try {
208                                 valueHandler.toDOM(valueElement, values.get(i), doc);
209                                 attributeElement.appendChild(valueElement);
210
211                         } catch (ValueHandlerException e) {
212                                 log.error("Value Handler unable to convert value to DOM Node: " + e);
213                         }
214                 }
215                 return attributeElement;
216         }
217
218         /**
219          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#registerValueHandler(edu.internet2.middleware.shibboleth.aa.attrresolv.provider.ValueHandler)
220          */
221         public void registerValueHandler(ValueHandler handler) {
222                 valueHandler = handler;
223         }
224
225         /**
226          * @see edu.internet2.middleware.shibboleth.aa.attrresolv.ArpAttribute#getRegisteredValueHandler()
227          */
228         public ValueHandler getRegisteredValueHandler() {
229                 return valueHandler;
230         }
231
232         /**
233          * @see java.lang.Object#equals(java.lang.Object)
234          */
235         public boolean equals(Object object) {
236
237                 if (!(object instanceof AAAttribute)) {
238                         return false;
239                 }
240                 if (lifetime != ((AAAttribute) object).lifetime) {
241                         return false;
242                 }
243                 if (!name.equals(((AAAttribute) object).name)) {
244                         return false;
245                 }
246                 if (!valueHandler.equals(((AAAttribute) object).valueHandler)) {
247                         return false;
248                 }
249                 
250                 ArrayList localValues = new ArrayList();
251                 for (Iterator iterator = getValues();iterator.hasNext();) {
252                         localValues.add(iterator.next());
253                 }
254                 
255                 ArrayList objectValues = new ArrayList();
256                 for (Iterator iterator = ((AAAttribute) object).getValues();iterator.hasNext();) {
257                         objectValues.add(iterator.next());
258                 }
259                 
260                 return localValues.equals(objectValues);
261         }
262
263 }
264
265 /**
266  *  Default <code>ValueHandler</code> implementation.  Expects all values to be String objects.
267  *
268  * @author Walter Hoehn (wassa@columbia.edu)
269  */
270 class StringValueHandler implements ValueHandler {
271
272         public void toDOM(Element valueElement, Object value, Document document) {
273                 valueElement.appendChild(document.createTextNode(value.toString()));
274         }
275
276         public Iterator getValues(Collection internalValues) {
277                 return internalValues.iterator();
278         }
279
280         /**
281          * @see java.lang.Object#equals(java.lang.Object)
282          */
283         public boolean equals(Object object) {
284                 if (object instanceof StringValueHandler) {
285                         return true;
286                 }
287                 return false;
288         }
289
290 }
291
292