001/*-
002 * #%L
003 * HAPI FHIR - Server Framework
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.rest.server.interceptor.consent;
021
022import java.util.stream.Stream;
023
024/**
025 * Something that produces a vote, along with static
026 * tools for combining votes.
027 */
028public interface IConsentVote {
029        /**
030         * Get the vote
031         * @return the vote
032         */
033        ConsentOperationStatusEnum getStatus();
034
035        /**
036         * Evaluate all verdicts together, allowing any to veto (i.e. REJECT) the operation.
037         * <ul>
038         * <li>If any vote is REJECT, then the result is REJECT.
039         * <li>If no vote is REJECT, and any vote is AUTHORIZED, then the result is AUTHORIZED.
040         * <li>If no vote is REJECT or AUTHORIZED, the result is PROCEED.
041         * </ul>
042         *
043         * @return REJECT if any reject, AUTHORIZED if no REJECT and some AUTHORIZED, PROCEED if empty or all PROCEED
044         */
045        static <T extends IConsentVote> T parallelReduce(T theSeed, Stream<T> theVoteStream) {
046                return theVoteStream.reduce(theSeed, IConsentVote::parallelReduce);
047        }
048
049        /**
050         * Evaluate two votes together, allowing either to veto (i.e. REJECT) the operation.
051         *
052         * @return REJECT if either reject, AUTHORIZED if no REJECT and some AUTHORIZED, PROCEED otherwise
053         */
054        static <T extends IConsentVote> T parallelReduce(T theAccumulator, T theNextVoter) {
055                if (theNextVoter.getStatus().getPrecedence()
056                                < theAccumulator.getStatus().getPrecedence()) {
057                        return theAccumulator;
058                } else {
059                        return theNextVoter;
060                }
061        }
062
063        /**
064         * Evaluate verdicts in order, taking the first "decision" (i.e. first non-PROCEED) verdict.
065         *
066         * @return the first decisive verdict, or theSeed when empty or all PROCEED.
067         */
068        static <T extends IConsentVote> T serialReduce(T theSeed, Stream<T> theVoterStream) {
069                return theVoterStream.filter(IConsentVote::isActiveVote).findFirst().orElse(theSeed);
070        }
071
072        /**
073         * Evaluate verdicts in order, taking the first "decision" (i.e. first non-PROCEED) verdict.
074         *
075         * @param theAccumulator the verdict so fat
076         * @param theNextVoter the next verdict to consider
077         * @return the combined verdict
078         */
079        static <T extends IConsentVote> T serialReduce(T theAccumulator, T theNextVoter) {
080                if (theAccumulator.getStatus().isAbstain()) {
081                        return theNextVoter;
082                } else {
083                        return theAccumulator;
084                }
085        }
086
087        private static <T extends IConsentVote> boolean isActiveVote(T nextVoter) {
088                return nextVoter.getStatus().isActiveVote();
089        }
090}