001package org.kuali.rice.krms.impl.util; 002 003import org.kuali.rice.core.api.exception.RiceIllegalArgumentException; 004import org.kuali.rice.core.api.exception.RiceIllegalStateException; 005import org.kuali.rice.krms.api.repository.RuleManagementService; 006import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition; 007import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition; 008import org.kuali.rice.krms.api.repository.agenda.AgendaTreeDefinition; 009import org.kuali.rice.krms.api.repository.agenda.AgendaTreeEntryDefinitionContract; 010import org.kuali.rice.krms.api.repository.proposition.PropositionDefinition; 011import org.kuali.rice.krms.api.repository.proposition.PropositionParameter; 012import org.kuali.rice.krms.api.repository.proposition.PropositionParameterType; 013import org.kuali.rice.krms.api.repository.proposition.PropositionType; 014import org.kuali.rice.krms.api.repository.reference.ReferenceObjectBinding; 015import org.kuali.rice.krms.api.repository.rule.RuleDefinition; 016import org.kuali.rice.krms.api.repository.term.TermDefinition; 017import org.kuali.rice.krms.api.repository.term.TermParameterDefinition; 018 019import java.util.ArrayList; 020import java.util.List; 021import javax.xml.namespace.QName; 022import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; 023import org.kuali.rice.krms.api.KrmsConstants; 024import org.kuali.rice.krms.api.repository.term.TermRepositoryService; 025import org.kuali.student.r2.common.exceptions.DataValidationErrorException; 026import org.kuali.student.r2.common.exceptions.DoesNotExistException; 027import org.kuali.student.r2.common.exceptions.InvalidParameterException; 028import org.kuali.student.r2.common.exceptions.MissingParameterException; 029import org.kuali.student.r2.common.exceptions.OperationFailedException; 030import org.kuali.student.r2.common.exceptions.PermissionDeniedException; 031import org.kuali.student.r2.common.exceptions.ReadOnlyException; 032import org.kuali.student.r2.common.exceptions.UnsupportedActionException; 033import org.kuali.student.r2.common.util.ContextUtils; 034import org.kuali.student.r2.core.constants.KSKRMSServiceConstants; 035import org.kuali.student.r2.core.krms.naturallanguage.TermParameterTypes; 036import org.kuali.student.r2.lum.clu.dto.CluSetInfo; 037import org.kuali.student.r2.lum.clu.service.CluService; 038import org.kuali.student.r2.lum.util.constants.CluServiceConstants; 039 040/** 041 * This class contains the copy logic for copying object references from one object to another 042 * 043 * @author christoff 044 */ 045public class KrmsRuleManagementCopyMethodsImpl implements KrmsRuleManagementCopyMethods { 046 047 private RuleManagementService ruleManagementService; 048 private TermRepositoryService termRepositoryService; 049 private CluService cluService; 050 051 @Override 052 public List<ReferenceObjectBinding> deepCopyReferenceObjectBindingsFromTo(String fromReferenceDiscriminatorType, 053 String fromReferenceObjectId, 054 String toReferenceDiscriminatorType, 055 String toReferenceObjectId, 056 List<String> optionKeys) 057 throws RiceIllegalArgumentException, 058 RiceIllegalStateException, PermissionDeniedException, MissingParameterException, InvalidParameterException, OperationFailedException { 059 _checkEmptyParam(fromReferenceDiscriminatorType, "fromReferenceDiscriminatorType"); 060 _checkEmptyParam(fromReferenceObjectId, "fromReferenceObjectId"); 061 _checkEmptyParam(toReferenceDiscriminatorType, "toReferenceDiscriminatorType"); 062 _checkEmptyParam(toReferenceObjectId, "toReferenceObjectId"); 063 List<ReferenceObjectBinding> copiedRefList = new ArrayList<ReferenceObjectBinding>(); 064 List<ReferenceObjectBinding> refsToCopy = this.getRuleManagementService().findReferenceObjectBindingsByReferenceObject(fromReferenceDiscriminatorType, fromReferenceObjectId); 065 for (ReferenceObjectBinding reference : refsToCopy) { 066 ReferenceObjectBinding.Builder refBldr = null; 067 //At the moment we only support agendas. 068 if (reference.getKrmsDiscriminatorType().equals(KSKRMSServiceConstants.KRMS_DISCRIMINATOR_TYPE_AGENDA)) { 069 AgendaTreeDefinition agendaTree = getRuleManagementService().getAgendaTree(reference.getKrmsObjectId()); 070 071 AgendaDefinition copiedAgenda = deepCopyAgenda(agendaTree, toReferenceObjectId); 072 refBldr = ReferenceObjectBinding.Builder.create(reference); 073 refBldr.setId(null); 074 refBldr.setVersionNumber(null); 075 refBldr.setReferenceObjectId(toReferenceObjectId); 076 refBldr.setReferenceDiscriminatorType(toReferenceDiscriminatorType); 077 refBldr.setKrmsObjectId(copiedAgenda.getId()); 078 } else { 079 //no support for copying any other krms types yet 080 throw new RiceIllegalStateException("unknown/unhandled KRMS discriminator type " + reference.getKrmsDiscriminatorType()); 081 } 082 ReferenceObjectBinding refBinding = getRuleManagementService().createReferenceObjectBinding(refBldr.build()); 083 copiedRefList.add(refBinding); 084 } 085 return copiedRefList; 086 } 087 088 private AgendaDefinition deepCopyAgenda(AgendaTreeDefinition agendaTree, String refObjectId) throws MissingParameterException, InvalidParameterException, OperationFailedException, PermissionDeniedException { 089 //clone the Agenda 090 AgendaDefinition oldAgenda = getRuleManagementService().getAgenda(agendaTree.getAgendaId()); 091 AgendaDefinition.Builder copiedAgendaBldr = AgendaDefinition.Builder.create(oldAgenda); 092 copiedAgendaBldr.setId(null); 093 copiedAgendaBldr.setVersionNumber(null); 094 copiedAgendaBldr.setFirstItemId(null); 095 copiedAgendaBldr.setName(refObjectId + ":" + oldAgenda.getTypeId() + ":1"); 096 AgendaDefinition copiedAgenda = getRuleManagementService().createAgenda(copiedAgendaBldr.build()); 097 098 AgendaItemDefinition.Builder previousAgendaItemBldr = null; 099 AgendaItemDefinition.Builder firstAgendaItemBldr = AgendaItemDefinition.Builder.create(null, copiedAgenda.getId()); 100 AgendaItemDefinition firstAgendaItem = getRuleManagementService().createAgendaItem(firstAgendaItemBldr.build()); 101 copiedAgendaBldr = AgendaDefinition.Builder.create(copiedAgenda); 102 copiedAgendaBldr.setFirstItemId(firstAgendaItem.getId()); 103 getRuleManagementService().updateAgenda(copiedAgendaBldr.build()); 104 copiedAgenda = getRuleManagementService().getAgenda(copiedAgenda.getId()); 105 106 boolean isFirstItem = true; 107 for (AgendaTreeEntryDefinitionContract entry : agendaTree.getEntries()) { 108 AgendaItemDefinition currentAgendaItem = getRuleManagementService().getAgendaItem(entry.getAgendaItemId()); 109 AgendaItemDefinition.Builder copiedAgendaItemBldr = AgendaItemDefinition.Builder.create(currentAgendaItem); 110 deepUpdateAgendaItem(copiedAgendaItemBldr, copiedAgenda.getId(), refObjectId); 111 if (isFirstItem) { 112 copiedAgendaItemBldr.setId(firstAgendaItem.getId()); 113 copiedAgendaItemBldr.setVersionNumber(firstAgendaItem.getVersionNumber()); 114 firstAgendaItemBldr = copiedAgendaItemBldr; 115 previousAgendaItemBldr = firstAgendaItemBldr; 116 isFirstItem = false; 117 } else { 118 copiedAgendaItemBldr.setId(null); 119 copiedAgendaItemBldr.setVersionNumber(null); 120 previousAgendaItemBldr.setWhenTrue(copiedAgendaItemBldr); 121 previousAgendaItemBldr = copiedAgendaItemBldr; 122 } 123 } 124 getRuleManagementService().updateAgendaItem(firstAgendaItemBldr.build()); 125 return copiedAgenda; 126 } 127 128 private void deepUpdateAgendaItem(AgendaItemDefinition.Builder copiedAgendaItemBldr, String copiedAgendaID, String refObjectId) throws MissingParameterException, PermissionDeniedException, InvalidParameterException, OperationFailedException { 129 copiedAgendaItemBldr.setId(null); 130 copiedAgendaItemBldr.setVersionNumber(null); 131 copiedAgendaItemBldr.setAgendaId(copiedAgendaID); 132 if (copiedAgendaItemBldr.getWhenTrueId() != null) { 133 deepUpdateAgendaItem(copiedAgendaItemBldr.getWhenTrue(), copiedAgendaID, refObjectId); 134 copiedAgendaItemBldr.setWhenTrueId(null); 135 } 136 if (copiedAgendaItemBldr.getWhenFalseId() != null) { 137 deepUpdateAgendaItem(copiedAgendaItemBldr.getWhenFalse(), copiedAgendaID, refObjectId); 138 copiedAgendaItemBldr.setWhenFalseId(null); 139 } 140 if (copiedAgendaItemBldr.getAlwaysId() != null) { 141 deepUpdateAgendaItem(copiedAgendaItemBldr.getAlways(), copiedAgendaID, refObjectId); 142 copiedAgendaItemBldr.setAlwaysId(null); 143 } 144 copiedAgendaItemBldr.setRuleId(null); 145 RuleDefinition.Builder copiedRuleBldr = copiedAgendaItemBldr.getRule(); 146 copiedRuleBldr.setId(null); 147 copiedRuleBldr.setVersionNumber(null); 148 copiedRuleBldr.setPropId(null); 149 copiedRuleBldr.setName(refObjectId + ":" + copiedRuleBldr.getTypeId() + ":1"); 150 if (copiedRuleBldr.getProposition() != null){ 151 deepUpdateForProposition(copiedRuleBldr.getProposition()); 152 } 153 154 } 155 156 private void deepUpdateForProposition(PropositionDefinition.Builder propBldr) throws PermissionDeniedException, MissingParameterException, InvalidParameterException, OperationFailedException { 157 propBldr.setId(null); 158 propBldr.setRuleId(null); 159 for (PropositionParameter.Builder propParmBldr : propBldr.getParameters()) { 160 propParmBldr.setId(null); 161 propParmBldr.setPropId(null); 162 if (PropositionParameterType.TERM.getCode().equals(propParmBldr.getParameterType())) { 163 TermDefinition termDef = null; 164 if (propParmBldr.getTermValue() != null) { 165 termDef = propParmBldr.getTermValue(); 166 } else { 167 termDef = getTermRepositoryService().getTerm(propParmBldr.getValue()); 168 } 169 propParmBldr.setValue(null); 170 TermDefinition.Builder termBldr = TermDefinition.Builder.create(termDef); 171 termBldr.setId(null); 172 for (TermParameterDefinition.Builder termParmBldr : termBldr.getParameters()) { 173 termParmBldr.setId(null); 174 termParmBldr.setTermId(null); 175 if (TermParameterTypes.COURSE_CLUSET_KEY.getId().equals(termParmBldr.getName()) || TermParameterTypes.PROGRAM_CLUSET_KEY.getId().equals(termParmBldr.getName()) || TermParameterTypes.CLUSET_KEY.getId().equals(termParmBldr.getName())) { 176 termParmBldr.setValue(createAdhocCluSet(termParmBldr.getValue())); 177 } 178 } 179 propParmBldr.setTermValue(termBldr.build()); 180 } 181 } 182 if (PropositionType.COMPOUND.getCode().equals(propBldr.getPropositionTypeCode())) { 183 for (PropositionDefinition.Builder subPropBldr : propBldr.getCompoundComponents()) { 184 deepUpdateForProposition(subPropBldr); 185 } 186 } 187 } 188 189 private String createAdhocCluSet(String cluSetId) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException { 190 try { 191 //get the set to check if its an ad-hoc set 192 CluSetInfo cluSet = getCluService().getCluSet(cluSetId, ContextUtils.createDefaultContextInfo()); 193 194 //if not reusable, create a copy of the set and use that id in the term parameter value. 195 if(!cluSet.getIsReusable()){ 196 cluSet.setId(null); 197 //Clear clu ids if membership info exists, they will be re-added based on membership info 198 if (cluSet.getMembershipQuery() != null) { 199 cluSet.getCluIds().clear(); 200 cluSet.getCluSetIds().clear(); 201 } else { 202 List<String> subCluSetIds = new ArrayList<String>(); 203 for(String subCluSetid : cluSet.getCluSetIds()){ 204 subCluSetIds.add(createAdhocCluSet(subCluSetid)); 205 } 206 cluSet.setCluSetIds(subCluSetIds); 207 } 208 209 cluSet = getCluService().createCluSet(cluSet.getTypeKey(), cluSet, ContextUtils.createDefaultContextInfo()); 210 return cluSet.getId(); 211 } 212 } catch (DoesNotExistException e) { 213 throw new OperationFailedException(e.getMessage()); 214 } catch (UnsupportedActionException e) { 215 throw new OperationFailedException(e.getMessage()); 216 } catch (DataValidationErrorException e) { 217 throw new OperationFailedException(e.getMessage()); 218 } catch (ReadOnlyException e) { 219 throw new OperationFailedException(e.getMessage()); 220 } 221 return cluSetId; 222 } 223 224 @Override 225 public int deleteReferenceObjectBindingsCascade(String referenceDiscriminatorType, 226 String referenceObjectId) 227 throws RiceIllegalArgumentException, RiceIllegalStateException { 228 _checkEmptyParam(referenceDiscriminatorType, "referenceDiscriminatorType"); 229 _checkEmptyParam(referenceObjectId, "referenceObjectId"); 230 231 List<ReferenceObjectBinding> refsToDelete = this.getRuleManagementService().findReferenceObjectBindingsByReferenceObject(referenceDiscriminatorType, 232 referenceObjectId); 233 for (ReferenceObjectBinding refToDelete : refsToDelete) { 234 if (refToDelete.getKrmsDiscriminatorType().equals(KSKRMSServiceConstants.KRMS_DISCRIMINATOR_TYPE_AGENDA)) { 235 this._deleteAgendaCascade(refToDelete.getKrmsObjectId()); 236 } else { 237 throw new RiceIllegalStateException("unknown/unhandled KRMS discriminator type " + refToDelete.getKrmsDiscriminatorType()); 238 } 239 } 240 for (ReferenceObjectBinding refToDelete : refsToDelete) { 241 this.getRuleManagementService().deleteReferenceObjectBinding(refToDelete.getId()); 242 } 243 return refsToDelete.size(); 244 } 245 246 private int _deleteAgendaCascade(String agendaId) { 247 AgendaDefinition agenda = this.getRuleManagementService().getAgenda(agendaId); 248 this._deleteAgendaItemCascade(agenda.getFirstItemId()); 249 this.getRuleManagementService().deleteAgenda(agendaId); 250 return 1; 251 } 252 253 private int _deleteAgendaItemCascade(String agendaItemId) { 254 AgendaItemDefinition item = this.getRuleManagementService().getAgendaItem(agendaItemId); 255 if (item.getAlwaysId() != null) { 256 AgendaItemDefinition.Builder bldr = AgendaItemDefinition.Builder.create(item); 257 bldr.setAlways(null); 258 bldr.setAlwaysId(null); 259 this.getRuleManagementService().updateAgendaItem(bldr.build()); 260 this._deleteAgendaItemCascade(item.getAlwaysId()); 261 item = this.getRuleManagementService().getAgendaItem(agendaItemId); 262 } 263 if (item.getWhenTrueId() != null) { 264 AgendaItemDefinition.Builder bldr = AgendaItemDefinition.Builder.create(item); 265 bldr.setWhenTrue(null); 266 bldr.setWhenTrueId(null); 267 this.getRuleManagementService().updateAgendaItem(bldr.build()); 268 this._deleteAgendaItemCascade(item.getWhenTrueId()); 269 item = this.getRuleManagementService().getAgendaItem(agendaItemId); 270 } 271 if (item.getWhenFalseId() != null) { 272 AgendaItemDefinition.Builder bldr = AgendaItemDefinition.Builder.create(item); 273 bldr.setWhenFalse(null); 274 bldr.setWhenFalseId(null); 275 this.getRuleManagementService().updateAgendaItem(bldr.build()); 276 this._deleteAgendaItemCascade(item.getWhenFalseId()); 277 item = this.getRuleManagementService().getAgendaItem(agendaItemId); 278 } 279 if (item.getSubAgendaId() != null) { 280 this._deleteAgendaCascade(item.getSubAgendaId()); 281 } 282 if (item.getRuleId() != null) { 283 AgendaItemDefinition.Builder bldr = AgendaItemDefinition.Builder.create(item); 284 bldr.setRule(null); 285 bldr.setRuleId(null); 286 this.getRuleManagementService().updateAgendaItem(bldr.build()); 287 this._deleteRuleCascade(item.getRuleId()); 288 } 289 this.getRuleManagementService().deleteAgendaItem(agendaItemId); 290 return 1; 291 } 292 293 294 private int _deleteRuleCascade(String ruleId) { 295 RuleDefinition rule = this.getRuleManagementService().getRule(ruleId); 296 // we can stop here because delete rule does a cascade (I think it does) 297 this.getRuleManagementService().deleteRule(ruleId); 298 return 1; 299 } 300 301 private void _checkEmptyParam(String param, String message) 302 throws RiceIllegalArgumentException { 303 if (param == null) { 304 throw new RiceIllegalArgumentException(message); 305 } 306 if (param.trim().isEmpty()) { 307 throw new RiceIllegalArgumentException(message); 308 } 309 } 310 311 public RuleManagementService getRuleManagementService() { 312 if (ruleManagementService == null) { 313 ruleManagementService = (RuleManagementService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "ruleManagementService")); 314 } 315 return ruleManagementService; 316 } 317 318 public void setRuleManagementService(RuleManagementService ruleManagementService) { 319 this.ruleManagementService = ruleManagementService; 320 } 321 322 public TermRepositoryService getTermRepositoryService() { 323 if (termRepositoryService == null) { 324 termRepositoryService = (TermRepositoryService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "termRepositoryService")); 325 } 326 return termRepositoryService; 327 } 328 329 public void setTermRepositoryService(TermRepositoryService termRepositoryService) { 330 this.termRepositoryService = termRepositoryService; 331 } 332 333 public CluService getCluService() { 334 if (cluService == null) { 335 cluService = (CluService) GlobalResourceLoader.getService(new QName(CluServiceConstants.NAMESPACE, "CluService")); 336 } 337 return cluService; 338 } 339 340 public void setCluService(CluService cluService) { 341 this.cluService = cluService; 342 } 343}