001/** 002 * Copyright 2005-2013 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krms.impl.repository; 017 018 019import org.apache.commons.lang.StringUtils; 020import org.kuali.rice.core.api.exception.RiceIllegalStateException; 021import org.kuali.rice.krad.service.BusinessObjectService; 022import org.kuali.rice.krms.api.repository.action.ActionDefinition; 023import org.kuali.rice.krms.api.repository.rule.RuleDefinition; 024import org.kuali.rice.krms.api.repository.type.KrmsAttributeDefinition; 025import org.kuali.rice.krms.impl.util.KrmsImplConstants.PropertyNames; 026 027import java.util.*; 028 029public final class KSRuleBoServiceImpl implements RuleBoService { 030 031 private BusinessObjectService businessObjectService; 032 private KrmsAttributeDefinitionService attributeDefinitionService; 033 034 /** 035 * This overridden creates a KRMS Rule in the repository 036 * 037 * @see org.kuali.rice.krms.impl.repository.RuleBoService#createRule(org.kuali.rice.krms.api.repository.rule.RuleDefinition) 038 */ 039 @Override 040 public RuleDefinition createRule(RuleDefinition rule) { 041 if (rule == null) { 042 throw new IllegalArgumentException("rule is null"); 043 } 044 final String nameKey = rule.getName(); 045 final String namespaceKey = rule.getNamespace(); 046 final RuleDefinition existing = getRuleByNameAndNamespace(nameKey, namespaceKey); 047 if (existing != null) { 048 throw new IllegalStateException("the rule to create already exists: " + rule); 049 } 050 RuleBo ruleBo = RuleBo.from(rule); 051 businessObjectService.save(ruleBo); 052 return RuleBo.to(ruleBo); 053 } 054 055 /** 056 * This overridden updates an existing Rule in the Repository 057 * 058 * @see org.kuali.rice.krms.impl.repository.RuleBoService#updateRule(org.kuali.rice.krms.api.repository.rule.RuleDefinition) 059 */ 060 @Override 061 public void updateRule(RuleDefinition rule) { 062 if (rule == null) { 063 throw new IllegalArgumentException("rule is null"); 064 } 065 066 // must already exist to be able to update 067 final String ruleIdKey = rule.getId(); 068 final RuleBo existing = businessObjectService.findBySinglePrimaryKey(RuleBo.class, ruleIdKey); 069 if (existing == null) { 070 throw new IllegalStateException("the rule does not exist: " + rule); 071 } 072 final RuleDefinition toUpdate; 073 if (!existing.getId().equals(rule.getId())) { 074 // if passed in id does not match existing id, correct it 075 final RuleDefinition.Builder builder = RuleDefinition.Builder.create(rule); 076 builder.setId(existing.getId()); 077 toUpdate = builder.build(); 078 } else { 079 toUpdate = rule; 080 } 081 082 // copy all updateable fields to bo 083 RuleBo boToUpdate = RuleBo.from(toUpdate); 084 updateActionAttributes(boToUpdate.getActions()); 085 086 // delete any old, existing attributes 087 Map<String, String> fields = new HashMap<String, String>(1); 088 fields.put(PropertyNames.Rule.RULE_ID, toUpdate.getId()); 089 businessObjectService.deleteMatching(RuleAttributeBo.class, fields); 090 091 // update the rule and create new attributes 092 businessObjectService.save(boToUpdate); 093 } 094 095 @Override 096 public void deleteRule(String ruleId) { 097 if (ruleId == null) { 098 throw new IllegalArgumentException("ruleId is null"); 099 } 100 final RuleDefinition existing = getRuleByRuleId(ruleId); 101 if (existing == null) { 102 throw new IllegalStateException("the Rule to delete does not exists: " + ruleId); 103 } 104 businessObjectService.delete(from(existing)); 105 } 106 107 /** 108 * This method retrieves a rule from the repository given the rule id. 109 * 110 * @see org.kuali.rice.krms.impl.repository.RuleBoService#getRuleByRuleId(java.lang.String) 111 */ 112 @Override 113 public RuleDefinition getRuleByRuleId(String ruleId) { 114 if (StringUtils.isBlank(ruleId)) { 115 throw new IllegalArgumentException("rule id is null"); 116 } 117 RuleBo bo = businessObjectService.findBySinglePrimaryKey(RuleBo.class, ruleId); 118 return RuleBo.to(bo); 119 } 120 121 /** 122 * This method retrieves a rule from the repository given the name of the rule 123 * and namespace. 124 * 125 * @see org.kuali.rice.krms.impl.repository.RuleBoService#getRuleByRuleId(java.lang.String) 126 */ 127 @Override 128 public RuleDefinition getRuleByNameAndNamespace(String name, String namespace) { 129 if (StringUtils.isBlank(name)) { 130 throw new IllegalArgumentException("name is null or blank"); 131 } 132 if (StringUtils.isBlank(namespace)) { 133 throw new IllegalArgumentException("namespace is null or blank"); 134 } 135 136 final Map<String, Object> map = new HashMap<String, Object>(); 137 map.put("name", name); 138 map.put("namespace", namespace); 139 140 RuleBo myRule = businessObjectService.findByPrimaryKey(RuleBo.class, Collections.unmodifiableMap(map)); 141 return RuleBo.to(myRule); 142 } 143 144// /** 145// * This overridden method ... 146// * 147// * @see org.kuali.rice.krms.impl.repository.RuleBoService#createRuleAttribute(org.kuali.rice.krms.api.repository.rule.RuleAttribute) 148// */ 149// @Override 150// public void createRuleAttribute(RuleAttribute attribute) { 151// if (attribute == null){ 152// throw new IllegalArgumentException("rule attribute is null"); 153// } 154// final String attrIdKey = attribute.getId(); 155// final RuleAttribute existing = getRuleAttributeById(attrIdKey); 156// if (existing != null){ 157// throw new IllegalStateException("the rule attribute to create already exists: " + attribute); 158// } 159// 160// businessObjectService.save(RuleAttributeBo.from(attribute)); 161// } 162// 163// /** 164// * This overridden method ... 165// * 166// * @see org.kuali.rice.krms.impl.repository.RuleBoService#updateRuleAttribute(org.kuali.rice.krms.api.repository.rule.RuleAttribute) 167// */ 168// @Override 169// public void updateRuleAttribute(RuleAttribute attribute) { 170// if (attribute == null){ 171// throw new IllegalArgumentException("rule attribute is null"); 172// } 173// final String attrIdKey = attribute.getId(); 174// final RuleAttribute existing = getRuleAttributeById(attrIdKey); 175// if (existing == null) { 176// throw new IllegalStateException("the rule attribute does not exist: " + attribute); 177// } 178// final RuleAttribute toUpdate; 179// if (!existing.getId().equals(attribute.getRuleId())){ 180// final RuleAttribute.Builder builder = RuleAttribute.Builder.create(attribute); 181// builder.setId(existing.getId()); 182// toUpdate = builder.build(); 183// } else { 184// toUpdate = attribute; 185// } 186// 187// businessObjectService.save(RuleAttributeBo.from(toUpdate)); 188// } 189// 190 191 /** 192 * This method ... 193 * 194 * @see org.kuali.rice.krms.impl.repository.RuleBoService#getRuleAttributeById(java.lang.String) 195 */ 196 public RuleAttributeBo getRuleAttributeById(String attrId) { 197 if (StringUtils.isBlank(attrId)) { 198 return null; 199 } 200 RuleAttributeBo bo = businessObjectService.findBySinglePrimaryKey(RuleAttributeBo.class, attrId); 201 return bo; 202 } 203 204 /** 205 * Converts a immutable {@link RuleDefinition} to its mutable {@link RuleBo} counterpart. 206 * 207 * @param rule the immutable object. 208 * @return a {@link RuleBo} the mutable RuleBo. 209 */ 210 public RuleBo from(RuleDefinition rule) { 211 if (rule == null) { 212 return null; 213 } 214 RuleBo ruleBo = new RuleBo(); 215 ruleBo.setName(rule.getName()); 216 ruleBo.setDescription(rule.getDescription()); 217 ruleBo.setNamespace(rule.getNamespace()); 218 ruleBo.setTypeId(rule.getTypeId()); 219 ruleBo.setPropId(rule.getPropId()); 220 ruleBo.setProposition(PropositionBo.from(rule.getProposition())); 221 ruleBo.setId(rule.getId()); 222 ruleBo.setActive(rule.isActive()); 223 ruleBo.setVersionNumber(rule.getVersionNumber()); 224// Set<RuleAttributeBo> attributes = buildAttributeBo(rule); 225 ruleBo.setActions(buildActionBoList(rule)); 226 ruleBo.setAttributeBos(buildAttributeBoList(rule)); 227 return ruleBo; 228 } 229 230 private Set<RuleAttributeBo> buildAttributeBo(RuleDefinition im) { 231 Set<RuleAttributeBo> attributes = new HashSet<RuleAttributeBo>(); 232 233 // build a map from attribute name to definition 234 Map<String, KrmsAttributeDefinition> attributeDefinitionMap = new HashMap<String, KrmsAttributeDefinition>(); 235 236 List<KrmsAttributeDefinition> attributeDefinitions = getAttributeDefinitionService().findAttributeDefinitionsByType(im.getTypeId()); 237 238 for (KrmsAttributeDefinition attributeDefinition : attributeDefinitions) { 239 attributeDefinitionMap.put(attributeDefinition.getName(), attributeDefinition); 240 } 241 242 // for each entry, build a RuleAttributeBo and add it to the set 243 if (im.getAttributes() != null) { 244 for (Map.Entry<String, String> entry : im.getAttributes().entrySet()) { 245 KrmsAttributeDefinition attrDef = attributeDefinitionMap.get(entry.getKey()); 246 247 if (attrDef != null) { 248 RuleAttributeBo attributeBo = new RuleAttributeBo(); 249 attributeBo.setRuleId(im.getId()); 250 attributeBo.setAttributeDefinitionId(attrDef.getId()); 251 attributeBo.setValue(entry.getValue()); 252 attributeBo.setAttributeDefinition(KrmsAttributeDefinitionBo.from(attrDef)); 253 attributes.add(attributeBo); 254 } else { 255 throw new RiceIllegalStateException("there is no attribute definition with the name '" + 256 entry.getKey() + "' that is valid for the rule type with id = '" + im.getTypeId() + "'"); 257 } 258 } 259 } 260 return attributes; 261 } 262 263 private List<RuleAttributeBo> buildAttributeBoList(RuleDefinition im) { 264 List<RuleAttributeBo> attributes = new LinkedList<RuleAttributeBo>(); 265 266 // build a map from attribute name to definition 267 Map<String, KrmsAttributeDefinition> attributeDefinitionMap = new HashMap<String, KrmsAttributeDefinition>(); 268 269 List<KrmsAttributeDefinition> attributeDefinitions = getAttributeDefinitionService().findAttributeDefinitionsByType(im.getTypeId()); 270 271 for (KrmsAttributeDefinition attributeDefinition : attributeDefinitions) { 272 attributeDefinitionMap.put(attributeDefinition.getName(), attributeDefinition); 273 } 274 275 // for each entry, build a RuleAttributeBo and add it to the set 276 if (im.getAttributes() != null) { 277 for (Map.Entry<String, String> entry : im.getAttributes().entrySet()) { 278 KrmsAttributeDefinition attrDef = attributeDefinitionMap.get(entry.getKey()); 279 280 if (attrDef != null) { 281 RuleAttributeBo attributeBo = new RuleAttributeBo(); 282 attributeBo.setRuleId(im.getId()); 283 attributeBo.setAttributeDefinitionId(attrDef.getId()); 284 attributeBo.setValue(entry.getValue()); 285 attributeBo.setAttributeDefinition(KrmsAttributeDefinitionBo.from(attrDef)); 286 attributes.add(attributeBo); 287 } else { 288 throw new RiceIllegalStateException("there is no attribute definition with the name '" + 289 entry.getKey() + "' that is valid for the rule type with id = '" + im.getTypeId() + "'"); 290 } 291 } 292 } 293 return attributes; 294 } 295 296 private List<ActionBo> buildActionBoList(RuleDefinition im) { 297 List<ActionBo> actions = new LinkedList<ActionBo>(); 298 299 for (ActionDefinition actionDefinition : im.getActions()) { 300 actions.add(ActionBo.from(actionDefinition)); 301 } 302 updateActionAttributes(actions); 303 304 return actions; 305 } 306 307 private void updateActionAttributes(List<ActionBo> actionBos) { 308 for (ActionBo action : actionBos) { 309 for (ActionAttributeBo aa : action.getAttributeBos()) { 310 final Map<String, Object> map = new HashMap<String, Object>(); 311 map.put("actionId", action.getId()); 312 313 List<ActionAttributeBo> aaBos = (List<ActionAttributeBo>) businessObjectService.findMatching(ActionAttributeBo.class, Collections.unmodifiableMap(map)); 314 for (ActionAttributeBo aaBo : aaBos) { 315 if (aaBo.getAttributeDefinitionId().equals(aa.getAttributeDefinitionId())) { 316 aa.setId(aaBo.getId()); 317 aa.setVersionNumber(aaBo.getVersionNumber()); 318 } 319 } 320 } 321 } 322 } 323 324 /** 325 * Sets the businessObjectService attribute value. 326 * 327 * @param businessObjectService The businessObjectService to set. 328 */ 329 public void setBusinessObjectService(final BusinessObjectService businessObjectService) { 330 this.businessObjectService = businessObjectService; 331 } 332 333 /** 334 * Converts a List<RuleBo> to an Unmodifiable List<Rule> 335 * 336 * @param ruleBos a mutable List<RuleBo> to made completely immutable. 337 * @return An unmodifiable List<Rule> 338 */ 339 public List<RuleDefinition> convertListOfBosToImmutables(final Collection<RuleBo> ruleBos) { 340 ArrayList<RuleDefinition> rules = new ArrayList<RuleDefinition>(); 341 for (RuleBo bo : ruleBos) { 342 RuleDefinition rule = RuleBo.to(bo); 343 rules.add(rule); 344 } 345 return Collections.unmodifiableList(rules); 346 } 347 348 349 protected KrmsAttributeDefinitionService getAttributeDefinitionService() { 350 if (attributeDefinitionService == null) { 351 attributeDefinitionService = KrmsRepositoryServiceLocator.getKrmsAttributeDefinitionService(); 352 } 353 return attributeDefinitionService; 354 } 355 356}