1 package org.kuali.rice.kim.impl.responsibility;
2
3 import org.apache.commons.lang.StringUtils;
4 import org.apache.commons.logging.Log;
5 import org.apache.commons.logging.LogFactory;
6 import org.kuali.rice.core.api.criteria.CriteriaLookupService;
7 import org.kuali.rice.core.api.criteria.GenericQueryResults;
8 import org.kuali.rice.core.api.criteria.LookupCustomizer;
9 import org.kuali.rice.core.api.criteria.Predicate;
10 import org.kuali.rice.core.api.criteria.QueryByCriteria;
11 import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
12 import org.kuali.rice.core.api.exception.RiceIllegalStateException;
13 import org.kuali.rice.core.api.mo.common.Attributes;
14 import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
15 import org.kuali.rice.core.util.AttributeSet;
16 import org.kuali.rice.kim.impl.common.attribute.AttributeTransform;
17 import org.kuali.rice.kim.api.common.delegate.Delegate;
18 import org.kuali.rice.kim.api.common.template.Template;
19 import org.kuali.rice.kim.api.common.template.TemplateQueryResults;
20 import org.kuali.rice.kim.api.responsibility.Responsibility;
21 import org.kuali.rice.kim.api.responsibility.ResponsibilityAction;
22 import org.kuali.rice.kim.api.responsibility.ResponsibilityQueryResults;
23 import org.kuali.rice.kim.api.responsibility.ResponsibilityService;
24 import org.kuali.rice.kim.api.role.Role;
25 import org.kuali.rice.kim.api.role.RoleResponsibilityAction;
26 import org.kuali.rice.kim.api.type.KimType;
27 import org.kuali.rice.kim.api.type.KimTypeInfoService;
28 import org.kuali.rice.kim.bo.role.dto.DelegateInfo;
29 import org.kuali.rice.kim.bo.role.dto.RoleMembershipInfo;
30 import org.kuali.rice.kim.impl.common.attribute.KimAttributeDataBo;
31 import org.kuali.rice.kim.impl.role.RoleResponsibilityActionBo;
32 import org.kuali.rice.kim.impl.role.RoleResponsibilityBo;
33 import org.kuali.rice.kim.service.RoleService;
34 import org.kuali.rice.kim.util.KIMPropertyConstants;
35 import org.kuali.rice.kns.service.BusinessObjectService;
36
37 import java.util.ArrayList;
38 import java.util.Collection;
39 import java.util.Collections;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43
44 import static org.kuali.rice.core.api.criteria.PredicateFactory.*;
45
46 public class ResponsibilityServiceImpl implements ResponsibilityService {
47
48 private static final Integer DEFAULT_PRIORITY_NUMBER = Integer.valueOf(1);
49 private static final Log LOG = LogFactory.getLog(ResponsibilityServiceImpl.class);
50
51 private BusinessObjectService businessObjectService;
52 private CriteriaLookupService criteriaLookupService;
53 private KimResponsibilityTypeService defaultResponsibilityTypeService;
54 private KimTypeInfoService kimTypeInfoService;
55 private RoleService roleService;
56
57 @Override
58 public void createResponsibility(final Responsibility responsibility) throws RiceIllegalArgumentException, RiceIllegalStateException {
59 if (responsibility == null) {
60 throw new RiceIllegalArgumentException("responsibility is null");
61 }
62
63 if (StringUtils.isNotBlank(responsibility.getId()) && getResponsibility(responsibility.getId()) != null) {
64 throw new RiceIllegalStateException("the responsibility to create already exists: " + responsibility);
65 }
66 List<ResponsibilityAttributeBo> attrBos = KimAttributeDataBo.createFrom(ResponsibilityAttributeBo.class, responsibility.getAttributes(), responsibility.getTemplate().getKimTypeId());
67 ResponsibilityBo bo = ResponsibilityBo.from(responsibility);
68 bo.setAttributeDetails(attrBos);
69 businessObjectService.save(bo);
70 }
71
72 @Override
73 public void updateResponsibility(final Responsibility responsibility) throws RiceIllegalArgumentException, RiceIllegalStateException {
74 if (responsibility == null) {
75 throw new RiceIllegalArgumentException("responsibility is null");
76 }
77
78 if (StringUtils.isBlank(responsibility.getId()) || getResponsibility(responsibility.getId()) == null) {
79 throw new RiceIllegalStateException("the responsibility does not exist: " + responsibility);
80 }
81
82 List<ResponsibilityAttributeBo> attrBos = KimAttributeDataBo.createFrom(ResponsibilityAttributeBo.class, responsibility.getAttributes(), responsibility.getTemplate().getKimTypeId());
83 ResponsibilityBo bo = ResponsibilityBo.from(responsibility);
84 bo.getAttributeDetails().addAll(attrBos);
85 businessObjectService.save(bo);
86 }
87
88 @Override
89 public Responsibility getResponsibility(final String id) {
90 if (id == null) {
91 throw new RiceIllegalArgumentException("id is null");
92 }
93
94 return ResponsibilityBo.to(businessObjectService.findBySinglePrimaryKey(ResponsibilityBo.class, id));
95 }
96
97 @Override
98 public List<Responsibility> findRespsByNamespaceCodeAndName(final String namespaceCode, final String name) {
99 if (namespaceCode == null) {
100 throw new RiceIllegalArgumentException("namespaceCode is null");
101 }
102
103 if (name == null) {
104 throw new RiceIllegalArgumentException("name is null");
105 }
106
107 final Map<String, String> crit = new HashMap<String, String>();
108 crit.put("namespaceCode", namespaceCode);
109 crit.put("name", name);
110 crit.put("active", "Y");
111
112 final Collection<ResponsibilityBo> bos = businessObjectService.findMatching(ResponsibilityBo.class, Collections.unmodifiableMap(crit));
113 final List<Responsibility> ims = new ArrayList<Responsibility>();
114 if (bos != null) {
115 for (ResponsibilityBo bo : bos) {
116 if (bo != null) {
117 ims.add(ResponsibilityBo.to(bo));
118 }
119 }
120 }
121
122 return Collections.unmodifiableList(ims);
123 }
124
125 @Override
126 public Template getResponsibilityTemplate(final String id) {
127 if (id == null) {
128 throw new RiceIllegalArgumentException("id is null");
129 }
130
131 return ResponsibilityTemplateBo.to(businessObjectService.findBySinglePrimaryKey(ResponsibilityTemplateBo.class, id));
132 }
133
134 @Override
135 public List<Template> findRespTemplatesByNamespaceCodeAndName(final String namespaceCode, final String name) {
136 if (namespaceCode == null) {
137 throw new RiceIllegalArgumentException("namespaceCode is null");
138 }
139
140 if (name == null) {
141 throw new RiceIllegalArgumentException("name is null");
142 }
143
144 final Map<String, String> crit = new HashMap<String, String>();
145 crit.put("namespaceCode", namespaceCode);
146 crit.put("name", name);
147 crit.put("active", "Y");
148
149 final Collection<ResponsibilityTemplateBo> bos = businessObjectService.findMatching(ResponsibilityTemplateBo.class, Collections.unmodifiableMap(crit));
150 final List<Template> ims = new ArrayList<Template>();
151 if (bos != null) {
152 for (ResponsibilityTemplateBo bo : bos) {
153 if (bo != null) {
154 ims.add(ResponsibilityTemplateBo.to(bo));
155 }
156 }
157 }
158
159 return Collections.unmodifiableList(ims);
160 }
161
162 @Override
163 public boolean hasResponsibility(final String principalId, final String namespaceCode, final String respName, final Attributes qualification, final Attributes responsibilityDetails) {
164
165 final List<Responsibility> responsibilities = findRespsByNamespaceCodeAndName(namespaceCode, respName);
166 return hasResp(principalId, namespaceCode, responsibilities, qualification, responsibilityDetails);
167 }
168
169 @Override
170 public boolean hasResponsibilityByTemplateName(final String principalId, final String namespaceCode, final String respTemplateName, final Attributes qualification, final Attributes responsibilityDetails) {
171
172 final List<Responsibility> responsibilities = findRespsByNamespaceCodeAndTemplateName(namespaceCode, respTemplateName);
173 return hasResp(principalId, namespaceCode, responsibilities, qualification, responsibilityDetails);
174 }
175
176 private boolean hasResp(final String principalId, final String namespaceCode, final List<Responsibility> responsibilities, final Attributes qualification, final Attributes responsibilityDetails) {
177
178 final List<String> ids = new ArrayList<String>();
179 for (Responsibility r : getMatchingResponsibilities(responsibilities, responsibilityDetails)) {
180 ids.add(r.getId());
181 }
182 final List<String> roleIds = getRoleIdsForResponsibilities(ids, qualification);
183 return roleService.principalHasRole(principalId, roleIds, new AttributeSet(qualification.toMap()));
184 }
185
186 @Override
187 public List<ResponsibilityAction> getResponsibilityActions(final String namespaceCode, final String responsibilityName, final Attributes qualification, final Attributes responsibilityDetails) {
188
189 List<Responsibility> responsibilities = findRespsByNamespaceCodeAndName(namespaceCode, responsibilityName);
190 return getRespActions(namespaceCode, responsibilities, qualification, responsibilityDetails);
191 }
192
193 @Override
194 public List<ResponsibilityAction> getResponsibilityActionsByTemplateName(final String namespaceCode, final String respTemplateName, final Attributes qualification, final Attributes responsibilityDetails) {
195
196 List<Responsibility> responsibilities = findRespsByNamespaceCodeAndTemplateName(namespaceCode, respTemplateName);
197 return getRespActions(namespaceCode, responsibilities, qualification, responsibilityDetails);
198 }
199
200 private List<ResponsibilityAction> getRespActions(final String namespaceCode, final List<Responsibility> responsibilities, final Attributes qualification, final Attributes responsibilityDetails) {
201
202 List<Responsibility> applicableResponsibilities = getMatchingResponsibilities(responsibilities, responsibilityDetails);
203 List<ResponsibilityAction> results = new ArrayList<ResponsibilityAction>();
204 for (Responsibility r : applicableResponsibilities) {
205 List<String> roleIds = getRoleIdsForResponsibility(r.getId(), qualification);
206 results.addAll(getActionsForResponsibilityRoles(r, roleIds, qualification));
207 }
208 return results;
209 }
210
211 private List<ResponsibilityAction> getActionsForResponsibilityRoles(Responsibility responsibility, List<String> roleIds, Attributes qualification) {
212 List<ResponsibilityAction> results = new ArrayList<ResponsibilityAction>();
213 Collection<RoleMembershipInfo> roleMembers = roleService.getRoleMembers(roleIds, new AttributeSet(qualification.toMap()));
214 for (RoleMembershipInfo rm : roleMembers) {
215
216 if (StringUtils.isNotBlank(rm.getMemberId())) {
217 final ResponsibilityAction.Builder rai = ResponsibilityAction.Builder.create();
218 rai.setMemberRoleId(rm.getEmbeddedRoleId());
219 rai.setRoleId(rm.getRoleId());
220 rai.setQualifier(Attributes.fromMap(rm.getQualifier()));
221 final List<Delegate.Builder> bs = new ArrayList<Delegate.Builder>();
222 for (DelegateInfo d : rm.getDelegates()) {
223 Delegate.Builder newD = Delegate.Builder.create(d.getDelegationId(), d.getDelegationTypeCode(), d.getMemberId(), d.getMemberTypeCode(), d.getRoleMemberId(), d.getQualifier());
224 bs.add(newD);
225 }
226 rai.setDelegates(bs);
227 rai.setResponsibilityId(responsibility.getId());
228 rai.setResponsibilityName(responsibility.getName());
229 rai.setResponsibilityNamespaceCode(responsibility.getNamespaceCode());
230
231 if (rm.getMemberTypeCode().equals(Role.PRINCIPAL_MEMBER_TYPE)) {
232 rai.setPrincipalId(rm.getMemberId());
233 } else {
234 rai.setGroupId(rm.getMemberId());
235 }
236
237 RoleResponsibilityAction action = getResponsibilityAction(rm.getRoleId(), responsibility.getId(), rm.getRoleMemberId());
238 if (action == null) {
239 LOG.error("Unable to get responsibility action record for role/responsibility/roleMember: "
240 + rm.getRoleId() + "/" + responsibility.getId() + "/" + rm.getRoleMemberId());
241 LOG.error("Skipping this role member in getActionsForResponsibilityRoles()");
242 continue;
243 }
244
245 rai.setActionTypeCode(action.getActionTypeCode());
246 rai.setActionPolicyCode(action.getActionPolicyCode());
247 rai.setPriorityNumber(action.getPriorityNumber() == null ? DEFAULT_PRIORITY_NUMBER : action.getPriorityNumber());
248 rai.setForceAction(action.isForceAction());
249 rai.setParallelRoutingGroupingCode((rm.getRoleSortingCode() == null) ? "" : rm.getRoleSortingCode());
250 rai.setRoleResponsibilityActionId(action.getId());
251 results.add(rai.build());
252 }
253 }
254 return results;
255 }
256
257 private RoleResponsibilityAction getResponsibilityAction(String roleId, String responsibilityId, String roleMemberId) {
258 final Predicate p =
259 or(
260 and(
261 equal("roleResponsibility.responsibilityId", responsibilityId),
262 equal("roleResponsibility.roleId", roleId),
263 equal("roleResponsibility.active", "Y"),
264 or(
265 equal(KIMPropertyConstants.RoleMember.ROLE_MEMBER_ID, roleMemberId),
266 equal(KIMPropertyConstants.RoleMember.ROLE_MEMBER_ID, "*")
267 )
268 ),
269 and(
270 equal("roleResponsibilityId", "*"),
271 equal(KIMPropertyConstants.RoleMember.ROLE_MEMBER_ID, roleMemberId)
272 )
273 );
274
275 final QueryByCriteria.Builder builder = QueryByCriteria.Builder.create();
276 builder.setPredicates(p);
277 final GenericQueryResults<RoleResponsibilityActionBo> results = criteriaLookupService.lookup(RoleResponsibilityActionBo.class, builder.build());
278 final List<RoleResponsibilityActionBo> bos = results.getResults();
279
280 return !bos.isEmpty() ? RoleResponsibilityActionBo.to(bos.get(0)) : null;
281 }
282
283 @Override
284 public List<String> getRoleIdsForResponsibility(String id, Attributes qualification) {
285 if (StringUtils.isBlank(id)) {
286 throw new RiceIllegalArgumentException("id is blank");
287 }
288
289 if (qualification == null) {
290 throw new RiceIllegalArgumentException("qualification is null");
291 }
292
293 final List<String> roleIds = getRoleIdsForPredicate(and(equal("responsibilityId", id), equal("active", "Y")));
294
295
296 return roleIds;
297 }
298
299 @Override
300 public ResponsibilityQueryResults findResponsibilities(final QueryByCriteria queryByCriteria) {
301 if (queryByCriteria == null) {
302 throw new RiceIllegalArgumentException("queryByCriteria is null");
303 }
304
305 LookupCustomizer.Builder<ResponsibilityBo> lc = LookupCustomizer.Builder.create();
306 lc.setPredicateTransform(AttributeTransform.getInstance());
307
308 GenericQueryResults<ResponsibilityBo> results = criteriaLookupService.lookup(ResponsibilityBo.class, queryByCriteria, lc.build());
309
310 ResponsibilityQueryResults.Builder builder = ResponsibilityQueryResults.Builder.create();
311 builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
312 builder.setTotalRowCount(results.getTotalRowCount());
313
314 final List<Responsibility.Builder> ims = new ArrayList<Responsibility.Builder>();
315 for (ResponsibilityBo bo : results.getResults()) {
316 ims.add(Responsibility.Builder.create(bo));
317 }
318
319 builder.setResults(ims);
320 return builder.build();
321 }
322
323 @Override
324 public TemplateQueryResults findResponsibilityTemplates(final QueryByCriteria queryByCriteria) {
325 if (queryByCriteria == null) {
326 throw new RiceIllegalArgumentException("queryByCriteria is null");
327 }
328
329 GenericQueryResults<ResponsibilityTemplateBo> results = criteriaLookupService.lookup(ResponsibilityTemplateBo.class, queryByCriteria);
330
331 TemplateQueryResults.Builder builder = TemplateQueryResults.Builder.create();
332 builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
333 builder.setTotalRowCount(results.getTotalRowCount());
334
335 final List<Template.Builder> ims = new ArrayList<Template.Builder>();
336 for (ResponsibilityTemplateBo bo : results.getResults()) {
337 ims.add(Template.Builder.create(bo));
338 }
339
340 builder.setResults(ims);
341 return builder.build();
342 }
343
344
345
346
347
348 private List<Responsibility> getMatchingResponsibilities(List<Responsibility> responsibilities, Attributes responsibilityDetails) {
349
350 if (responsibilityDetails == null || responsibilityDetails.isEmpty()) {
351 return responsibilities;
352 }
353
354 final List<Responsibility> applicableResponsibilities = new ArrayList<Responsibility>();
355
356
357 Map<String, KimResponsibilityTypeService> responsibilityTypeServices = getResponsibilityTypeServicesByTemplateId(responsibilities);
358
359 Map<String, List<Responsibility>> responsibilityMap = groupResponsibilitiesByTemplate(responsibilities);
360
361
362 for (Map.Entry<String, List<Responsibility>> respEntry : responsibilityMap.entrySet()) {
363 KimResponsibilityTypeService responsibilityTypeService = responsibilityTypeServices.get(respEntry.getKey());
364 List<Responsibility> responsibilityInfos = respEntry.getValue();
365 if (responsibilityTypeService == null) {
366 responsibilityTypeService = defaultResponsibilityTypeService;
367 }
368 applicableResponsibilities.addAll(responsibilityTypeService.getMatchingResponsibilities(new AttributeSet(responsibilityDetails.toMap()), responsibilityInfos));
369 }
370 return applicableResponsibilities;
371 }
372
373 private Map<String, KimResponsibilityTypeService> getResponsibilityTypeServicesByTemplateId(Collection<Responsibility> responsibilities) {
374 Map<String, KimResponsibilityTypeService> responsibilityTypeServices = new HashMap<String, KimResponsibilityTypeService>(responsibilities.size());
375 for (Responsibility responsibility : responsibilities) {
376 final Template t = responsibility.getTemplate();
377 final KimType type = kimTypeInfoService.getKimType(t.getKimTypeId());
378
379 final String serviceName = type.getServiceName();
380 if (serviceName != null) {
381 KimResponsibilityTypeService responsibiltyTypeService = GlobalResourceLoader.getService(serviceName);
382 if (responsibiltyTypeService != null) {
383 responsibilityTypeServices.put(responsibility.getTemplate().getId(), responsibiltyTypeService);
384 } else {
385 responsibilityTypeServices.put(responsibility.getTemplate().getId(), defaultResponsibilityTypeService);
386 }
387 }
388 }
389 return responsibilityTypeServices;
390 }
391
392 private Map<String, List<Responsibility>> groupResponsibilitiesByTemplate(Collection<Responsibility> responsibilities) {
393 final Map<String, List<Responsibility>> results = new HashMap<String, List<Responsibility>>();
394 for (Responsibility responsibility : responsibilities) {
395 List<Responsibility> responsibilityInfos = results.get(responsibility.getTemplate().getId());
396 if (responsibilityInfos == null) {
397 responsibilityInfos = new ArrayList<Responsibility>();
398 results.put(responsibility.getTemplate().getId(), responsibilityInfos);
399 }
400 responsibilityInfos.add(responsibility);
401 }
402 return results;
403 }
404
405 private List<String> getRoleIdsForResponsibilities(Collection<String> ids, Attributes qualification) {
406 final List<String> roleIds = getRoleIdsForPredicate(and(in("responsibilityId", ids.toArray()), equal("active", "Y")));
407
408
409 return roleIds;
410 }
411
412 private List<String> getRoleIdsForPredicate(Predicate p) {
413 final QueryByCriteria.Builder builder = QueryByCriteria.Builder.create();
414 builder.setPredicates(p);
415 final GenericQueryResults<RoleResponsibilityBo> qr = criteriaLookupService.lookup(RoleResponsibilityBo.class, builder.build());
416
417 final List<String> roleIds = new ArrayList<String>();
418 for (RoleResponsibilityBo bo : qr.getResults()) {
419 roleIds.add(bo.getRoleId());
420 }
421 return roleIds;
422 }
423
424 private List<Responsibility> findRespsByNamespaceCodeAndTemplateName(final String namespaceCode, final String templateName) {
425 if (namespaceCode == null) {
426 throw new RiceIllegalArgumentException("namespaceCode is null");
427 }
428
429 if (templateName == null) {
430 throw new RiceIllegalArgumentException("name is null");
431 }
432
433 final Map<String, String> crit = new HashMap<String, String>();
434 crit.put("namespaceCode", namespaceCode);
435 crit.put("name", templateName);
436 crit.put("active", "Y");
437
438 final Collection<ResponsibilityBo> bos = businessObjectService.findMatching(ResponsibilityBo.class, Collections.unmodifiableMap(crit));
439 final List<Responsibility> ims = new ArrayList<Responsibility>();
440 if (bos != null) {
441 for (ResponsibilityBo bo : bos) {
442 if (bo != null) {
443 ims.add(ResponsibilityBo.to(bo));
444 }
445 }
446 }
447
448 return Collections.unmodifiableList(ims);
449 }
450
451 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
452 this.businessObjectService = businessObjectService;
453 }
454
455 public void setCriteriaLookupService(final CriteriaLookupService criteriaLookupService) {
456 this.criteriaLookupService = criteriaLookupService;
457 }
458
459 public void setDefaultResponsibilityTypeService(final KimResponsibilityTypeService defaultResponsibilityTypeService) {
460 this.defaultResponsibilityTypeService = defaultResponsibilityTypeService;
461 }
462
463 public void setKimTypeInfoService(final KimTypeInfoService kimTypeInfoService) {
464 this.kimTypeInfoService = kimTypeInfoService;
465 }
466
467 public void setRoleService(final RoleService roleService) {
468 this.roleService = roleService;
469 }
470 }