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