View Javadoc
1   package org.kuali.rice.krms.impl.util;
2   
3   import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
4   import org.kuali.rice.core.api.exception.RiceIllegalStateException;
5   import org.kuali.rice.krms.api.repository.RuleManagementService;
6   import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
7   import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition;
8   import org.kuali.rice.krms.api.repository.agenda.AgendaTreeDefinition;
9   import org.kuali.rice.krms.api.repository.agenda.AgendaTreeEntryDefinitionContract;
10  import org.kuali.rice.krms.api.repository.proposition.PropositionDefinition;
11  import org.kuali.rice.krms.api.repository.proposition.PropositionParameter;
12  import org.kuali.rice.krms.api.repository.proposition.PropositionParameterType;
13  import org.kuali.rice.krms.api.repository.proposition.PropositionType;
14  import org.kuali.rice.krms.api.repository.reference.ReferenceObjectBinding;
15  import org.kuali.rice.krms.api.repository.rule.RuleDefinition;
16  import org.kuali.rice.krms.api.repository.term.TermDefinition;
17  import org.kuali.rice.krms.api.repository.term.TermParameterDefinition;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  import javax.xml.namespace.QName;
22  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
23  import org.kuali.rice.krms.api.KrmsConstants;
24  import org.kuali.rice.krms.api.repository.term.TermRepositoryService;
25  import org.kuali.student.r2.common.exceptions.DataValidationErrorException;
26  import org.kuali.student.r2.common.exceptions.DoesNotExistException;
27  import org.kuali.student.r2.common.exceptions.InvalidParameterException;
28  import org.kuali.student.r2.common.exceptions.MissingParameterException;
29  import org.kuali.student.r2.common.exceptions.OperationFailedException;
30  import org.kuali.student.r2.common.exceptions.PermissionDeniedException;
31  import org.kuali.student.r2.common.exceptions.ReadOnlyException;
32  import org.kuali.student.r2.common.exceptions.UnsupportedActionException;
33  import org.kuali.student.common.util.security.ContextUtils;
34  import org.kuali.student.r2.core.constants.KSKRMSServiceConstants;
35  import org.kuali.student.r2.core.krms.naturallanguage.TermParameterTypes;
36  import org.kuali.student.r2.lum.clu.dto.CluSetInfo;
37  import org.kuali.student.r2.lum.clu.service.CluService;
38  import org.kuali.student.r2.lum.util.constants.CluServiceConstants;
39  
40  /**
41   * This class contains the copy logic for copying object references from one object to another
42   *
43   * @author christoff
44   */
45  public class KrmsRuleManagementCopyMethodsImpl implements KrmsRuleManagementCopyMethods {
46  
47      private RuleManagementService ruleManagementService;
48      private TermRepositoryService termRepositoryService;
49      private CluService cluService;
50  
51      @Override
52      public List<ReferenceObjectBinding> deepCopyReferenceObjectBindingsFromTo(String fromReferenceDiscriminatorType,
53                                                                                String fromReferenceObjectId,
54                                                                                String toReferenceDiscriminatorType,
55                                                                                String toReferenceObjectId,
56                                                                                List<String> optionKeys)
57              throws RiceIllegalArgumentException,
58              RiceIllegalStateException, PermissionDeniedException, MissingParameterException, InvalidParameterException, OperationFailedException {
59          _checkEmptyParam(fromReferenceDiscriminatorType, "fromReferenceDiscriminatorType");
60          _checkEmptyParam(fromReferenceObjectId, "fromReferenceObjectId");
61          _checkEmptyParam(toReferenceDiscriminatorType, "toReferenceDiscriminatorType");
62          _checkEmptyParam(toReferenceObjectId, "toReferenceObjectId");
63          List<ReferenceObjectBinding> copiedRefList = new ArrayList<ReferenceObjectBinding>();
64          List<ReferenceObjectBinding> refsToCopy = this.getRuleManagementService().findReferenceObjectBindingsByReferenceObject(fromReferenceDiscriminatorType, fromReferenceObjectId);
65          for (ReferenceObjectBinding reference : refsToCopy) {
66              ReferenceObjectBinding.Builder refBldr = null;
67              //At the moment we only support agendas.
68              if (reference.getKrmsDiscriminatorType().equals(KSKRMSServiceConstants.KRMS_DISCRIMINATOR_TYPE_AGENDA)) {
69                  AgendaTreeDefinition agendaTree = getRuleManagementService().getAgendaTree(reference.getKrmsObjectId());
70  
71                  AgendaDefinition copiedAgenda = deepCopyAgenda(agendaTree, toReferenceObjectId);
72                  refBldr = ReferenceObjectBinding.Builder.create(reference);
73                  refBldr.setId(null);
74                  refBldr.setVersionNumber(null);
75                  refBldr.setReferenceObjectId(toReferenceObjectId);
76                  refBldr.setReferenceDiscriminatorType(toReferenceDiscriminatorType);
77                  refBldr.setKrmsObjectId(copiedAgenda.getId());
78              } else {
79                  //no support for copying any other krms types yet
80                  throw new RiceIllegalStateException("unknown/unhandled KRMS discriminator type " + reference.getKrmsDiscriminatorType());
81              }
82              ReferenceObjectBinding refBinding = getRuleManagementService().createReferenceObjectBinding(refBldr.build());
83              copiedRefList.add(refBinding);
84          }
85          return copiedRefList;
86      }
87  
88      private AgendaDefinition deepCopyAgenda(AgendaTreeDefinition agendaTree, String refObjectId) throws MissingParameterException, InvalidParameterException, OperationFailedException, PermissionDeniedException {
89          //clone the Agenda
90          AgendaDefinition oldAgenda = getRuleManagementService().getAgenda(agendaTree.getAgendaId());
91          AgendaDefinition.Builder copiedAgendaBldr = AgendaDefinition.Builder.create(oldAgenda);
92          copiedAgendaBldr.setId(null);
93          copiedAgendaBldr.setVersionNumber(null);
94          copiedAgendaBldr.setFirstItemId(null);
95          copiedAgendaBldr.setName(refObjectId + ":" + oldAgenda.getTypeId() + ":1");
96          AgendaDefinition copiedAgenda = getRuleManagementService().createAgenda(copiedAgendaBldr.build());
97  
98          AgendaItemDefinition.Builder previousAgendaItemBldr = null;
99          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 }