Coverage Report - org.kuali.rice.krms.impl.rule.AgendaEditorBusRule
 
Classes in this File Line Coverage Branch Coverage Complexity
AgendaEditorBusRule
0%
0/137
0%
0/80
4.278
 
 1  
 /**
 2  
  * Copyright 2005-2011 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.krms.impl.rule;
 17  
 
 18  
 import org.apache.commons.collections.CollectionUtils;
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.kuali.rice.core.api.uif.RemotableAttributeError;
 21  
 import org.kuali.rice.core.api.util.RiceKeyConstants;
 22  
 import org.kuali.rice.krad.bo.GlobalBusinessObject;
 23  
 import org.kuali.rice.krad.bo.PersistableBusinessObject;
 24  
 import org.kuali.rice.krad.document.MaintenanceDocument;
 25  
 import org.kuali.rice.krad.rules.MaintenanceDocumentRuleBase;
 26  
 import org.kuali.rice.krad.util.KRADConstants;
 27  
 import org.kuali.rice.krms.api.KrmsConstants;
 28  
 import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
 29  
 import org.kuali.rice.krms.api.repository.rule.RuleDefinition;
 30  
 import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
 31  
 import org.kuali.rice.krms.api.repository.type.KrmsTypeRepositoryService;
 32  
 import org.kuali.rice.krms.framework.type.ActionTypeService;
 33  
 import org.kuali.rice.krms.framework.type.AgendaTypeService;
 34  
 import org.kuali.rice.krms.impl.authorization.AgendaAuthorizationService;
 35  
 import org.kuali.rice.krms.impl.repository.ActionBo;
 36  
 import org.kuali.rice.krms.impl.repository.AgendaBo;
 37  
 import org.kuali.rice.krms.impl.repository.AgendaBoService;
 38  
 import org.kuali.rice.krms.impl.repository.AgendaItemBo;
 39  
 import org.kuali.rice.krms.impl.repository.ContextBoService;
 40  
 import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
 41  
 import org.kuali.rice.krms.impl.repository.RuleBo;
 42  
 import org.kuali.rice.krms.impl.repository.RuleBoService;
 43  
 import org.kuali.rice.krms.impl.ui.AgendaEditor;
 44  
 import org.kuali.rice.krms.impl.util.KRMSPropertyConstants;
 45  
 
 46  
 import java.util.List;
 47  
 import java.util.Map;
 48  
 
 49  
 /**
 50  
  * This class contains the rules for the AgendaEditor.
 51  
  */
 52  0
 public class AgendaEditorBusRule extends MaintenanceDocumentRuleBase {
 53  
 
 54  
     @Override
 55  
     protected boolean primaryKeyCheck(MaintenanceDocument document) {
 56  
         // default to success if no failures
 57  0
         boolean success = true;
 58  0
         Class<?> dataObjectClass = document.getNewMaintainableObject().getDataObjectClass();
 59  
 
 60  
         // Since the dataObject is a wrapper class we need to return the agendaBo instead.
 61  0
         Object oldBo = ((AgendaEditor) document.getOldMaintainableObject().getDataObject()).getAgenda();
 62  0
         Object newDataObject = ((AgendaEditor) document.getNewMaintainableObject().getDataObject()).getAgenda();
 63  
 
 64  
         // We dont do primaryKeyChecks on Global Business Object maintenance documents. This is
 65  
         // because it doesnt really make any sense to do so, given the behavior of Globals. When a
 66  
         // Global Document completes, it will update or create a new record for each BO in the list.
 67  
         // As a result, there's no problem with having existing BO records in the system, they will
 68  
         // simply get updated.
 69  0
         if (newDataObject instanceof GlobalBusinessObject) {
 70  0
             return success;
 71  
         }
 72  
 
 73  
         // fail and complain if the person has changed the primary keys on
 74  
         // an EDIT maintenance document.
 75  0
         if (document.isEdit()) {
 76  0
             if (!getDataObjectMetaDataService().equalsByPrimaryKeys(oldBo, newDataObject)) {
 77  
                 // add a complaint to the errors
 78  0
                 putDocumentError(KRADConstants.DOCUMENT_ERRORS,
 79  
                         RiceKeyConstants.ERROR_DOCUMENT_MAINTENANCE_PRIMARY_KEYS_CHANGED_ON_EDIT,
 80  
                         getHumanReadablePrimaryKeyFieldNames(dataObjectClass));
 81  0
                 success &= false;
 82  
             }
 83  
         }
 84  
 
 85  
         // fail and complain if the person has selected a new object with keys that already exist
 86  
         // in the DB.
 87  0
         else if (document.isNew()) {
 88  
 
 89  
             // TODO: when/if we have standard support for DO retrieval, do this check for DO's
 90  0
             if (newDataObject instanceof PersistableBusinessObject) {
 91  
 
 92  
                 // get a map of the pk field names and values
 93  0
                 Map<String, ?> newPkFields = getDataObjectMetaDataService().getPrimaryKeyFieldValues(newDataObject);
 94  
 
 95  
                 // TODO: Good suggestion from Aaron, dont bother checking the DB, if all of the
 96  
                 // objects PK fields dont have values. If any are null or empty, then
 97  
                 // we're done. The current way wont fail, but it will make a wasteful
 98  
                 // DB call that may not be necessary, and we want to minimize these.
 99  
 
 100  
                 // attempt to do a lookup, see if this object already exists by these Primary Keys
 101  0
                 PersistableBusinessObject testBo = getBoService()
 102  
                         .findByPrimaryKey(dataObjectClass.asSubclass(PersistableBusinessObject.class), newPkFields);
 103  
 
 104  
                 // if the retrieve was successful, then this object already exists, and we need
 105  
                 // to complain
 106  0
                 if (testBo != null) {
 107  0
                     putDocumentError(KRADConstants.DOCUMENT_ERRORS,
 108  
                             RiceKeyConstants.ERROR_DOCUMENT_MAINTENANCE_KEYS_ALREADY_EXIST_ON_CREATE_NEW,
 109  
                             getHumanReadablePrimaryKeyFieldNames(dataObjectClass));
 110  0
                     success &= false;
 111  
                 }
 112  
             }
 113  
         }
 114  
 
 115  0
         return success;
 116  
     }
 117  
 
 118  
 
 119  
 
 120  
     @Override
 121  
     protected boolean processCustomSaveDocumentBusinessRules(MaintenanceDocument document) {
 122  0
         boolean isValid = true;
 123  
 
 124  0
         AgendaEditor agenda = (AgendaEditor) document.getNewMaintainableObject().getDataObject();
 125  0
         AgendaEditor oldAgenda = (AgendaEditor) document.getOldMaintainableObject().getDataObject();
 126  0
         isValid &= validContext(agenda);
 127  0
         isValid &= validAgendaName(agenda);
 128  0
         isValid &= validAgendaAttributes(oldAgenda, agenda);
 129  
 
 130  0
         return isValid;
 131  
     }
 132  
 
 133  
     /**
 134  
      * Check if the context exists and if user has authorization to edit agendas under this context.
 135  
      * @param agenda
 136  
      * @return true if the context exist and has authorization, false otherwise
 137  
      */
 138  
     private boolean validContext(AgendaEditor agenda) {
 139  0
         boolean isValid = true;
 140  
 
 141  
         try {
 142  0
             if (getContextBoService().getContextByContextId(agenda.getAgenda().getContextId()) == null) {
 143  0
                 this.putFieldError(KRMSPropertyConstants.Agenda.CONTEXT, "error.agenda.invalidContext");
 144  0
                 isValid = false;
 145  
             } else {
 146  0
                 if (!getAgendaAuthorizationService().isAuthorized(KrmsConstants.MAINTAIN_KRMS_AGENDA,
 147  
                         agenda.getAgenda().getContextId())) {
 148  0
                     this.putFieldError(KRMSPropertyConstants.Agenda.CONTEXT, "error.agenda.unauthorizedContext");
 149  0
                     isValid = false;
 150  
                 }
 151  
             }
 152  
         }
 153  0
         catch (IllegalArgumentException e) {
 154  0
             this.putFieldError(KRMSPropertyConstants.Agenda.CONTEXT, "error.agenda.invalidContext");
 155  0
             isValid = false;
 156  0
         }
 157  
 
 158  0
         return isValid;
 159  
     }
 160  
 
 161  
     private boolean validAgendaAttributes(AgendaEditor oldAgenda, AgendaEditor newAgenda) {
 162  0
         boolean isValid = true;
 163  
 
 164  0
         String typeId = newAgenda.getAgenda().getTypeId();
 165  
 
 166  0
         if (!StringUtils.isEmpty(typeId)) {
 167  0
             KrmsTypeDefinition typeDefinition = getKrmsTypeRepositoryService().getTypeById(typeId);
 168  
 
 169  0
             if (typeDefinition == null) {
 170  0
                 throw new IllegalStateException("agenda typeId must match the id of a valid krms type");
 171  0
             } else if (StringUtils.isBlank(typeDefinition.getServiceName())) {
 172  0
                 throw new IllegalStateException("agenda type definition must have a non-blank service name");
 173  
             } else {
 174  0
                 AgendaTypeService agendaTypeService =
 175  
                         (AgendaTypeService)KrmsRepositoryServiceLocator.getService(typeDefinition.getServiceName());
 176  
 
 177  0
                 if (agendaTypeService == null) {
 178  0
                     throw new IllegalStateException("typeDefinition must have a valid serviceName");
 179  
                 } else {
 180  
 
 181  
                     List<RemotableAttributeError> errors;
 182  0
                     if (oldAgenda == null) {
 183  0
                         errors = agendaTypeService.validateAttributes(typeId, newAgenda.getCustomAttributesMap());
 184  
                     } else {
 185  0
                         errors = agendaTypeService.validateAttributesAgainstExisting(typeId, newAgenda.getCustomAttributesMap(), oldAgenda.getCustomAttributesMap());
 186  
                     }
 187  
 
 188  0
                     if (!CollectionUtils.isEmpty(errors)) {
 189  0
                         isValid = false;
 190  0
                         for (RemotableAttributeError error : errors) {
 191  0
                             for (String errorStr : error.getErrors()) {
 192  0
                                 this.putFieldError(
 193  
                                         KRMSPropertyConstants.AgendaEditor.CUSTOM_ATTRIBUTES_MAP +
 194  
                                                 "['" + error.getAttributeName() + "']",
 195  
                                         errorStr
 196  
                                 );
 197  
                             }
 198  
                         }
 199  
                     }
 200  
                 }
 201  
             }
 202  
         }
 203  0
         return isValid;
 204  
     }
 205  
 
 206  
     /**
 207  
      * Check if an agenda with that name exists already in the context.
 208  
      * @param agenda
 209  
      * @return true if agenda name is unique, false otherwise
 210  
      */
 211  
     private boolean validAgendaName(AgendaEditor agenda) {
 212  
         try {
 213  0
             AgendaDefinition agendaFromDataBase = getAgendaBoService().getAgendaByNameAndContextId(agenda.getAgenda().getName(),
 214  
                     agenda.getAgenda().getContextId());
 215  0
             if ((agendaFromDataBase != null) && !StringUtils.equals(agendaFromDataBase.getId(), agenda.getAgenda().getId())) {
 216  0
                 this.putFieldError(KRMSPropertyConstants.Agenda.NAME, "error.agenda.duplicateName");
 217  0
                 return false;
 218  
             }
 219  
         }
 220  0
         catch (IllegalArgumentException e) {
 221  0
             this.putFieldError(KRMSPropertyConstants.Agenda.NAME, "error.agenda.invalidName");
 222  0
             return false;
 223  0
         }
 224  0
         return true;
 225  
     }
 226  
 
 227  
     public boolean processAgendaItemBusinessRules(MaintenanceDocument document) {
 228  0
         boolean isValid = true;
 229  
 
 230  0
         AgendaEditor newAgendaEditor = (AgendaEditor) document.getNewMaintainableObject().getDataObject();
 231  0
         AgendaEditor oldAgendaEditor = (AgendaEditor) document.getOldMaintainableObject().getDataObject();
 232  0
         RuleBo rule = newAgendaEditor.getAgendaItemLine().getRule();
 233  0
         isValid &= validateRuleName(rule, newAgendaEditor.getAgenda());
 234  0
         isValid &= validateRuleAction(oldAgendaEditor, newAgendaEditor);
 235  
 
 236  0
         return isValid;
 237  
     }
 238  
 
 239  
     /**
 240  
      * Check if a rule with that name exists already in the namespace.
 241  
      * @param rule
 242  
      * @parm agenda
 243  
      * @return true if rule name is unique, false otherwise
 244  
      */
 245  
     private boolean validateRuleName(RuleBo rule, AgendaBo agenda) {
 246  0
         if (StringUtils.isBlank(rule.getName())) {
 247  0
             this.putFieldError(KRMSPropertyConstants.Rule.NAME, "error.rule.invalidName");
 248  0
             return false;
 249  
         }
 250  
         // check current bo for rules (including ones that aren't persisted to the database)
 251  0
         for (AgendaItemBo agendaItem : agenda.getItems()) {
 252  0
             if (!StringUtils.equals(agendaItem.getRule().getId(), rule.getId()) && StringUtils.equals(agendaItem.getRule().getName(), rule.getName())
 253  
                     && StringUtils.equals(agendaItem.getRule().getNamespace(), rule.getNamespace())) {
 254  0
                 this.putFieldError(KRMSPropertyConstants.Rule.NAME, "error.rule.duplicateName");
 255  0
                 return false;
 256  
             }
 257  
         }
 258  
 
 259  
         // check database for rules used with other agendas - the namespace might not yet be specified on new agendas.
 260  0
         if (StringUtils.isNotBlank(rule.getNamespace())) {
 261  0
             RuleDefinition ruleFromDatabase = getRuleBoService().getRuleByNameAndNamespace(rule.getName(), rule.getNamespace());
 262  
             try {
 263  0
                 if ((ruleFromDatabase != null) && !StringUtils.equals(ruleFromDatabase.getId(), rule.getId())) {
 264  0
                     this.putFieldError(KRMSPropertyConstants.Rule.NAME, "error.rule.duplicateName");
 265  0
                     return false;
 266  
                 }
 267  
             }
 268  0
             catch (IllegalArgumentException e) {
 269  0
                 this.putFieldError(KRMSPropertyConstants.Rule.NAME, "error.rule.invalidName");
 270  0
                 return false;
 271  0
             }
 272  
         }
 273  0
         return true;
 274  
     }
 275  
 
 276  
     private boolean validateRuleAction(AgendaEditor oldAgendaEditor, AgendaEditor newAgendaEditor) {
 277  0
         boolean isValid = true;
 278  0
         ActionBo newActionBo = newAgendaEditor.getAgendaItemLineRuleAction();
 279  
 
 280  0
         isValid &= validRuleActionType(newActionBo.getTypeId());
 281  0
         if (isValid && StringUtils.isNotBlank(newActionBo.getTypeId())) {
 282  0
             isValid &= validRuleActionName(newActionBo.getName());
 283  0
             isValid &= validRuleActionAttributes(oldAgendaEditor, newAgendaEditor);
 284  0
             isValid &= validRuleActionDescription(newActionBo.getDescription());
 285  
         }
 286  0
         return isValid;
 287  
     }
 288  
 
 289  
     /**
 290  
      * Check that the rule type is valid when specified.
 291  
      */
 292  
     private boolean validRuleActionType(String typeId) {
 293  0
         if (StringUtils.isBlank(typeId) || (getKrmsTypeRepositoryService().getTypeById(typeId) != null)) {
 294  0
             return true;
 295  
         } else {
 296  0
             this.putFieldError(KRMSPropertyConstants.Action.TYPE, "error.action.invalidType");
 297  0
             return false;
 298  
         }
 299  
     }
 300  
 
 301  
     /**
 302  
      * Check that a action name is specified.
 303  
      */
 304  
     private boolean validRuleActionName(String name) {
 305  0
         if (StringUtils.isNotBlank(name)) {
 306  0
             return true;
 307  
         } else {
 308  0
             this.putFieldError(KRMSPropertyConstants.Action.NAME, "error.action.missingName");
 309  0
             return false;
 310  
         }
 311  
     }
 312  
 
 313  
     private boolean validRuleActionAttributes(AgendaEditor oldAgenda, AgendaEditor newAgenda) {
 314  0
         boolean isValid = true;
 315  
 
 316  0
         String typeId = newAgenda.getAgendaItemLineRuleAction().getTypeId();
 317  
 
 318  0
         if (!StringUtils.isBlank(typeId)) {
 319  0
             KrmsTypeDefinition typeDefinition = getKrmsTypeRepositoryService().getTypeById(typeId);
 320  
 
 321  0
             if (typeDefinition == null) {
 322  0
                 throw new IllegalStateException("action typeId must match the id of a valid krms type");
 323  0
             } else if (StringUtils.isBlank(typeDefinition.getServiceName())) {
 324  0
                 throw new IllegalStateException("action type definition must have a non-blank service name");
 325  
             } else {
 326  0
                 ActionTypeService actionTypeService = getActionTypeService(typeDefinition.getServiceName());
 327  
 
 328  0
                 if (actionTypeService == null) {
 329  0
                     throw new IllegalStateException("typeDefinition must have a valid serviceName");
 330  
                 } else {
 331  
 
 332  
                     List<RemotableAttributeError> errors;
 333  0
                     if (oldAgenda == null) {
 334  0
                         errors = actionTypeService.validateAttributes(typeId, newAgenda.getCustomRuleActionAttributesMap());
 335  
                     } else {
 336  0
                         errors = actionTypeService.validateAttributesAgainstExisting(typeId, newAgenda.getCustomRuleActionAttributesMap(), oldAgenda.getCustomRuleActionAttributesMap());
 337  
                     }
 338  
 
 339  0
                     if (!CollectionUtils.isEmpty(errors)) {
 340  0
                         isValid = false;
 341  0
                         for (RemotableAttributeError error : errors) {
 342  0
                             for (String errorStr : error.getErrors()) {
 343  0
                                 this.putFieldError(
 344  
                                         KRMSPropertyConstants.AgendaEditor.CUSTOM_RULE_ACTION_ATTRIBUTES_MAP +
 345  
                                                 "['" + error.getAttributeName() + "']",
 346  
                                         errorStr
 347  
                                 );
 348  
                             }
 349  
                         }
 350  
                     }
 351  
                 }
 352  
             }
 353  
         }
 354  0
         return isValid;
 355  
     }
 356  
 
 357  
     /**
 358  
      * Check that a action description is specified.
 359  
      */
 360  
     private boolean validRuleActionDescription(String description) {
 361  0
         if (StringUtils.isNotBlank(description)) {
 362  0
             return true;
 363  
         } else {
 364  0
             this.putFieldError(KRMSPropertyConstants.Action.DESCRIPTION, "error.action.missingDescription");
 365  0
             return false;
 366  
         }
 367  
     }
 368  
 
 369  
 
 370  
     public ContextBoService getContextBoService() {
 371  0
         return KrmsRepositoryServiceLocator.getContextBoService();
 372  
     }
 373  
 
 374  
     public AgendaBoService getAgendaBoService() {
 375  0
         return KrmsRepositoryServiceLocator.getAgendaBoService();
 376  
     }
 377  
 
 378  
     public RuleBoService getRuleBoService() {
 379  0
         return KrmsRepositoryServiceLocator.getRuleBoService();
 380  
     }
 381  
 
 382  
     public KrmsTypeRepositoryService getKrmsTypeRepositoryService() {
 383  0
         return KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService();
 384  
     }
 385  
 
 386  
     public ActionTypeService getActionTypeService(String serviceName) {
 387  0
         return (ActionTypeService)KrmsRepositoryServiceLocator.getService(serviceName);
 388  
     }
 389  
     private AgendaAuthorizationService getAgendaAuthorizationService() {
 390  0
         return KrmsRepositoryServiceLocator.getAgendaAuthorizationService();
 391  
     }
 392  
 
 393  
 }
 394