Index: uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/LdapRecord.java =================================================================== --- uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/LdapRecord.java (revision 0) +++ uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/LdapRecord.java (revision 0) @@ -0,0 +1,50 @@ +/** + * Copyright 2008 The JA-SIG Collaborative. All rights reserved. + * See license distributed with this file and + * available online at http://www.uportal.org/license.html + */ + +package org.jasig.portal.groups.smartldap; + +import java.util.Collections; +import java.util.List; + +import org.jasig.portal.groups.IEntityGroup; + +public final class LdapRecord { + + // Instance Members. + private final IEntityGroup group; + private final List keysOfChildren; + + /* + * Public API. + */ + + public LdapRecord(IEntityGroup group, List keysOfChildren) { + + // Assertions. + if (group == null) { + String msg = "Argument 'group' cannot be null."; + throw new IllegalArgumentException(msg); + } + if (keysOfChildren == null) { + String msg = "Argument 'keysOfChildren' cannot be null."; + throw new IllegalArgumentException(msg); + } + + // Instance Members. + this.group = group; + this.keysOfChildren = Collections.unmodifiableList(keysOfChildren); + + } + + public IEntityGroup getGroup() { + return group; + } + + public List getKeysOfChildren() { + return keysOfChildren; + } + +} Index: uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/SmartLdapEntitySearcher.java =================================================================== --- uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/SmartLdapEntitySearcher.java (revision 0) +++ uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/SmartLdapEntitySearcher.java (revision 0) @@ -0,0 +1,50 @@ +/** + * Copyright 2008 The JA-SIG Collaborative. All rights reserved. + * See license distributed with this file and + * available online at http://www.uportal.org/license.html + */ + +package org.jasig.portal.groups.smartldap; + +import org.jasig.portal.EntityIdentifier; +import org.jasig.portal.groups.GroupsException; +import org.jasig.portal.groups.IEntityGroupStore; +import org.jasig.portal.groups.IEntitySearcher; +import org.jasig.portal.groups.IEntitySearcherFactory; + +public class SmartLdapEntitySearcher implements IEntitySearcher { + + // Instance Members. + private final IEntityGroupStore store; + + /* + * Public API. + */ + + public static final class Factory implements IEntitySearcherFactory { + + /* + * Public API. + */ + + public IEntitySearcher newEntitySearcher() throws GroupsException { + return new SmartLdapEntitySearcher(new SmartLdapGroupStore.Factory().newGroupStore()); + } + + } + + public EntityIdentifier[] searchForEntities(String query, int method, Class type) throws GroupsException { + return store.searchForGroups(query, method, type); + } + + /* + * Implementation. + */ + + private SmartLdapEntitySearcher(IEntityGroupStore store) { + + // Instance Members. + this.store = store; + } + +} Index: uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/SmartLdapEntityStore.java =================================================================== --- uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/SmartLdapEntityStore.java (revision 0) +++ uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/SmartLdapEntityStore.java (revision 0) @@ -0,0 +1,47 @@ +/** + * Copyright 2008 The JA-SIG Collaborative. All rights reserved. + * See license distributed with this file and + * available online at http://www.uportal.org/license.html + */ + +package org.jasig.portal.groups.smartldap; + +import org.jasig.portal.groups.EntityImpl; +import org.jasig.portal.groups.GroupsException; +import org.jasig.portal.groups.IEntity; +import org.jasig.portal.groups.IEntityStore; +import org.jasig.portal.groups.IEntityStoreFactory; + +public class SmartLdapEntityStore implements IEntityStore { + + /* + * Public API. + */ + + public static final class Factory implements IEntityStoreFactory { + + /* + * Public API. + */ + + public IEntityStore newEntityStore() throws GroupsException { + return new SmartLdapEntityStore(); + } + + } + + public IEntity newInstance(String key) throws GroupsException { + return newInstance(key, null); + } + + public IEntity newInstance(String key, Class type) throws GroupsException { + return new EntityImpl(key, type); + } + + /* + * Implementation. + */ + + private SmartLdapEntityStore() {} + +} Index: uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/SmartLdapGroupStore.java =================================================================== --- uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/SmartLdapGroupStore.java (revision 0) +++ uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/SmartLdapGroupStore.java (revision 0) @@ -0,0 +1,578 @@ +/** + * Copyright 2008 The JA-SIG Collaborative. All rights reserved. + * See license distributed with this file and + * available online at http://www.uportal.org/license.html + */ + +package org.jasig.portal.groups.smartldap; + +import java.net.URL; +import java.util.Collections; +import java.util.Iterator; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.danann.cernunnos.Task; +import org.danann.cernunnos.runtime.RuntimeRequestResponse; +import org.danann.cernunnos.runtime.ScriptRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.FileSystemXmlApplicationContext; + +import org.jasig.portal.EntityIdentifier; +import org.jasig.portal.groups.ComponentGroupServiceDescriptor; +import org.jasig.portal.groups.EntityTestingGroupImpl; +import org.jasig.portal.groups.GroupsException; +import org.jasig.portal.groups.IEntityGroup; +import org.jasig.portal.groups.IEntityGroupStore; +import org.jasig.portal.groups.IEntityGroupStoreFactory; +import org.jasig.portal.groups.IGroupConstants; +import org.jasig.portal.groups.IGroupMember; +import org.jasig.portal.groups.ILockableEntityGroup; +import org.jasig.portal.properties.PropertiesManager; +import org.jasig.portal.security.IPerson; +import org.jasig.portal.security.PersonFactory; +import org.jasig.portal.services.PersonDirectory; + +public class SmartLdapGroupStore implements IEntityGroupStore { + + // Instance Members. + private ApplicationContext spring_context = null; + private final ScriptRunner runner; + private final Task initTask; + private final Log log = LogFactory.getLog(getClass()); + private boolean initialized; + + /* + * Indexed Collections. + */ + + /** + * Map of all groups keyed by 'key' (DN). Includes ROOT_GROUP. + */ + private Map groups; + + /** + * Map of all parent relationships keyed by the 'key' (DN) of the child; + * the values are lists of the 'keys' (DNs) of its parents. + * Includes ROOT_GROUP. + */ + private Map> parents; + + /** + * Map of all child relationships keyed by the 'key' (DN) of the parent; + * the values are lists of the 'keys' (DNs) of its children. + * Includes ROOT_GROUP. + */ + private Map> children; + + /** + * Map of all 'keys' (DNs) of SmartLdap managed groups indexed by group + * name in upper case. Includes ROOT_GROUP. + */ + private Map> keysByUpperCaseName; + + /* + * Public API. + */ + + public static final String UNSUPPORTED_MESSAGE = + "The SmartLdap implementation of JA-SIG Groups and Permissions (GaP) " + + "does not support this operation."; + + public static final String ROOT_KEY = "SmartLdap ROOT"; + public static final String ROOT_DESC = "A root group provided for the SmartLdapGroupStore."; + + public static final EntityIdentifier ENTITY_IDENTIFIER = new EntityIdentifier(ROOT_KEY, + org.jasig.portal.groups.IEntityGroup.class); + + public static final IEntityGroup ROOT_GROUP; + static { + + try { + ROOT_GROUP = new EntityTestingGroupImpl(ROOT_KEY, IPerson.class); + ROOT_GROUP.setCreatorID("System"); + ROOT_GROUP.setName(ROOT_KEY); + ROOT_GROUP.setDescription(ROOT_DESC); + } catch (Throwable t) { + throw new RuntimeException(t); + } + + } + + public static final class Factory implements IEntityGroupStoreFactory { + + private static final IEntityGroupStore INSTANCE = new SmartLdapGroupStore(); + + /* + * Public API. + */ + + public IEntityGroupStore newGroupStore() throws GroupsException { + return INSTANCE; + } + + public IEntityGroupStore newGroupStore(ComponentGroupServiceDescriptor svcDescriptor) throws GroupsException { + return INSTANCE; + } + + } + + public boolean contains(IEntityGroup group, IGroupMember member) throws GroupsException { + log.warn("Unsupported method accessed: SmartLdapGroupStore.contains"); + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + public void delete(IEntityGroup group) throws GroupsException { + log.warn("Unsupported method accessed: SmartLdapGroupStore.delete"); + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + /** + * Returns an instance of the IEntityGroup from the data store. + * @return org.jasig.portal.groups.IEntityGroup + * @param key java.lang.String + */ + public IEntityGroup find(String key) throws GroupsException { + + if (!initialized) { + init(); + } + + if (log.isDebugEnabled()) { + log.debug("Invoking find() for key: " + key); + } + + // All of our groups (incl. ROOT_GROUP) + // are indexed in the 'groups' map by key... + return groups.get(key); + + } + + /** + * Returns an Iterator over the Collection of + * IEntityGroups that the IGroupMember belongs to. + * @return java.util.Iterator + * @param gm org.jasig.portal.groups.IEntityGroup + */ + public Iterator findContainingGroups(IGroupMember gm) throws GroupsException { + + if (!initialized) { + init(); + } + + List rslt = new LinkedList(); + if (gm.isGroup()) { // Check the local indeces... + IEntityGroup group = (IEntityGroup) gm; + List list = parents.get(group.getLocalKey()); + if (list != null) { + // should only reach this code if its a SmartLdap managed group... + for (String s : list) { + rslt.add(groups.get(s)); + } + } + } else if (gm.isEntity()) { // Ask the individual... + + // Build an IPerson... + EntityIdentifier ei = gm.getUnderlyingEntityIdentifier(); + Map> seed = new HashMap>(); + List seedValue = new LinkedList(); + seedValue.add(ei.getKey()); + seed.put(IPerson.USERNAME, seedValue); + Map> attr = PersonDirectory.getPersonAttributeDao().getMultivaluedUserAttributes(seed); + IPerson p = PersonFactory.createPerson(); + p.setAttributes(attr); + + // Analyze its memberships... + String attrName = (String) spring_context.getBean("memberOfAttributeName"); + Object groupKeys = p.getAttributeValues(attrName); + // IPerson returns null if no value is defined for this attribute... + if (groupKeys != null) { + + List list = new LinkedList(); + if (groupKeys instanceof String) { + list.add((String) groupKeys); + } else if (groupKeys instanceof Object[]) { + Object[] objs = (Object[]) groupKeys; + for (Object o : objs) { + list.add((String) o); + } + } else if (groupKeys instanceof List) { + List objs = (List) groupKeys; + for (Object o : objs) { + list.add((String) o); + } + } + + for (String s : list) { + if (groups.containsKey(s)) { + rslt.add(groups.get(s)); + } + } + } + + } else { + // WTF... + log.warn("The specified IGroupMember is neither a group nor an entity: " + gm.getKey()); + } + + return rslt.iterator(); + + } + + /** + * Returns an Iterator over the Collection of + * IEntities that are members of this IEntityGroup. + * @return java.util.Iterator + * @param group org.jasig.portal.groups.IEntityGroup + */ + public Iterator findEntitiesForGroup(IEntityGroup group) throws GroupsException { + + + if (!initialized) { + init(); + } + + if (log.isDebugEnabled()) { + log.debug("Invoking findEntitiesForGroup() for group: " + group.getLocalKey()); + } + + // We only deal w/ group-group relationships here... + return findMemberGroups(group); + + } + + public ILockableEntityGroup findLockable(String key) throws GroupsException { + log.warn("Unsupported method accessed: SmartLdapGroupStore.findLockable"); + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + /** + * Returns a String[] containing the keys of IEntityGroups + * that are members of this IEntityGroup. In a composite group + * system, a group may contain a member group from a different service. This is + * called a foreign membership, and is only possible in an internally-managed + * service. A group store in such a service can return the key of a foreign member + * group, but not the group itself, which can only be returned by its local store. + * + * @return String[] + * @param group org.jasig.portal.groups.IEntityGroup + */ + public String[] findMemberGroupKeys(IEntityGroup group) throws GroupsException { + + if (!initialized) { + init(); + } + + if (log.isDebugEnabled()) { + log.debug("Invoking findMemberGroupKeys() for group: " + group.getLocalKey()); + } + + List rslt = new LinkedList(); + for (Iterator it=findMemberGroups(group); it.hasNext();) { + IEntityGroup g = (IEntityGroup) it.next(); + // Return composite keys here... + rslt.add(g.getKey()); + } + + return rslt.toArray(new String[0]); + + } + + /** + * Returns an Iterator over the Collection of + * IEntityGroups that are members of this IEntityGroup. + * @return java.util.Iterator + * @param group org.jasig.portal.groups.IEntityGroup + */ + public Iterator findMemberGroups(IEntityGroup group) throws GroupsException { + + if (!initialized) { + init(); + } + + if (log.isDebugEnabled()) { + log.debug("Invoking findMemberGroups() for group: " + group.getLocalKey()); + } + + List rslt = new LinkedList(); + + List list = children.get(group.getLocalKey()); + if (list != null) { + // should only reach this code if its a SmartLdap managed group... + for (String s : list) { + rslt.add(groups.get(s)); + } + } + + return rslt.iterator(); + + } + + public IEntityGroup newInstance(Class entityType) throws GroupsException { + log.warn("Unsupported method accessed: SmartLdapGroupStore.newInstance"); + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + public EntityIdentifier[] searchForGroups(String query, int method, Class leaftype) throws GroupsException { + + if (!initialized) { + init(); + } + + if (log.isDebugEnabled()) { + log.debug("Invoking searchForGroups(): query=" + query + ", method=" + + method + ", leaftype=" + leaftype.getClass().getName()); + } + + // We only match the IPerson leaf type... + if (!leaftype.equals(IPerson.class)) { + return new EntityIdentifier[0]; + } + + // Establish the regex pattern to match on... + String regex = null; + switch (method) { + case IGroupConstants.IS: + regex = query.toUpperCase(); + break; + case IGroupConstants.STARTS_WITH: + regex = query.toUpperCase() + ".*"; + break; + case IGroupConstants.ENDS_WITH: + regex = ".*" + query.toUpperCase(); + break; + case IGroupConstants.CONTAINS: + regex = ".*" + query.toUpperCase() + ".*"; + break; + default: + String msg = "Unsupported search method: " + method; + throw new GroupsException(msg); + } + + List rslt = new LinkedList(); + for (Map.Entry> y : keysByUpperCaseName.entrySet()) { + if (y.getKey().matches(regex)) { + List keys = y.getValue(); + for (String k : keys) { + rslt.add(new EntityIdentifier(k, IEntityGroup.class)); + } + } + } + + return rslt.toArray(new EntityIdentifier[0]); + + } + + public void update(IEntityGroup group) throws GroupsException { + log.warn("Unsupported method accessed: SmartLdapGroupStore.update"); + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + public void updateMembers(IEntityGroup group) throws GroupsException { + log.warn("Unsupported method accessed: SmartLdapGroupStore.updateMembers"); + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + public synchronized void init() { + + if (initialized) { + return; + } + + // Prepare the new local indeces... + Map new_groups = Collections.synchronizedMap(new HashMap()); + Map> new_parents = Collections.synchronizedMap(new HashMap>()); + Map> new_children = Collections.synchronizedMap(new HashMap>()); + Map> new_keysByUpperCaseName = Collections.synchronizedMap(new HashMap>()); + + // Gather IEntityGroup objects from LDAP... + RuntimeRequestResponse req = new RuntimeRequestResponse(); + List list = new LinkedList(); + req.setAttribute("GROUPS", list); + for (String name : spring_context.getBeanDefinitionNames()) { + req.setAttribute(name, spring_context.getBean(name)); + } + runner.run(initTask, req); + + if (log.isInfoEnabled()) { + String msg = "init() found " + list.size() + " records."; + log.info(msg); + } + + // Do a first loop to build the main catalog (new_groups)... + for (LdapRecord r : list) { + + // new_groups (me)... + IEntityGroup g = r.getGroup(); + new_groups.put(g.getLocalKey(), g); + + } + + // Do a second loop to build local indeces... + for (LdapRecord r : list) { + + IEntityGroup g = r.getGroup(); + + // new_parents (I am a parent for all my children)... + for (String childKey : r.getKeysOfChildren()) { + + // NB: We're only interested in relationships between + // objects in the main catalog (i.e. new_groups); + // discard everything else... + if (!new_groups.containsKey(childKey)) { + break; + } + + List parentsList = new_parents.get(childKey); + if (parentsList == null) { + // first parent for this child... + parentsList = Collections.synchronizedList(new LinkedList()); + new_parents.put(childKey, parentsList); + } + parentsList.add(g.getLocalKey()); + + } + + // new_children... + List childrenList = Collections.synchronizedList(new LinkedList()); + for (String childKey : r.getKeysOfChildren()) { + // NB: We're only interested in relationships between + // objects in the main catalog (i.e. new_groups); + // discard everything else... + if (new_groups.containsKey(childKey)) { + childrenList.add(childKey); + } + } + new_children.put(g.getLocalKey(), childrenList); + + // new_keysByUpperCaseName... + List groupsWithMyName = new_keysByUpperCaseName.get(g.getName().toUpperCase()); + if (groupsWithMyName == null) { + // I am the first group with my name (pretty likely)... + groupsWithMyName = Collections.synchronizedList(new LinkedList()); + new_keysByUpperCaseName.put(g.getName().toUpperCase(), groupsWithMyName); + } + groupsWithMyName.add(g.getLocalKey()); + + } + + /* + * Now load the ROOT_GROUP into the collections... + */ + + // new_groups (me)... + new_groups.put(ROOT_GROUP.getLocalKey(), ROOT_GROUP); + + // new_parents (I am a parent for all groups that have no other parent)... + List childrenOfRoot = Collections.synchronizedList(new LinkedList()); // for later... + for (String possibleChildKey : new_groups.keySet()) { + if (!possibleChildKey.equals(ROOT_GROUP.getLocalKey()) && !new_parents.containsKey(possibleChildKey)) { + List p = Collections.synchronizedList(new LinkedList()); + p.add(ROOT_GROUP.getLocalKey()); + new_parents.put(possibleChildKey, p); + childrenOfRoot.add(possibleChildKey); // for later... + } + } + + // new_children... + new_children.put(ROOT_GROUP.getLocalKey(), childrenOfRoot); + + // new_keysByUpperCaseName... + List groupsWithMyName = new_keysByUpperCaseName.get(ROOT_GROUP.getName().toUpperCase()); + if (groupsWithMyName == null) { + // I am the first group with my name (pretty likely)... + groupsWithMyName = Collections.synchronizedList(new LinkedList()); + new_keysByUpperCaseName.put(ROOT_GROUP.getName().toUpperCase(), groupsWithMyName); + } + groupsWithMyName.add(ROOT_GROUP.getLocalKey()); + + if (log.isInfoEnabled()) { + String msg = "init() :: final size of each collection is as follows..." + + "\n\tgroups=" + new_groups.size() + + "\n\tparents=" + new_parents.size() + + "\n\tchildren=" + new_children.size() + + "\n\tkeysByUpperCaseName=" + new_keysByUpperCaseName.size(); + log.info(msg); + } + + if (log.isTraceEnabled()) { + + StringBuilder msg = new StringBuilder(); + + // new_groups... + msg.setLength(0); + msg.append("Here are the keys of the new_groups collection:"); + for (String s : new_groups.keySet()) { + msg.append("\n\t").append(s); + } + log.trace(msg.toString()); + + // new_parents... + msg.setLength(0); + msg.append("Here are the parents of each child in the new_parents collection:"); + for (Map.Entry> y : new_parents.entrySet()) { + msg.append("\n\tchild=").append(y.getKey()); + for (String s : y.getValue()) { + msg.append("\n\t\tparent=").append(s); + } + } + log.trace(msg.toString()); + + // new_children... + msg.setLength(0); + msg.append("Here are the children of each parent in the new_children collection:"); + for (Map.Entry> y : new_children.entrySet()) { + msg.append("\n\tparent=").append(y.getKey()); + for (String s : y.getValue()) { + msg.append("\n\t\tchild=").append(s); + } + } + log.trace(msg.toString()); + + // new_keysByUpperCaseName... + msg.append("Here are the groups that have each name in the new_keysByUpperCaseName collection:"); + for (Map.Entry> y : new_keysByUpperCaseName.entrySet()) { + msg.append("\n\tname=").append(y.getKey()); + for (String s : y.getValue()) { + msg.append("\n\t\tgroup=").append(s); + } + } + log.trace(msg.toString()); + + } + + // Replace the old with the new... + this.groups = new_groups; + this.parents = new_parents; + this.children = new_children; + this.keysByUpperCaseName = new_keysByUpperCaseName; + + // Set the 'initialized' flag... + this.initialized = true; + + } + + /* + * Implementation. + */ + + private SmartLdapGroupStore() { + + // Spring tech... + URL u = getClass().getResource("/properties/groups/SmartLdapGroupStoreConfig.xml"); + spring_context = new FileSystemXmlApplicationContext(u.toExternalForm()); + + // Cernunnos tech... + runner = new ScriptRunner(); + initTask = runner.compileTask(getClass().getResource("init.crn").toExternalForm()); + + // SmartLdapGroupStore will be initialized on first use... + initialized = false; + + } + +} Index: uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/SimpleAttributesMapper.java =================================================================== --- uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/SimpleAttributesMapper.java (revision 0) +++ uportal-impl/src/main/java/org/jasig/portal/groups/smartldap/SimpleAttributesMapper.java (revision 0) @@ -0,0 +1,130 @@ +/** + * Copyright 2008 The JA-SIG Collaborative. All rights reserved. + * See license distributed with this file and + * available online at http://www.uportal.org/license.html + */ + +package org.jasig.portal.groups.smartldap; + +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.List; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jasig.portal.groups.EntityTestingGroupImpl; +import org.jasig.portal.groups.IEntityGroup; +import org.jasig.portal.security.IPerson; +import org.springframework.ldap.core.AttributesMapper; + +public final class SimpleAttributesMapper implements AttributesMapper { + + private static final String GROUP_DESCRIPTION = + "This group was pulled from the directory server."; + + /** + * Name of the LDAP attribute on a group that tells you + * its key (normally 'dn'). + */ + private String keyAttributeName = null; + + /** + * Name of the LDAP attribute on a group that tells you + * the name of the group. + */ + private String groupNameAttributeName = null; + + /** + * Name of the LDAP attribute on a group that tells you + * who its children are. + */ + private String membershipAttributeName = null; + + private final Log log = LogFactory.getLog(getClass()); + + /* + * Public API. + */ + + public Object mapFromAttributes(Attributes attr) { + + // Assertions. + if (keyAttributeName == null) { + String msg = "The property 'keyAttributeName' must be set."; + throw new IllegalStateException(msg); + } + if (groupNameAttributeName == null) { + String msg = "The property 'groupNameAttributeName' must be set."; + throw new IllegalStateException(msg); + } + if (membershipAttributeName == null) { + String msg = "The property 'membershipAttributeName' must be set."; + throw new IllegalStateException(msg); + } + + if (log.isInfoEnabled()) { + String msg = "SimpleAttributesMapper.mapFromAttributes() :: settings: keyAttributeName='" + + keyAttributeName + "', groupNameAttributeName='" + + groupNameAttributeName + "', groupNameAttributeName='" + + groupNameAttributeName + "'"; + log.info(msg); + } + + LdapRecord rslt; + + try { + + String key = (String) attr.get(keyAttributeName).get(); + String groupName = (String) attr.get(groupNameAttributeName).get(); + + IEntityGroup g = new EntityTestingGroupImpl(key, IPerson.class); + g.setCreatorID("System"); + g.setName(groupName); + g.setDescription(GROUP_DESCRIPTION); + List membership = new LinkedList(); + Attribute m = attr.get(membershipAttributeName); + if (m != null) { + for (Enumeration en=m.getAll(); en.hasMoreElements();) { + membership.add((String) en.nextElement()); + } + } + rslt = new LdapRecord(g, membership); + + if (log.isDebugEnabled()) { + StringBuilder msg = new StringBuilder(); + msg.append("Record Details:") + .append("\n\tkey=").append(key) + .append("\n\tgroupName=").append(groupName) + .append("\n\tmembers:"); + for (String s : membership) { + msg.append("\n\t\t").append(s); + } + log.debug(msg.toString()); + } + + } catch (Throwable t) { + log.error("Error in SimpleAttributesMapper", t); + String msg = "SimpleAttributesMapper failed to create a LdapRecord " + + "from the specified Attributes: " + attr; + throw new RuntimeException(msg, t); + } + + return rslt; + + } + + public void setKeyAttributeName(String keyAttributeName) { + this.keyAttributeName = keyAttributeName; + } + + public void setGroupNameAttributeName(String groupNameAttributeName) { + this.groupNameAttributeName = groupNameAttributeName; + } + + public void setMembershipAttributeName(String membershipAttributeName) { + this.membershipAttributeName = membershipAttributeName; + } + +} Index: uportal-impl/src/main/resources/org/jasig/portal/groups/smartldap/init.crn =================================================================== --- uportal-impl/src/main/resources/org/jasig/portal/groups/smartldap/init.crn (revision 0) +++ uportal-impl/src/main/resources/org/jasig/portal/groups/smartldap/init.crn (revision 0) @@ -0,0 +1,17 @@ + + + + + + SmartLdap adding record for group: ${groovy(record.getGroup().getName())} + + + + \ No newline at end of file Index: uportal-impl/src/main/resources/properties/groups/compositeGroupServices.xml =================================================================== --- uportal-impl/src/main/resources/properties/groups/compositeGroupServices.xml (revision 44174) +++ uportal-impl/src/main/resources/properties/groups/compositeGroupServices.xml (working copy) @@ -54,5 +54,24 @@ --> + + Index: uportal-impl/src/main/resources/properties/groups/SmartLdapGroupStoreConfig.xml =================================================================== --- uportal-impl/src/main/resources/properties/groups/SmartLdapGroupStoreConfig.xml (revision 0) +++ uportal-impl/src/main/resources/properties/groups/SmartLdapGroupStoreConfig.xml (revision 0) @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + changeme + + + + + + + (objectCategory=group) + + + + + memberOf + + + + + + + distinguishedName + + + + cn + + + + member + + + +