View Javadoc
1   /**
2    * Copyright 2005-2016 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krms.impl.ui;
17  
18  import org.apache.commons.collections.CollectionUtils;
19  import org.kuali.rice.krad.maintenance.MaintainableImpl;
20  import org.kuali.rice.krad.maintenance.MaintenanceDocument;
21  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
22  import org.kuali.rice.krad.uif.view.ViewModel;
23  import org.kuali.rice.krad.util.KRADConstants;
24  import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
25  import org.kuali.rice.krms.api.repository.context.ContextDefinition;
26  import org.kuali.rice.krms.impl.repository.ContextBo;
27  import org.kuali.rice.krms.impl.repository.ContextValidTermBo;
28  import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
29  import org.kuali.rice.krms.impl.repository.TermSpecificationBo;
30  
31  import java.util.ArrayList;
32  import java.util.List;
33  import java.util.ListIterator;
34  import java.util.Map;
35  
36  /**
37   * {@link org.kuali.rice.krad.maintenance.Maintainable} for the {@link AgendaEditor}
38   *
39   * @author Kuali Rice Team (rice.collab@kuali.org)
40   *
41   */
42  public class TermSpecificationMaintainable extends MaintainableImpl {
43  	
44  	private static final long serialVersionUID = 1L;
45  
46      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(TermSpecificationMaintainable.class);
47  
48      @Override
49      public Object retrieveObjectForEditOrCopy(MaintenanceDocument document, Map<String, String> dataObjectKeys) {
50  
51          TermSpecificationBo termSpecificationBo = (TermSpecificationBo) super.retrieveObjectForEditOrCopy(document,
52                  dataObjectKeys);
53  
54          if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(getMaintenanceAction())) {
55              document.getDocumentHeader().setDocumentDescription("New Term Specification Document");
56          }
57  
58          return termSpecificationBo;
59      }
60  
61      /**
62  	 * {@inheritDoc}
63  	 */
64  	@Override
65  	public void processAfterNew(MaintenanceDocument document,
66  		Map<String, String[]> requestParameters) {
67  
68  		super.processAfterNew(document, requestParameters);
69          document.getDocumentHeader().setDocumentDescription("New Term Specification Document");
70  
71  	}
72  
73      /**
74       * {@inheritDoc}
75       */
76      @Override
77      public void processAfterEdit(MaintenanceDocument document, Map<String, String[]> requestParameters) {
78          super.processAfterEdit(document, requestParameters);
79          document.getDocumentHeader().setDocumentDescription("Edited Term Specification Document");
80      }
81  
82      @Override
83      public void processAfterCopy(MaintenanceDocument document, Map<String, String[]> requestParameters) {
84          super.processAfterCopy(document, requestParameters);
85          copyContextsOldToNewBo(document);
86          setNewContextValidTermsNewBO(document);
87      }
88  
89      /**
90       * Copy the contexts from the old TermSpecificationBo to the newTermSpecificationBo of the maintenance document.
91       * <p>
92       * Since the contexts is a transient field it doesn't get copied by the deepCopy in
93       * MaintenanceDocumentServiceImpl.setupMaintenanceObject, we manually need to copy the values over.
94       * For performance reasons a shallow copy is done since the ContextBo themselves are never changed.
95       * </p>
96       * @param document that contains the old and new TermSpecificationBos
97       */
98      private void copyContextsOldToNewBo(MaintenanceDocument document) {
99          TermSpecificationBo newTermSpec = (TermSpecificationBo) document.getNewMaintainableObject().getDataObject();
100 
101         // Hydrade contexts as they are transient
102         newTermSpec.getContexts().clear();
103         newTermSpec.getContexts();
104     }
105 
106     private void setNewContextValidTermsNewBO(MaintenanceDocument document) {
107         TermSpecificationBo newTermSpec = (TermSpecificationBo) document.getNewMaintainableObject().getDataObject();
108         for (ContextValidTermBo contextValidTermBo : newTermSpec.getContextValidTerms()) {
109             contextValidTermBo.setId(null);
110             contextValidTermBo.setTermSpecification(newTermSpec);
111         }
112     }
113 
114     /**
115      * Overrides the parent method to additionaly clear the contexts list, which is needed for serialization performance
116      * & space.
117      *
118      * @see org.kuali.rice.krad.maintenance.Maintainable#prepareForSave
119      */
120     @Override
121     public void prepareForSave() {
122         super.prepareForSave();
123 
124         TermSpecificationBo termSpec = (TermSpecificationBo) getDataObject();
125         termSpec.getContexts().clear();
126     }
127 
128     /**
129      * For context addition, adds the item to the persisted contextValidTerms collection on the data object.
130      *
131      * <p>Without this step, the context is only added to a transient collection and the relationship will never be
132      * persisted. </p>
133      */
134     @Override
135     public void processAfterAddLine(ViewModel viewModel, Object addLine, String collectionId, String collectionPath,
136             boolean isValidLine) {
137         // we only want to do our custom processing if a context has been added
138         if (addLine == null || !(addLine instanceof ContextBo)) {
139             super.processAfterAddLine(viewModel, addLine, collectionId, collectionPath, isValidLine);
140             return;
141         }
142 
143         ContextBo addedContext = (ContextBo) addLine;
144         TermSpecificationBo termSpec = getDataObjectFromForm(viewModel);
145 
146         boolean alreadyHasContextValidTerm = false;
147 
148         for (ContextValidTermBo contextValidTerm : termSpec.getContextValidTerms()) {
149             if (contextValidTerm.getContextId().equals(addedContext.getId())) {
150                 alreadyHasContextValidTerm = true;
151                 break;
152             }
153         }
154 
155         if (!alreadyHasContextValidTerm) {
156             ContextValidTermBo contextValidTerm = new ContextValidTermBo();
157             contextValidTerm.setContextId(addedContext.getId());
158             contextValidTerm.setTermSpecification(termSpec);
159             termSpec.getContextValidTerms().add(contextValidTerm);
160         }
161     }
162 
163     /**
164      * For context removal, removes the given item from the persisted contextValidTerms collection on the data object.
165      *
166      * <p>Without this step, the context is only removed from a transient collection and the severed relationship will
167      * never be persisted. </p>
168      */
169     @Override
170     public void processCollectionDeleteLine(ViewModel viewModel, String collectionId, String collectionPath,
171             int lineIndex) {
172         List collection = ObjectPropertyUtils.getPropertyValue(viewModel, collectionPath);
173         Object deletedItem = collection.get(lineIndex);
174 
175         // we only want to do our custom processing if a context has been deleted
176         if (deletedItem == null || !(deletedItem instanceof ContextBo)) {
177             super.processCollectionDeleteLine(viewModel, collectionId, collectionPath, lineIndex);
178             return;
179         }
180 
181         ContextBo context = (ContextBo) deletedItem;
182         TermSpecificationBo termSpec = getDataObjectFromForm(viewModel);
183 
184         // find the context and remove it using the special powers of ListIterator
185         ListIterator<ContextValidTermBo> contextValidTermListIter = termSpec.getContextValidTerms().listIterator();
186         while (contextValidTermListIter.hasNext()) {
187             ContextValidTermBo contextValidTerm = contextValidTermListIter.next();
188 
189             if (contextValidTerm.getContextId().equals(context.getId())) {
190                 contextValidTerm.setTermSpecification(null);
191                 contextValidTermListIter.remove();
192                 termSpec.getContexts().remove(context);
193             }
194         }
195     }
196 
197     /**
198      * Pulls the data object out of the given form and returns it, casting it to the desired type.
199      *
200      * <p>Assumes that the form is actually a MaintenanceDocumentForm.  The
201      * form.document.newMaintainableObject.dataObject is returned.</p>
202      *
203      * @param form
204      * @param <T> the type of data object to return
205      * @return the data object
206      */
207     private static <T> T getDataObjectFromForm(ViewModel form) {
208         if (form == null) { return null; }
209 
210         return (T) ((MaintenanceDocumentForm)form).getDocument().getNewMaintainableObject().getDataObject();
211     }
212 
213     @Override
214     public Class getDataObjectClass() {
215         return TermSpecificationBo.class;
216     }
217 
218     /**
219      * Recreate the contexts from the contextIDs (needed due to serialization)
220      *
221      * @see org.kuali.rice.krad.maintenance.Maintainable#processAfterRetrieve
222      */
223     @Override
224     public void processAfterRetrieve() {
225         super.processAfterRetrieve();
226     }
227 }