blob: 740e000028f0414cfcacd971e2ec8ede93f39cf6 [file] [log] [blame]
Xander Uiterlindenb64a8e22012-04-03 14:42:23 +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.impl.index;
20
21import java.util.ArrayList;
22import java.util.HashMap;
23import java.util.Iterator;
24import java.util.List;
25import java.util.Map;
26import java.util.Set;
27import java.util.SortedSet;
28import java.util.TreeSet;
29
30import org.apache.felix.dm.DependencyManager;
31import org.apache.felix.dm.FilterIndex;
32import org.apache.felix.dm.ServiceUtil;
33import org.apache.felix.dm.tracker.ServiceTracker;
34import org.apache.felix.dm.tracker.ServiceTrackerCustomizer;
35import org.osgi.framework.BundleContext;
36import org.osgi.framework.Constants;
37import org.osgi.framework.InvalidSyntaxException;
38import org.osgi.framework.ServiceEvent;
39import org.osgi.framework.ServiceListener;
40import org.osgi.framework.ServiceReference;
41
42/**
43 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
44 */
45public class AdapterFilterIndex implements FilterIndex, ServiceTrackerCustomizer {
46 // (&(objectClass=com.beinformed.product.platform.interfaces.Resource)(|(service.id=18233)(org.apache.felix.dependencymanager.aspect=18233)))
47 private static final String FILTER_START = "(&(" + Constants.OBJECTCLASS + "=";
48 private static final String FILTER_SUBSTRING_0 = ")(|(" + Constants.SERVICE_ID + "=";
49 private static final String FILTER_SUBSTRING_1 = ")(" + DependencyManager.ASPECT + "=";
50 private static final String FILTER_END = ")))";
51 private final Object m_lock = new Object();
52 private ServiceTracker m_tracker;
53 private BundleContext m_context;
54 private final Map /* <Long, SortedSet<ServiceReference>> */ m_sidToServiceReferencesMap = new HashMap();
55 private final Map /* <String, List<ServiceListener>> */ m_sidToListenersMap = new HashMap();
56 private final Map /* <ServiceListener, String> */ m_listenerToFilterMap = new HashMap();
57
58 public void open(BundleContext context) {
59 synchronized (m_lock) {
60 if (m_context != null) {
61 throw new IllegalStateException("Filter already open.");
62 }
63 try {
64 m_tracker = new ServiceTracker(context, context.createFilter("(" + Constants.OBJECTCLASS + "=*)"), this);
65 }
66 catch (InvalidSyntaxException e) {
67 throw new Error();
68 }
69 m_context = context;
70 }
71 m_tracker.open(true, true);
72 }
73
74 public void close() {
75 ServiceTracker tracker;
76 synchronized (m_lock) {
77 if (m_context == null) {
78 throw new IllegalStateException("Filter already closed.");
79 }
80 tracker = m_tracker;
81 m_tracker = null;
82 m_context = null;
83 }
84 tracker.close();
85 }
86
87 public boolean isApplicable(String clazz, String filter) {
88 return getFilterData(clazz, filter) != null;
89 }
90
91 /** Returns a value object with the relevant filter data, or <code>null</code> if this filter was not valid. */
92 private FilterData getFilterData(String clazz, String filter) {
93 // something like:
94 // (&(objectClass=com.beinformed.product.platform.interfaces.Resource)(|(service.id=18233)(org.apache.felix.dependencymanager.aspect=18233)))
95 if ((filter != null)
96 && (filter.startsWith(FILTER_START))
97 && (filter.endsWith(FILTER_END))
98 ) {
99 // service-id =
100 int i0 = filter.indexOf(FILTER_SUBSTRING_0);
101 if (i0 == -1) {
102 return null;
103 }
104 // org.apache.felix.dependencymanager.aspect =
105 int i1 = filter.indexOf(FILTER_SUBSTRING_1);
106 if (i1 == -1 || i1 <= i0) {
107 return null;
108 }
109 long sid = Long.parseLong(filter.substring(i0 + FILTER_SUBSTRING_0.length(), i1));
110 long sid2 = Long.parseLong(filter.substring(i1 + FILTER_SUBSTRING_1.length(), filter.length() - FILTER_END.length()));
111 if (sid != sid2) {
112 return null;
113 }
114 FilterData result = new FilterData();
115 result.serviceId = sid;
116 return result;
117 }
118 return null;
119 }
120
121 public List getAllServiceReferences(String clazz, String filter) {
122 List /* <ServiceReference> */ result = new ArrayList();
123 FilterData data = getFilterData(clazz, filter);
124 if (data != null) {
125 SortedSet /* <ServiceReference> */ list = null;
126 synchronized (m_sidToServiceReferencesMap) {
127 list = (SortedSet) m_sidToServiceReferencesMap.get(Long.valueOf(data.serviceId));
128 }
129 if (list != null) {
130 Iterator iterator = list.iterator();
131 while (iterator.hasNext()) {
132 result.add((ServiceReference) iterator.next());
133 }
134 }
135 }
136 return result;
137 }
138
139 public void serviceChanged(ServiceEvent event) {
140 ServiceReference reference = event.getServiceReference();
141 Long sid = ServiceUtil.getServiceIdObject(reference);
142 synchronized (m_sidToListenersMap) {
143 List /* <Integer, ServiceListener> */ list = (ArrayList) m_sidToListenersMap.get(sid);
144 if (list != null) {
145 Iterator iterator = list.iterator();
146 while (iterator.hasNext()) {
147 ServiceListener listener = (ServiceListener) iterator.next();
148 listener.serviceChanged(event);
149 }
150 }
151 }
152 }
153
154 public void addServiceListener(ServiceListener listener, String filter) {
155 FilterData data = getFilterData(null, filter);
156 if (data != null) {
157 Long sidObject = Long.valueOf(data.serviceId);
158 synchronized (m_sidToListenersMap) {
159 List /* <ServiceListener> */ listeners = (List) m_sidToListenersMap.get(sidObject);
160 if (listeners == null) {
161 listeners = new ArrayList();
162 m_sidToListenersMap.put(sidObject, listeners);
163 }
164 listeners.add(listener);
165 }
166 }
167 }
168
169 public void removeServiceListener(ServiceListener listener) {
170 synchronized (m_sidToListenersMap) {
171 String filter = (String) m_listenerToFilterMap.remove(listener);
172 FilterData data = getFilterData(null, filter);
173 if (data != null) {
174 Long sidObject = Long.valueOf(data.serviceId);
175 List /* ServiceListener */ listeners = (List) m_sidToListenersMap.get(sidObject);
176 if (listeners != null) {
177 listeners.remove(listener);
178 }
179 }
180 }
181 }
182
183 public Object addingService(ServiceReference reference) {
184 BundleContext context;
185 synchronized (m_lock) {
186 context = m_context;
187 }
188 if (context != null) {
189 return context.getService(reference);
190 }
191 else {
192 throw new IllegalStateException("No valid bundle context.");
193 }
194 }
195
196 public void addedService(ServiceReference reference, Object service) {
197 add(reference);
198 }
199
200 public void modifiedService(ServiceReference reference, Object service) {
201 modify(reference);
202 }
203
204 public void removedService(ServiceReference reference, Object service) {
205 remove(reference);
206 }
207
208 public void add(ServiceReference reference) {
209 Long sid = ServiceUtil.getServiceIdObject(reference);
210 synchronized (m_sidToServiceReferencesMap) {
211 Set list = (Set) m_sidToServiceReferencesMap.get(sid);
212 if (list == null) {
213 list = new TreeSet();
214 m_sidToServiceReferencesMap.put(sid, list);
215 }
216 list.add(reference);
217 }
218 }
219
220 public void modify(ServiceReference reference) {
221 remove(reference);
222 add(reference);
223 }
224
225 public void remove(ServiceReference reference) {
226 Long sid = ServiceUtil.getServiceIdObject(reference);
227 synchronized (m_sidToServiceReferencesMap) {
228 Set list = (Set) m_sidToServiceReferencesMap.get(sid);
229 if (list != null) {
230 list.remove(reference);
231 }
232 }
233 }
234
235 public String toString() {
236 StringBuffer sb = new StringBuffer();
237 sb.append("AdapterFilterIndex[");
238 sb.append("S2L: " + m_sidToListenersMap.size());
239 sb.append(", S2SR: " + m_sidToServiceReferencesMap.size());
240 sb.append(", L2F: " + m_listenerToFilterMap.size());
241 sb.append("]");
242 return sb.toString();
243 }
244
245 /** Structure to hold internal filter data. */
246 private static class FilterData {
247 public long serviceId;
248 }
249
250}