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
024public enum ConsentOperationStatusEnum {
025
026        /**
027         * The requested operation cannot proceed, and an operation outcome suitable for
028         * the user is available
029         */
030        REJECT,
031
032        /**
033         * The requested operation is allowed to proceed, but the engine will review each
034         * resource before sending to the client
035         */
036        PROCEED,
037
038        /**
039         * The engine has nothing to say about the operation  (same as proceed, but the
040         * host application need not consult the engine - can use more efficient
041         * counting/caching methods)
042         */
043        AUTHORIZED,
044        ;
045
046        /**
047         * Assigns ordinals to the verdicts by strength:
048         * REJECT > AUTHORIZED > PROCEED.
049         * @return 2/1/0 for REJECT/AUTHORIZED/PROCEED
050         */
051        int getPrecedence() {
052                switch (this) {
053                        case REJECT:
054                                return 2;
055                        case AUTHORIZED:
056                                return 1;
057                        case PROCEED:
058                        default:
059                                return 0;
060                }
061        }
062        /**
063         * Evaluate verdicts in order, taking the first "decision" (i.e. first non-PROCEED) verdict.
064         *
065         * @return the first decisive verdict, or PROCEED when empty or all PROCEED.
066         */
067        public static ConsentOperationStatusEnum serialEvaluate(Stream<ConsentOperationStatusEnum> theVoteStream) {
068                return theVoteStream.filter(verdict -> PROCEED != verdict).findFirst().orElse(PROCEED);
069        }
070
071        /**
072         * Evaluate verdicts in order, taking the first "decision" (i.e. first non-PROCEED) verdict.
073         *
074         * @param theNextVerdict the next verdict to consider
075         * @return the combined verdict
076         */
077        public ConsentOperationStatusEnum serialReduce(ConsentOperationStatusEnum theNextVerdict) {
078                if (this != PROCEED) {
079                        return this;
080                } else {
081                        return theNextVerdict;
082                }
083        }
084
085        /**
086         * Evaluate all verdicts together, allowing any to veto (i.e. REJECT) the operation.
087         * <ul>
088         * <li>If any vote is REJECT, then the result is REJECT.
089         * <li>If no vote is REJECT, and any vote is AUTHORIZED, then the result is AUTHORIZED.
090         * <li>If no vote is REJECT or AUTHORIZED, the result is PROCEED.
091         * </ul>
092         *
093         * @return REJECT if any reject, AUTHORIZED if no REJECT and some AUTHORIZED, PROCEED if empty or all PROCEED
094         */
095        public static ConsentOperationStatusEnum parallelEvaluate(Stream<ConsentOperationStatusEnum> theVoteStream) {
096                return theVoteStream.reduce(PROCEED, ConsentOperationStatusEnum::parallelReduce);
097        }
098
099        /**
100         * Evaluate two verdicts together, allowing either to veto (i.e. REJECT) the operation.
101         *
102         * @return REJECT if either reject, AUTHORIZED if no REJECT and some AUTHORIZED, PROCEED otherwise
103         */
104        public ConsentOperationStatusEnum parallelReduce(ConsentOperationStatusEnum theNextVerdict) {
105                if (theNextVerdict.getPrecedence() > this.getPrecedence()) {
106                        return theNextVerdict;
107                } else {
108                        return this;
109                }
110        }
111}