001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.kew.impl.peopleflow; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.core.api.membership.MemberType; 020import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; 021import org.kuali.rice.core.api.uif.RemotableAttributeField; 022import org.kuali.rice.kew.api.KewApiServiceLocator; 023import org.kuali.rice.kew.api.peopleflow.PeopleFlowDefinition; 024import org.kuali.rice.kew.api.repository.type.KewTypeDefinition; 025import org.kuali.rice.kew.framework.peopleflow.PeopleFlowTypeService; 026import org.kuali.rice.krad.bo.Note; 027import org.kuali.rice.krad.maintenance.MaintainableImpl; 028import org.kuali.rice.krad.uif.container.CollectionGroup; 029import org.kuali.rice.krad.uif.container.Container; 030import org.kuali.rice.krad.uif.util.ObjectPropertyUtils; 031import org.kuali.rice.krad.uif.view.View; 032import org.kuali.rice.krad.util.KRADConstants; 033import org.kuali.rice.krad.web.form.MaintenanceDocumentForm; 034 035import javax.xml.namespace.QName; 036import java.util.ArrayList; 037import java.util.Collection; 038import java.util.Collections; 039import java.util.Comparator; 040import java.util.List; 041 042/** 043 * Custom view helper for the people flow maintenance document to retrieve the type attribute remotable fields 044 * 045 * @author Kuali Rice Team (rice.collab@kuali.org) 046 */ 047public class PeopleFlowMaintainableImpl extends MaintainableImpl { 048 049 050 /** 051 * sort {@link org.kuali.rice.kew.impl.peopleflow.PeopleFlowMemberBo}s by stop number (priority), and clean 052 * out the actionRequestPolicyCode for non-ROLE members. 053 * 054 * @param collection - the Collection to add the given addLine to 055 * @param addLine - the line to add to the given collection 056 * @param insertFirst - indicates if the item should be inserted as the first item 057 */ 058 @Override 059 protected void addLine(Collection<Object> collection, Object addLine, boolean insertFirst) { 060 if (collection instanceof List) { 061 ((List) collection).add(0, addLine); 062 if (addLine instanceof PeopleFlowMemberBo) { 063 064 // action request policy is only valid for MemberType.ROLE 065 PeopleFlowMemberBo member = (PeopleFlowMemberBo) addLine; 066 if (member.getMemberType() != MemberType.ROLE) { 067 member.setActionRequestPolicyCode(null); 068 } 069 070 Collections.sort((List) collection, new Comparator<Object>() { 071 public int compare(Object o1, Object o2) { 072 if ((o1 instanceof PeopleFlowMemberBo) && (o1 instanceof PeopleFlowMemberBo)) { 073 return ((PeopleFlowMemberBo) o1).getPriority() - ((PeopleFlowMemberBo) o2) 074 .getPriority(); 075 } 076 return 0; // if not both PeopleFlowMemberBo something strange is going on. Use equals as doing nothing. 077 } 078 }); 079 } 080 } else { 081 collection.add(addLine); 082 } 083 } 084 085 /** 086 * Invokes the {@link org.kuali.rice.kew.api.repository.type.KewTypeRepositoryService} to retrieve the remotable 087 * field definitions for the attributes associated with the selected type 088 * 089 * @param view - view instance 090 * @param model - object containing the form data, from which the selected type will be pulled 091 * @param container - container that holds the remotable fields 092 * @return List<RemotableAttributeField> instances for the type attributes, or empty list if not attributes exist 093 */ 094 public List<RemotableAttributeField> retrieveTypeAttributes(View view, Object model, Container container) { 095 List<RemotableAttributeField> remoteFields = new ArrayList<RemotableAttributeField>(); 096 097 PeopleFlowBo peopleFlow = 098 (PeopleFlowBo) ((MaintenanceDocumentForm) model).getDocument().getNewMaintainableObject().getDataObject(); 099 100 // retrieve the type service and invoke to get the remotable field definitions 101 String typeId = peopleFlow.getTypeId(); 102 if (StringUtils.isNotBlank(typeId)) { 103 KewTypeDefinition typeDefinition = KewApiServiceLocator.getKewTypeRepositoryService().getTypeById(typeId); 104 PeopleFlowTypeService peopleFlowTypeService = GlobalResourceLoader.<PeopleFlowTypeService>getService( 105 QName.valueOf(typeDefinition.getServiceName())); 106 remoteFields = peopleFlowTypeService.getAttributeFields(typeId); 107 } 108 109 return remoteFields; 110 } 111 112 /** 113 * Set the attribute bo list from the map of attribute key/value pairs and then calls 114 * {@link org.kuali.rice.kew.api.peopleflow.PeopleFlowService} to save the people flow instance 115 */ 116 @Override 117 public void saveDataObject() { 118 ((PeopleFlowBo) getDataObject()).updateAttributeBoValues(); 119 120 PeopleFlowDefinition peopleFlowDefinition; 121 if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(getMaintenanceAction())) { 122 peopleFlowDefinition = PeopleFlowBo.maintenanceCopy(((PeopleFlowBo) getDataObject())); 123 } else { 124 // this to method ends up copying a versionNumber to null versionNumber 125 peopleFlowDefinition = PeopleFlowBo.to(((PeopleFlowBo) getDataObject())); 126 } 127 if (StringUtils.isNotBlank(peopleFlowDefinition.getId())) { 128 KewApiServiceLocator.getPeopleFlowService().updatePeopleFlow(peopleFlowDefinition); 129 } else { 130 KewApiServiceLocator.getPeopleFlowService().createPeopleFlow(peopleFlowDefinition); 131 } 132 } 133 134 /** 135 * In the case of edit maintenance adds a new blank line to the old side 136 * This method is intended to override the method in MaintainableImpl 137 * but has a different set of parameters, so it is not actually an override. 138 * This version was needed to fetch the old collection from a different path 139 * than MaintainableImpl uses. 140 * 141 * @see org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl#processAfterAddLine(org.kuali.rice.krad.uif.view.View, 142 * org.kuali.rice.krad.uif.container.CollectionGroup, java.lang.Object, 143 * java.lang.Object) 144 */ 145 protected void processAfterAddLine(View view, CollectionGroup collectionGroup, Object model, Object addLine, String collectionPath) { 146 // Check for maintenance documents in edit but exclude notes 147 if (model instanceof MaintenanceDocumentForm 148 && KRADConstants.MAINTENANCE_EDIT_ACTION.equals(((MaintenanceDocumentForm)model).getMaintenanceAction()) && !(addLine instanceof Note)) { 149// MaintenanceDocumentForm maintenanceForm = (MaintenanceDocumentForm) model; 150// MaintenanceDocument document = maintenanceForm.getDocument(); 151 152 // get the old object's collection 153 String oldCollectionPath = collectionPath.replace("newMaintainableObject","oldMaintainableObject"); 154 Collection<Object> oldCollection = ObjectPropertyUtils.getPropertyValue(model, oldCollectionPath ); 155 try { 156 Object blankLine = collectionGroup.getCollectionObjectClass().newInstance(); 157 oldCollection.add(blankLine); 158 } catch (Exception e) { 159 throw new RuntimeException("Unable to create new line instance for old maintenance object", e); 160 } 161 } 162 } 163 164 /** 165 * This method is an override of ViewHelperService.processCollectionDeleteLine(). 166 * It is virtually identical except that a local processAfterDeleteLine() method is called 167 * with a different parameter set than is called from within this method to delete the line 168 * from the old maintainable object. 169 * @see org.kuali.rice.krad.uif.service.ViewHelperService#processCollectionDeleteLine(org.kuali.rice.krad.uif.view.View, 170 * java.lang.Object, java.lang.String, int) 171 */ 172 @Override 173 public void processCollectionDeleteLine(View view, Object model, String collectionPath, int lineIndex) { 174 // get the collection group from the view 175 CollectionGroup collectionGroup = view.getViewIndex().getCollectionGroupByPath(collectionPath); 176 if (collectionGroup == null) { 177 logAndThrowRuntime("Unable to get collection group component for path: " + collectionPath); 178 } 179 180 // get the collection instance for adding the new line 181 Collection<Object> collection = ObjectPropertyUtils.getPropertyValue(model, collectionPath); 182 if (collection == null) { 183 logAndThrowRuntime("Unable to get collection property from model for path: " + collectionPath); 184 } 185 186 // TODO: look into other ways of identifying a line so we can deal with 187 // unordered collections 188 if (collection instanceof List) { 189 Object deleteLine = ((List<Object>) collection).get(lineIndex); 190 191 // validate the delete action is allowed for this line 192 boolean isValid = performDeleteLineValidation(view, collectionGroup, deleteLine); 193 if (isValid) { 194 ((List<Object>) collection).remove(lineIndex); 195 processAfterDeleteLine(view, collectionPath, model, lineIndex); 196 } 197 } else { 198 logAndThrowRuntime("Only List collection implementations are supported for the delete by index method"); 199 } 200 } 201 202 /** 203 * In the case of edit maintenance deleted the item on the old side. 204 * This method is intended to override the method in MaintainableImpl 205 * but has a different set of parameters, so it is not actually an override. 206 * This was needed to fetch the old collection from a different path 207 * than MaintainableImpl uses. This version has the path (to the newMaintainableObject 208 * provided as a parameter, this is used to generate a path to the oldMaintainableObject 209 * 210 * 211 * @see org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl#processAfterDeleteLine(View, 212 * org.kuali.rice.krad.uif.container.CollectionGroup, java.lang.Object, int) 213 */ 214 protected void processAfterDeleteLine(View view, String collectionPath, Object model, int lineIndex) { 215 216 // Check for maintenance documents in edit 217 if (model instanceof MaintenanceDocumentForm 218 && KRADConstants.MAINTENANCE_EDIT_ACTION.equals(((MaintenanceDocumentForm)model).getMaintenanceAction())) { 219 220 // get the old object's collection 221 String oldCollectionPath = collectionPath.replace("newMaintainableObject","oldMaintainableObject"); 222 Collection<Object> oldCollection = ObjectPropertyUtils.getPropertyValue(model, oldCollectionPath); 223 try { 224 // Remove the object at lineIndex from the collection 225 oldCollection.remove(oldCollection.toArray()[lineIndex]); 226 } catch (Exception e) { 227 throw new RuntimeException("Unable to delete line instance for old maintenance object", e); 228 } 229 } 230 } 231 232 233}