blob: 10e2f081f526d7d70ad9883db5b3fd2f0c0a12eb [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.adapter;
22import static org.apache.felix.dm.lambda.DependencyManagerActivator.component;
23
24import java.util.Map;
25import java.util.Properties;
26
27import org.apache.felix.dm.Component;
28import org.apache.felix.dm.DependencyManager;
29import org.junit.Assert;
30
31/**
32 * Test for FELIX-4334 issue.
33 *
34 * Three components: A, B and C
35 *
36 * - A provided with property foo=bar
37 * - B adapts A, B has no filters on A, and B.init() method adds an instance bound required dependency to C.
38 * - C depends on A(foo=bar)
39 * - Now someone modifies the service properties of A: foo=bar2
40 * - As a result of that, C becomes unavailable and is unbound from B.
41 * - Since B has an instance bound required dependency to C: B should not be destroyed: it should be called in B.stop(), B.remove(C), B.change(A, "foo=bar2))
42 *
43 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
44 */
45public class AdapterWithModifiedInstanceBoundDependencyTest extends TestBase {
46 public static interface A {
47 }
48
49 static class AImpl implements A {
50 final Ensure m_e;
51 AImpl(Ensure e) {
52 m_e = e;
53 }
54 }
55
56 public static interface C {
57 }
58
59 static class CImpl implements C {
60 volatile A m_a;
61 }
62
63 public static interface B {
64 }
65
66 public static class BImpl implements B {
67 final Ensure m_e;
68 volatile A m_a;
69 volatile C m_c;
70
71 BImpl(Ensure e) {
72 m_e = e;
73 }
74
75 void init(Component comp) {
76 m_e.step(2);
Pierre De Rop11527502016-02-18 21:07:16 +000077 component(comp, c->c.withSvc(C.class, s->s.add("addC").remove("removeC")));
Pierre De Ropfaca2892016-01-31 23:27:05 +000078 }
79
80 void addA(A a, Map<String, Object> properties) {
81 m_e.step(1);
82 }
83
84 public void addC(C c) {
85 m_e.step(3);
86 }
87
88 public void start() {
89 m_e.step(4);
90 }
91
92 public void stop() { // C becomes unsatisfied when A properties are changed to foo=bar2
93 m_e.step(5);
94 }
95
96 public void removeC(C c) {
97 m_e.step(6);
98 }
99
100 public void changeA(A a, Map<String, Object> properties) {
101 Assert.assertEquals("bar2", properties.get("foo"));
102 m_e.step(7);
103 }
104
105 public void destroy() {
106 m_e.step(8);
107 }
108
109 public void removeA(A a, Map<String, Object> properties) {
110 m_e.step(9);
111 }
112 }
113
114 public void testAdapterWithChangedInstanceBoundDependency() {
115 DependencyManager m = getDM();
116 Ensure e = new Ensure();
117
118 Component a = component(m).impl(new AImpl(e)).provides(A.class).properties(foo -> "bar").build();
Pierre De Rop11527502016-02-18 21:07:16 +0000119 Component b = adapter(m, A.class).provides(B.class).impl(new BImpl(e)).add("addA").change("changeA").remove("removeA").build();
120 Component c = component(m).impl(new CImpl()).provides(C.class).withSvc(A.class, "(foo=bar)").build();
Pierre De Ropfaca2892016-01-31 23:27:05 +0000121
122 m.add(a);
123 m.add(c);
124 m.add(b);
125
126 e.waitForStep(4, 5000);
127
128 System.out.println("changing A props ...");
129 Properties props = new Properties();
130 props.put("foo", "bar2");
131 a.setServiceProperties(props);
132
133 e.waitForStep(7, 5000);
134
135 m.remove(c);
136 m.remove(a);
137 m.remove(b);
138
139 e.waitForStep(9, 5000);
140 }
141
142 public void testAdapterWithChangedInstanceBoundDependencyRef() {
143 DependencyManager m = getDM();
144 Ensure e = new Ensure();
145
146 Component a = component(m).impl(new AImpl(e)).provides(A.class).properties(foo -> "bar").build();
Pierre De Rop11527502016-02-18 21:07:16 +0000147 Component b = adapter(m, A.class).impl(new BImpl(e)).provides(B.class).add(BImpl::addA).change(BImpl::changeA).remove(BImpl::removeA).build();
148 Component c = component(m).impl(new CImpl()).provides(C.class).withSvc(A.class, s -> s.filter("(foo=bar)")).build();
Pierre De Ropfaca2892016-01-31 23:27:05 +0000149
150 m.add(a);
151 m.add(c);
152 m.add(b);
153
154 e.waitForStep(4, 5000);
155
156 System.out.println("changing A props ...");
157 Properties props = new Properties();
158 props.put("foo", "bar2");
159 a.setServiceProperties(props);
160
161 e.waitForStep(7, 5000);
162
163 m.remove(c);
164 m.remove(a);
165 m.remove(b);
166
167 e.waitForStep(9, 5000);
168 }
169}