blob: e13f41f24fc127cce70429b72ff5f2b4b37ef897 [file] [log] [blame]
Pierre De Ropfaca2892016-01-31 23:27:05 +00001/**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.felix.dm.lambda.itest;
20
21import static org.apache.felix.dm.lambda.DependencyManagerActivator.aspect;
22import static org.apache.felix.dm.lambda.DependencyManagerActivator.component;
23
24import java.lang.reflect.InvocationHandler;
25import java.lang.reflect.Method;
26import java.lang.reflect.Proxy;
27
28import org.apache.felix.dm.Component;
29import org.apache.felix.dm.DependencyManager;
30import org.junit.Assert;
31
32/**
33 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
34 */
35@SuppressWarnings({"rawtypes"})
36public class DynamicProxyAspectTest extends TestBase {
37 public void testImplementGenericAspectWithDynamicProxyAndFactory() {
38 DependencyManager m = getDM();
39 // helper class that ensures certain steps get executed in sequence
40 Ensure e = new Ensure();
41
42 DynamicProxyHandler.resetCounter();
43
44 // create two service providers, each providing a different service interface
45 Component sp1 = component(m).impl(new ServiceProvider(e)).provides(ServiceInterface.class).build();
46 Component sp2 = component(m).impl(new ServiceProvider2(e)).provides(ServiceInterface2.class).build();
47
48 // create a dynamic proxy based aspect and hook it up to both services
49 Component a1 = aspect(m, ServiceInterface.class)
50 .rank(10)
51 .autoConfig("m_service")
52 .factory(new Factory(e, ServiceInterface.class, "ServiceInterfaceProxy"), "create")
53 .build();
54
55 Component a2 = aspect(m, ServiceInterface2.class)
56 .rank(10)
57 .autoConfig("m_service")
58 .factory(new Factory(e, ServiceInterface2.class, "ServiceInterfaceProxy2"), "create")
59 .build();
60
61 // create a client that invokes a method on boths services, validate that it goes
62 // through the proxy twice
63 Component sc = component(m)
64 .impl(new ServiceConsumer(e))
Pierre De Rop11527502016-02-18 21:07:16 +000065 .withSvc(ServiceInterface.class, ServiceInterface2.class).build();
Pierre De Ropfaca2892016-01-31 23:27:05 +000066
67 // register both producers, validate that both services are started
68 m.add(sp1);
69 e.waitForStep(1, 2000);
70 m.add(sp2);
71 e.waitForStep(2, 2000);
72
73 // add both aspects, and validate that both instances have been created
74 m.add(a1);
75 m.add(a2);
76 e.waitForStep(4, 4000);
77
78 // add the client, which will automatically invoke both services
79 m.add(sc);
80
81 // wait until both services have been invoked
82 e.waitForStep(6, 4000);
83
84 // make sure the proxy has been called twice
85 Assert.assertEquals("Proxy should have been invoked this many times.", 2, DynamicProxyHandler.getCounter());
86
87 m.remove(sc);
88 m.remove(a2);
89 m.remove(a1);
90 m.remove(sp2);
91 m.remove(sp1);
92 m.remove(a2);
93 m.remove(a1);
94 }
95
96 public void testImplementGenericAspectWithDynamicProxyAndFactoryRef() {
97 DependencyManager m = getDM();
98 // helper class that ensures certain steps get executed in sequence
99 Ensure e = new Ensure();
100
101 DynamicProxyHandler.resetCounter();
102
103 // create two service providers, each providing a different service interface
104 Component sp1 = component(m).impl(new ServiceProvider(e)).provides(ServiceInterface.class).build();
105 Component sp2 = component(m).impl(new ServiceProvider2(e)).provides(ServiceInterface2.class).build();
106
107 // create a dynamic proxy based aspect and hook it up to both services
108 Component a1 = aspect(m, ServiceInterface.class).rank(10).autoConfig("m_service")
109 .factory(() -> new Factory(e, ServiceInterface.class, "ServiceInterfaceProxy"), Factory::create).build();
110 Component a2 = aspect(m, ServiceInterface2.class).rank(10).autoConfig("m_service")
111 .factory(() -> new Factory(e, ServiceInterface2.class, "ServiceInterfaceProxy2"), Factory::create).build();
112
113 // create a client that invokes a method on boths services, validate that it goes
114 // through the proxy twice
115 Component sc = component(m)
116 .impl(new ServiceConsumer(e))
Pierre De Rop11527502016-02-18 21:07:16 +0000117 .withSvc(ServiceInterface.class, ServiceInterface2.class).build();
Pierre De Ropfaca2892016-01-31 23:27:05 +0000118
119 // register both producers, validate that both services are started
120 m.add(sp1);
121 e.waitForStep(1, 2000);
122 m.add(sp2);
123 e.waitForStep(2, 2000);
124
125 // add both aspects, and validate that both instances have been created
126 m.add(a1);
127 m.add(a2);
128 e.waitForStep(4, 4000);
129
130 // add the client, which will automatically invoke both services
131 m.add(sc);
132
133 // wait until both services have been invoked
134 e.waitForStep(6, 4000);
135
136 // make sure the proxy has been called twice
137 Assert.assertEquals("Proxy should have been invoked this many times.", 2, DynamicProxyHandler.getCounter());
138
139 m.remove(sc);
140 m.remove(a2);
141 m.remove(a1);
142 m.remove(sp2);
143 m.remove(sp1);
144 m.remove(a2);
145 m.remove(a1);
146 }
147
148 static interface ServiceInterface {
149 public void invoke(Runnable run);
150 }
151
152 static interface ServiceInterface2 {
153 public void invoke(Runnable run);
154 }
155
156 static class ServiceProvider implements ServiceInterface {
157 private final Ensure m_ensure;
158 public ServiceProvider(Ensure e) {
159 m_ensure = e;
160 }
161 public void start() {
162 m_ensure.step(1);
163 }
164 public void invoke(Runnable run) {
165 run.run();
166 }
167 }
168
169 static class ServiceProvider2 implements ServiceInterface2 {
170 private final Ensure m_ensure;
171 public ServiceProvider2(Ensure ensure) {
172 m_ensure = ensure;
173 }
174 public void start() {
175 m_ensure.step(2);
176 }
177 public void invoke(Runnable run) {
178 run.run();
179 }
180 }
181
182 static class ServiceConsumer implements Runnable {
183 private volatile ServiceInterface m_service;
184 private volatile ServiceInterface2 m_service2;
185 private final Ensure m_ensure;
186
187 public ServiceConsumer(Ensure e) {
188 m_ensure = e;
189 }
190
191 public void init() {
192 Thread t = new Thread(this);
193 t.start();
194 }
195
196 public void run() {
197 m_service.invoke(Ensure.createRunnableStep(m_ensure, 5));
198 m_service2.invoke(Ensure.createRunnableStep(m_ensure, 6));
199 }
200 }
201
202 static class DynamicProxyHandler implements InvocationHandler {
203 public volatile Object m_service; // ISSUE, we cannot inject into "Object" at the moment
204 private final String m_label;
205 private static volatile int m_counter = 0;
206
207 public DynamicProxyHandler(String label) {
208 m_label = label;
209 }
210
211 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
212 System.out.println("IIIIIIINVOKE--------------------------" + method.getName());
213 if (m_service == null) {
214 Assert.fail("No service was injected into dynamic proxy handler " + m_label);
215 }
216 Method m = m_service.getClass().getMethod(method.getName(), method.getParameterTypes());
217 if (m == null) {
218 Assert.fail("No method " + method.getName() + " was found in instance " + m_service + " in dynamic proxy handler " + m_label);
219 }
220 if (method.getName().equals("invoke")) {
221 // only count methods called 'invoke' because those are actually the ones
222 // both interfaces implement (and the dynamic proxy might be invoked for
223 // other methods, such as toString() as well)
224 m_counter++;
225 }
226 return m.invoke(m_service, args);
227 }
228
229 public static int getCounter() {
230 return m_counter;
231 }
232
233 public static void resetCounter() {
234 m_counter = 0;
235 }
236 }
237
238 static class Factory {
239 private final String m_label;
240 private Class m_class;
241 private final Ensure m_ensure;
242
243 public Factory(Ensure ensure, Class clazz, String label) {
244 m_ensure = ensure;
245 m_class = clazz;
246 m_label = label;
247 }
248
249 public Object create() {
250 m_ensure.step();
251 return Proxy.newProxyInstance(m_class.getClassLoader(), new Class[] { m_class }, new DynamicProxyHandler(m_label));
252 }
253 }
254}