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