001/*-
002 * #%L
003 * HAPI FHIR - Core Library
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.interceptor.api;
021
022import com.google.common.collect.ArrayListMultimap;
023import com.google.common.collect.ListMultimap;
024import com.google.common.collect.Multimaps;
025import jakarta.annotation.Nonnull;
026import org.apache.commons.lang3.Validate;
027
028import java.util.Collection;
029import java.util.Collections;
030import java.util.List;
031import java.util.function.Supplier;
032import java.util.stream.Collectors;
033
034public class HookParams {
035
036        private ListMultimap<Class<?>, Object> myParams = ArrayListMultimap.create();
037
038        /**
039         * Constructor
040         */
041        public HookParams() {}
042
043        /**
044         * Constructor
045         */
046        public HookParams(Object... theParams) {
047                for (Object next : theParams) {
048                        add(next);
049                }
050        }
051
052        @SuppressWarnings("unchecked")
053        public <T> HookParams add(@Nonnull T theNext) {
054                Class<T> nextClass = (Class<T>) theNext.getClass();
055                add(nextClass, theNext);
056                return this;
057        }
058
059        public <T> HookParams add(Class<T> theType, T theParam) {
060                return doAdd(theType, theParam);
061        }
062
063        //      /**
064        //       * This is useful for providing a lazy-loaded (generally expensive to create)
065        //       * parameters
066        //       */
067        //      public <T> HookParams addSupplier(Class<T> theType, Supplier<T> theParam) {
068        //              return doAdd(theType, theParam);
069        //      }
070
071        private <T> HookParams doAdd(Class<T> theType, Object theParam) {
072                Validate.isTrue(theType.equals(Supplier.class) == false, "Can not add parameters of type Supplier");
073                myParams.put(theType, theParam);
074                return this;
075        }
076
077        public <T> T get(Class<T> theParamType) {
078                return get(theParamType, 0);
079        }
080
081        @SuppressWarnings("unchecked")
082        public <T> T get(Class<T> theParamType, int theIndex) {
083                List<Object> objects = myParams.get(theParamType);
084                Object retVal = null;
085                if (objects.size() > theIndex) {
086                        retVal = objects.get(theIndex);
087                }
088
089                retVal = unwrapValue(retVal);
090
091                return (T) retVal;
092        }
093
094        private Object unwrapValue(Object theValue) {
095                if (theValue instanceof Supplier) {
096                        theValue = ((Supplier) theValue).get();
097                }
098                return theValue;
099        }
100
101        /**
102         * Returns an unmodifiable multimap of the params, where the
103         * key is the param type and the value is the actual instance
104         */
105        public ListMultimap<Class<?>, Object> getParamsForType() {
106                ArrayListMultimap<Class<?>, Object> retVal = ArrayListMultimap.create();
107                myParams.entries().forEach(entry -> retVal.put(entry.getKey(), unwrapValue(entry.getValue())));
108                return Multimaps.unmodifiableListMultimap(retVal);
109        }
110
111        public Collection<Object> values() {
112                return Collections.unmodifiableCollection(myParams.values()).stream()
113                                .map(t -> unwrapValue(t))
114                                .collect(Collectors.toList());
115        }
116
117        @SuppressWarnings("unchecked")
118        public <T> HookParams addIfMatchesType(Class<T> theType, Object theParam) {
119                if (theParam == null) {
120                        add(theType, null);
121                } else {
122                        if (theType.isAssignableFrom(theParam.getClass())) {
123                                T param = (T) theParam;
124                                add(theType, param);
125                        } else {
126                                add(theType, null);
127                        }
128                }
129                return this;
130        }
131
132        @Override
133        public String toString() {
134                StringBuilder b = new StringBuilder();
135                myParams.forEach((key, value) -> {
136                        b.append("  ")
137                                        .append(key.getSimpleName())
138                                        .append(": ")
139                                        .append(value)
140                                        .append("\n");
141                });
142                return b.toString();
143        }
144}