1 package org.apache.fulcrum.security.util;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.Serializable;
23 import java.util.Collection;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.TreeMap;
29
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.fulcrum.security.entity.SecurityEntity;
32
33 /**
34 * This class represents a set of Security Entities. It makes it easy to build a
35 * UI. It wraps a TreeSet object to enforce that only relevant methods are
36 * available. TreeSet's contain only unique Objects (no duplicates) based on the
37 * ID. They may or may not have a name, that depends on the implementation. Want
38 * to get away from requiring an ID and a name... Nothing should force Name to
39 * be unique in the basic architecture of Fulcrum Security.
40 *
41 * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>
42 * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
43 * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
44 * @author <a href="mailto:marco@intermeta.de">Marco Knüttel</a>
45 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
46 * @version $Id$
47 */
48 public abstract class SecuritySet<T extends SecurityEntity> implements Serializable, Set<T>, Iterable<T> {
49 /** Serial version */
50 private static final long serialVersionUID = 2251987059226422569L;
51
52 /** Map for "name" is "security object" */
53 protected Map<String, T> nameMap = null;
54
55 /** Map for "id" is "security object" */
56 protected Map<Object, T> idMap = null;
57
58 /**
59 * Constructs an empty Set
60 */
61 public SecuritySet()
62 {
63 nameMap = new TreeMap<String, T>(String.CASE_INSENSITIVE_ORDER);
64 idMap = new TreeMap<Object, T>();
65 }
66
67 /**
68 * Returns a set of security objects in this object.
69 *
70 * @return A Set Object
71 *
72 */
73 public Set<T> getSet()
74 {
75 return new HashSet<T>(idMap.values());
76 }
77
78 /**
79 * Returns a set of Names in this Object.
80 *
81 * @return The Set of Names in this Object, backed by the actual data.
82 */
83 public Set<String> getNames()
84 {
85 return nameMap.keySet();
86 }
87
88 /**
89 * Returns a set of Id values in this Object.
90 *
91 * @return The Set of Ids in this Object, backed by the actual data.
92 */
93 public Set<Object> getIds()
94 {
95 return idMap.keySet();
96 }
97
98 /**
99 * 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 }