001/** 002 * Copyright 2005-2016 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 RuleBoServiceImpl 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){ throw new IllegalArgumentException("ruleId is null"); } 098 final RuleDefinition existing = getRuleByRuleId(ruleId); 099 if (existing == null){ throw new IllegalStateException("the Rule to delete does not exists: " + ruleId);} 100 businessObjectService.delete(from(existing)); 101 } 102 103 /** 104 * This method retrieves a rule from the repository given the rule id. 105 * 106 * @see org.kuali.rice.krms.impl.repository.RuleBoService#getRuleByRuleId(java.lang.String) 107 */ 108 @Override 109 public RuleDefinition getRuleByRuleId(String ruleId) { 110 if (StringUtils.isBlank(ruleId)){ 111 throw new IllegalArgumentException("rule id is null"); 112 } 113 RuleBo bo = businessObjectService.findBySinglePrimaryKey(RuleBo.class, ruleId); 114 return RuleBo.to(bo); 115 } 116 117 /** 118 * This method retrieves a rule from the repository given the name of the rule 119 * and namespace. 120 * 121 * @see org.kuali.rice.krms.impl.repository.RuleBoService#getRuleByRuleId(java.lang.String) 122 */ 123 @Override 124 public RuleDefinition getRuleByNameAndNamespace(String name, String namespace) { 125 if (StringUtils.isBlank(name)) { 126 throw new IllegalArgumentException("name is null or blank"); 127 } 128 if (StringUtils.isBlank(namespace)) { 129 throw new IllegalArgumentException("namespace is null or blank"); 130 } 131 132 final Map<String, Object> map = new HashMap<String, Object>(); 133 map.put("name", name); 134 map.put("namespace", namespace); 135 136 RuleBo myRule = businessObjectService.findByPrimaryKey(RuleBo.class, Collections.unmodifiableMap(map)); 137 return RuleBo.to(myRule); 138 } 139 140// /** 141// * This overridden method ... 142// * 143// * @see org.kuali.rice.krms.impl.repository.RuleBoService#createRuleAttribute(org.kuali.rice.krms.api.repository.rule.RuleAttribute) 144// */ 145// @Override 146// public void createRuleAttribute(RuleAttribute attribute) { 147// if (attribute == null){ 148// throw new IllegalArgumentException("rule attribute is null"); 149// } 150// final String attrIdKey = attribute.getId(); 151// final RuleAttribute existing = getRuleAttributeById(attrIdKey); 152// if (existing != null){ 153// throw new IllegalStateException("the rule attribute to create already exists: " + attribute); 154// } 155// 156// businessObjectService.save(RuleAttributeBo.from(attribute)); 157// } 158// 159// /** 160// * This overridden method ... 161// * 162// * @see org.kuali.rice.krms.impl.repository.RuleBoService#updateRuleAttribute(org.kuali.rice.krms.api.repository.rule.RuleAttribute) 163// */ 164// @Override 165// public void updateRuleAttribute(RuleAttribute attribute) { 166// if (attribute == null){ 167// throw new IllegalArgumentException("rule attribute is null"); 168// } 169// final String attrIdKey = attribute.getId(); 170// final RuleAttribute existing = getRuleAttributeById(attrIdKey); 171// if (existing == null) { 172// throw new IllegalStateException("the rule attribute does not exist: " + attribute); 173// } 174// final RuleAttribute toUpdate; 175// if (!existing.getId().equals(attribute.getRuleId())){ 176// final RuleAttribute.Builder builder = RuleAttribute.Builder.create(attribute); 177// builder.setId(existing.getId()); 178// toUpdate = builder.build(); 179// } else { 180// toUpdate = attribute; 181// } 182// 183// businessObjectService.save(RuleAttributeBo.from(toUpdate)); 184// } 185// 186 /** 187 * This method ... 188 * 189 * @see org.kuali.rice.krms.impl.repository.RuleBoService#getRuleAttributeById(java.lang.String) 190 */ 191 public RuleAttributeBo getRuleAttributeById(String attrId) { 192 if (StringUtils.isBlank(attrId)){ 193 return null; 194 } 195 RuleAttributeBo bo = businessObjectService.findBySinglePrimaryKey(RuleAttributeBo.class, attrId); 196 return bo; 197 } 198 199 /** 200 * Converts a immutable {@link RuleDefinition} to its mutable {@link RuleBo} counterpart. 201 * @param rule the immutable object. 202 * @return a {@link RuleBo} the mutable RuleBo. 203 * 204 */ 205 public RuleBo from(RuleDefinition rule) { 206 if (rule == null) { return null; } 207 RuleBo ruleBo = new RuleBo(); 208 ruleBo.setName(rule.getName()); 209 ruleBo.setDescription(rule.getDescription()); 210 ruleBo.setNamespace(rule.getNamespace()); 211 ruleBo.setTypeId(rule.getTypeId()); 212 ruleBo.setPropId(rule.getPropId()); 213 ruleBo.setProposition(PropositionBo.from(rule.getProposition())); 214 ruleBo.setId(rule.getId()); 215 ruleBo.setActive(rule.isActive()); 216 ruleBo.setVersionNumber(rule.getVersionNumber()); 217 // TODO collections, etc. 218// Set<RuleAttributeBo> attributes = buildAttributeBo(rule); 219 ruleBo.setActions(buildActionBoList(rule)); 220 ruleBo.setAttributeBos(buildAttributeBoList(rule)); 221 return ruleBo; 222 } 223 224 private Set<RuleAttributeBo> buildAttributeBo(RuleDefinition im) { 225 Set<RuleAttributeBo> attributes = new HashSet<RuleAttributeBo>(); 226 227 // build a map from attribute name to definition 228 Map<String, KrmsAttributeDefinition> attributeDefinitionMap = new HashMap<String, KrmsAttributeDefinition>(); 229 230 List<KrmsAttributeDefinition> attributeDefinitions = getAttributeDefinitionService().findAttributeDefinitionsByType(im.getTypeId()); 231 232 for (KrmsAttributeDefinition attributeDefinition : attributeDefinitions) { 233 attributeDefinitionMap.put(attributeDefinition.getName(), attributeDefinition); 234 } 235 236 // for each entry, build a RuleAttributeBo and add it to the set 237 if (im.getAttributes() != null) { 238 for (Map.Entry<String,String> entry : im.getAttributes().entrySet()) { 239 KrmsAttributeDefinition attrDef = attributeDefinitionMap.get(entry.getKey()); 240 241 if (attrDef != null) { 242 RuleAttributeBo attributeBo = new RuleAttributeBo(); 243 attributeBo.setRuleId( im.getId() ); 244 attributeBo.setAttributeDefinitionId(attrDef.getId()); 245 attributeBo.setValue(entry.getValue()); 246 attributeBo.setAttributeDefinition(KrmsAttributeDefinitionBo.from(attrDef)); 247 attributes.add( attributeBo ); 248 } else { 249 throw new RiceIllegalStateException("there is no attribute definition with the name '" + 250 entry.getKey() + "' that is valid for the rule type with id = '" + im.getTypeId() +"'"); 251 } 252 } 253 } 254 return attributes; 255 } 256 257 private List<RuleAttributeBo> buildAttributeBoList(RuleDefinition im) { 258 List<RuleAttributeBo> attributes = new LinkedList<RuleAttributeBo>(); 259 260 // build a map from attribute name to definition 261 Map<String, KrmsAttributeDefinition> attributeDefinitionMap = new HashMap<String, KrmsAttributeDefinition>(); 262 263 List<KrmsAttributeDefinition> attributeDefinitions = getAttributeDefinitionService().findAttributeDefinitionsByType(im.getTypeId()); 264 265 for (KrmsAttributeDefinition attributeDefinition : attributeDefinitions) { 266 attributeDefinitionMap.put(attributeDefinition.getName(), attributeDefinition); 267 } 268 269 // for each entry, build a RuleAttributeBo and add it to the set 270 if (im.getAttributes() != null) { 271 for (Map.Entry<String,String> entry : im.getAttributes().entrySet()) { 272 KrmsAttributeDefinition attrDef = attributeDefinitionMap.get(entry.getKey()); 273 274 if (attrDef != null) { 275 RuleAttributeBo attributeBo = new RuleAttributeBo(); 276 attributeBo.setRuleId( im.getId() ); 277 attributeBo.setAttributeDefinitionId(attrDef.getId()); 278 attributeBo.setValue(entry.getValue()); 279 attributeBo.setAttributeDefinition(KrmsAttributeDefinitionBo.from(attrDef)); 280 attributes.add( attributeBo ); 281 } else { 282 throw new RiceIllegalStateException("there is no attribute definition with the name '" + 283 entry.getKey() + "' that is valid for the rule type with id = '" + im.getTypeId() +"'"); 284 } 285 } 286 } 287 return attributes; 288 } 289 290 private List<ActionBo> buildActionBoList(RuleDefinition im) { 291 List<ActionBo> actions = new LinkedList<ActionBo>(); 292 293 for (ActionDefinition actionDefinition : im.getActions()) { 294 actions.add(ActionBo.from(actionDefinition)); 295 } 296 updateActionAttributes(actions); 297 298 return actions; 299 } 300 301 private void updateActionAttributes(List<ActionBo> actionBos) { 302 for (ActionBo action : actionBos) { 303 for (ActionAttributeBo aa : action.getAttributeBos()) { 304 Map<String, Object> map = new HashMap<String, Object>(); 305 map.put("actionId", action.getId()); 306 Collection<ActionAttributeBo> aaBos = businessObjectService.findMatching(ActionAttributeBo.class, map); 307 308 for (ActionAttributeBo aaBo : aaBos) { 309 if (aaBo.getAttributeDefinitionId().equals(aa.getAttributeDefinitionId())) { 310 aa.setId(aaBo.getId()); 311 aa.setVersionNumber(aaBo.getVersionNumber()); 312 } 313 } 314 } 315 } 316 } 317 318 /** 319 * Sets the businessObjectService attribute value. 320 * 321 * @param businessObjectService The businessObjectService to set. 322 */ 323 public void setBusinessObjectService(final BusinessObjectService businessObjectService) { 324 this.businessObjectService = businessObjectService; 325 } 326 327 /** 328 * Converts a List<RuleBo> to an Unmodifiable List<Rule> 329 * 330 * @param ruleBos a mutable List<RuleBo> to made completely immutable. 331 * @return An unmodifiable List<Rule> 332 */ 333 public List<RuleDefinition> convertListOfBosToImmutables(final Collection<RuleBo> ruleBos) { 334 ArrayList<RuleDefinition> rules = new ArrayList<RuleDefinition>(); 335 for (RuleBo bo : ruleBos) { 336 RuleDefinition rule = RuleBo.to(bo); 337 rules.add(rule); 338 } 339 return Collections.unmodifiableList(rules); 340 } 341 342 343 protected KrmsAttributeDefinitionService getAttributeDefinitionService() { 344 if (attributeDefinitionService == null) { 345 attributeDefinitionService = KrmsRepositoryServiceLocator.getKrmsAttributeDefinitionService(); 346 } 347 return attributeDefinitionService; 348 } 349 350}