SDSS WAYF patch for multi-federation support
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / wayf / IdPSite.java
1 /*
2  * Copyright [2005] [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 edu.internet2.middleware.shibboleth.wayf;
18
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.Enumeration;
22 import java.util.Iterator;
23 import java.util.NoSuchElementException;
24 import java.util.StringTokenizer;
25 import java.util.TreeSet;
26
27 import edu.internet2.middleware.shibboleth.metadata.EntitiesDescriptor;
28 import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
29 import edu.internet2.middleware.shibboleth.metadata.Metadata;
30
31 import edu.internet2.middleware.shibboleth.metadata.Organization;
32
33 public class IdPSite implements Comparable {
34
35         private final EntityDescriptor entity;
36         
37         public IdPSite(EntityDescriptor entity)
38         {
39                 this.entity = entity;
40         }
41         
42         public String getName()
43         {
44                 return entity.getId();
45         }
46         
47         public String getDisplayName()
48         {
49                 Organization org = entity.getOrganization();
50                 
51                 if (org == null) {
52                         return entity.getId();
53                 }
54                 else {
55                         return org.getDisplayName();
56                 }
57         }
58         
59         public boolean equals(Object obj)
60         {
61                 return ((obj instanceof IdPSite) && (((IdPSite)obj).getName().equals(getName())));
62         }
63
64         /**
65          * Based on 1.2 Origin.isMatch.  There must have been a reason for it...
66          * [Kindas of] support for the search function in the wayf.  This return many false positives
67          * but given the aim is to provide input for a pull down list...
68          * 
69          * @param str      What to match
70          * @param config   Provides list of tokens to not lookup
71          * @return         Whether this item matches  
72          */
73         
74         public int compareTo(Object o) {
75                 
76                 if (equals(o)) return 0;
77                 
78                 int result = getDisplayName().toLowerCase().compareTo(((IdPSite) o).getDisplayName().toLowerCase());
79                 if (result == 0) {
80                         result = getDisplayName().compareTo(((IdPSite) o).getDisplayName());
81                 }
82                 return result;
83         }
84
85         static private boolean isMatch(EntityDescriptor entity, String str, HandlerConfig config) {
86                 
87                 Enumeration input = new StringTokenizer(str);
88                 while (input.hasMoreElements()) {
89                         String currentToken = (String) input.nextElement();
90
91                         if (config.isIgnoredForMatch(currentToken)) {                           
92                                 continue;
93                         }
94                         
95                         currentToken = currentToken.toLowerCase(); 
96
97                         if (entity.getId().indexOf(currentToken) > -1) {
98                                 return true; 
99                         }
100                                         
101                         Organization org = entity.getOrganization();
102                         
103                         if (org != null) {
104                                 
105                                 if (org.getName().toLowerCase().indexOf(currentToken) > -1) {
106                                         return true; 
107                                 }
108                                 
109                                 if (org.getDisplayName().toLowerCase().indexOf(currentToken) > -1) {
110                                         return true; 
111                                 }
112                                  
113                         }
114                 }
115                 return false;
116         }
117         
118         static public Collection /*<IdPSite>*/ seachForMatchingOrigins(Metadata metadata,
119                                                                                                         String searchString, 
120                                                                                                         HandlerConfig config)
121         {
122                 TreeSet /*<IdPSite>*/ result = new TreeSet /*<IdPSite>*/ ();
123                 Iterator /*<EntityDescriptor>*/ entities = Entities(metadata);
124                 
125                 while (entities.hasNext()) {
126                                 
127                         EntityDescriptor entity = (EntityDescriptor) entities.next();
128                                 
129                         if ((entity.isValid() &&
130                                  entity.getIDPSSODescriptor(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS) != null) &&
131                                  isMatch(entity, searchString, config)) {               
132
133                                 result.add(new IdPSite(entity));
134                         }
135                 } // check entities 
136                 return result;
137         }
138         
139         static public Collection /*<IdPSite>*/ getIdPSites(Metadata metadata)
140         {
141                 TreeSet /*<IdPSite>*/ result = new TreeSet /*<IdPSite>*/ ();
142                 Iterator /*<EntityDescriptor>*/ entities = Entities(metadata);
143                 
144                 while (entities.hasNext()) {
145                         EntityDescriptor entity = (EntityDescriptor) entities.next();
146                         
147                         if (entity.isValid() &&
148                             entity.getIDPSSODescriptor(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS) != null) {
149
150                                 result.add(new IdPSite(entity));
151                                 }
152                 } // iterate over all entities
153                 return result;
154         }
155         
156         /**
157          * Lookup
158          */
159         public String getAddressFor() {
160                 return entity.getIDPSSODescriptor(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS).getSingleSignOnServiceManager().getDefaultEndpoint().getLocation();
161         }
162         /**
163          * entitiesIterator:
164          * 
165          * Given a metadata object return an iterator which will enumerate all the
166          * entities inside it.  There are two options for what is at the root of metadata
167          * (either a single entity or a single entities list) so we just create the right 
168          * sort of iterator
169          * 
170          * @param metadata:  What to traverse
171          * @return an iterator
172          */
173         
174         private static Iterator /*<EntityDescriptor>*/ Entities(Metadata metadata) {
175
176                 EntitiesDescriptor entities = metadata.getRootEntities();
177                 EntityDescriptor entity = metadata.getRootEntity();
178
179                 if (entities != null) {
180                         return new EntityIterator(entities);
181                 }
182                 
183                 return Collections.singleton(entity).iterator();
184         }
185         
186         private static class EntityIterator implements Iterator /*<EntityDescriptor>*/ {
187                 
188                 private Iterator /*<EntitiesDescriptor>*/ entitiesIterator;
189                 private Iterator /*<EntityDescriptor>*/ entityIterator;
190                 
191                 /**
192                 * An invariant of this class is that the inner iterator (entityIterator) should always be valid.
193                 * This means that when the current one is at the end we step the outer iterator (entitiesIterator)
194                 * along and get the next innter iterator.
195                 * 
196                 * However because the returned inner iterator may already be empty we need to 
197                 * loop until we either get to the end of the outer iterator or the inner iterator has a value
198                 * to return.  Think of it as priming a pump.
199                 *
200                 * This method does the work.  It is called at the start (in the constructor) and also whenever
201                 * any innter iterator reaches the end.
202                 */
203
204                 private void getNextNonEmptyIterator() {
205                         while (!entityIterator.hasNext() && entitiesIterator.hasNext()) {
206                                 entityIterator = new EntityIterator((EntitiesDescriptor) entitiesIterator.next());
207                         }
208                 }
209                 
210                 private EntityIterator(EntitiesDescriptor entities)
211                 {
212                         entitiesIterator = entities.getEntitiesDescriptors();
213                         entityIterator = entities.getEntityDescriptors();
214                         
215                         if (entitiesIterator == null) {
216                                 entitiesIterator = new NullIterator /*<EntitiesDescriptor>*/();
217                         }
218                         
219                         if (entityIterator == null) {
220                                 entityIterator = new NullIterator /*<EntityDescriptor>*/();
221                         }
222                         
223                         // prime the pump to get entityIterator valid.
224                         getNextNonEmptyIterator();
225                 }
226                 
227                 
228                 public boolean hasNext() {
229                         return entityIterator.hasNext();
230                 }
231         
232                 public Object /*EntityDescriptor*/ next() {
233                         Object /*EntityDescriptor*/ ret = entityIterator.next();
234
235                         //
236                         // make entityIterator valid
237                         ///
238                         getNextNonEmptyIterator();
239                         return ret;
240                 }
241         
242                 public void remove() {
243                         entityIterator.remove();
244                 }
245                 
246                 // 
247                 // Implementation note - should be removed in Java 5 and replaced by
248                 // the iterator from an empty collection.
249                 //
250                 private static class NullIterator /*<E>*/ implements Iterator/*<E>*/ {
251
252                         public boolean hasNext() {
253                                 return false;
254                         }
255
256                         public /*E*/ Object next() {
257                                 throw new NoSuchElementException();
258                         }
259
260                         public void remove() {
261                                 throw new UnsupportedOperationException();
262                         }
263                 } //NullIterator        
264         } // Class EntitiesIterator
265 }       
266