001package org.apache.fulcrum.security.util; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.Serializable; 023import java.util.Collection; 024import java.util.HashSet; 025import java.util.Iterator; 026import java.util.Map; 027import java.util.Set; 028import java.util.TreeMap; 029 030import org.apache.commons.lang3.StringUtils; 031import org.apache.fulcrum.security.entity.SecurityEntity; 032 033/** 034 * This class represents a set of Security Entities. It makes it easy to build a 035 * UI. It wraps a TreeSet object to enforce that only relevant methods are 036 * available. TreeSet's contain only unique Objects (no duplicates) based on the 037 * ID. They may or may not have a name, that depends on the implementation. Want 038 * to get away from requiring an ID and a name... Nothing should force Name to 039 * be unique in the basic architecture of Fulcrum Security. 040 * 041 * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a> 042 * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a> 043 * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a> 044 * @author <a href="mailto:marco@intermeta.de">Marco Knüttel</a> 045 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> 046 * @version $Id$ 047 */ 048public abstract class SecuritySet<T extends SecurityEntity> implements Serializable, Set<T>, Iterable<T> { 049 /** Serial version */ 050 private static final long serialVersionUID = 2251987059226422569L; 051 052 /** Map for "name" is "security object" */ 053 protected Map<String, T> nameMap = null; 054 055 /** Map for "id" is "security object" */ 056 protected Map<Object, T> idMap = null; 057 058 /** 059 * Constructs an empty Set 060 */ 061 public SecuritySet() 062 { 063 nameMap = new TreeMap<String, T>(String.CASE_INSENSITIVE_ORDER); 064 idMap = new TreeMap<Object, T>(); 065 } 066 067 /** 068 * Returns a set of security objects in this object. 069 * 070 * @return A Set Object 071 * 072 */ 073 public Set<T> getSet() 074 { 075 return new HashSet<T>(idMap.values()); 076 } 077 078 /** 079 * Returns a set of Names in this Object. 080 * 081 * @return The Set of Names in this Object, backed by the actual data. 082 */ 083 public Set<String> getNames() 084 { 085 return nameMap.keySet(); 086 } 087 088 /** 089 * Returns a set of Id values in this Object. 090 * 091 * @return The Set of Ids in this Object, backed by the actual data. 092 */ 093 public Set<Object> getIds() 094 { 095 return idMap.keySet(); 096 } 097 098 /** 099 * Removes all Objects from this Set. 100 */ 101 @Override 102 public void clear() 103 { 104 nameMap.clear(); 105 idMap.clear(); 106 } 107 108 /** 109 * Searches if an Object with a given name is in the Set 110 * 111 * @param name Name of the Security Object. 112 * @return True if argument matched an Object in this Set; false if no match. 113 */ 114 public boolean containsName(String name) 115 { 116 return StringUtils.isNotEmpty(name) ? nameMap.containsKey(name) : false; 117 } 118 119 /** 120 * Searches if an Object with a given Id is in the Set 121 * 122 * @param id Id of the Security Object. 123 * @return True if argument matched an Object in this Set; false if no match. 124 */ 125 public boolean containsId(Object id) 126 { 127 return (id == null) ? false : idMap.containsKey(id); 128 } 129 130 /** 131 * Returns an Iterator for Objects in this Set. 132 * 133 * @return An iterator for the Set 134 */ 135 @Override 136 public Iterator<T> iterator() 137 { 138 return idMap.values().iterator(); 139 } 140 141 /** 142 * Returns size (cardinality) of this set. 143 * 144 * @return The cardinality of this Set. 145 */ 146 @Override 147 public int size() 148 { 149 return idMap.size(); 150 } 151 152 /** 153 * list of role names in this set 154 * 155 * @return The string representation of this Set. 156 */ 157 @Override 158 public String toString() 159 { 160 StringBuilder sbuf = new StringBuilder(12 * size()); 161 162 for (Iterator<T> it = iterator(); it.hasNext();) { 163 T se = it.next(); 164 sbuf.append('['); 165 sbuf.append(se.getName()); 166 sbuf.append(" -> "); 167 sbuf.append(se.getId()); 168 sbuf.append(']'); 169 if (it.hasNext()) { 170 sbuf.append(", "); 171 } 172 } 173 174 return sbuf.toString(); 175 } 176 177 // methods from Set 178 /** 179 * @see java.util.Collection#add(java.lang.Object) 180 */ 181 @Override 182 public boolean add(T o) 183 { 184 if (contains(o)) 185 { 186 return false; 187 } 188 189 if (o.getId() != null) 190 { 191 idMap.put(o.getId(), o); 192 } 193 194 if (o.getName() != null) 195 { 196 nameMap.put(o.getName(), o); 197 } 198 199 return true; 200 } 201 202 /** 203 * Adds the entities in a Collection to this SecuritySet. 204 * 205 * @param collection A Collection of entities. 206 * @return True if this Set changed as a result; false if no change to this Set 207 * occurred (this Set already contained all members of the added Set). 208 */ 209 public boolean add(Collection<? extends T> collection) 210 { 211 return addAll(collection); 212 } 213 214 @Override 215 public boolean addAll(Collection<? extends T> collection) 216 { 217 boolean res = false; 218 219 for (T o : collection) 220 res |= add(o); 221 222 return res; 223 } 224 225 @Override 226 public boolean isEmpty() 227 { 228 return idMap.isEmpty(); 229 } 230 231 @Override 232 public boolean containsAll(Collection<?> collection) 233 { 234 for (Object object : collection) 235 { 236 if (!contains(object)) 237 { 238 return false; 239 } 240 } 241 return true; 242 } 243 244 @Override 245 public boolean removeAll(Collection<?> collection) 246 { 247 boolean changed = false; 248 for (Object object : collection) 249 { 250 boolean result = remove(object); 251 if (result) 252 { 253 changed = true; 254 } 255 } 256 257 return changed; 258 } 259 260 @Override 261 public boolean retainAll(Collection<?> collection) 262 { 263 throw new RuntimeException("not implemented"); 264 } 265 266 /* 267 * (non-Javadoc) 268 * 269 * @see java.util.Collection#toArray() 270 */ 271 @Override 272 public Object[] toArray() 273 { 274 return getSet().toArray(); 275 } 276 277 /** 278 * Checks whether this SecuritySet contains an entity. 279 * 280 * @param o An entity. 281 * @return True if this Set contains the entity, false otherwise. 282 */ 283 @Override 284 public boolean contains(Object o) 285 { 286 if (o == null || !(o instanceof SecurityEntity)) 287 { 288 return false; 289 } 290 else 291 { 292 return containsId(((SecurityEntity) o).getId()); 293 } 294 } 295 296 /** 297 * Removes an entity from this SecuritySet. 298 * 299 * @param o An entity. 300 * @return True if this Set contained the entity before it was removed. 301 */ 302 @Override 303 public boolean remove(Object o) 304 { 305 if (o instanceof SecurityEntity) 306 { 307 boolean res = contains(o); 308 idMap.remove(((SecurityEntity) o).getId()); 309 nameMap.remove(((SecurityEntity) o).getName()); 310 return res; 311 } 312 313 return false; 314 } 315 316 /* (non-Javadoc) 317 * @see java.util.Set#toArray(java.lang.Object[]) 318 */ 319 @Override 320 public <A> A[] toArray(A[] a) 321 { 322 return getSet().toArray(a); 323 } 324 325 /** 326 * Returns an entity with the given name, if it is contained in this 327 * SecuritySet. 328 * 329 * @param name Name of entity. 330 * @return entity if argument matched an entity in this Set; null if no match. 331 */ 332 public T getByName(String name) 333 { 334 return nameMap.get(name); 335 } 336 337 /** 338 * Returns an entity with the given id, if it is contained in this SecuritySet. 339 * 340 * @param id ID of entity. 341 * @return entity if argument matched an entity in this Set; null if no match. 342 */ 343 public T getById(Object id) 344 { 345 return idMap.get(id); 346 } 347}