/**
* 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);
}
}