View Javadoc
1   /**
2    * Copyright 2005-2014 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.kew.impl.peopleflow;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.membership.MemberType;
20  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
21  import org.kuali.rice.core.api.uif.RemotableAttributeField;
22  import org.kuali.rice.kew.api.KewApiServiceLocator;
23  import org.kuali.rice.kew.api.peopleflow.PeopleFlowDefinition;
24  import org.kuali.rice.kew.api.repository.type.KewTypeDefinition;
25  import org.kuali.rice.kew.framework.peopleflow.PeopleFlowTypeService;
26  import org.kuali.rice.krad.bo.Note;
27  import org.kuali.rice.krad.maintenance.MaintainableImpl;
28  import org.kuali.rice.krad.uif.UifConstants;
29  import org.kuali.rice.krad.uif.container.CollectionGroup;
30  import org.kuali.rice.krad.uif.container.Container;
31  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
32  import org.kuali.rice.krad.uif.view.View;
33  import org.kuali.rice.krad.uif.view.ViewModel;
34  import org.kuali.rice.krad.util.KRADConstants;
35  import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
36  
37  import javax.xml.namespace.QName;
38  import java.util.ArrayList;
39  import java.util.Collection;
40  import java.util.Collections;
41  import java.util.Comparator;
42  import java.util.List;
43  
44  /**
45   * Custom view helper for the people flow maintenance document to retrieve the type attribute remotable fields
46   *
47   * @author Kuali Rice Team (rice.collab@kuali.org)
48   */
49  public class PeopleFlowMaintainableImpl extends MaintainableImpl {
50  
51  
52      /**
53       * sort {@link org.kuali.rice.kew.impl.peopleflow.PeopleFlowMemberBo}s by stop number (priority), and clean
54       * out the actionRequestPolicyCode for non-ROLE members.
55       *
56       * @param collection - the Collection to add the given addLine to
57       * @param addLine - the line to add to the given collection
58       * @param insertFirst - indicates if the item should be inserted as the first item
59       */
60      @Override
61      protected int addLine(Collection<Object> collection, Object addLine, boolean insertFirst) {
62          if (collection instanceof List) {
63              ((List) collection).add(0, addLine);
64              if (addLine instanceof PeopleFlowMemberBo) {
65  
66                  // action request policy is only valid for MemberType.ROLE
67                  PeopleFlowMemberBo member = (PeopleFlowMemberBo) addLine;
68                  if (member.getMemberType() != MemberType.ROLE) {
69                      member.setActionRequestPolicyCode(null);
70                  }
71  
72                  Collections.sort((List) collection, new Comparator<Object>() {
73                      public int compare(Object o1, Object o2) {
74                          if ((o1 instanceof PeopleFlowMemberBo) && (o1 instanceof PeopleFlowMemberBo)) {
75                              return ((PeopleFlowMemberBo) o1).getPriority() - ((PeopleFlowMemberBo) o2)
76                                      .getPriority();
77                          }
78                          return 0; // if not both PeopleFlowMemberBo something strange is going on.  Use equals as doing nothing.
79                      }
80                  });
81              }
82          } else {
83              collection.add(addLine);
84          }
85          // find the index where we added it after the sort so we can return that index
86          int index = 0;
87          for (Object element : collection) {
88              if (element == addLine) {
89                  return index;
90              }
91              index++;
92          }
93          return -1;
94      }
95  
96      /**
97       * Invokes the {@link org.kuali.rice.kew.api.repository.type.KewTypeRepositoryService} to retrieve the remotable
98       * field definitions for the attributes associated with the selected type
99       *
100      * @param view - view instance
101      * @param model - object containing the form data, from which the selected type will be pulled
102      * @param container - container that holds the remotable fields
103      * @return List<RemotableAttributeField> instances for the type attributes, or empty list if not attributes exist
104      */
105     public List<RemotableAttributeField> retrieveTypeAttributes(View view, Object model, Container container) {
106         List<RemotableAttributeField> remoteFields = new ArrayList<RemotableAttributeField>();
107 
108         PeopleFlowBo peopleFlow =
109                 (PeopleFlowBo) ((MaintenanceDocumentForm) model).getDocument().getNewMaintainableObject().getDataObject();
110 
111         // retrieve the type service and invoke to get the remotable field definitions
112         String typeId = peopleFlow.getTypeId();
113         if (StringUtils.isNotBlank(typeId)) {
114             KewTypeDefinition typeDefinition = KewApiServiceLocator.getKewTypeRepositoryService().getTypeById(typeId);
115             PeopleFlowTypeService peopleFlowTypeService = GlobalResourceLoader.<PeopleFlowTypeService>getService(
116                 QName.valueOf(typeDefinition.getServiceName()));
117             remoteFields = peopleFlowTypeService.getAttributeFields(typeId);
118         }
119 
120         return remoteFields;
121     }
122 
123     /**
124      * Set the attribute bo list from the map of attribute key/value pairs.
125      */
126     @Override
127     public void prepareForSave() {
128         ((PeopleFlowBo) getDataObject()).updateAttributeBoValues();
129     }
130 
131     /**
132      * Set the map of attribute key/value pairs list from the attribute bo list and update the members.
133      */
134     @Override
135     public void processAfterRetrieve() {
136         ((PeopleFlowBo) getDataObject()).postLoad();
137     }
138 
139     /**
140      * Calls {@link org.kuali.rice.kew.api.peopleflow.PeopleFlowService} to save the people flow instance
141      */
142     @Override
143     public void saveDataObject() {
144         PeopleFlowDefinition peopleFlowDefinition;
145         if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(getMaintenanceAction())) {
146             peopleFlowDefinition = PeopleFlowBo.maintenanceCopy(((PeopleFlowBo) getDataObject()));
147         } else {
148         // this to method ends up copying a versionNumber to null versionNumber 
149             peopleFlowDefinition = PeopleFlowBo.to(((PeopleFlowBo) getDataObject()));
150         }
151         if (StringUtils.isNotBlank(peopleFlowDefinition.getId())) {
152             KewApiServiceLocator.getPeopleFlowService().updatePeopleFlow(peopleFlowDefinition);
153         } else {
154             KewApiServiceLocator.getPeopleFlowService().createPeopleFlow(peopleFlowDefinition);
155         }
156     }
157 
158     /**
159      * In the case of edit maintenance adds a new blank line to the old side
160      * This method is intended to override the method in MaintainableImpl
161      * but has a different set of parameters, so it is not actually an override.
162      * This version was needed to fetch the old collection from a different path
163      * than MaintainableImpl uses.
164      *
165      * @see org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl#processAfterAddLine(org.kuali.rice.krad.uif.view.View,
166      * org.kuali.rice.krad.uif.container.CollectionGroup, Object, Object, boolean)
167      */
168     @Override
169     public void processAfterAddLine(ViewModel model, Object addLine, String collectionId, String collectionPath,
170                 boolean isValidLine) {
171         // Check for maintenance documents in edit but exclude notes
172         if (model instanceof MaintenanceDocumentForm
173                 && KRADConstants.MAINTENANCE_EDIT_ACTION.equals(((MaintenanceDocumentForm)model).getMaintenanceAction()) && !(addLine instanceof Note)) {
174 
175             Class<?> collectionObjectClass = (Class<?>) model.getViewPostMetadata().getComponentPostData(collectionId,
176                     UifConstants.PostMetadata.COLL_OBJECT_CLASS);
177 
178             // get the old object's collection
179             String oldCollectionPath = collectionPath.replace("newMaintainableObject","oldMaintainableObject");
180             Collection<Object> oldCollection = ObjectPropertyUtils.getPropertyValue(model, oldCollectionPath );
181             try {
182                 Object blankLine = collectionObjectClass.newInstance();
183                 oldCollection.add(blankLine);
184             } catch (Exception e) {
185                 throw new RuntimeException("Unable to create new line instance for old maintenance object", e);
186             }
187         }
188     }
189 
190     /**
191      * This method is an override of ViewHelperService.processCollectionDeleteLine().
192      * It is virtually identical except that a local processAfterDeleteLine() method is called
193      * with a different parameter set than is called from within this method to delete the line
194      * from the old maintainable object.
195      * @see org.kuali.rice.krad.uif.service.ViewHelperService#processCollectionDeleteLine(org.kuali.rice.krad.uif.view.View,
196      *      java.lang.Object, java.lang.String, int)
197      */
198     @Override
199     public void processCollectionDeleteLine(ViewModel model, String collectionId, String collectionPath, int lineIndex) {
200 
201         // get the collection instance for adding the new line
202         Collection<Object> collection = ObjectPropertyUtils.getPropertyValue(model, collectionPath);
203         if (collection == null) {
204             logAndThrowRuntime("Unable to get collection property from model for path: " + collectionPath);
205         }
206 
207         // TODO: look into other ways of identifying a line so we can deal with
208         // unordered collections
209         if (collection instanceof List) {
210             Object deleteLine = ((List<Object>) collection).get(lineIndex);
211 
212             // validate the delete action is allowed for this line
213             boolean isValid = performDeleteLineValidation(model, collectionId, collectionPath, deleteLine);
214             if (isValid) {
215                 ((List<Object>) collection).remove(lineIndex);
216                 processAfterDeleteLine(model, collectionId, collectionPath, lineIndex);
217             }
218         } else {
219             logAndThrowRuntime("Only List collection implementations are supported for the delete by index method");
220         }
221     }
222 
223     /**
224      * In the case of edit maintenance deleted the item on the old side.
225      * This method is intended to override the method in MaintainableImpl
226      * but has a different set of parameters, so it is not actually an override.
227      * This was needed to fetch the old collection from a different path
228      * than MaintainableImpl uses. This version has the path (to the newMaintainableObject
229      * provided as a parameter, this is used to generate a path to the oldMaintainableObject
230      *
231      *
232      * @see org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl#processAfterDeleteLine(View,
233      *      org.kuali.rice.krad.uif.container.CollectionGroup, java.lang.Object,  int)
234      */
235     @Override
236     public void processAfterDeleteLine(ViewModel model, String collectionId, String collectionPath, int lineIndex) {
237 
238         // Check for maintenance documents in edit
239         if (model instanceof MaintenanceDocumentForm
240                 && KRADConstants.MAINTENANCE_EDIT_ACTION.equals(((MaintenanceDocumentForm)model).getMaintenanceAction())) {
241 
242             // get the old object's collection
243             String oldCollectionPath = collectionPath.replace("newMaintainableObject","oldMaintainableObject");
244             Collection<Object> oldCollection = ObjectPropertyUtils.getPropertyValue(model, oldCollectionPath);
245             try {
246                 // Remove the object at lineIndex from the collection
247                 oldCollection.remove(oldCollection.toArray()[lineIndex]);
248             } catch (Exception e) {
249                 throw new RuntimeException("Unable to delete line instance for old maintenance object", e);
250             }
251         }
252     }
253 
254 
255 }