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 termParmBldr.setValue(createAdhocCluSet(termParmBldr.getValue())); 171 } 172 } 173 propParmBldr.setTermValue(termBldr.build()); 174 } 175 } 176 if (PropositionType.COMPOUND.getCode().equals(propBldr.getPropositionTypeCode())) { 177 for (PropositionDefinition.Builder subPropBldr : propBldr.getCompoundComponents()) { 178 deepUpdateForProposition(subPropBldr); 179 } 180 } 181 } 182 183 private String createAdhocCluSet(String cluSetId) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException { 184 try { 185 //get the set to check if its an ad-hoc set 186 CluSetInfo cluSet = getCluService().getCluSet(cluSetId, ContextUtils.createDefaultContextInfo()); 187 188 //if not reusable, create a copy of the set and use that id in the term parameter value. 189 if(!cluSet.getIsReusable()){ 190 cluSet.setId(null); 191 //Clear clu ids if membership info exists, they will be re-added based on membership info 192 if (cluSet.getMembershipQuery() != null) { 193 cluSet.getCluIds().clear(); 194 cluSet.getCluSetIds().clear(); 195 } else { 196 List<String> subCluSetIds = new ArrayList<String>(); 197 for(String subCluSetid : cluSet.getCluSetIds()){ 198 subCluSetIds.add(createAdhocCluSet(subCluSetid)); 199 } 200 cluSet.setCluSetIds(subCluSetIds); 201 } 202 203 cluSet = getCluService().createCluSet(cluSet.getTypeKey(), cluSet, ContextUtils.createDefaultContextInfo()); 204 return cluSet.getId(); 205 } 206 } catch (DoesNotExistException e) { 207 throw new OperationFailedException(e.getMessage()); 208 } catch (UnsupportedActionException e) { 209 throw new OperationFailedException(e.getMessage()); 210 } catch (DataValidationErrorException e) { 211 throw new OperationFailedException(e.getMessage()); 212 } catch (ReadOnlyException e) { 213 throw new OperationFailedException(e.getMessage()); 214 } 215 return cluSetId; 216 } 217 218 @Override 219 public int deleteReferenceObjectBindingsCascade(String referenceDiscriminatorType, 220 String referenceObjectId) 221 throws RiceIllegalArgumentException, RiceIllegalStateException { 222 _checkEmptyParam(referenceDiscriminatorType, "referenceDiscriminatorType"); 223 _checkEmptyParam(referenceObjectId, "referenceObjectId"); 224 225 List<ReferenceObjectBinding> refsToDelete = this.getRuleManagementService().findReferenceObjectBindingsByReferenceObject(referenceDiscriminatorType, 226 referenceObjectId); 227 for (ReferenceObjectBinding refToDelete : refsToDelete) { 228 if (refToDelete.getKrmsDiscriminatorType().equals(KSKRMSServiceConstants.KRMS_DISCRIMINATOR_TYPE_AGENDA)) { 229 this._deleteAgendaCascade(refToDelete.getKrmsObjectId()); 230 } else { 231 throw new RiceIllegalStateException("unknown/unhandled KRMS discriminator type " + refToDelete.getKrmsDiscriminatorType()); 232 } 233 } 234 for (ReferenceObjectBinding refToDelete : refsToDelete) { 235 this.getRuleManagementService().deleteReferenceObjectBinding(refToDelete.getId()); 236 } 237 return refsToDelete.size(); 238 } 239 240 private int _deleteAgendaCascade(String agendaId) { 241 AgendaDefinition agenda = this.getRuleManagementService().getAgenda(agendaId); 242 this._deleteAgendaItemCascade(agenda.getFirstItemId()); 243 this.getRuleManagementService().deleteAgenda(agendaId); 244 return 1; 245 } 246 247 private int _deleteAgendaItemCascade(String agendaItemId) { 248 AgendaItemDefinition item = this.getRuleManagementService().getAgendaItem(agendaItemId); 249 if (item.getAlwaysId() != null) { 250 AgendaItemDefinition.Builder bldr = AgendaItemDefinition.Builder.create(item); 251 bldr.setAlways(null); 252 bldr.setAlwaysId(null); 253 this.getRuleManagementService().updateAgendaItem(bldr.build()); 254 this._deleteAgendaItemCascade(item.getAlwaysId()); 255 item = this.getRuleManagementService().getAgendaItem(agendaItemId); 256 } 257 if (item.getWhenTrueId() != null) { 258 AgendaItemDefinition.Builder bldr = AgendaItemDefinition.Builder.create(item); 259 bldr.setWhenTrue(null); 260 bldr.setWhenTrueId(null); 261 this.getRuleManagementService().updateAgendaItem(bldr.build()); 262 this._deleteAgendaItemCascade(item.getWhenTrueId()); 263 item = this.getRuleManagementService().getAgendaItem(agendaItemId); 264 } 265 if (item.getWhenFalseId() != null) { 266 AgendaItemDefinition.Builder bldr = AgendaItemDefinition.Builder.create(item); 267 bldr.setWhenFalse(null); 268 bldr.setWhenFalseId(null); 269 this.getRuleManagementService().updateAgendaItem(bldr.build()); 270 this._deleteAgendaItemCascade(item.getWhenFalseId()); 271 item = this.getRuleManagementService().getAgendaItem(agendaItemId); 272 } 273 if (item.getSubAgendaId() != null) { 274 this._deleteAgendaCascade(item.getSubAgendaId()); 275 } 276 if (item.getRuleId() != null) { 277 AgendaItemDefinition.Builder bldr = AgendaItemDefinition.Builder.create(item); 278 bldr.setRule(null); 279 bldr.setRuleId(null); 280 this.getRuleManagementService().updateAgendaItem(bldr.build()); 281 this._deleteRuleCascade(item.getRuleId()); 282 } 283 this.getRuleManagementService().deleteAgendaItem(agendaItemId); 284 return 1; 285 } 286 287 288 private int _deleteRuleCascade(String ruleId) { 289 RuleDefinition rule = this.getRuleManagementService().getRule(ruleId); 290 // we can stop here because delete rule does a cascade (I think it does) 291 this.getRuleManagementService().deleteRule(ruleId); 292 return 1; 293 } 294 295 private void _checkEmptyParam(String param, String message) 296 throws RiceIllegalArgumentException { 297 if (param == null) { 298 throw new RiceIllegalArgumentException(message); 299 } 300 if (param.trim().isEmpty()) { 301 throw new RiceIllegalArgumentException(message); 302 } 303 } 304 305 public RuleManagementService getRuleManagementService() { 306 if (ruleManagementService == null) { 307 ruleManagementService = (RuleManagementService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "ruleManagementService")); 308 } 309 return ruleManagementService; 310 } 311 312 public void setRuleManagementService(RuleManagementService ruleManagementService) { 313 this.ruleManagementService = ruleManagementService; 314 } 315 316 public TermRepositoryService getTermRepositoryService() { 317 if (termRepositoryService == null) { 318 termRepositoryService = (TermRepositoryService) GlobalResourceLoader.getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "termRepositoryService")); 319 } 320 return termRepositoryService; 321 } 322 323 public void setTermRepositoryService(TermRepositoryService termRepositoryService) { 324 this.termRepositoryService = termRepositoryService; 325 } 326 327 public CluService getCluService() { 328 if (cluService == null) { 329 cluService = (CluService) GlobalResourceLoader.getService(new QName(CluServiceConstants.NAMESPACE, "CluService")); 330 } 331 return cluService; 332 } 333 334 public void setCluService(CluService cluService) { 335 this.cluService = cluService; 336 } 337}