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.setName(refObjectId + ":" + oldAgenda.getTypeId() + ":1"); 095 AgendaDefinition copiedAgenda = getRuleManagementService().createAgenda(copiedAgendaBldr.build()); 096 097 AgendaItemDefinition.Builder firstAgendaItemBldr = null; 098 AgendaItemDefinition.Builder previousAgendaItemBldr = null; 099 boolean firstItem = true; 100 for (AgendaTreeEntryDefinitionContract entry : agendaTree.getEntries()) { 101 AgendaItemDefinition currentAgendaItem = getRuleManagementService().getAgendaItem(entry.getAgendaItemId()); 102 AgendaItemDefinition.Builder copiedAgendaItemBldr = AgendaItemDefinition.Builder.create(currentAgendaItem); 103 deepUpdateAgendaItem(copiedAgendaItemBldr, copiedAgenda.getId(), refObjectId); 104 if (firstItem) { 105 AgendaItemDefinition existingFirstItem = getRuleManagementService().getAgendaItem(copiedAgenda.getFirstItemId()); 106 copiedAgendaItemBldr.setId((copiedAgenda.getFirstItemId())); 107 copiedAgendaItemBldr.setVersionNumber(existingFirstItem.getVersionNumber()); 108 firstAgendaItemBldr = copiedAgendaItemBldr; 109 previousAgendaItemBldr = firstAgendaItemBldr; 110 } else { 111 copiedAgendaItemBldr.setId(null); 112 copiedAgendaItemBldr.setVersionNumber(null); 113 previousAgendaItemBldr.setWhenTrue(copiedAgendaItemBldr); 114 previousAgendaItemBldr = copiedAgendaItemBldr; 115 } 116 firstItem = false; 117 } 118 getRuleManagementService().updateAgendaItem(firstAgendaItemBldr.build()); 119 return copiedAgenda; 120 } 121 122 private void deepUpdateAgendaItem(AgendaItemDefinition.Builder copiedAgendaItemBldr, String copiedAgendaID, String refObjectId) throws MissingParameterException, PermissionDeniedException, InvalidParameterException, OperationFailedException { 123 copiedAgendaItemBldr.setId(null); 124 copiedAgendaItemBldr.setVersionNumber(null); 125 copiedAgendaItemBldr.setAgendaId(copiedAgendaID); 126 if (copiedAgendaItemBldr.getWhenTrueId() != null) { 127 deepUpdateAgendaItem(copiedAgendaItemBldr.getWhenTrue(), copiedAgendaID, refObjectId); 128 copiedAgendaItemBldr.setWhenTrueId(null); 129 } 130 if (copiedAgendaItemBldr.getWhenFalseId() != null) { 131 deepUpdateAgendaItem(copiedAgendaItemBldr.getWhenFalse(), copiedAgendaID, refObjectId); 132 copiedAgendaItemBldr.setWhenFalseId(null); 133 } 134 if (copiedAgendaItemBldr.getAlwaysId() != null) { 135 deepUpdateAgendaItem(copiedAgendaItemBldr.getAlways(), copiedAgendaID, refObjectId); 136 copiedAgendaItemBldr.setAlwaysId(null); 137 } 138 copiedAgendaItemBldr.setRuleId(null); 139 RuleDefinition.Builder copiedRuleBldr = copiedAgendaItemBldr.getRule(); 140 copiedRuleBldr.setId(null); 141 copiedRuleBldr.setVersionNumber(null); 142 copiedRuleBldr.setPropId(null); 143 copiedRuleBldr.setName(refObjectId + ":" + copiedRuleBldr.getTypeId() + ":1"); 144 if (copiedRuleBldr.getProposition() != null){ 145 deepUpdateForProposition(copiedRuleBldr.getProposition()); 146 } 147 148 } 149 150 private void deepUpdateForProposition(PropositionDefinition.Builder propBldr) throws PermissionDeniedException, MissingParameterException, InvalidParameterException, OperationFailedException { 151 propBldr.setId(null); 152 propBldr.setRuleId(null); 153 for (PropositionParameter.Builder propParmBldr : propBldr.getParameters()) { 154 propParmBldr.setId(null); 155 propParmBldr.setPropId(null); 156 if (PropositionParameterType.TERM.getCode().equals(propParmBldr.getParameterType())) { 157 TermDefinition termDef = null; 158 if (propParmBldr.getTermValue() != null) { 159 termDef = propParmBldr.getTermValue(); 160 } else { 161 termDef = getTermRepositoryService().getTerm(propParmBldr.getValue()); 162 } 163 propParmBldr.setValue(null); 164 TermDefinition.Builder termBldr = TermDefinition.Builder.create(termDef); 165 termBldr.setId(null); 166 for (TermParameterDefinition.Builder termParmBldr : termBldr.getParameters()) { 167 termParmBldr.setId(null); 168 termParmBldr.setTermId(null); 169 if (TermParameterTypes.COURSE_CLUSET_KEY.getId().equals(termParmBldr.getName()) || TermParameterTypes.PROGRAM_CLUSET_KEY.getId().equals(termParmBldr.getName()) || TermParameterTypes.CLUSET_KEY.getId().equals(termParmBldr.getName())) { 170 try { 171 //get the set to check if its an ad-hoc set 172 CluSetInfo cluSet = getCluService().getCluSet(termParmBldr.getValue(), ContextUtils.createDefaultContextInfo()); 173 174 //if not reusable, create a copy of the set and use that id in the term parameter value. 175 if(!cluSet.getIsReusable()){ 176 cluSet.setId(null); 177 //Clear clu ids if membership info exists, they will be re-added based on membership info 178 if (cluSet.getMembershipQuery() != null) { 179 cluSet.getCluIds().clear(); 180 cluSet.getCluSetIds().clear(); 181 } 182 183 cluSet = getCluService().createCluSet(cluSet.getTypeKey(), cluSet, ContextUtils.createDefaultContextInfo()); 184 termParmBldr.setValue(cluSet.getId()); 185 } 186 } catch (DoesNotExistException e) { 187 throw new OperationFailedException(e.getMessage()); 188 } catch (UnsupportedActionException e) { 189 throw new OperationFailedException(e.getMessage()); 190 } catch (DataValidationErrorException e) { 191 throw new OperationFailedException(e.getMessage()); 192 } catch (ReadOnlyException e) { 193 throw new OperationFailedException(e.getMessage()); 194 } 195 196 } 197 } 198 propParmBldr.setTermValue(termBldr.build()); 199 } 200 } 201 if (PropositionType.COMPOUND.getCode().equals(propBldr.getPropositionTypeCode())) { 202 for (PropositionDefinition.Builder subPropBldr : propBldr.getCompoundComponents()) { 203 deepUpdateForProposition(subPropBldr); 204 } 205 } 206 } 207 208 @Override 209 public int deleteReferenceObjectBindingsCascade(String referenceDiscriminatorType, 210 String referenceObjectId) 211 throws RiceIllegalArgumentException, RiceIllegalStateException { 212 _checkEmptyParam(referenceDiscriminatorType, "referenceDiscriminatorType"); 213 _checkEmptyParam(referenceObjectId, "referenceObjectId"); 214 215 List<ReferenceObjectBinding> refsToDelete = this.getRuleManagementService().findReferenceObjectBindingsByReferenceObject(referenceDiscriminatorType, 216 referenceObjectId); 217 for (ReferenceObjectBinding refToDelete : refsToDelete) { 218 if (refToDelete.getKrmsDiscriminatorType().equals(KSKRMSServiceConstants.KRMS_DISCRIMINATOR_TYPE_AGENDA)) { 219 this._deleteAgendaCascade(refToDelete.getKrmsObjectId()); 220 } else { 221 throw new RiceIllegalStateException("unknown/unhandled KRMS discriminator type " + refToDelete.getKrmsDiscriminatorType()); 222 } 223 } 224 for (ReferenceObjectBinding refToDelete : refsToDelete) { 225 this.getRuleManagementService().deleteReferenceObjectBinding(refToDelete.getId()); 226 } 227 return refsToDelete.size(); 228 } 229 230 private int _deleteAgendaCascade(String agendaId) { 231 AgendaDefinition agenda = this.getRuleManagementService().getAgenda(agendaId); 232 this._deleteAgendaItemCascade(agenda.getFirstItemId()); 233 this.getRuleManagementService().deleteAgenda(agendaId); 234 return 1; 235 } 236 237 private int _deleteAgendaItemCascade(String agendaItemId) { 238 AgendaItemDefinition item = this.getRuleManagementService().getAgendaItem(agendaItemId); 239 if (item.getAlwaysId() != null) { 240 AgendaItemDefinition.Builder bldr = AgendaItemDefinition.Builder.create(item); 241 bldr.setAlways(null); 242 bldr.setAlwaysId(null); 243 this.getRuleManagementService().updateAgendaItem(bldr.build()); 244 this._deleteAgendaItemCascade(item.getAlwaysId()); 245 item = this.getRuleManagementService().getAgendaItem(agendaItemId); 246 } 247 if (item.getWhenTrueId() != null) { 248 AgendaItemDefinition.Builder bldr = AgendaItemDefinition.Builder.create(item); 249 bldr.setWhenTrue(null); 250 bldr.setWhenTrueId(null); 251 this.getRuleManagementService().updateAgendaItem(bldr.build()); 252 this._deleteAgendaItemCascade(item.getWhenTrueId()); 253 item = this.getRuleManagementService().getAgendaItem(agendaItemId); 254 } 255 if (item.getWhenFalseId() != null) { 256 AgendaItemDefinition.Builder bldr = AgendaItemDefinition.Builder.create(item); 257 bldr.setWhenFalse(null); 258 bldr.setWhenFalseId(null); 259 this.getRuleManagementService().updateAgendaItem(bldr.build()); 260 this._deleteAgendaItemCascade(item.getWhenFalseId()); 261 item = this.getRuleManagementService().getAgendaItem(agendaItemId); 262 } 263 if (item.getSubAgendaId() != null) { 264 this._deleteAgendaCascade(item.getSubAgendaId()); 265 } 266 if (item.getRuleId() != null) { 267 AgendaItemDefinition.Builder bldr = AgendaItemDefinition.Builder.create(item); 268 bldr.setRule(null); 269 bldr.setRuleId(null); 270 this.getRuleManagementService().updateAgendaItem(bldr.build()); 271 this._deleteRuleCascade(item.getRuleId()); 272 } 273 this.getRuleManagementService().deleteAgendaItem(agendaItemId); 274 return 1; 275 } 276 277 278 private int _deleteRuleCascade(String ruleId) { 279 RuleDefinition rule = this.getRuleManagementService().getRule(ruleId); 280 // we can stop here because delete rule does a cascade (I think it does) 281 this.getRuleManagementService().deleteRule(ruleId); 282 return 1; 283 } 284 285 private void _checkEmptyParam(String param, String message) 286 throws RiceIllegalArgumentException { 287 if (param == null) { 288 throw new RiceIllegalArgumentException(message); 289 } 290 if (param.trim().isEmpty()) { 291 throw new RiceIllegalArgumentException(message); 292 } 293 } 294 295 public RuleManagementService getRuleManagementService() { 296 if (ruleManagementService == null) { 297 ruleManagementService = (RuleManagementService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "ruleManagementService")); 298 } 299 return ruleManagementService; 300 } 301 302 public void setRuleManagementService(RuleManagementService ruleManagementService) { 303 this.ruleManagementService = ruleManagementService; 304 } 305 306 public TermRepositoryService getTermRepositoryService() { 307 if (termRepositoryService == null) { 308 termRepositoryService = (TermRepositoryService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "termRepositoryService")); 309 } 310 return termRepositoryService; 311 } 312 313 public void setTermRepositoryService(TermRepositoryService termRepositoryService) { 314 this.termRepositoryService = termRepositoryService; 315 } 316 317 public CluService getCluService() { 318 if (cluService == null) { 319 cluService = (CluService) GlobalResourceLoader.getService(new QName(CluServiceConstants.NAMESPACE, "CluService")); 320 } 321 return cluService; 322 } 323 324 public void setCluService(CluService cluService) { 325 this.cluService = cluService; 326 } 327}