001package ca.uhn.fhir.interceptor.api;
002
003/*-
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2019 University Health Network
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import com.google.common.collect.ArrayListMultimap;
024import com.google.common.collect.ListMultimap;
025import com.google.common.collect.Multimaps;
026import org.apache.commons.lang3.Validate;
027
028import javax.annotation.Nonnull;
029import java.util.Collection;
030import java.util.Collections;
031import java.util.List;
032import java.util.function.Supplier;
033import java.util.stream.Collectors;
034
035public class HookParams {
036
037        private ListMultimap<Class<?>, Object> myParams = ArrayListMultimap.create();
038
039        /**
040         * Constructor
041         */
042        public HookParams() {
043        }
044
045        /**
046         * Constructor
047         */
048        public HookParams(Object... theParams) {
049                for (Object next : theParams) {
050                        add(next);
051                }
052        }
053
054        @SuppressWarnings("unchecked")
055        public <T> HookParams add(@Nonnull T theNext) {
056                Class<T> nextClass = (Class<T>) theNext.getClass();
057                add(nextClass, theNext);
058                return this;
059        }
060
061        public <T> HookParams add(Class<T> theType, T theParam) {
062                return doAdd(theType, theParam);
063        }
064
065//      /**
066//       * This is useful for providing a lazy-loaded (generally expensive to create)
067//       * parameters
068//       */
069//      public <T> HookParams addSupplier(Class<T> theType, Supplier<T> theParam) {
070//              return doAdd(theType, theParam);
071//      }
072
073        private <T> HookParams doAdd(Class<T> theType, Object theParam) {
074                Validate.isTrue(theType.equals(Supplier.class) == false, "Can not add parameters of type Supplier");
075                myParams.put(theType, theParam);
076                return this;
077        }
078
079        public <T> T get(Class<T> theParamType) {
080                return get(theParamType, 0);
081        }
082
083        @SuppressWarnings("unchecked")
084        public <T> T get(Class<T> theParamType, int theIndex) {
085                List<Object> objects = myParams.get(theParamType);
086                Object retVal = null;
087                if (objects.size() > theIndex) {
088                        retVal = objects.get(theIndex);
089                }
090
091                retVal = unwrapValue(retVal);
092
093                return (T) retVal;
094        }
095
096        private Object unwrapValue(Object theValue) {
097                if (theValue instanceof Supplier) {
098                        theValue = ((Supplier) theValue).get();
099                }
100                return theValue;
101        }
102
103        /**
104         * Returns an unmodifiable multimap of the params, where the
105         * key is the param type and the value is the actual instance
106         */
107        public ListMultimap<Class<?>, Object> getParamsForType() {
108                ArrayListMultimap<Class<?>, Object> retVal = ArrayListMultimap.create();
109                myParams.entries().forEach(entry -> retVal.put(entry.getKey(), unwrapValue(entry.getValue())));
110                return Multimaps.unmodifiableListMultimap(retVal);
111        }
112
113        public Collection<Object> values() {
114                return
115                        Collections.unmodifiableCollection(myParams.values())
116                                .stream()
117                                .map(t -> unwrapValue(t))
118                                .collect(Collectors.toList());
119        }
120
121        @SuppressWarnings("unchecked")
122        public <T> HookParams addIfMatchesType(Class<T> theType, Object theParam) {
123                if (theParam == null) {
124                        add(theType, null);
125                } else {
126                        if (theType.isAssignableFrom(theParam.getClass())) {
127                                T param = (T) theParam;
128                                add(theType, param);
129                        } else {
130                                add(theType, null);
131                        }
132                }
133                return this;
134        }
135}