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}