blob: bbb0995f02486c80eab8bd9352358deabc7df9ff [file] [log] [blame]
Marcel Offermans2f6e82b2011-04-19 07:19:58 +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 */
Marcel Offermans90ba4fa2011-04-27 07:57:44 +000019package org.apache.felix.dm.impl.index;
Marcel Offermans227dd712011-04-19 07:14:22 +000020
Xander Uiterlinden48f267b2013-06-03 12:13:09 +000021import java.util.ArrayList;
Marcel Offermans227dd712011-04-19 07:14:22 +000022import java.util.HashMap;
23import java.util.Iterator;
24import java.util.List;
25import java.util.Map;
26import java.util.concurrent.CopyOnWriteArrayList;
27
Marcel Offermans837cc962011-04-27 08:00:29 +000028import org.apache.felix.dm.FilterIndex;
Xander Uiterlinden48f267b2013-06-03 12:13:09 +000029import org.apache.felix.dm.impl.Logger;
Marcel Offermans227dd712011-04-19 07:14:22 +000030import org.osgi.framework.BundleContext;
31import org.osgi.framework.ServiceEvent;
32import org.osgi.framework.ServiceListener;
Marcel Offermans227dd712011-04-19 07:14:22 +000033import org.osgi.framework.ServiceRegistration;
34
Marcel Offermans5be5f142011-04-26 10:47:12 +000035/**
36 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
37 */
Marcel Offermansfd7deb02011-04-20 11:26:09 +000038public class ServiceRegistryCache implements ServiceListener/*, CommandProvider*/ {
Xander Uiterlinden48f267b2013-06-03 12:13:09 +000039 private static final String INDEX_PERFLOG = "org.apache.felix.dependencymanager.index.logmissingindices";
40 private final List /* <FilterIndex> */ m_filterIndexList = new CopyOnWriteArrayList();
Marcel Offermans227dd712011-04-19 07:14:22 +000041 private final BundleContext m_context;
42 private final FilterIndexBundleContext m_filterIndexBundleContext;
43 private final Map /* <BundleContext, BundleContextInterceptor> */ m_bundleContextInterceptorMap = new HashMap();
44 private long m_currentVersion = 0;
45 private long m_arrayVersion = -1;
46 private BundleContextInterceptor[] m_interceptors = null;
47 private ServiceRegistration m_registration;
Xander Uiterlinden48f267b2013-06-03 12:13:09 +000048 private boolean m_dumpUnIndexedFilters = "true".equals(System.getProperty(INDEX_PERFLOG));
49 private List m_unindexedFilters = new ArrayList();
50 private Logger m_logger;
Marcel Offermans227dd712011-04-19 07:14:22 +000051
52 public ServiceRegistryCache(BundleContext context) {
53 m_context = context;
Xander Uiterlinden48f267b2013-06-03 12:13:09 +000054 // only obtain the logservice when we actually want to log something.
55 if (System.getProperty(INDEX_PERFLOG) != null) {
56 m_logger = new Logger(context);
57 }
Marcel Offermans227dd712011-04-19 07:14:22 +000058 m_filterIndexBundleContext = new FilterIndexBundleContext(m_context);
59 }
60
61 public void open() {
62 m_context.addServiceListener(this);
Marcel Offermansfd7deb02011-04-20 11:26:09 +000063// m_registration = m_context.registerService(CommandProvider.class.getName(), this, null);
Marcel Offermans227dd712011-04-19 07:14:22 +000064 }
65
66 public void close() {
Marcel Offermansfd7deb02011-04-20 11:26:09 +000067// m_registration.unregister();
Marcel Offermans227dd712011-04-19 07:14:22 +000068 m_context.removeServiceListener(this);
69 }
70
71 public void addFilterIndex(FilterIndex index) {
72 m_filterIndexList.add(index);
73 index.open(m_filterIndexBundleContext);
74 }
75
76 public void removeFilterIndex(FilterIndex index) {
77 index.close();
78 m_filterIndexList.remove(index);
79 }
80
81 public void serviceChanged(ServiceEvent event) {
82 // any incoming event is first dispatched to the list of filter indices
83 m_filterIndexBundleContext.serviceChanged(event);
84 // and then all the other listeners can access it
85 synchronized (m_bundleContextInterceptorMap) {
86 if (m_currentVersion != m_arrayVersion) {
87 // if our copy is out of date, we make a new one
88 m_interceptors = (BundleContextInterceptor[]) m_bundleContextInterceptorMap.values().toArray(new BundleContextInterceptor[m_bundleContextInterceptorMap.size()]);
89 m_arrayVersion = m_currentVersion;
90 }
91 }
Marcel Offermansad965fb2011-05-10 08:07:08 +000092
93 serviceChangedForFilterIndices(event);
Marcel Offermans227dd712011-04-19 07:14:22 +000094 }
95
96 /** Creates an interceptor for a bundle context that uses our cache. */
97 public BundleContext createBundleContextInterceptor(BundleContext context) {
98 synchronized (m_bundleContextInterceptorMap) {
99 BundleContextInterceptor bundleContextInterceptor = (BundleContextInterceptor) m_bundleContextInterceptorMap.get(context);
100 if (bundleContextInterceptor == null) {
Xander Uiterlinden48f267b2013-06-03 12:13:09 +0000101 bundleContextInterceptor = new BundleContextInterceptor(this, context, m_logger);
Marcel Offermans227dd712011-04-19 07:14:22 +0000102 m_bundleContextInterceptorMap.put(context, bundleContextInterceptor);
103 m_currentVersion++;
104 // TODO figure out a good way to clean up bundle contexts that are no longer valid so they can be garbage collected
105 }
106 return bundleContextInterceptor;
107 }
108 }
109
110 public FilterIndex hasFilterIndexFor(String clazz, String filter) {
111 Iterator iterator = m_filterIndexList.iterator();
112 while (iterator.hasNext()) {
113 FilterIndex filterIndex = (FilterIndex) iterator.next();
114 if (filterIndex.isApplicable(clazz, filter)) {
115 return filterIndex;
116 }
117 }
Xander Uiterlinden48f267b2013-06-03 12:13:09 +0000118 if (m_dumpUnIndexedFilters) {
119 String filterStr = clazz + ":" + filter;
120 if (!m_unindexedFilters.contains(filterStr)) {
121 m_unindexedFilters.add(filterStr);
122 m_logger.log(Logger.LOG_DEBUG, "No filter index for " + filterStr);
123 }
124 }
Marcel Offermans227dd712011-04-19 07:14:22 +0000125 return null;
126 }
127
128 public void serviceChangedForFilterIndices(ServiceEvent event) {
129 Iterator iterator = m_filterIndexList.iterator();
130 while (iterator.hasNext()) {
131 FilterIndex filterIndex = (FilterIndex) iterator.next();
132 filterIndex.serviceChanged(event);
133 }
134 }
135
Marcel Offermansfd7deb02011-04-20 11:26:09 +0000136// public void _sc(CommandInterpreter ci) {
137// ci.println(toString());
138// }
139//
140// public void _fi(CommandInterpreter ci) {
141// String arg = ci.nextArgument();
142// if (arg != null) {
143// int x = Integer.parseInt(arg);
144// FilterIndex filterIndex = (FilterIndex) m_filterIndexList.get(x);
145// String a1 = ci.nextArgument();
146// String a2 = null;
147// if (a1 != null) {
148// if ("-".equals(a1)) {
149// a1 = null;
150// }
151// a2 = ci.nextArgument();
152// }
153// if (filterIndex.isApplicable(a1, a2)) {
154// List /* <ServiceReference> */ references = filterIndex.getAllServiceReferences(a1, a2);
155// ci.println("Found " + references.size() + " references:");
156// for (int i = 0; i < references.size(); i++) {
157// ci.println("" + i + " - " + references.get(i));
158// }
159// }
160// else {
161// ci.println("Filter not applicable.");
162// }
163// }
164// else {
165// ci.println("FilterIndices:");
166// Iterator iterator = m_filterIndexList.iterator();
167// int index = 0;
168// while (iterator.hasNext()) {
169// FilterIndex filterIndex = (FilterIndex) iterator.next();
170// ci.println("" + index + " " + filterIndex);
171// index++;
172// }
173// }
174// }
175//
176// public String getHelp() {
177// return "I'm not going to help you!";
178// }
Marcel Offermans227dd712011-04-19 07:14:22 +0000179
180 public String toString() {
181 StringBuffer sb = new StringBuffer();
182 sb.append("ServiceRegistryCache[");
183 sb.append("FilterIndices: " + m_filterIndexList.size());
184 sb.append(", BundleContexts intercepted: " + m_bundleContextInterceptorMap.size());
185 sb.append("]");
186 return sb.toString();
187 }
Xander Uiterlinden3c194c32012-06-19 14:51:52 +0000188
189 public List getFilterIndices() {
190 return m_filterIndexList;
191 }
Marcel Offermans227dd712011-04-19 07:14:22 +0000192}