/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of the License at the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ package org.apereo.portal.groups; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.naming.InvalidNameException; import javax.naming.Name; import org.apereo.portal.EntityIdentifier; import org.apereo.portal.concurrency.CachingException; import org.apereo.portal.services.EntityCachingService; import org.apereo.portal.services.GroupService; public class ReferenceCompositeGroupService extends ReferenceComponentGroupService implements ICompositeGroupService { // Factory for IEntities: protected IEntityStore entityFactory = null; // See CompositeGroupService.xml: protected IIndividualGroupService defaultService; /** ReferenceCompositeGroupService constructor comment. */ public ReferenceCompositeGroupService() throws GroupsException { super(); } /** * Returns groups that contain the <code>IGroupMember</code>. Delegates to the component * services, but only after checking that they might actually contain a membership for this * member. * * @param gm IGroupMember */ public Iterator findParentGroups(IGroupMember gm) throws GroupsException { Collection allGroups = new ArrayList(); for (IIndividualGroupService service : (Collection<IIndividualGroupService>) getComponentServices().values()) { if (!gm.isGroup() || service.isEditable() || getComponentService(((IEntityGroup) gm).getServiceName()) == service) { { for (Iterator groups = service.findParentGroups(gm); groups.hasNext(); ) { allGroups.add((IEntityGroup) groups.next()); } } } } return allGroups.iterator(); } /** * Returns a pre-existing <code>IEntityGroup</code> or null if the <code>IGroupMember</code> * does not exist. */ public IEntityGroup findGroup(String key) throws GroupsException { CompositeEntityIdentifier ent = newCompositeEntityIdentifier(key); IIndividualGroupService service = getComponentService(ent); return (service == null) ? null : service.findGroup(ent); } /** * Returns a pre-existing <code>IEntityGroup</code> or null if the <code>IGroupMember</code> * does not exist. */ public ILockableEntityGroup findGroupWithLock(String key, String lockOwner) throws GroupsException { CompositeEntityIdentifier ent = newCompositeEntityIdentifier(key); IIndividualGroupService service = getComponentService(ent); return (service == null) ? null : service.findGroupWithLock(ent.getLocalKey(), lockOwner); } /** @return IIndividualGroupService */ protected IIndividualGroupService getComponentService(Name serviceName) { return (IIndividualGroupService) getComponentServices().get(serviceName); } /** @return IIndividualGroupService */ protected IIndividualGroupService getComponentService(CompositeEntityIdentifier entId) { return getComponentService(entId.getServiceName()); } /** * Returns the <code>IIndividualGroupService</code> designated as the default service in the * configuration document. */ protected IIndividualGroupService getDefaultService() { return defaultService; } /** * Returns an <code>IEntity</code> representing a portal entity. This does not guarantee that * the entity actually exists. */ public IEntity getEntity(String key, Class type) throws GroupsException { return getEntity(key, type, null); } /** * Returns an <code>IEntity</code> representing a portal entity. This does not guarantee that * the entity actually exists. */ public IEntity getEntity(String key, Class type, String svcName) throws GroupsException { IIndividualGroupService svc = null; if (svcName == null) { svc = getDefaultService(); } else { try { Name n = GroupService.parseServiceName(svcName); svc = getComponentService(n); } catch (InvalidNameException ine) { throw new GroupsException("Invalid service name."); } } return (svc == null) ? null : svc.getEntity(key, type); } /** * Returns an <code>IGroupMember</code> representing either a group or a portal entity. If the * parm <code>type</code> is the group type, the <code>IGroupMember</code> is an <code> * IEntityGroup</code> else it is an <code>IEntity</code>. */ public IGroupMember getGroupMember(String key, Class type) throws GroupsException { IGroupMember gm = null; if (type == ICompositeGroupService.GROUP_ENTITY_TYPE) gm = findGroup(key); else gm = getEntity(key, type); return gm; } /** * Assembles the group services composite. Once the leaf services have been retrieved, they are * held in a (one-dimensional) Map. The composite identity of a service is preserved in its Map * key, a javax.naming.Name. Each node of the Name is the name of a component service, starting * with the service closest to the composite service and ending with the name of the leaf * service. The key is built up layer by layer. * * @exception GroupsException */ protected void initializeComponentServices() throws GroupsException { Name leafServiceName = null; try { GroupServiceConfiguration cfg = GroupServiceConfiguration.getConfiguration(); List services = cfg.getServiceDescriptors(); for (Iterator it = services.iterator(); it.hasNext(); ) { ComponentGroupServiceDescriptor descriptor = (ComponentGroupServiceDescriptor) it.next(); String factoryName = descriptor.getServiceFactoryName(); IComponentGroupServiceFactory factory = (IComponentGroupServiceFactory) Class.forName(factoryName).newInstance(); IComponentGroupService service = factory.newGroupService(descriptor); // If it's a leaf service, add it to the Map. if (service.isLeafService()) { leafServiceName = GroupService.parseServiceName(descriptor.getName()); service.setServiceName(leafServiceName); getComponentServices().put(leafServiceName, service); } // Otherwise, get its leaf services and for each, push our node onto the service Name // and add the service to the Map. else { Map componentMap = service.getComponentServices(); for (Iterator components = componentMap.values().iterator(); components.hasNext(); ) { IIndividualGroupService leafService = (IIndividualGroupService) components.next(); leafServiceName = leafService.getServiceName(); leafServiceName.add(0, descriptor.getName()); getComponentServices().put(leafServiceName, leafService); } } } Name defaultServiceName = GroupService.parseServiceName(cfg.getDefaultService()); defaultService = (IIndividualGroupService) getComponentService(defaultServiceName); } catch (Exception ex) { throw new GroupsException("Problem initializing component services", ex); } } /** * Returns a <code>CompositeEntityIdentifier</code> for the group identified by <code>key</code> * . */ protected CompositeEntityIdentifier newCompositeEntityIdentifier(String key) throws GroupsException { return new CompositeEntityIdentifier(key, ICompositeGroupService.GROUP_ENTITY_TYPE); } /** Returns a new <code>IEntityGroup</code> from the named service. */ public IEntityGroup newGroup(Class type, Name serviceName) throws GroupsException { return getComponentService(serviceName).newGroup(type); } /** * Returns a pre-existing <code>IEntityGroup</code> or null if the <code>IGroupMember</code> * does not exist. */ protected IEntityGroup primFindGroup(String key) throws GroupsException { CompositeEntityIdentifier ent = newCompositeEntityIdentifier(key); IIndividualGroupService service = getComponentService(ent); return (service == null) ? null : service.findGroup(ent); } /** * Find EntityIdentifiers for entities whose name matches the query string according to the * specified method and is of the specified type */ public EntityIdentifier[] searchForEntities(String query, int method, Class type) throws GroupsException { Set allIds = new HashSet(); for (Iterator services = getComponentServices().values().iterator(); services.hasNext(); ) { IIndividualGroupService service = (IIndividualGroupService) services.next(); EntityIdentifier[] ids = service.searchForEntities(query, method, type); for (int i = 0; i < ids.length; i++) { allIds.add(ids[i]); } } return (EntityIdentifier[]) allIds.toArray(new EntityIdentifier[allIds.size()]); } /** * Find EntityIdentifiers for entities whose name matches the query string according to the * specified method, is of the specified type and descends from the specified group */ public EntityIdentifier[] searchForEntities( String query, int method, Class type, IEntityGroup ancestor) throws GroupsException { Set allIds = new HashSet(); for (Iterator services = getComponentServices().values().iterator(); services.hasNext(); ) { IIndividualGroupService service = (IIndividualGroupService) services.next(); EntityIdentifier[] ids = service.searchForEntities(query, method, type, ancestor); for (int i = 0; i < ids.length; i++) { allIds.add(ids[i]); } } return (EntityIdentifier[]) allIds.toArray(new EntityIdentifier[allIds.size()]); } /** * Find EntityIdentifiers for groups whose name matches the query string according to the * specified method and matches the provided leaf type */ public EntityIdentifier[] searchForGroups(String query, int method, Class leaftype) throws GroupsException { Set allIds = new HashSet(); for (Iterator services = getComponentServices().values().iterator(); services.hasNext(); ) { IIndividualGroupService service = (IIndividualGroupService) services.next(); EntityIdentifier[] ids = service.searchForGroups(query, method, leaftype); for (int i = 0; i < ids.length; i++) { try { CompositeEntityIdentifier cei = new CompositeEntityIdentifier(ids[i].getKey(), ids[i].getType()); cei.setServiceName(service.getServiceName()); allIds.add(cei); } catch (javax.naming.InvalidNameException ine) { } } } return (EntityIdentifier[]) allIds.toArray(new EntityIdentifier[allIds.size()]); } /** * Find EntityIdentifiers for groups whose name matches the query string according to the * specified method, has the provided leaf type and descends from the specified group */ public EntityIdentifier[] searchForGroups( String query, int method, Class leaftype, IEntityGroup ancestor) throws GroupsException { Set allIds = new HashSet(); for (Iterator services = getComponentServices().values().iterator(); services.hasNext(); ) { IIndividualGroupService service = (IIndividualGroupService) services.next(); EntityIdentifier[] ids = service.searchForGroups(query, method, leaftype, ancestor); for (int i = 0; i < ids.length; i++) { try { CompositeEntityIdentifier cei = new CompositeEntityIdentifier(ids[i].getKey(), ids[i].getType()); cei.setServiceName(service.getServiceName()); allIds.add(cei); } catch (javax.naming.InvalidNameException ine) { } } } return (EntityIdentifier[]) allIds.toArray(new EntityIdentifier[allIds.size()]); } protected void cacheAdd(IGroupMember gm) throws GroupsException { try { EntityCachingService.instance().add(gm); } catch (CachingException ce) { throw new GroupsException( "Problem adding group member " + gm.getKey() + " to cache", ce); } } protected void cacheRemove(IGroupMember gm) throws GroupsException { try { EntityCachingService.instance().remove(gm.getEntityIdentifier()); } catch (CachingException ce) { throw new GroupsException( "Problem removing group member " + gm.getKey() + " from cache", ce); } } protected void cacheUpdate(IGroupMember gm) throws GroupsException { try { EntityCachingService.instance().update(gm); } catch (CachingException ce) { throw new GroupsException( "Problem updating group member " + gm.getKey() + " in cache", ce); } } /** Returns a cached <code>IEntity</code> or null if it has not been cached. */ protected IEntity getEntityFromCache(String key) throws CachingException { return (IEntity) EntityCachingService.instance().get(ICompositeGroupService.LEAF_ENTITY_TYPE, key); } }