Java tutorial
/** * Copyright 2005-2014 The Kuali Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ecl2.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kuali.rice.krms.impl.rule; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.kuali.rice.core.api.uif.RemotableAttributeError; import org.kuali.rice.core.api.util.RiceKeyConstants; import org.kuali.rice.krad.bo.PersistableBusinessObject; import org.kuali.rice.krad.maintenance.BulkUpdateMaintenanceDataObject; import org.kuali.rice.krad.maintenance.MaintenanceDocument; import org.kuali.rice.krad.rules.MaintenanceDocumentRuleBase; import org.kuali.rice.krad.service.KRADServiceLocatorWeb; import org.kuali.rice.krad.util.KRADConstants; import org.kuali.rice.krms.api.KrmsConstants; import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition; import org.kuali.rice.krms.api.repository.rule.RuleDefinition; import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition; import org.kuali.rice.krms.api.repository.type.KrmsTypeRepositoryService; import org.kuali.rice.krms.framework.type.ActionTypeService; import org.kuali.rice.krms.framework.type.AgendaTypeService; import org.kuali.rice.krms.impl.authorization.AgendaAuthorizationService; import org.kuali.rice.krms.impl.repository.ActionBo; import org.kuali.rice.krms.impl.repository.AgendaBo; import org.kuali.rice.krms.impl.repository.AgendaBoService; import org.kuali.rice.krms.impl.repository.AgendaItemBo; import org.kuali.rice.krms.impl.repository.ContextBoService; import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator; import org.kuali.rice.krms.impl.repository.RuleBo; import org.kuali.rice.krms.impl.repository.RuleBoService; import org.kuali.rice.krms.impl.ui.AgendaEditor; import org.kuali.rice.krms.impl.util.KRMSPropertyConstants; import java.util.List; import java.util.Map; import static org.kuali.rice.krms.impl.repository.BusinessObjectServiceMigrationUtils.findSingleMatching; /** * This class contains the rules for the AgendaEditor. */ public class AgendaEditorBusRule extends MaintenanceDocumentRuleBase { @Override protected boolean primaryKeyCheck(MaintenanceDocument document) { // default to success if no failures boolean success = true; Class<?> dataObjectClass = document.getNewMaintainableObject().getDataObjectClass(); // Since the dataObject is a wrapper class we need to return the agendaBo instead. Object oldBo = ((AgendaEditor) document.getOldMaintainableObject().getDataObject()).getAgenda(); Object newDataObject = ((AgendaEditor) document.getNewMaintainableObject().getDataObject()).getAgenda(); // We dont do primaryKeyChecks on Global Business Object maintenance documents. This is // because it doesnt really make any sense to do so, given the behavior of Globals. When a // Global Document completes, it will update or create a new record for each BO in the list. // As a result, there's no problem with having existing BO records in the system, they will // simply get updated. if (newDataObject instanceof BulkUpdateMaintenanceDataObject) { return success; } // fail and complain if the person has changed the primary keys on // an EDIT maintenance document. if (document.isEdit()) { if (!KRADServiceLocatorWeb.getLegacyDataAdapter().equalsByPrimaryKeys(oldBo, newDataObject)) { // add a complaint to the errors putDocumentError(KRADConstants.DOCUMENT_ERRORS, RiceKeyConstants.ERROR_DOCUMENT_MAINTENANCE_PRIMARY_KEYS_CHANGED_ON_EDIT, getHumanReadablePrimaryKeyFieldNames(dataObjectClass)); success &= false; } } // fail and complain if the person has selected a new object with keys that already exist // in the DB. else if (document.isNew()) { // TODO: when/if we have standard support for DO retrieval, do this check for DO's if (newDataObject instanceof PersistableBusinessObject) { // get a map of the pk field names and values Map<String, ?> newPkFields = KRADServiceLocatorWeb.getLegacyDataAdapter() .getPrimaryKeyFieldValues(newDataObject); // TODO: Good suggestion from Aaron, dont bother checking the DB, if all of the // objects PK fields dont have values. If any are null or empty, then // we're done. The current way wont fail, but it will make a wasteful // DB call that may not be necessary, and we want to minimize these. // attempt to do a lookup, see if this object already exists by these Primary Keys PersistableBusinessObject testBo = findSingleMatching(getDataObjectService(), dataObjectClass.asSubclass(PersistableBusinessObject.class), newPkFields); // if the retrieve was successful, then this object already exists, and we need // to complain if (testBo != null) { putDocumentError(KRADConstants.DOCUMENT_ERRORS, RiceKeyConstants.ERROR_DOCUMENT_MAINTENANCE_KEYS_ALREADY_EXIST_ON_CREATE_NEW, getHumanReadablePrimaryKeyFieldNames(dataObjectClass)); success &= false; } } } return success; } @Override protected boolean processCustomSaveDocumentBusinessRules(MaintenanceDocument document) { boolean isValid = true; AgendaEditor agendaEditor = (AgendaEditor) document.getNewMaintainableObject().getDataObject(); AgendaEditor oldAgendaEditor = (AgendaEditor) document.getOldMaintainableObject().getDataObject(); isValid &= validContext(agendaEditor); isValid &= validAgendaName(agendaEditor); isValid &= validContextAgendaNamespace(agendaEditor); isValid &= validAgendaTypeAndAttributes(oldAgendaEditor, agendaEditor); return isValid; } /** * Check if the context exists and if user has authorization to edit agendas under this context. * @param agendaEditor * @return true if the context exist and has authorization, false otherwise */ public boolean validContext(AgendaEditor agendaEditor) { boolean isValid = true; try { if (getContextBoService().getContextByContextId(agendaEditor.getAgenda().getContextId()) == null) { this.putFieldError(KRMSPropertyConstants.Agenda.CONTEXT, "error.agenda.invalidContext"); isValid = false; } else { if (!getAgendaAuthorizationService().isAuthorized(KrmsConstants.MAINTAIN_KRMS_AGENDA, agendaEditor.getAgenda().getContextId())) { this.putFieldError(KRMSPropertyConstants.Agenda.CONTEXT, "error.agenda.unauthorizedContext"); isValid = false; } } } catch (IllegalArgumentException e) { this.putFieldError(KRMSPropertyConstants.Agenda.CONTEXT, "error.agenda.invalidContext"); isValid = false; } return isValid; } /** * Check if for namespace. * @param agendaEditor * @return */ public boolean validContextAgendaNamespace(AgendaEditor agendaEditor) { if (StringUtils.isNotBlank(agendaEditor.getNamespace()) && getContextBoService() .getContextByNameAndNamespace(agendaEditor.getContextName(), agendaEditor.getNamespace()) != null) { return true; } else { this.putFieldError(KRMSPropertyConstants.Context.NAMESPACE, "error.context.invalidNamespace"); return false; } } private boolean validAgendaTypeAndAttributes(AgendaEditor oldAgendaEditor, AgendaEditor newAgendaEditor) { if (validAgendaType(newAgendaEditor.getAgenda().getTypeId(), newAgendaEditor.getAgenda().getContextId())) { return validAgendaAttributes(oldAgendaEditor, newAgendaEditor); } else { return false; } } private boolean validAgendaType(String typeId, String contextId) { boolean isValid = true; if (!StringUtils.isBlank(typeId) && !StringUtils.isBlank(contextId)) { if (getKrmsTypeRepositoryService().getAgendaTypeByAgendaTypeIdAndContextId(typeId, contextId) != null) { return true; } else { this.putFieldError(KRMSPropertyConstants.Agenda.TYPE, "error.agenda.invalidType"); return false; } } return isValid; } private boolean validAgendaAttributes(AgendaEditor oldAgendaEditor, AgendaEditor newAgendaEditor) { boolean isValid = true; String typeId = newAgendaEditor.getAgenda().getTypeId(); if (!StringUtils.isEmpty(typeId)) { KrmsTypeDefinition typeDefinition = getKrmsTypeRepositoryService().getTypeById(typeId); if (typeDefinition == null) { throw new IllegalStateException("agenda typeId must match the id of a valid krms type"); } else if (StringUtils.isBlank(typeDefinition.getServiceName())) { throw new IllegalStateException("agenda type definition must have a non-blank service name"); } else { AgendaTypeService agendaTypeService = (AgendaTypeService) KrmsRepositoryServiceLocator .getService(typeDefinition.getServiceName()); if (agendaTypeService == null) { throw new IllegalStateException("typeDefinition must have a valid serviceName"); } else { List<RemotableAttributeError> errors; if (oldAgendaEditor == null) { errors = agendaTypeService.validateAttributes(typeId, newAgendaEditor.getCustomAttributesMap()); } else { errors = agendaTypeService.validateAttributesAgainstExisting(typeId, newAgendaEditor.getCustomAttributesMap(), oldAgendaEditor.getCustomAttributesMap()); } if (!CollectionUtils.isEmpty(errors)) { isValid = false; for (RemotableAttributeError error : errors) { for (String errorStr : error.getErrors()) { this.putFieldError(KRMSPropertyConstants.AgendaEditor.CUSTOM_ATTRIBUTES_MAP + "['" + error.getAttributeName() + "']", errorStr); } } } } } } return isValid; } /** * Check if an agenda with that name exists already in the context. * @param agendaEditor * @return true if agenda name is unique, false otherwise */ public boolean validAgendaName(AgendaEditor agendaEditor) { try { AgendaDefinition agendaFromDataBase = getAgendaBoService().getAgendaByNameAndContextId( agendaEditor.getAgenda().getName(), agendaEditor.getAgenda().getContextId()); if ((agendaFromDataBase != null) && !StringUtils.equals(agendaFromDataBase.getId(), agendaEditor.getAgenda().getId())) { this.putFieldError(KRMSPropertyConstants.Agenda.NAME, "error.agenda.duplicateName"); return false; } } catch (IllegalArgumentException e) { this.putFieldError(KRMSPropertyConstants.Agenda.NAME, "error.agenda.invalidName"); return false; } return true; } /** * Check if a agenda item is valid. * * @param document, the Agenda document of the added/edited agenda item * @return true if agenda item is valid, false otherwise */ public boolean processAgendaItemBusinessRules(MaintenanceDocument document) { boolean isValid = true; AgendaEditor newAgendaEditor = (AgendaEditor) document.getNewMaintainableObject().getDataObject(); AgendaEditor oldAgendaEditor = (AgendaEditor) document.getOldMaintainableObject().getDataObject(); RuleBo rule = newAgendaEditor.getAgendaItemLine().getRule(); isValid &= validateRuleName(rule, newAgendaEditor.getAgenda()); isValid &= validRuleType(rule.getTypeId(), newAgendaEditor.getAgenda().getContextId()); isValid &= validateRuleAction(oldAgendaEditor, newAgendaEditor); return isValid; } /** * Check if a rule with that name exists already in the namespace. * @param rule * @parm agenda * @return true if rule name is unique, false otherwise */ private boolean validateRuleName(RuleBo rule, AgendaBo agenda) { if (StringUtils.isBlank(rule.getName())) { this.putFieldError(KRMSPropertyConstants.Rule.NAME, "error.rule.invalidName"); return false; } // check current bo for rules (including ones that aren't persisted to the database) for (AgendaItemBo agendaItem : agenda.getItems()) { if (!StringUtils.equals(agendaItem.getRule().getId(), rule.getId()) && StringUtils.equals(agendaItem.getRule().getName(), rule.getName()) && StringUtils.equals(agendaItem.getRule().getNamespace(), rule.getNamespace())) { this.putFieldError(KRMSPropertyConstants.Rule.NAME, "error.rule.duplicateName"); return false; } } // check database for rules used with other agendas - the namespace might not yet be specified on new agendas. if (StringUtils.isNotBlank(rule.getNamespace())) { RuleDefinition ruleFromDatabase = getRuleBoService().getRuleByNameAndNamespace(rule.getName(), rule.getNamespace()); try { if ((ruleFromDatabase != null) && !StringUtils.equals(ruleFromDatabase.getId(), rule.getId())) { this.putFieldError(KRMSPropertyConstants.Rule.NAME, "error.rule.duplicateName"); return false; } } catch (IllegalArgumentException e) { this.putFieldError(KRMSPropertyConstants.Rule.NAME, "error.rule.invalidName"); return false; } } return true; } /** * Check that the rule type is valid when specified. * @param ruleTypeId, the type id * @param contextId, the contextId the action needs to belong to. * @return true if valid, false otherwise. */ private boolean validRuleType(String ruleTypeId, String contextId) { if (StringUtils.isBlank(ruleTypeId)) { return true; } if (getKrmsTypeRepositoryService().getRuleTypeByRuleTypeIdAndContextId(ruleTypeId, contextId) != null) { return true; } else { this.putFieldError(KRMSPropertyConstants.Rule.TYPE, "error.rule.invalidType"); return false; } } private boolean validateRuleAction(AgendaEditor oldAgendaEditor, AgendaEditor newAgendaEditor) { boolean isValid = true; ActionBo newActionBo = newAgendaEditor.getAgendaItemLineRuleAction(); isValid &= validRuleActionType(newActionBo.getTypeId(), newAgendaEditor.getAgenda().getContextId()); if (isValid && StringUtils.isNotBlank(newActionBo.getTypeId())) { isValid &= validRuleActionName(newActionBo.getName()); isValid &= validRuleActionAttributes(oldAgendaEditor, newAgendaEditor); } return isValid; } /** * Check that the rule action type is valid when specified. * @param typeId, the action type id * @parm contextId, the contextId the action needs to belong to. * @return true if valid, false otherwise. */ private boolean validRuleActionType(String typeId, String contextId) { if (StringUtils.isBlank(typeId)) { return true; } if (getKrmsTypeRepositoryService().getActionTypeByActionTypeIdAndContextId(typeId, contextId) != null) { return true; } else { this.putFieldError(KRMSPropertyConstants.Action.TYPE, "error.action.invalidType"); return false; } } /** * Check that a action name is specified. */ private boolean validRuleActionName(String name) { if (StringUtils.isNotBlank(name)) { return true; } else { this.putFieldError(KRMSPropertyConstants.Action.NAME, "error.action.missingName"); return false; } } private boolean validRuleActionAttributes(AgendaEditor oldAgendaEditor, AgendaEditor newAgendaEditor) { boolean isValid = true; String typeId = newAgendaEditor.getAgendaItemLineRuleAction().getTypeId(); if (!StringUtils.isBlank(typeId)) { KrmsTypeDefinition typeDefinition = getKrmsTypeRepositoryService().getTypeById(typeId); if (typeDefinition == null) { throw new IllegalStateException("rule action typeId must match the id of a valid krms type"); } else if (StringUtils.isBlank(typeDefinition.getServiceName())) { throw new IllegalStateException("rule action type definition must have a non-blank service name"); } else { ActionTypeService actionTypeService = getActionTypeService(typeDefinition.getServiceName()); if (actionTypeService == null) { throw new IllegalStateException("typeDefinition must have a valid serviceName"); } else { List<RemotableAttributeError> errors; if (oldAgendaEditor == null) { errors = actionTypeService.validateAttributes(typeId, newAgendaEditor.getCustomRuleActionAttributesMap()); } else { errors = actionTypeService.validateAttributesAgainstExisting(typeId, newAgendaEditor.getCustomRuleActionAttributesMap(), oldAgendaEditor.getCustomRuleActionAttributesMap()); } if (!CollectionUtils.isEmpty(errors)) { isValid = false; for (RemotableAttributeError error : errors) { for (String errorStr : error.getErrors()) { this.putFieldError( KRMSPropertyConstants.AgendaEditor.CUSTOM_RULE_ACTION_ATTRIBUTES_MAP + "['" + error.getAttributeName() + "']", errorStr); } } } } } } return isValid; } public ContextBoService getContextBoService() { return KrmsRepositoryServiceLocator.getContextBoService(); } public AgendaBoService getAgendaBoService() { return KrmsRepositoryServiceLocator.getAgendaBoService(); } public RuleBoService getRuleBoService() { return KrmsRepositoryServiceLocator.getRuleBoService(); } public KrmsTypeRepositoryService getKrmsTypeRepositoryService() { return KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService(); } public ActionTypeService getActionTypeService(String serviceName) { return (ActionTypeService) KrmsRepositoryServiceLocator.getService(serviceName); } public AgendaAuthorizationService getAgendaAuthorizationService() { return KrmsRepositoryServiceLocator.getAgendaAuthorizationService(); } }