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