Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 1 | package org.apache.felix.dm.lambda.impl; |
| 2 | |
| 3 | import java.util.ArrayList; |
| 4 | import java.util.Dictionary; |
| 5 | import java.util.List; |
| 6 | import java.util.Objects; |
| 7 | import java.util.function.Consumer; |
| 8 | import java.util.stream.Stream; |
| 9 | |
| 10 | import org.apache.felix.dm.Component; |
| 11 | import org.apache.felix.dm.DependencyManager; |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 12 | import org.apache.felix.dm.context.ComponentContext; |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 13 | import org.apache.felix.dm.lambda.ComponentBuilder; |
| 14 | import org.apache.felix.dm.lambda.FactoryPidAdapterBuilder; |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 15 | import org.apache.felix.dm.lambda.callbacks.CbConfiguration; |
| 16 | import org.apache.felix.dm.lambda.callbacks.CbConfigurationComponent; |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 17 | import org.apache.felix.dm.lambda.callbacks.CbDictionary; |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 18 | import org.apache.felix.dm.lambda.callbacks.CbDictionaryComponent; |
| 19 | import org.apache.felix.dm.lambda.callbacks.InstanceCbConfiguration; |
| 20 | import org.apache.felix.dm.lambda.callbacks.InstanceCbConfigurationComponent; |
| 21 | import org.apache.felix.dm.lambda.callbacks.InstanceCbDictionary; |
| 22 | import org.apache.felix.dm.lambda.callbacks.InstanceCbDictionaryComponent; |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 23 | |
| 24 | public class FactoryPidAdapterBuilderImpl implements AdapterBase<FactoryPidAdapterBuilder>, FactoryPidAdapterBuilder { |
| 25 | private String m_factoryPid; |
| 26 | private boolean m_propagate; |
| 27 | private final DependencyManager m_dm; |
| 28 | private boolean m_autoAdd = true; |
| 29 | private String m_updateMethodName; |
| 30 | private Object m_updateCallbackInstance; |
| 31 | private boolean m_hasMethodRefs; |
| 32 | private boolean m_hasReflectionCallback; |
| 33 | private Consumer<ComponentBuilder<?>> m_compBuilder = (componentBuilder -> {}); |
| 34 | private final List<MethodRef<Object>> m_refs = new ArrayList<>(); |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 35 | private Class<?> m_configType; |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 36 | |
| 37 | @FunctionalInterface |
| 38 | interface MethodRef<I> { |
| 39 | public void accept(I instance, Component c, Dictionary<String, Object> props); |
| 40 | } |
| 41 | |
| 42 | public FactoryPidAdapterBuilderImpl(DependencyManager dm) { |
| 43 | m_dm = dm; |
| 44 | } |
| 45 | |
| 46 | public void andThenBuild(Consumer<ComponentBuilder<?>> builder) { |
| 47 | m_compBuilder = m_compBuilder.andThen(builder); |
| 48 | } |
| 49 | |
| 50 | @Override |
| 51 | public FactoryPidAdapterBuilderImpl autoAdd(boolean autoAdd) { |
| 52 | m_autoAdd = autoAdd; |
| 53 | return this; |
| 54 | } |
| 55 | |
| 56 | public boolean isAutoAdd() { |
| 57 | return m_autoAdd; |
| 58 | } |
| 59 | |
| 60 | @Override |
| 61 | public FactoryPidAdapterBuilder factoryPid(String pid) { |
| 62 | m_factoryPid = pid; |
| 63 | return this; |
| 64 | } |
| 65 | |
| 66 | @Override |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 67 | public FactoryPidAdapterBuilder propagate() { |
| 68 | m_propagate = true; |
| 69 | return this; |
| 70 | } |
| 71 | |
| 72 | @Override |
| 73 | public FactoryPidAdapterBuilder propagate(boolean propagate) { |
| 74 | m_propagate = propagate; |
| 75 | return this; |
| 76 | } |
| 77 | |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 78 | @Override |
| 79 | public FactoryPidAdapterBuilder update(String update) { |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 80 | checkHasNoMethodRefs(); |
| 81 | m_hasReflectionCallback = true; |
| 82 | m_updateMethodName = update; |
| 83 | return this; |
| 84 | } |
| 85 | |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 86 | @Override |
| 87 | public FactoryPidAdapterBuilder update(Class<?> configType, String updateMethod) { |
| 88 | update(updateMethod); |
| 89 | m_configType = configType; |
| 90 | return this; |
| 91 | } |
| 92 | |
| 93 | @Override |
| 94 | public FactoryPidAdapterBuilder update(Object callbackInstance, String update) { |
| 95 | update(update); |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 96 | m_updateCallbackInstance = callbackInstance; |
| 97 | return this; |
| 98 | } |
| 99 | |
| 100 | @Override |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 101 | public FactoryPidAdapterBuilder update(Class<?> configType, Object callbackInstance, String updateMethod) { |
| 102 | update(callbackInstance, updateMethod); |
| 103 | m_configType = configType; |
| 104 | return this; |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 105 | } |
| 106 | |
| 107 | @Override |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 108 | public <T> FactoryPidAdapterBuilder update(CbDictionary<T> callback) { |
| 109 | Class<T> type = Helpers.getLambdaArgType(callback, 0); |
| 110 | return setComponentCallbackRef(type, (instance, component, props) -> { callback.accept((T) instance, props); }); |
| 111 | } |
| 112 | |
| 113 | @Override |
| 114 | public <T, U> FactoryPidAdapterBuilder update(Class<U> configType, CbConfiguration<T, U> callback) { |
| 115 | Class<T> type = Helpers.getLambdaArgType(callback, 0); |
| 116 | m_factoryPid = m_factoryPid == null ? configType.getName() : m_factoryPid; |
| 117 | return setComponentCallbackRef(type, (instance, component, props) -> { |
| 118 | U configProxy = ((ComponentContext) component).createConfigurationProxy(configType, props); |
| 119 | callback.accept((T) instance, configProxy); |
| 120 | }); |
| 121 | } |
| 122 | |
| 123 | @Override |
| 124 | public <T> FactoryPidAdapterBuilder update(CbDictionaryComponent<T> callback) { |
| 125 | Class<T> type = Helpers.getLambdaArgType(callback, 0); |
| 126 | return setComponentCallbackRef(type, (instance, component, props) -> { callback.accept((T) instance, props, component); }); |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 127 | } |
| 128 | |
| 129 | @Override |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 130 | public <T, U> FactoryPidAdapterBuilder update(Class<U> configType, CbConfigurationComponent<T, U> callback) { |
| 131 | Class<T> type = Helpers.getLambdaArgType(callback, 0); |
| 132 | m_factoryPid = m_factoryPid == null ? configType.getName() : m_factoryPid; |
| 133 | return setComponentCallbackRef(type, (instance, component, props) -> { |
| 134 | U configProxy = ((ComponentContext) component).createConfigurationProxy(configType, props); |
| 135 | callback.accept((T) instance, configProxy, component); |
| 136 | }); |
| 137 | } |
| 138 | |
| 139 | @Override |
| 140 | public FactoryPidAdapterBuilder update(InstanceCbDictionary callback) { |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 141 | return setInstanceCallbackRef((instance, component, props) -> { callback.accept(props); }); |
| 142 | } |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 143 | |
| 144 | @Override |
| 145 | public <T> FactoryPidAdapterBuilder update(Class<T> configType, InstanceCbConfiguration<T> callback) { |
| 146 | return setInstanceCallbackRef((instance, component, props) -> { |
| 147 | T configProxy = ((ComponentContext) component).createConfigurationProxy(configType, props); |
| 148 | callback.accept(configProxy); |
| 149 | }); |
| 150 | } |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 151 | |
| 152 | @Override |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 153 | public FactoryPidAdapterBuilder update(InstanceCbDictionaryComponent callback) { |
| 154 | return setInstanceCallbackRef((instance, component, props) -> { callback.accept(props, component); }); |
| 155 | } |
| 156 | |
| 157 | @Override |
| 158 | public <T> FactoryPidAdapterBuilder update(Class<T> configType, InstanceCbConfigurationComponent<T> callback) { |
| 159 | return setInstanceCallbackRef((instance, component, props) -> { |
| 160 | T configProxy = ((ComponentContext) component).createConfigurationProxy(configType, props); |
| 161 | callback.accept(configProxy, component); |
| 162 | }); |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | @Override |
| 166 | public Component build() { |
| 167 | Objects.nonNull(m_factoryPid); |
| 168 | Component c = null; |
| 169 | |
| 170 | if (m_hasMethodRefs) { |
| 171 | Object wrapCallback = new Object() { |
| 172 | @SuppressWarnings("unused") |
| 173 | public void updated(Component comp, Dictionary<String, Object> conf) { |
| 174 | m_refs.forEach(mref -> mref.accept(null, comp, conf)); |
| 175 | } |
| 176 | }; |
| 177 | c = m_dm.createFactoryConfigurationAdapterService(m_factoryPid, "updated", m_propagate, wrapCallback); |
| 178 | } else { |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 179 | c = m_dm.createFactoryConfigurationAdapterService(m_factoryPid, m_updateMethodName, m_propagate, m_updateCallbackInstance, m_configType); |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 180 | } |
| 181 | ComponentBuilderImpl cb = new ComponentBuilderImpl(c, false); |
| 182 | m_compBuilder.accept (cb); |
| 183 | return cb.build(); |
| 184 | } |
| 185 | |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 186 | private <T> FactoryPidAdapterBuilder setInstanceCallbackRef(MethodRef<T> ref) { |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 187 | checkHasNoReflectionCallbacks(); |
| 188 | m_hasMethodRefs = true; |
| 189 | m_refs.add((instance, component, props) -> ref.accept(null, component, props)); |
| 190 | return this; |
| 191 | } |
| 192 | |
| 193 | @SuppressWarnings("unchecked") |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 194 | private <T> FactoryPidAdapterBuilder setComponentCallbackRef(Class<T> type, MethodRef<T> ref) { |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 195 | checkHasNoReflectionCallbacks(); |
| 196 | m_hasMethodRefs = true; |
| 197 | m_refs.add((instance, component, props) -> { |
| 198 | Object componentImpl = Stream.of(component.getInstances()) |
| 199 | .filter(impl -> Helpers.getClass(impl).equals(type)) |
| 200 | .findFirst() |
| 201 | .orElseThrow(() -> new IllegalStateException("The method reference " + ref + " does not match any available component impl classes.")); |
Pierre De Rop | 1152750 | 2016-02-18 21:07:16 +0000 | [diff] [blame^] | 202 | ref.accept((T) componentImpl, component, props); |
Pierre De Rop | faca289 | 2016-01-31 23:27:05 +0000 | [diff] [blame] | 203 | }); |
| 204 | return this; |
| 205 | } |
| 206 | |
| 207 | private void checkHasNoMethodRefs() { |
| 208 | if (m_hasMethodRefs) { |
| 209 | throw new IllegalStateException("Can't mix method references with reflection based callbacks"); |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | private void checkHasNoReflectionCallbacks() { |
| 214 | if (m_hasReflectionCallback) { |
| 215 | throw new IllegalStateException("Can't mix method references with reflection based callbacks"); |
| 216 | } |
| 217 | } |
| 218 | } |