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.kim.api.identity.Person;
019import org.kuali.rice.krad.datadictionary.DocumentEntry;
020import org.kuali.rice.krad.document.authorization.PessimisticLock;
021import org.kuali.rice.krad.service.DataDictionaryService;
022import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
023
024/**
025 * Base class for all Transactional Document authorizers.
026 *
027 * @author Kuali Rice Team (rice.collab@kuali.org)
028 */
029public class TransactionalDocumentAuthorizerBase extends DocumentAuthorizerBase implements TransactionalDocumentAuthorizer {
030
031    private static final long serialVersionUID = 3255133642834256283L;
032
033    private DataDictionaryService dataDictionaryService;
034
035    /**
036     * {@inheritDoc}
037     *
038     * <p>
039     * The {@code user} can only close the {@code document} if it is a transactional document.
040     * </p>
041     */
042    @Override
043    public boolean canClose(Document document, Person user) {
044        return true;
045    }
046
047    /**
048     * {@inheritDoc}
049     *
050     * <p>
051     * The {@code user} can only save the {@code document} if they have permission and, if pessimistic locking is turned
052     * on for the {@code document}, they can establish a pessimistic lock.
053     * </p>
054     */
055    @Override
056    public boolean canSave(Document document, Person user) {
057        boolean canSave = super.canSave(document, user);
058
059        if (!isUsingPessimisticLocking(document)) {
060            return canSave;
061        }
062
063        return canSave && canEstablishPessimisticLock(document, user);
064    }
065
066    /**
067     * {@inheritDoc}
068     *
069     * <p>
070     * The {@code user} can only route the {@code document} if they have permission and, if pessimistic locking is
071     * turned on for the {@code document}, they can establish a pessimistic lock.
072     * </p>
073     */
074    @Override
075    public boolean canRoute(Document document, Person user) {
076        boolean canRoute = super.canRoute(document, user);
077
078        if (!isUsingPessimisticLocking(document)) {
079            return canRoute;
080        }
081
082        return canRoute && canEstablishPessimisticLock(document, user);
083    }
084
085    /**
086     * {@inheritDoc}
087     *
088     * <p>
089     * The {@code user} can only cancel the {@code document} if they have permission and, if pessimistic locking is
090     * turned on for the {@code document}, they can establish a pessimistic lock.
091     * </p>
092     */
093    @Override
094    public boolean canCancel(Document document, Person user) {
095        boolean canCancel = super.canCancel(document, user);
096
097        if (!isUsingPessimisticLocking(document)) {
098            return canCancel;
099        }
100
101        return canCancel && canEstablishPessimisticLock(document, user);
102    }
103
104    /**
105     * {@inheritDoc}
106     *
107     * <p>
108     * The {@code user} can only blanket approve the {@code document} if they have permission and, if pessimistic
109     * locking is turned on for the {@code document}, they can establish a pessimistic lock.
110     * </p>
111     */
112    @Override
113    public boolean canBlanketApprove(Document document, Person user) {
114        boolean canBlanketApprove = super.canBlanketApprove(document, user);
115
116        if (!isUsingPessimisticLocking(document)) {
117            return canBlanketApprove;
118        }
119
120        return canBlanketApprove && canEstablishPessimisticLock(document, user);
121    }
122
123    /**
124     * Returns whether the {@code document} is using pessimistic locking.
125     *
126     * @param document the document to check for using pessimistic locking
127     *
128     * @return true if the {@code document} is using pessimistic locking, false otherwise.
129     */
130    protected boolean isUsingPessimisticLocking(Document document) {
131        String documentClassName = document.getClass().getName();
132        DocumentEntry documentEntry = getDataDictionaryService().getDataDictionary().getDocumentEntry(documentClassName);
133
134        return documentEntry.getUsePessimisticLocking();
135    }
136
137    /**
138     * Returns whether {@code user} can establish a pessimistic lock on the document.
139     *
140     * <p>
141     * The {@code user} can only establish a pessimistic lock on the document {@code document} if there are no existing
142     * locks or if they already have a lock on the {@code document}.
143     * </p>
144     *
145     * @param document the document to check for pessimistic locks
146     * @param user the user to check for pessimistic locks
147     *
148     * @return true if the {@code user} can establish a pessimistic lock on the document, false otherwise
149     */
150    protected boolean canEstablishPessimisticLock(Document document, Person user) {
151        if (document.getPessimisticLocks().isEmpty()) {
152            return true;
153        }
154
155        for (PessimisticLock pessimisticLock : document.getPessimisticLocks()) {
156            if (pessimisticLock.isOwnedByUser(user)) {
157                return true;
158            }
159        }
160
161        return false;
162    }
163
164    protected DataDictionaryService getDataDictionaryService() {
165        if (dataDictionaryService == null) {
166            dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
167        }
168
169        return dataDictionaryService;
170    }
171
172    protected void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
173        this.dataDictionaryService = dataDictionaryService;
174    }
175
176}