View Javadoc
1   /**
2    * Copyright 2014 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   *
15   * Created by venkat on 3/13/14
16   */
17  package org.kuali.student.cm.maintenance;
18  
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.rice.kew.api.WorkflowDocument;
21  import org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent;
22  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange;
23  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
24  import org.kuali.rice.krad.maintenance.Maintainable;
25  import org.kuali.rice.krad.maintenance.MaintenanceDocumentBase;
26  import org.kuali.rice.krad.rules.rule.event.BlanketApproveDocumentEvent;
27  import org.kuali.rice.krad.rules.rule.event.KualiDocumentEvent;
28  import org.kuali.rice.krad.rules.rule.event.SaveEvent;
29  import org.kuali.student.cm.proposal.service.ProposalMaintainable;
30  import org.kuali.student.r2.core.proposal.dto.ProposalInfo;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  import javax.persistence.Entity;
35  
36  /**
37   * Document class for all CM maintenance documents which skips the xml serialization of <class>MaintainableImpl</class>
38   * Also, on document save, the data will be stored in KS tables instead of serializing the data to KRNS_MAINT_DOC_T.
39   * As we skipped the serialization, on retrieve, this class should take care of loading the data from KS tables
40   * whenever we load the maintenace document. This happens at <method>processAfterRetrieve()</method> which should
41   * be calling <method>CMMaintainable.retrieveDataObject()</method> to load the data.
42   *
43   * @author Kuali Student Team
44   */
45  
46  @Entity
47  public class CMMaintenanceDocument extends MaintenanceDocumentBase {
48  
49      private static final long serialVersionUID = -505085142412593315L;
50      private static final Logger LOG = LoggerFactory.getLogger(CMMaintenanceDocument.class);
51  
52      public CMMaintenanceDocument() {
53          super();
54      }
55  
56      public CMMaintenanceDocument(String documentTypeName) {
57          super(documentTypeName);
58      }
59  
60      @Override
61      public void processAfterRetrieve() {
62  
63          if (documentHeader == null || !documentHeader.hasWorkflowDocument()) {
64              throw new RuntimeException("Document Header or workflow document is null");
65          }
66  
67          String documentTypeName = documentHeader.getWorkflowDocument().getDocumentTypeName();
68  
69          Class clazz = getDocumentDictionaryService().getMaintainableClass(documentTypeName);
70  
71          if (!CMMaintainable.class.isAssignableFrom(clazz)) {
72              throw new RuntimeException("Maintainable should be of CMMaintainable type");
73          }
74  
75          try {
76  
77              Class<?> dataObjectClazz = getDocumentDictionaryService().getMaintenanceDataObjectClass(documentTypeName);
78  
79              /**
80               * Null check needed here as DocumentServiceImpl.validateAndPersistDocument() calls this method after
81               * save. In that case, it's not needed to create a new instance.
82               */
83              if (oldMaintainableObject == null) {
84                  oldMaintainableObject = (CMMaintainable) clazz.newInstance();
85                  oldMaintainableObject.setDataObject(dataObjectClazz.newInstance());
86                  oldMaintainableObject.setDataObjectClass(dataObjectClazz);
87              }
88  
89              if (newMaintainableObject == null) {
90                  newMaintainableObject = (CMMaintainable) clazz.newInstance();
91                  newMaintainableObject.setDataObject(dataObjectClazz.newInstance());
92                  newMaintainableObject.setDataObjectClass(dataObjectClazz);
93              }
94  
95          } catch (InstantiationException e) {
96              throw new RuntimeException("Unable to initialize maintainables of type " + clazz.getName(), e);
97          } catch (IllegalAccessException e) {
98              throw new RuntimeException("Unable to initialize maintainables of type " + clazz.getName(), e);
99          }
100 
101         // calling the super method which will eventually call the populateMaintainablesFromXmlDocumentContents() method as overriden below
102         super.processAfterRetrieve();
103 
104     }
105 
106     @Override
107     public void prepareForSave(KualiDocumentEvent event) {
108         super.prepareForSave(event);
109 
110         if ( (event instanceof SaveEvent) || (event instanceof BlanketApproveDocumentEvent) ) {
111             // set the application document id to the proposal id since this is needed for some KEW and KIM processing related to collaborators
112             if (getDocumentHeader() != null && getDocumentHeader().getWorkflowDocument() != null && getNewMaintainableObject().getDataObject() != null) {
113                 if (ProposalMaintainable.class.isAssignableFrom(getNewMaintainableObject().getClass())) {
114                     ProposalInfo proposalInfo = ((ProposalMaintainable)getNewMaintainableObject()).getProposalInfo();
115                     if (proposalInfo != null) {
116                         getDocumentHeader().getWorkflowDocument().setApplicationDocumentId(proposalInfo.getId());
117                     } else {
118                         LOG.warn("No ProposalInfo object found for document with id: " + getDocumentHeader().getWorkflowDocument().getDocumentId());
119                     }
120                 }
121             }
122             getNewMaintainableObject().saveDataObject();
123         }
124     }
125 
126     /**
127      * The original intention of this method was to deal with (de)serialization of the MaintainableImpl so that the xml can be stored in a KRAD
128      * table. However, due to the fact that Curriculum Management uses versioning of objects in the database, this method has been overriden
129      * so that the (de)serialization can be ignored and the #xmlDocumentContents can be set to an empty string.
130      */
131     @Override
132     public void populateXmlDocumentContentsFromMaintainables() {
133         xmlDocumentContents = StringUtils.EMPTY;
134     }
135 
136     /**
137      * The original intention of this method for MaintenanceDocuments was to populate the old and new maintainables from the xml document contents
138      * string. However, due to the fact that Curriculum Management uses versioning of objects in the database, this method has been modified to
139      * do a fetch from the database using a custom maintainable method: {@link org.kuali.student.cm.maintenance.CMMaintainable#retrieveDataObject()}
140      * for the #newMaintainableObject only (the #oldMaintainableObject only comes into play in comparison views and it is managed directly).
141      */
142     @Override
143     public void populateMaintainablesFromXmlDocumentContents() {
144         // first set the xmlDocumentContents to empty since we don't use the xml doc contents for data storage
145         xmlDocumentContents = StringUtils.EMPTY;
146 
147         // set the document number just a bit early since we need it to retrieve our data object
148         newMaintainableObject.setDocumentNumber(documentNumber);
149         // do the actual retrieve of the data by using a custom Maintainable method
150         ((CMMaintainable) newMaintainableObject).retrieveDataObject();
151     }
152 
153     @Override
154     public void doActionTaken(ActionTakenEvent actionTakenEvent) {
155         Maintainable maintainable = getNewMaintainableObject();
156         Class clazz = (maintainable!=null)?maintainable.getClass() : null;
157         if (clazz==null || !ProposalMaintainable.class.isAssignableFrom(clazz)) {
158             throw new RuntimeException("Maintainable should be of ProposalMaintainable type");
159         }
160         try {
161             ((ProposalMaintainable)getNewMaintainableObject()).doActionTaken(actionTakenEvent);
162         } catch (Exception e) {
163             LOG.error("Error caught operating on action taken", e);
164             throw new RuntimeException(e);
165         }
166     }
167 
168     @Override
169     public void doRouteLevelChange(DocumentRouteLevelChange documentRouteLevelChange) {
170         Maintainable maintainable = getNewMaintainableObject();
171         Class clazz = (maintainable!=null)?maintainable.getClass() : null;
172         if (clazz==null || !ProposalMaintainable.class.isAssignableFrom(clazz)) {
173             throw new RuntimeException("Maintainable should be of ProposalMaintainable type");
174         }
175         try {
176             ((ProposalMaintainable)getNewMaintainableObject()).doRouteLevelChange(documentRouteLevelChange);
177         } catch (Exception e) {
178             LOG.error("Error caught performing route level change", e);
179             throw new RuntimeException(e);
180         }
181     }
182 
183     @Override
184     public void doRouteStatusChange(DocumentRouteStatusChange documentRouteStatusChange) {
185         Maintainable maintainable = getNewMaintainableObject();
186         Class clazz = (maintainable!=null)?maintainable.getClass() : null;
187         if (clazz==null || !ProposalMaintainable.class.isAssignableFrom(clazz)) {
188             throw new RuntimeException("Maintainable should be of ProposalMaintainable type");
189         }
190         try {
191             ((ProposalMaintainable)getNewMaintainableObject()).doRouteStatusChange(documentRouteStatusChange);
192         } catch (Exception e) {
193             LOG.error("Error caught performing route status change", e);
194             throw new RuntimeException(e);
195         }
196 
197         // add in processing from standard maintenance documents
198         WorkflowDocument workflowDocument = getDocumentHeader().getWorkflowDocument();
199         // commit the changes to the Maintainable BusinessObject when it goes to Processed (ie, fully approved),
200         // and also unlock it
201         if (workflowDocument.isProcessed()) {
202             // since we don't use KRAD notes or attachments we can ignore that processing
203 
204             // need to remove locks as we do use those
205             getMaintenanceDocumentService().deleteLocks(workflowDocument.getDocumentId());
206 
207             // we also do not allow record deletion so we can ignore that processing
208         }
209 
210         // unlock the document when its canceled or disapproved or recalled
211         else if (workflowDocument.isCanceled() || workflowDocument.isDisapproved() || workflowDocument.isRecalled()) {
212             // since we don't use KRAD notes or attachments we can ignore that processing
213 
214             getMaintenanceDocumentService().deleteLocks(workflowDocument.getDocumentId());
215         }
216         // current maintenance framework removes locks if the document routes to exception routing
217 //        else if (workflowDocument.isException()) {
218 //            // since we don't use KRAD notes or attachments we can ignore that processing
219 //
220 //            getMaintenanceDocumentService().deleteLocks(workflowDocument.getDocumentId());
221 //        }
222     }
223 
224 }