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}