View Javadoc

1   /*
2    * Copyright 2007-2010 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kim.service.impl;
17  
18  import org.apache.commons.collections.CollectionUtils;
19  import org.apache.commons.collections.Predicate;
20  import org.apache.log4j.Logger;
21  import org.kuali.rice.core.exception.RiceRuntimeException;
22  import org.kuali.rice.kim.bo.group.dto.GroupInfo;
23  import org.kuali.rice.kim.bo.group.impl.GroupAttributeDataImpl;
24  import org.kuali.rice.kim.bo.group.impl.GroupMemberImpl;
25  import org.kuali.rice.kim.bo.impl.GroupImpl;
26  import org.kuali.rice.kim.service.GroupUpdateService;
27  import org.kuali.rice.kim.service.KIMServiceLocator;
28  import org.kuali.rice.kim.util.KIMPropertyConstants;
29  import org.kuali.rice.kim.util.KIMWebServiceConstants;
30  import org.kuali.rice.kim.util.KimCommonUtils;
31  import org.kuali.rice.kim.util.KimConstants.KimGroupMemberTypes;
32  import org.mortbay.log.Log;
33  
34  import javax.jws.WebService;
35  import java.util.*;
36  
37  /**
38   * This is the default implementation for the {@link GroupUpdateService}, where the write methods for KIM groups are located.
39   *
40   * @author Kuali Rice Team (rice.collab@kuali.org)
41   *
42   */
43  @WebService(endpointInterface = KIMWebServiceConstants.GroupUpdateService.INTERFACE_CLASS, serviceName = KIMWebServiceConstants.GroupUpdateService.WEB_SERVICE_NAME, portName = KIMWebServiceConstants.GroupUpdateService.WEB_SERVICE_PORT, targetNamespace = KIMWebServiceConstants.MODULE_TARGET_NAMESPACE)
44  public class GroupUpdateServiceImpl extends GroupServiceBase implements GroupUpdateService {
45  
46  	private static final Logger LOG = Logger.getLogger(GroupUpdateServiceImpl.class);
47  
48  	/**
49       * @see org.kuali.rice.kim.service.GroupService#addGroupToGroup(java.lang.String, java.lang.String)
50       */
51      public boolean addGroupToGroup(String childId, String parentId) {
52          if(childId.equals(parentId)) {
53              throw new IllegalArgumentException("Can't add group to itself.");
54          }
55  
56          if(isGroupMemberOfGroup(parentId, childId)) {
57              throw new IllegalArgumentException("Circular group reference.");
58          }
59  
60          GroupMemberImpl groupMember = new GroupMemberImpl();
61          groupMember.setGroupId(parentId);
62          groupMember.setMemberTypeCode( KimGroupMemberTypes.GROUP_MEMBER_TYPE );
63          groupMember.setMemberId(childId);
64  
65          getBusinessObjectService().save(groupMember);
66          getIdentityManagementNotificationService().groupUpdated();
67  
68          return true;
69      }
70  
71      /**
72       * @see org.kuali.rice.kim.service.GroupService#addPrincipalToGroup(java.lang.String, java.lang.String)
73       */
74      public boolean addPrincipalToGroup(String principalId, String groupId) {
75          GroupMemberImpl groupMember = new GroupMemberImpl();
76          groupMember.setGroupId(groupId);
77          groupMember.setMemberTypeCode( KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE );
78          groupMember.setMemberId(principalId);
79  
80          getBusinessObjectService().save(groupMember);
81          KIMServiceLocator.getGroupInternalService().updateForUserAddedToGroup(groupMember.getMemberId(), groupMember.getGroupId());
82          getIdentityManagementNotificationService().groupUpdated();
83          return true;
84      }
85  
86      public GroupInfo createGroup(GroupInfo groupInfo) {
87          GroupImpl group = new GroupImpl();
88  
89          group = KimCommonUtils.copyInfoToGroup(groupInfo, group);
90  
91          saveGroup(group);
92  
93          GroupInfo newGroupInfo = getGroupInfoByName(groupInfo.getNamespaceCode(), groupInfo.getGroupName());
94  
95          if(groupInfo.getAttributes() != null && groupInfo.getAttributes().size() > 0) {
96              List<GroupAttributeDataImpl> groupAttributes =
97              		KimCommonUtils.copyInfoAttributesToGroupAttributes(groupInfo.getAttributes(), newGroupInfo.getGroupId(), newGroupInfo.getKimTypeId());
98              saveGroupAttributes(groupAttributes);
99          }
100         return getGroupInfo(newGroupInfo.getGroupId());
101     }
102 
103     /**
104     *
105     * @see org.kuali.rice.kim.service.GroupUpdateService#removeAllGroupMembers(java.lang.String)
106     */
107    public void removeAllGroupMembers(String groupId) {
108        List<String> memberPrincipalsBefore = KIMServiceLocator.getGroupService().getMemberPrincipalIds(groupId);
109 
110        Collection<GroupMemberImpl> toDeactivate = getActiveGroupMembers(groupId, null, null);
111        java.sql.Timestamp today = new java.sql.Timestamp(System.currentTimeMillis());
112 
113        // Set principals as inactive
114         for (GroupMemberImpl aToDeactivate : toDeactivate) {
115             aToDeactivate.setActiveToDate(today);
116         }
117 
118        // Save
119        getBusinessObjectService().save(new ArrayList<GroupMemberImpl>(toDeactivate));
120        List<String> memberPrincipalsAfter = KIMServiceLocator.getGroupService().getMemberPrincipalIds(groupId);
121 
122        if (!CollectionUtils.isEmpty(memberPrincipalsAfter)) {
123     	   // should never happen!
124     	   Log.warn("after attempting removal of all members, group with id '" + groupId + "' still has principal members");
125        }
126 
127        // do updates
128        KIMServiceLocator.getGroupInternalService().updateForWorkgroupChange(groupId, memberPrincipalsBefore, memberPrincipalsAfter);
129        getIdentityManagementNotificationService().groupUpdated();
130    }
131 
132 	/**
133      * @see org.kuali.rice.kim.service.GroupService#removeGroupFromGroup(java.lang.String, java.lang.String)
134      */
135     public boolean removeGroupFromGroup(String childId, String parentId) {
136     	java.sql.Timestamp today = new java.sql.Timestamp(System.currentTimeMillis());
137 
138     	List<GroupMemberImpl> groupMembers =
139     		getActiveGroupMembers(parentId, childId, KimGroupMemberTypes.GROUP_MEMBER_TYPE);
140 
141         if(groupMembers.size() == 1) {
142         	GroupMemberImpl groupMember = groupMembers.get(0);
143         	groupMember.setActiveToDate(today);
144             getBusinessObjectService().save(groupMember);
145             getIdentityManagementNotificationService().groupUpdated();
146             return true;
147         }
148 
149         return false;
150     }
151 
152 	/**
153      * @see org.kuali.rice.kim.service.GroupService#removePrincipalFromGroup(java.lang.String, java.lang.String)
154      */
155     @SuppressWarnings("unchecked")
156     public boolean removePrincipalFromGroup(String principalId, String groupId) {
157     	List<GroupMemberImpl> groupMembers =
158     		getActiveGroupMembers(groupId, principalId, KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE);
159 
160         if(groupMembers.size() == 1) {
161         	GroupMemberImpl member = groupMembers.iterator().next();
162         	member.setActiveToDate(new java.sql.Timestamp(System.currentTimeMillis()));
163         	getBusinessObjectService().save(member);
164             KIMServiceLocator.getGroupInternalService().updateForUserRemovedFromGroup(member.getMemberId(), member.getGroupId());
165             getIdentityManagementNotificationService().groupUpdated();
166             return true;
167         }
168 
169         return false;
170     }
171 
172 	/**
173 	 * This overridden method ...
174 	 *
175 	 * @see org.kuali.rice.kim.service.GroupUpdateService#updateGroup(java.lang.String, org.kuali.rice.kim.bo.group.dto.GroupInfo)
176 	 */
177 	public GroupInfo updateGroup(String groupId, GroupInfo groupInfo) {
178         // TODO sgibson - can this be used to change id?
179         GroupImpl group = getGroupImpl(groupId);
180 
181         if (group == null) {
182             throw new IllegalArgumentException("Group not found for update.");
183         }
184 
185         group = KimCommonUtils.copyInfoToGroup(groupInfo, group);
186 
187         //delete old group attributes
188         Map<String,String> criteria = new HashMap<String,String>();
189         criteria.put(KIMPropertyConstants.Group.GROUP_ID, group.getGroupId());
190         getBusinessObjectService().deleteMatching(GroupAttributeDataImpl.class, criteria);
191 
192 
193         saveGroup(group);
194 
195         //create new group attributes
196         if(groupInfo.getAttributes() != null && groupInfo.getAttributes().size() > 0) {
197             List<GroupAttributeDataImpl> groupAttributes =
198             		KimCommonUtils.copyInfoAttributesToGroupAttributes(groupInfo.getAttributes(), group.getGroupId(), group.getKimTypeId());
199             saveGroupAttributes(groupAttributes);
200         }
201 
202         return getGroupInfo(groupInfo.getGroupId());
203     }
204 
205 	protected void saveGroup(GroupImpl group) {
206 		if ( group == null ) {
207 			return;
208 		} else if (group.getGroupId() != null) {
209 			// Get the version of the group that is in the DB
210 			GroupImpl oldGroup = getGroupImpl(group.getGroupId());
211 
212 			if (oldGroup != null) {
213 				// Inactivate and re-add members no longer in the group (in order to preserve history).
214 				java.sql.Timestamp activeTo = new java.sql.Timestamp(System.currentTimeMillis());
215 				List<GroupMemberImpl> toReAdd = null;
216 
217 				if (oldGroup.getMembers() != null) for (GroupMemberImpl member : oldGroup.getMembers()) {
218 					// if the old member isn't in the new group
219 					if (group.getMembers() == null || !group.getMembers().contains(member)) {
220 						// inactivate the member
221 						member.setActiveToDate(activeTo);
222 						if (toReAdd == null) { toReAdd = new ArrayList<GroupMemberImpl>(); }
223 						// queue it up for re-adding
224 						toReAdd.add(member);
225 					}
226 				}
227 
228 				// do the re-adding
229 				if (toReAdd != null) {
230 					List<GroupMemberImpl> groupMembers = group.getMembers();
231 					if (groupMembers == null) { groupMembers = new ArrayList<GroupMemberImpl>(toReAdd.size()); }
232 					group.setMembers(groupMembers);
233 				}
234 			}
235 		}
236 
237 		// GroupInternalService handles KEW update duties
238 		KIMServiceLocator.getGroupInternalService().saveWorkgroup(group);
239 		getIdentityManagementNotificationService().groupUpdated();
240 	}
241 
242 	protected void saveGroupAttributes(List<GroupAttributeDataImpl> groupAttributes) {
243         if ( groupAttributes == null ) {
244             return;
245         }
246         getBusinessObjectService().save( groupAttributes );
247     }
248 
249 	protected void deleteGroupAttribute(GroupAttributeDataImpl groupAttribute) {
250         if ( groupAttribute == null ) {
251             return;
252         }
253         getBusinessObjectService().delete( groupAttribute );
254     }
255 
256 	/**
257 	 * This helper method gets the active group members of the specified type (see {@link KimGroupMemberTypes}).
258 	 * If the optional params are null, it will return all active members for the specified group regardless
259 	 * of type.
260 	 *
261 	 * @param parentId
262 	 * @param childId optional, but if provided then memberType must be too
263 	 * @param memberType optional, but must be provided if childId is
264      * @return a list of group members
265 	 */
266 	private List<GroupMemberImpl> getActiveGroupMembers(String parentId,
267 			String childId, String memberType) {
268     	final java.sql.Date today = new java.sql.Date(System.currentTimeMillis());
269 
270     	if (childId != null && memberType == null) throw new RiceRuntimeException("memberType must be non-null if childId is non-null");
271 
272 		Map<String,Object> criteria = new HashMap<String,Object>(4);
273         criteria.put(KIMPropertyConstants.GroupMember.GROUP_ID, parentId);
274 
275         if (childId != null) {
276         	criteria.put(KIMPropertyConstants.GroupMember.MEMBER_ID, childId);
277         	criteria.put(KIMPropertyConstants.GroupMember.MEMBER_TYPE_CODE, memberType);
278         }
279 
280         Collection<GroupMemberImpl> groupMembers = getBusinessObjectService().findMatching(GroupMemberImpl.class, criteria);
281 
282         CollectionUtils.filter(groupMembers, new Predicate() {
283 			public boolean evaluate(Object object) {
284 				GroupMemberImpl member = (GroupMemberImpl) object;
285 				// keep in the collection (return true) if the activeToDate is null, or if it is set to a future date
286 				return member.getActiveToDate() == null || today.before(member.getActiveToDate());
287 			}
288 		});
289 
290         return new ArrayList<GroupMemberImpl>(groupMembers);
291 	}
292 
293 }