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