001/**
002 * Copyright 2005-2018 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.krad.document;
017
018import org.kuali.rice.kew.api.action.ActionType;
019import org.kuali.rice.kew.api.exception.WorkflowException;
020import org.kuali.rice.kim.api.identity.Person;
021import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
022import org.kuali.rice.krad.service.PessimisticLockService;
023import org.kuali.rice.krad.uif.UifConstants;
024import org.kuali.rice.krad.util.GlobalVariables;
025import org.kuali.rice.krad.util.KRADConstants;
026import org.kuali.rice.krad.web.form.DialogResponse;
027import org.kuali.rice.krad.web.form.DocumentFormBase;
028import org.kuali.rice.krad.data.KradDataServiceLocator;
029import org.kuali.rice.krad.data.MaterializeOption;
030import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
031import org.kuali.rice.krad.util.GlobalVariables;
032import org.kuali.rice.krad.web.form.TransactionalDocumentFormBase;
033import org.kuali.rice.krad.web.form.UifFormBase;
034import org.springframework.web.servlet.ModelAndView;
035
036/**
037 * Default implementation of the transactional document controller service.
038 *
039 * @author Kuali Rice Team (rice.collab@kuali.org)
040 */
041public class TransactionalDocumentControllerServiceImpl extends DocumentControllerServiceImpl implements TransactionalDocumentControllerService {
042
043    private PessimisticLockService pessimisticLockService;
044
045    /**
046     * {@inheritDoc}
047     */
048    @Override
049    public ModelAndView copy(TransactionalDocumentFormBase form) {
050        try {
051            // Load any lazy loaded data before proceeding with copy
052            KradDataServiceLocator.getDataObjectService().wrap(form.getDocument()).materializeReferencedObjectsToDepth(3,
053                    MaterializeOption.UPDATE_UPDATABLE_REFS);
054
055            // Clones the original and detach the data
056            form.setDocument(KradDataServiceLocator.getDataObjectService().copyInstance(form.getDocument()));
057
058            // Generate the header data after the copy
059            ((Copyable) form.getDocument()).toCopy();
060        } catch (WorkflowException e) {
061            throw new RuntimeException("Unable to copy transactional document", e);
062        }
063
064        form.setEvaluateFlagsAndModes(true);
065        form.setCanEditView(null);
066
067        return getModelAndViewService().getModelAndView(form);
068    }
069
070    /**
071     * {@inheritDoc}
072     *
073     * <p>
074     * Releases the pessimistic locks before continuing.
075     * </p>
076     */
077    @Override
078    public ModelAndView cancel(UifFormBase form) {
079        ModelAndView modelAndView = super.cancel(form);
080
081        releasePessimisticLocks((DocumentFormBase) form);
082
083        return modelAndView;
084    }
085
086    /**
087     * {@inheritDoc}
088     *
089     * <p>
090     * Releases the pessimistic locks before continuing.
091     * </p>
092     */
093    @Override
094    public ModelAndView route(DocumentFormBase form) {
095        ModelAndView modelAndView = super.route(form);
096
097        releasePessimisticLocks(form);
098
099        return modelAndView;
100    }
101
102    /**
103     * {@inheritDoc}
104     *
105     * <p>
106     * Releases the pessimistic locks before continuing.
107     * </p>
108     */
109    @Override
110    public ModelAndView approve(DocumentFormBase form) {
111        ModelAndView modelAndView = super.approve(form);
112
113        releasePessimisticLocks(form);
114
115        return modelAndView;
116    }
117
118    /**
119     * {@inheritDoc}
120     *
121     * <p>
122     * Releases the pessimistic locks before continuing.
123     * </p>
124     */
125    @Override
126    public ModelAndView disapprove(DocumentFormBase form) {
127        ModelAndView modelAndView = super.disapprove(form);
128
129        releasePessimisticLocks(form);
130
131        return modelAndView;
132    }
133
134    /**
135     * {@inheritDoc}
136     *
137     * <p>
138     * Releases the pessimistic locks before continuing.
139     * </p>
140     */
141    @Override
142    public ModelAndView acknowledge(DocumentFormBase form) {
143        ModelAndView modelAndView = super.acknowledge(form);
144
145        releasePessimisticLocks(form);
146
147        return modelAndView;
148    }
149
150    /**
151     * {@inheritDoc}
152     *
153     * <p>
154     * Prompts for save and releases the pessimistic locks before continuing.
155     * </p>
156     */
157    @Override
158    public ModelAndView close(DocumentFormBase form) {
159        Document document = form.getDocument();
160
161        // only offer to save if it is a valid action
162        if (document.getDocumentHeader().getWorkflowDocument().isValidAction(ActionType.SAVE)) {
163            // initialize the dialog to prompt for save
164            DialogResponse dialogResponse = form.getDialogResponse(KRADConstants.QUESTION_ACTION_CLOSE_RESPONSE);
165
166            if (dialogResponse == null) {
167                return getModelAndViewService().showDialog(KRADConstants.QUESTION_ACTION_CLOSE_RESPONSE, false, form);
168            }
169
170            // save if the user answers yes in the dialog
171            if (dialogResponse.getResponseAsBoolean()) {
172                // get the explanation from the document and check it for sensitive data
173                String explanation = document.getDocumentHeader().getExplanation();
174                ModelAndView sensitiveDataDialogModelAndView = checkSensitiveDataAndWarningDialog(explanation, form);
175
176                // if a sensitive data warning dialog is returned then display it
177                if (sensitiveDataDialogModelAndView != null) {
178                    return sensitiveDataDialogModelAndView;
179                }
180
181                performWorkflowAction(form, UifConstants.WorkflowAction.SAVE);
182            }
183        }
184
185        releasePessimisticLocks(form);
186
187        return super.close(form);
188    }
189
190    /**
191     * Releases the pessimistic locks for the current user.
192     *
193     * @param form form instance containing the transactional document data
194     */
195    protected void releasePessimisticLocks(DocumentFormBase form) {
196        Document document = form.getDocument();
197
198        if (!document.getPessimisticLocks().isEmpty()) {
199            Person user = GlobalVariables.getUserSession().getPerson();
200            getPessimisticLockService().releaseAllLocksForUser(document.getPessimisticLocks(), user);
201            document.refreshPessimisticLocks();
202        }
203    }
204
205    protected PessimisticLockService getPessimisticLockService() {
206        if (pessimisticLockService == null) {
207            pessimisticLockService = KRADServiceLocatorWeb.getPessimisticLockService();
208        }
209
210        return pessimisticLockService;
211    }
212
213    protected void setPessimisticLockService(PessimisticLockService pessimisticLockService) {
214        this.pessimisticLockService = pessimisticLockService;
215    }
216
217}