001: /* Copyright 2004 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.groups.pags;
007:
008: import java.lang.reflect.Constructor;
009: import java.util.ArrayList;
010: import java.util.Collection;
011: import java.util.Collections;
012: import java.util.HashMap;
013: import java.util.HashSet;
014: import java.util.Iterator;
015: import java.util.List;
016: import java.util.Map;
017: import java.util.Properties;
018: import java.util.Set;
019: import java.util.Vector;
020:
021: import org.apache.commons.logging.Log;
022: import org.apache.commons.logging.LogFactory;
023: import org.jasig.portal.EntityIdentifier;
024: import org.jasig.portal.EntityTypes;
025: import org.jasig.portal.groups.EntityImpl;
026: import org.jasig.portal.groups.EntityTestingGroupImpl;
027: import org.jasig.portal.groups.GroupsException;
028: import org.jasig.portal.groups.IEntity;
029: import org.jasig.portal.groups.IEntityGroup;
030: import org.jasig.portal.groups.IEntityGroupStore;
031: import org.jasig.portal.groups.IEntitySearcher;
032: import org.jasig.portal.groups.IEntityStore;
033: import org.jasig.portal.groups.IGroupMember;
034: import org.jasig.portal.groups.ILockableEntityGroup;
035: import org.jasig.portal.security.IPerson;
036: import org.jasig.portal.security.PersonFactory;
037: import org.jasig.portal.security.provider.RestrictedPerson;
038: import org.jasig.portal.services.PersonDirectory;
039: import org.jasig.portal.services.persondir.IPersonAttributeDao;
040:
041: /**
042: * The Person Attributes Group Store uses attributes stored in the IPerson object to determine
043: * group membership. It can use attributes from any data source supported by the PersonDirectory
044: * service.
045: *
046: * @author Al Wold
047: * @version $Revision: 42262 $
048: */
049: public class PersonAttributesGroupStore implements IEntityGroupStore,
050: IEntityStore, IEntitySearcher {
051: private static final Log log = LogFactory
052: .getLog(PersonAttributesGroupStore.class);
053: private static final Class IPERSON_CLASS = IPerson.class;
054: private static final EntityIdentifier[] EMPTY_SEARCH_RESULTS = new EntityIdentifier[0];
055: private Properties props;
056: private Map groupDefinitions;
057: private Map groups;
058: private Map containingGroups;
059:
060: public PersonAttributesGroupStore() {
061: groups = new HashMap();
062: containingGroups = new HashMap();
063: try {
064: props = new Properties();
065: props
066: .load(PersonAttributesGroupStore.class
067: .getResourceAsStream("/properties/groups/pags.properties"));
068: IPersonAttributesConfiguration config = getConfig(props
069: .getProperty("org.jasig.portal.groups.pags.PersonAttributesGroupStore.configurationClass"));
070: groupDefinitions = config.getConfig();
071: initGroups();
072: } catch (Exception e) {
073: String errorMsg = "PersonAttributeGroupStore.init(): "
074: + "Problem initializing groups: " + e.getMessage();
075: log.error("Problem initializing groups.", e);
076: throw new RuntimeException(errorMsg);
077: }
078: }
079:
080: private IPersonAttributesConfiguration getConfig(String className)
081: throws ClassNotFoundException, InstantiationException,
082: IllegalAccessException {
083: Class configClass = Class.forName(className);
084: Object o = configClass.newInstance();
085: return (IPersonAttributesConfiguration) o;
086: }
087:
088: /**
089: * Iterates over the groupDefinitions Collection and creates the
090: * corresponding groups. Then, caches parents for each child group.
091: */
092: private void initGroups() throws GroupsException {
093: Iterator i = null;
094: Collection groupDefs = groupDefinitions.values();
095:
096: for (i = groupDefs.iterator(); i.hasNext();) {
097: GroupDefinition groupDef = (GroupDefinition) i.next();
098: IEntityGroup group = new EntityTestingGroupImpl(groupDef
099: .getKey(), IPERSON_CLASS);
100: group.setName(groupDef.getName());
101: group.setDescription(groupDef.getDescription());
102: cachePut(group);
103: }
104: cacheContainingGroupsForGroups();
105: }
106:
107: private IPersonTester initializeTester(String tester,
108: String attribute, String value) {
109: try {
110: Class testerClass = Class.forName(tester);
111: Constructor c = testerClass.getConstructor(new Class[] {
112: String.class, String.class });
113: Object o = c.newInstance(new Object[] { attribute, value });
114: return (IPersonTester) o;
115: } catch (Exception e) {
116: e.printStackTrace();
117: return null;
118: }
119: }
120:
121: private IEntityGroup cacheGet(String key) {
122: return (IEntityGroup) groups.get(key);
123: }
124:
125: private void cachePut(IEntityGroup group) {
126: groups.put(group.getLocalKey(), group);
127: }
128:
129: public boolean contains(IEntityGroup group, IGroupMember member)
130: throws GroupsException {
131: GroupDefinition groupDef = (GroupDefinition) groupDefinitions
132: .get(group.getLocalKey());
133: if (member.isGroup()) {
134: String key = ((IEntityGroup) member).getLocalKey();
135: return groupDef.hasMember(key);
136: } else {
137: if (member.getEntityType() != IPERSON_CLASS) {
138: return false;
139: }
140: IPerson person = null;
141: try {
142: IPersonAttributeDao pa = PersonDirectory
143: .getPersonAttributeDao();
144: Map attrs = pa.getUserAttributes(member.getKey());
145: RestrictedPerson rp = PersonFactory
146: .createRestrictedPerson();
147: rp.setAttributes(attrs);
148:
149: person = rp;
150: } catch (Exception ex) {
151: log.error("Exception acquiring attributes for member "
152: + member + " while checking if group " + group
153: + " contains this member.", ex);
154: return false;
155: }
156: return testRecursively(groupDef, person, member);
157: }
158: }
159:
160: public void delete(IEntityGroup group) throws GroupsException {
161: throw new UnsupportedOperationException(
162: "PersonAttributesGroupStore: Method delete() not supported.");
163: }
164:
165: public IEntityGroup find(String key) throws GroupsException {
166: return (IEntityGroup) groups.get(key);
167: }
168:
169: private void cacheContainingGroupsForGroups()
170: throws GroupsException {
171: Iterator i = null;
172: // Find potential parent groups, those whose GroupDefinitions have members.
173: List parentGroupsList = new ArrayList();
174: for (i = groupDefinitions.values().iterator(); i.hasNext();) {
175: GroupDefinition groupDef = (GroupDefinition) i.next();
176: if (!groupDef.members.isEmpty()) {
177: parentGroupsList.add(cacheGet(groupDef.getKey()));
178: }
179: }
180: IEntityGroup[] parentGroupsArray = (IEntityGroup[]) parentGroupsList
181: .toArray(new IEntityGroup[parentGroupsList.size()]);
182:
183: // Check each group for its parents and cache the references.
184: for (i = groups.values().iterator(); i.hasNext();) {
185: IEntityGroup childGroup = (IEntityGroup) i.next();
186: parentGroupsList = new ArrayList(5);
187: for (int idx = 0; idx < parentGroupsArray.length; idx++) {
188: if (contains(parentGroupsArray[idx], childGroup)) {
189: parentGroupsList.add(parentGroupsArray[idx]);
190: }
191: }
192: containingGroups.put(childGroup.getLocalKey(),
193: parentGroupsList);
194: }
195: }
196:
197: private boolean testRecursively(GroupDefinition groupDef,
198: IPerson person, IGroupMember member) throws GroupsException {
199: if (!groupDef.contains(person)) {
200: return false;
201: } else {
202: IEntityGroup group = cacheGet(groupDef.getKey());
203: IEntityGroup parentGroup = null;
204: Set allParents = primGetAllContainingGroups(group,
205: new HashSet());
206: boolean testPassed = true;
207: for (Iterator i = allParents.iterator(); i.hasNext()
208: && testPassed;) {
209: parentGroup = (IEntityGroup) i.next();
210: GroupDefinition parentGroupDef = (GroupDefinition) groupDefinitions
211: .get(parentGroup.getLocalKey());
212: testPassed = parentGroupDef.test(person);
213: }
214:
215: if (!testPassed && log.isWarnEnabled()) {
216: StringBuffer sb = new StringBuffer();
217: sb.append("PAGS group=").append(group.getKey());
218: sb.append(" contained person=").append(member.getKey());
219: sb
220: .append(", but the person failed to be contained in ");
221: sb.append("ancesters of this group");
222: sb.append((parentGroup != null ? " (parentGroup="
223: + parentGroup.getKey() + ")" : ""));
224: sb.append(". This may indicate a ");
225: sb.append("misconfigured PAGS group ");
226: sb
227: .append("store. Please check PAGSGroupStoreConfig.xml.");
228: log.warn(sb.toString());
229: }
230: return testPassed;
231: }
232: }
233:
234: private java.util.Set primGetAllContainingGroups(
235: IEntityGroup group, Set s) throws GroupsException {
236: Iterator i = findContainingGroups(group);
237: while (i.hasNext()) {
238: IEntityGroup parentGroup = (IEntityGroup) i.next();
239: s.add(parentGroup);
240: primGetAllContainingGroups(parentGroup, s);
241: }
242: return s;
243: }
244:
245: public Iterator findContainingGroups(IGroupMember member)
246: throws GroupsException {
247: return (member.isEntity()) ? findContainingGroupsForEntity((IEntity) member)
248: : findContainingGroupsForGroup((IEntityGroup) member);
249: }
250:
251: private Iterator findContainingGroupsForGroup(IEntityGroup group) {
252: List parents = (List) containingGroups.get(group.getLocalKey());
253: return (parents != null) ? parents.iterator()
254: : Collections.EMPTY_LIST.iterator();
255: }
256:
257: private Iterator findContainingGroupsForEntity(IEntity member)
258: throws GroupsException {
259: List results = new ArrayList();
260: for (Iterator i = groups.values().iterator(); i.hasNext();) {
261: IEntityGroup group = (IEntityGroup) i.next();
262: if (contains(group, member)) {
263: results.add(group);
264: }
265: }
266: return results.iterator();
267: }
268:
269: public Iterator findEntitiesForGroup(IEntityGroup group)
270: throws GroupsException {
271: return Collections.EMPTY_LIST.iterator();
272: }
273:
274: public ILockableEntityGroup findLockable(String key)
275: throws GroupsException {
276: throw new UnsupportedOperationException(
277: "PersonAttributesGroupStore: Method findLockable() not supported");
278: }
279:
280: public String[] findMemberGroupKeys(IEntityGroup group)
281: throws GroupsException {
282: List keys = new ArrayList();
283: GroupDefinition groupDef = (GroupDefinition) groupDefinitions
284: .get(group.getLocalKey());
285: if (groupDef != null) {
286: for (Iterator i = groupDef.members.iterator(); i.hasNext();) {
287: keys.add((String) i.next());
288: }
289: }
290: return (String[]) keys.toArray(new String[] {});
291: }
292:
293: public Iterator findMemberGroups(IEntityGroup group)
294: throws GroupsException {
295: String[] keys = findMemberGroupKeys(group);
296: List results = new ArrayList();
297: for (int i = 0; i < keys.length; i++) {
298: results.add(cacheGet(keys[i]));
299: }
300: return results.iterator();
301: }
302:
303: public IEntityGroup newInstance(Class entityType)
304: throws GroupsException {
305: throw new UnsupportedOperationException(
306: "PersonAttributesGroupStore: Method newInstance() not supported");
307: }
308:
309: public EntityIdentifier[] searchForGroups(String query, int method,
310: Class leaftype) throws GroupsException {
311: if (leaftype != IPERSON_CLASS) {
312: return EMPTY_SEARCH_RESULTS;
313: }
314: List results = new ArrayList();
315: switch (method) {
316: case IS:
317: for (Iterator i = groups.values().iterator(); i.hasNext();) {
318: IEntityGroup g = (IEntityGroup) i.next();
319: if (g.getName().equalsIgnoreCase(query)) {
320: results.add(g.getEntityIdentifier());
321: }
322: }
323: break;
324: case STARTS_WITH:
325: for (Iterator i = groups.values().iterator(); i.hasNext();) {
326: IEntityGroup g = (IEntityGroup) i.next();
327: if (g.getName().toUpperCase().startsWith(
328: query.toUpperCase())) {
329: results.add(g.getEntityIdentifier());
330: }
331: }
332: break;
333: case ENDS_WITH:
334: for (Iterator i = groups.values().iterator(); i.hasNext();) {
335: IEntityGroup g = (IEntityGroup) i.next();
336: if (g.getName().toUpperCase().endsWith(
337: query.toUpperCase())) {
338: results.add(g.getEntityIdentifier());
339: }
340: }
341: break;
342: case CONTAINS:
343: for (Iterator i = groups.values().iterator(); i.hasNext();) {
344: IEntityGroup g = (IEntityGroup) i.next();
345: if (g.getName().toUpperCase().indexOf(
346: query.toUpperCase()) != -1) {
347: results.add(g.getEntityIdentifier());
348: }
349: }
350: break;
351: }
352: return (EntityIdentifier[]) results
353: .toArray(new EntityIdentifier[] {});
354: }
355:
356: public void update(IEntityGroup group) throws GroupsException {
357: throw new UnsupportedOperationException(
358: "PersonAttributesGroupStore: Method update() not supported.");
359: }
360:
361: public void updateMembers(IEntityGroup group)
362: throws GroupsException {
363: throw new UnsupportedOperationException(
364: "PersonAttributesGroupStore: Method updateMembers() not supported.");
365: }
366:
367: public static class GroupDefinition {
368: private String key;
369: private String name;
370: private String description;
371: private List members;
372: private List testGroups;
373:
374: public GroupDefinition() {
375: members = new Vector();
376: testGroups = new Vector();
377: }
378:
379: public void setKey(String key) {
380: this .key = key;
381: }
382:
383: public String getKey() {
384: return key;
385: }
386:
387: public void setName(String name) {
388: this .name = name;
389: }
390:
391: public String getName() {
392: return name;
393: }
394:
395: public void setDescription(String description) {
396: this .description = description;
397: }
398:
399: public String getDescription() {
400: return description;
401: }
402:
403: public void addMember(String key) {
404: members.add(key);
405: }
406:
407: public boolean hasMember(String key) {
408: return members.contains(key);
409: }
410:
411: public void addTestGroup(TestGroup testGroup) {
412: testGroups.add(testGroup);
413: }
414:
415: public boolean contains(IPerson person) {
416: return (testGroups.isEmpty()) ? false : test(person);
417: }
418:
419: public boolean test(IPerson person) {
420: if (testGroups.isEmpty())
421: return true;
422: for (Iterator i = testGroups.iterator(); i.hasNext();) {
423: TestGroup testGroup = (TestGroup) i.next();
424: if (testGroup.test(person)) {
425: return true;
426: }
427: }
428: return false;
429: }
430:
431: public String toString() {
432: return "GroupDefinition " + key + " (" + name + ")";
433: }
434: }
435:
436: public static class TestGroup {
437: private List tests;
438:
439: public TestGroup() {
440: tests = new Vector();
441: }
442:
443: public void addTest(IPersonTester test) {
444: tests.add(test);
445: }
446:
447: public boolean test(IPerson person) {
448: for (Iterator i = tests.iterator(); i.hasNext();) {
449: IPersonTester tester = (IPersonTester) i.next();
450: if (!tester.test(person)) {
451: return false;
452: }
453: }
454: return true;
455: }
456: }
457:
458: public IEntity newInstance(String key, Class type)
459: throws GroupsException {
460: if (EntityTypes.getEntityTypeID(type) == null) {
461: throw new GroupsException("Invalid entity type: "
462: + type.getName());
463: }
464: return new EntityImpl(key, type);
465: }
466:
467: public IEntity newInstance(String key) throws GroupsException {
468: return new EntityImpl(key, null);
469: }
470:
471: public EntityIdentifier[] searchForEntities(String query,
472: int method, Class type) throws GroupsException {
473: return EMPTY_SEARCH_RESULTS;
474: }
475:
476: }
|