blob: 9c71882ab5dc3f372c44dd43092d630b5c6d1530 [file] [log] [blame]
Carsten Ziegeler64c6f7a2007-08-15 09:58:35 +00001/*
Felix Meschbergerc90e3162007-03-28 14:34:01 +00002 * 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 */
Felix Meschberger9c778652009-07-09 13:02:12 +000019package org.apache.felix.scr.impl.manager;
Felix Meschbergerc90e3162007-03-28 14:34:01 +000020
21
Felix Meschberger3e26f2d2009-04-20 11:13:27 +000022import java.util.ArrayList;
23import java.util.Collections;
24import java.util.Dictionary;
25import java.util.HashMap;
26import java.util.List;
27import java.util.Map;
Felix Meschbergerc90e3162007-03-28 14:34:01 +000028
Felix Meschbergerd25a63d2007-11-23 13:02:49 +000029import org.apache.felix.scr.Reference;
Felix Meschberger9c778652009-07-09 13:02:12 +000030import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
Felix Meschberger3e26f2d2009-04-20 11:13:27 +000031import org.osgi.framework.BundleContext;
32import org.osgi.framework.Constants;
33import org.osgi.framework.Filter;
34import org.osgi.framework.InvalidSyntaxException;
35import org.osgi.framework.ServiceEvent;
36import org.osgi.framework.ServiceListener;
37import org.osgi.framework.ServiceReference;
Felix Meschbergerba3da7a2009-07-09 12:26:58 +000038import org.osgi.service.component.ComponentConstants;
Felix Meschberger29e04e32007-08-30 14:53:12 +000039import org.osgi.service.log.LogService;
Felix Meschbergerc90e3162007-03-28 14:34:01 +000040
41
42/**
Felix Meschberger43d2a712007-09-17 08:51:36 +000043 * The <code>DependencyManager</code> manages the references to services
44 * declared by a single <code>&lt;reference&gt;</code element in component
45 * descriptor.
Felix Meschbergerc90e3162007-03-28 14:34:01 +000046 */
Felix Meschberger9c778652009-07-09 13:02:12 +000047public class DependencyManager implements ServiceListener, Reference
Felix Meschbergerc90e3162007-03-28 14:34:01 +000048{
49 // mask of states ok to send events
50 private static final int STATE_MASK = AbstractComponentManager.STATE_UNSATISFIED
51 | AbstractComponentManager.STATE_ACTIVATING | AbstractComponentManager.STATE_ACTIVE
52 | AbstractComponentManager.STATE_REGISTERED | AbstractComponentManager.STATE_FACTORY;
Felix Meschberger9b6b5092007-10-01 14:18:04 +000053
Felix Meschberger9dadeef2007-09-17 10:57:44 +000054 // the ServiceReference class instance
55 private static final Class SERVICE_REFERENCE_CLASS = ServiceReference.class;
Felix Meschberger9b6b5092007-10-01 14:18:04 +000056
Felix Meschberger9dadeef2007-09-17 10:57:44 +000057 // pseudo service to mark a bound service without actual service instance
58 private static final Object BOUND_SERVICE_SENTINEL = new Object();
Felix Meschbergerc90e3162007-03-28 14:34:01 +000059
60 // the component to which this dependency belongs
61 private AbstractComponentManager m_componentManager;
62
63 // Reference to the metadata
64 private ReferenceMetadata m_dependencyMetadata;
65
Felix Meschberger43d2a712007-09-17 08:51:36 +000066 // The map of bound services indexed by their ServiceReference
67 private Map m_bound;
Felix Meschberger9b6b5092007-10-01 14:18:04 +000068
Felix Meschberger43d2a712007-09-17 08:51:36 +000069 // the number of matching services registered in the system
70 private int m_size;
Felix Meschbergerc90e3162007-03-28 14:34:01 +000071
Felix Meschberger3e26f2d2009-04-20 11:13:27 +000072 // the object on which the bind/undind methods are to be called
73 private transient Object m_componentInstance;
Felix Meschberger5d89d562009-06-16 09:36:14 +000074
Felix Meschberger9dadeef2007-09-17 10:57:44 +000075 // the bind method
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +000076 private BindMethod m_bind;
Felix Meschberger9b6b5092007-10-01 14:18:04 +000077
Felix Meschberger9dadeef2007-09-17 10:57:44 +000078 // whether the bind method takes a service reference
79 private boolean m_bindUsesReference;
Felix Meschberger9b6b5092007-10-01 14:18:04 +000080
Felix Meschberger9dadeef2007-09-17 10:57:44 +000081 // the unbind method
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +000082 private UnbindMethod m_unbind;
Felix Meschberger9b6b5092007-10-01 14:18:04 +000083
Felix Meschberger9dadeef2007-09-17 10:57:44 +000084 // whether the unbind method takes a service reference
85 private boolean m_unbindUsesReference;
Felix Meschbergerc90e3162007-03-28 14:34:01 +000086
Felix Meschberger9b6b5092007-10-01 14:18:04 +000087 // the target service filter string
88 private String m_target;
89
90 // the target service filter
91 private Filter m_targetFilter;
Felix Meschberger5d89d562009-06-16 09:36:14 +000092
Felix Meschberger9b6b5092007-10-01 14:18:04 +000093
Felix Meschbergerc90e3162007-03-28 14:34:01 +000094 /**
95 * Constructor that receives several parameters.
Carsten Ziegeler64c6f7a2007-08-15 09:58:35 +000096 *
Felix Meschbergerc90e3162007-03-28 14:34:01 +000097 * @param dependency An object that contains data about the dependency
98 */
99 DependencyManager( AbstractComponentManager componentManager, ReferenceMetadata dependency )
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000100 {
Carsten Ziegeler7cbcef52007-08-15 11:37:08 +0000101 m_componentManager = componentManager;
102 m_dependencyMetadata = dependency;
Felix Meschberger43d2a712007-09-17 08:51:36 +0000103 m_bound = Collections.synchronizedMap( new HashMap() );
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000104
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000105 // setup the target filter from component descriptor
106 setTargetFilter( m_dependencyMetadata.getTarget() );
107
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000108 m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager " + getName() + " created: filter="
Felix Meschbergerc7325602009-05-25 21:07:04 +0000109 + getTarget() + ", interface=" + m_dependencyMetadata.getInterface(), m_componentManager
110 .getComponentMetadata(), null );
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000111 }
112
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +0000113 /**
114 * Initialize binding methods.
115 */
116 private void initBindingMethods()
117 {
118 BindMethod.Logger logger = new BindMethod.Logger()
119 {
120
121 public void log( int level, String message )
122 {
123 log( level, message, null );
124 }
125
126 public void log( int level, String message, Throwable ex )
127 {
128 m_componentManager.log( level, message, m_componentManager.getComponentMetadata(), ex );
129 }
130 };
131 m_bind = new BindMethod( m_dependencyMetadata.getBind(),
132 m_componentInstance.getClass(),
133 m_dependencyMetadata.getName(),
134 m_dependencyMetadata.getInterface(),
135 logger
136 );
137 m_unbind = new UnbindMethod( m_dependencyMetadata.getUnbind(),
138 m_componentInstance.getClass(),
139 m_dependencyMetadata.getName(),
140 m_dependencyMetadata.getInterface(),
141 logger
142 );
143 }
144
145
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000146
147 //---------- ServiceListener interface ------------------------------------
148
Felix Meschberger38b77d72007-09-18 09:22:10 +0000149 /**
150 * Called when a registered service changes state. In the case of service
151 * modification the service is assumed to be removed and added again.
152 */
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000153 public void serviceChanged( ServiceEvent event )
154 {
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000155 final ServiceReference ref = event.getServiceReference();
156 final String serviceString = "Service " + m_dependencyMetadata.getInterface() + "/"
157 + ref.getProperty( Constants.SERVICE_ID );
158
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000159 switch ( event.getType() )
160 {
161 case ServiceEvent.REGISTERED:
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000162 m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager: Adding " + serviceString,
163 m_componentManager.getComponentMetadata(), null );
Felix Meschberger5d89d562009-06-16 09:36:14 +0000164
Felix Meschbergerf60039b2009-04-27 09:44:55 +0000165 // consider the service if the filter matches
166 if ( targetFilterMatch( ref ) )
167 {
168 m_size++;
169 serviceAdded( ref );
170 }
171 else
172 {
173 m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager: Ignoring added Service for "
174 + m_dependencyMetadata.getName() + " : does not match target filter " + getTarget(),
175 m_componentManager.getComponentMetadata(), null );
176 }
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000177 break;
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000178
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000179 case ServiceEvent.MODIFIED:
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000180 m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager: Updating " + serviceString,
181 m_componentManager.getComponentMetadata(), null );
Felix Meschberger5d89d562009-06-16 09:36:14 +0000182
Felix Meschbergerf60039b2009-04-27 09:44:55 +0000183 // remove the service first
Felix Meschbergerafbd25f2009-07-31 15:55:42 +0000184 // only continue with further event handling if the service
185 // removal did not cause the component to be deactivated
186 if ( serviceRemoved( ref ) )
187 {
188 // recalculate the number of services matching the filter
189 // because we don't know whether this service previously matched
190 // or not
191 ServiceReference refs[] = getFrameworkServiceReferences();
192 m_size = ( refs == null ) ? 0 : refs.length;
Felix Meschberger5d89d562009-06-16 09:36:14 +0000193
Felix Meschbergerafbd25f2009-07-31 15:55:42 +0000194 // now try to bind the service - if it matches the target filter
195 // without recalculating the size (already done).
196 if ( targetFilterMatch( ref ) )
197 {
198 serviceAdded( ref );
199 }
200 }
Felix Meschbergerf60039b2009-04-27 09:44:55 +0000201
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000202 break;
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000203
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000204 case ServiceEvent.UNREGISTERING:
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000205 m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager: Removing " + serviceString,
206 m_componentManager.getComponentMetadata(), null );
Felix Meschberger5d89d562009-06-16 09:36:14 +0000207
Felix Meschbergerf60039b2009-04-27 09:44:55 +0000208 // manage the service counter if the filter matchs
209 if ( targetFilterMatch( ref ) )
210 {
211 m_size--;
212 }
213 else
214 {
215 m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager: Not counting Service for "
216 + m_dependencyMetadata.getName() + " : Service " + ref.getProperty( Constants.SERVICE_ID )
217 + " does not match target filter " + getTarget(), m_componentManager.getComponentMetadata(),
218 null );
219 }
220
221 // remove the service ignoring the filter match because if the
222 // service is bound, it has to be removed no matter what
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000223 serviceRemoved( ref );
Felix Meschberger5d89d562009-06-16 09:36:14 +0000224
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000225 break;
226 }
227 }
228
229
Felix Meschberger38b77d72007-09-18 09:22:10 +0000230 /**
231 * Called by the {@link #serviceChanged(ServiceEvent)} method if a new
232 * service is registered with the system or if a registered service has been
233 * modified.
234 * <p>
235 * Depending on the component state and dependency configuration, the
236 * component may be activated, re-activated or the service just be provided.
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000237 *
Felix Meschberger38b77d72007-09-18 09:22:10 +0000238 * @param reference The reference to the service newly registered or
239 * modified.
240 */
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000241 private void serviceAdded( ServiceReference reference )
242 {
243 // if the component is currently unsatisfied, it may become satisfied
Felix Meschberger8b3d4642009-05-25 21:13:24 +0000244 // by adding this service, try to activate (also schedule activation
245 // if the component is pending deactivation)
Felix Meschbergerd3fc8bf2009-06-02 14:43:54 +0000246 if ( m_componentManager.getState() == AbstractComponentManager.STATE_ENABLED )
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000247 {
Felix Meschberger1f928f22008-05-30 19:56:02 +0000248 m_componentManager.log( LogService.LOG_INFO, "Dependency Manager: Service "
Felix Meschberger8b3d4642009-05-25 21:13:24 +0000249 + m_dependencyMetadata.getName() + " registered, activate component", m_componentManager
Felix Meschberger1f928f22008-05-30 19:56:02 +0000250 .getComponentMetadata(), null );
Felix Meschberger3f870872007-09-20 11:05:51 +0000251
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000252 m_componentManager.activate();
253 }
254
255 // otherwise check whether the component is in a state to handle the event
256 else if ( handleServiceEvent() )
257 {
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000258
Felix Meschbergerafbd25f2009-07-31 15:55:42 +0000259 // FELIX-1413: if the dependency is static and the component is
260 // satisfied (active) added services are not considered until
261 // the component is reactivated for other reasons.
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000262 if ( m_dependencyMetadata.isStatic() )
263 {
Felix Meschbergerafbd25f2009-07-31 15:55:42 +0000264 m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager: Added service "
265 + m_dependencyMetadata.getName() + " is ignored for static reference", m_componentManager
266 .getComponentMetadata(), null );
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000267 }
Felix Meschberger5d89d562009-06-16 09:36:14 +0000268
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000269 // otherwise bind if we have a bind method and the service needs
270 // be bound
Felix Meschbergere956e032009-02-19 20:09:13 +0000271 else if ( m_dependencyMetadata.getBind() != null )
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000272 {
Felix Meschbergere956e032009-02-19 20:09:13 +0000273 // multiple bindings or not bound at all yet
274 if ( m_dependencyMetadata.isMultiple() || !isBound() )
275 {
276 // bind the service, getting it if required
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000277 invokeBindMethod( reference );
Felix Meschbergere956e032009-02-19 20:09:13 +0000278 }
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000279 }
280 }
Felix Meschberger5d89d562009-06-16 09:36:14 +0000281
282 else
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000283 {
Felix Meschbergerd3fc8bf2009-06-02 14:43:54 +0000284 m_componentManager.log( LogService.LOG_DEBUG,
285 "Dependency Manager: Ignoring service addition, wrong state "
286 + m_componentManager.state(),
287 m_componentManager.getComponentMetadata(), null );
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000288 }
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000289 }
Felix Meschberger5d89d562009-06-16 09:36:14 +0000290
291
Felix Meschberger38b77d72007-09-18 09:22:10 +0000292 /**
293 * Called by the {@link #serviceChanged(ServiceEvent)} method if an existing
294 * service is unregistered from the system or if a registered service has
295 * been modified.
296 * <p>
297 * Depending on the component state and dependency configuration, the
298 * component may be deactivated, re-activated, the service just be unbound
299 * with or without a replacement service.
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000300 *
Felix Meschberger38b77d72007-09-18 09:22:10 +0000301 * @param reference The reference to the service unregistering or being
302 * modified.
Felix Meschbergerafbd25f2009-07-31 15:55:42 +0000303 *
304 * @return <code>true</code> if the service has been removed without the
305 * component being deactivated. <code>true</code> is also returned
306 * if the service was not bound at all. <code>false</code> is returned
307 * if the component has been deactivated due to this service being
308 * removed.
Felix Meschberger38b77d72007-09-18 09:22:10 +0000309 */
Felix Meschbergerafbd25f2009-07-31 15:55:42 +0000310 private boolean serviceRemoved( ServiceReference reference )
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000311 {
Felix Meschbergeraed494d2007-11-28 17:50:22 +0000312 // check whether we are bound to that service, do nothing if not
313 if ( getBoundService( reference ) == null )
314 {
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000315 m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager: Ignoring removed Service for "
316 + m_dependencyMetadata.getName() + " : Service " + reference.getProperty( Constants.SERVICE_ID )
317 + " not bound", m_componentManager.getComponentMetadata(), null );
Felix Meschbergerafbd25f2009-07-31 15:55:42 +0000318
319 // service was not bound, we can continue without interruption
320 return true;
Felix Meschbergeraed494d2007-11-28 17:50:22 +0000321 }
322
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000323 // otherwise check whether the component is in a state to handle the event
324 else if ( handleServiceEvent() )
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000325 {
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000326
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000327 // if the dependency is not satisfied anymore, we have to
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000328 // deactivate the component
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000329 if ( !isSatisfied() )
330 {
331 m_componentManager.getActivator()
332 .log(
333 LogService.LOG_DEBUG,
334 "Dependency Manager: Deactivating component due to mandatory dependency on "
335 + m_dependencyMetadata.getName() + "/" + m_dependencyMetadata.getInterface()
336 + " not satisfied", m_componentManager.getComponentMetadata(), null );
Felix Meschberger5d89d562009-06-16 09:36:14 +0000337
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000338 // deactivate the component now
Felix Meschbergerba3da7a2009-07-09 12:26:58 +0000339 m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
Felix Meschbergerafbd25f2009-07-31 15:55:42 +0000340
341 // component is deactivated, this does all for this service
342 return false;
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000343 }
Felix Meschberger5d89d562009-06-16 09:36:14 +0000344
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000345 // if the dependency is static, we have to reactivate the component
346 // to "remove" the dependency
347 else if ( m_dependencyMetadata.isStatic() )
348 {
349 try
350 {
Felix Meschberger1f928f22008-05-30 19:56:02 +0000351 m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager: Static dependency on "
352 + m_dependencyMetadata.getName() + "/" + m_dependencyMetadata.getInterface() + " is broken",
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000353 m_componentManager.getComponentMetadata(), null );
Felix Meschbergerba3da7a2009-07-09 12:26:58 +0000354 m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
355 m_componentManager.activate();
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000356 }
357 catch ( Exception ex )
358 {
Felix Meschberger1f928f22008-05-30 19:56:02 +0000359 m_componentManager.log( LogService.LOG_ERROR, "Exception while recreating dependency ",
360 m_componentManager.getComponentMetadata(), ex );
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000361 }
Felix Meschbergerafbd25f2009-07-31 15:55:42 +0000362
363 // static reference removal causes reactivation, nothing more to do
364 return false;
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000365 }
Felix Meschberger5d89d562009-06-16 09:36:14 +0000366
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000367 // dynamic dependency, multiple or single but this service is the bound one
368 else
369 {
Felix Meschberger5d89d562009-06-16 09:36:14 +0000370
Felix Meschberger38b77d72007-09-18 09:22:10 +0000371 // try to bind a replacement service first if this is a unary
372 // cardinality reference and a replacement is available.
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000373 if ( !m_dependencyMetadata.isMultiple() )
374 {
Felix Meschberger38b77d72007-09-18 09:22:10 +0000375 // if the dependency is mandatory and no replacement is
376 // available, bind returns false and we deactivate
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000377 if ( !bind() )
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000378 {
Felix Meschberger1f928f22008-05-30 19:56:02 +0000379 m_componentManager.log( LogService.LOG_DEBUG,
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000380 "Dependency Manager: Deactivating component due to mandatory dependency on "
381 + m_dependencyMetadata.getName() + "/" + m_dependencyMetadata.getInterface()
382 + " not satisfied", m_componentManager.getComponentMetadata(), null );
Felix Meschbergerba3da7a2009-07-09 12:26:58 +0000383 m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
Felix Meschberger5d89d562009-06-16 09:36:14 +0000384
Felix Meschbergerafbd25f2009-07-31 15:55:42 +0000385 // required service could not be replaced, component
386 // is deactivated and we are done
387 return false;
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000388 }
389 }
Felix Meschberger5d89d562009-06-16 09:36:14 +0000390
Felix Meschberger38b77d72007-09-18 09:22:10 +0000391 // call the unbind method if one is defined
392 if ( m_dependencyMetadata.getUnbind() != null )
393 {
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000394 invokeUnbindMethod( reference );
Felix Meschberger38b77d72007-09-18 09:22:10 +0000395 }
Felix Meschberger5d89d562009-06-16 09:36:14 +0000396
Felix Meschberger514de152009-05-26 08:03:25 +0000397 // make sure the service is returned
398 ungetService( reference );
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000399 }
400 }
Felix Meschberger5d89d562009-06-16 09:36:14 +0000401
402 else
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000403 {
Felix Meschbergerd3fc8bf2009-06-02 14:43:54 +0000404 m_componentManager.log( LogService.LOG_DEBUG,
405 "Dependency Manager: Ignoring service removal, wrong state "
406 + m_componentManager.state(),
407 m_componentManager.getComponentMetadata(), null );
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000408 }
Felix Meschbergerafbd25f2009-07-31 15:55:42 +0000409
410 // everything is fine, the component is still active and we continue
411 return true;
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000412 }
Felix Meschberger5d89d562009-06-16 09:36:14 +0000413
414
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000415 private boolean handleServiceEvent()
416 {
417 return ( m_componentManager.getState() & STATE_MASK ) != 0;
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000418 }
419
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000420
Felix Meschbergerd25a63d2007-11-23 13:02:49 +0000421 //---------- Reference interface ------------------------------------------
422
Felix Meschbergerd25a63d2007-11-23 13:02:49 +0000423 public String getServiceName()
424 {
425 return m_dependencyMetadata.getInterface();
426 }
427
428
429 public ServiceReference[] getServiceReferences()
430 {
431 return getBoundServiceReferences();
432 }
433
434
435 public boolean isOptional()
436 {
437 return m_dependencyMetadata.isOptional();
438 }
439
440
441 public boolean isMultiple()
442 {
443 return m_dependencyMetadata.isMultiple();
444 }
445
446
447 public boolean isStatic()
448 {
449 return m_dependencyMetadata.isStatic();
450 }
451
452
453 public String getBindMethodName()
454 {
455 return m_dependencyMetadata.getBind();
456 }
457
458
459 public String getUnbindMethodName()
460 {
461 return m_dependencyMetadata.getUnbind();
462 }
463
464
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000465 //---------- Service tracking support -------------------------------------
466
467 /**
Felix Meschberger73a39e62009-05-25 12:38:48 +0000468 * Enables this dependency manager by starting to listen for service
469 * events.
470 * @throws InvalidSyntaxException if the target filter is invalid
471 */
472 void enable() throws InvalidSyntaxException
473 {
Felix Meschbergerc7325602009-05-25 21:07:04 +0000474 // get the current number of registered services available
475 ServiceReference refs[] = getFrameworkServiceReferences();
476 m_size = ( refs == null ) ? 0 : refs.length;
477
Felix Meschberger73a39e62009-05-25 12:38:48 +0000478 // register the service listener
479 String filterString = "(" + Constants.OBJECTCLASS + "=" + m_dependencyMetadata.getInterface() + ")";
480 m_componentManager.getActivator().getBundleContext().addServiceListener( this, filterString );
Felix Meschbergerc7325602009-05-25 21:07:04 +0000481
482 m_componentManager.log( LogService.LOG_DEBUG, "Registered for service events, currently " + m_size
483 + " service(s) match the filter", m_componentManager.getComponentMetadata(), null );
Felix Meschberger73a39e62009-05-25 12:38:48 +0000484 }
Felix Meschberger5d89d562009-06-16 09:36:14 +0000485
Felix Meschberger73a39e62009-05-25 12:38:48 +0000486 /**
Felix Meschberger38b77d72007-09-18 09:22:10 +0000487 * Disposes off this dependency manager by removing as a service listener
488 * and ungetting all services, which are still kept in the list of our
489 * bound services. This list will not be empty if the service lookup
490 * method is used by the component to access the service.
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000491 */
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000492 void dispose()
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000493 {
Carsten Ziegeler7cbcef52007-08-15 11:37:08 +0000494 BundleContext context = m_componentManager.getActivator().getBundleContext();
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000495 context.removeServiceListener( this );
496
Felix Meschberger43d2a712007-09-17 08:51:36 +0000497 m_size = 0;
498
499 // unget all services we once got
500 ServiceReference[] boundRefs = getBoundServiceReferences();
501 if ( boundRefs != null )
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000502 {
Felix Meschberger43d2a712007-09-17 08:51:36 +0000503 for ( int i = 0; i < boundRefs.length; i++ )
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000504 {
Felix Meschberger43d2a712007-09-17 08:51:36 +0000505 ungetService( boundRefs[i] );
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000506 }
507 }
508 }
509
510
511 /**
Felix Meschberger43d2a712007-09-17 08:51:36 +0000512 * Returns the number of services currently registered in the system,
513 * which match the service criteria (interface and optional target filter)
514 * configured for this dependency. The number returned by this method has
515 * no correlation to the number of services bound to this dependency
516 * manager. It is actually the maximum number of services which may be
517 * bound to this dependency manager.
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000518 *
Felix Meschberger43d2a712007-09-17 08:51:36 +0000519 * @see #isValid()
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000520 */
521 int size()
522 {
Felix Meschberger43d2a712007-09-17 08:51:36 +0000523 return m_size;
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000524 }
525
526
527 /**
Felix Meschberger43d2a712007-09-17 08:51:36 +0000528 * Returns an array of <code>ServiceReference</code> instances for services
529 * implementing the interface and complying to the (optional) target filter
530 * declared for this dependency. If no matching service can be found
531 * <code>null</code> is returned. If the configured target filter is
532 * syntactically incorrect an error message is logged with the LogService
533 * and <code>null</code> is returned.
534 * <p>
535 * This method always directly accesses the framework's service registry
536 * and ignores the services bound by this dependency manager.
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000537 */
Felix Meschbergerd25a63d2007-11-23 13:02:49 +0000538 ServiceReference[] getFrameworkServiceReferences()
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000539 {
Felix Meschbergere21cefd2009-07-28 13:58:48 +0000540 return getFrameworkServiceReferences( getTarget() );
541 }
542
543
544 private ServiceReference[] getFrameworkServiceReferences( String targetFilter )
545 {
Felix Meschberger43d2a712007-09-17 08:51:36 +0000546 try
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000547 {
Felix Meschberger43d2a712007-09-17 08:51:36 +0000548 return m_componentManager.getActivator().getBundleContext().getServiceReferences(
Felix Meschbergere21cefd2009-07-28 13:58:48 +0000549 m_dependencyMetadata.getInterface(), targetFilter );
Felix Meschberger43d2a712007-09-17 08:51:36 +0000550 }
551 catch ( InvalidSyntaxException ise )
552 {
Felix Meschbergere21cefd2009-07-28 13:58:48 +0000553 m_componentManager.log( LogService.LOG_ERROR, "Unexpected problem with filter '" + targetFilter + "'",
Felix Meschberger43d2a712007-09-17 08:51:36 +0000554 m_componentManager.getComponentMetadata(), ise );
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000555 return null;
556 }
557 }
558
559
560 /**
Felix Meschbergere956e032009-02-19 20:09:13 +0000561 * Returns a <code>ServiceReference</code> instances for a service
562 * implementing the interface and complying to the (optional) target filter
563 * declared for this dependency. If no matching service can be found
564 * <code>null</code> is returned. If the configured target filter is
565 * syntactically incorrect an error message is logged with the LogService
566 * and <code>null</code> is returned. If multiple matching services are
567 * registered the service with the highest service.ranking value is
568 * returned. If multiple matching services have the same service.ranking
569 * value, the service with the lowest service.id is returned.
570 * <p>
571 * This method always directly accesses the framework's service registry
572 * and ignores the services bound by this dependency manager.
573 */
574 ServiceReference getFrameworkServiceReference()
575 {
576 // get the framework registered services and short cut
577 ServiceReference[] refs = getFrameworkServiceReferences();
578 if ( refs == null )
579 {
580 return null;
581 }
582 else if ( refs.length == 1 )
583 {
584 return refs[0];
585 }
586
587 // is it correct to assume an ordered bound services set ?
588 int maxRanking = Integer.MIN_VALUE;
589 long minId = Long.MAX_VALUE;
590 ServiceReference selectedRef = null;
591
592 // find the service with the highest ranking
593 for ( int i = 0; refs != null && i < refs.length; i++ )
594 {
595 ServiceReference ref = refs[i];
596 int ranking = getServiceRanking( ref );
597 long id = getServiceId( ref );
598 if ( maxRanking < ranking || ( maxRanking == ranking && id < minId ) )
599 {
600 maxRanking = ranking;
601 minId = id;
602 selectedRef = ref;
603 }
604 }
605
606 return selectedRef;
607 }
608
609
610 /**
Felix Meschberger43d2a712007-09-17 08:51:36 +0000611 * Returns the service instance for the service reference returned by the
Felix Meschbergere956e032009-02-19 20:09:13 +0000612 * {@link #getFrameworkServiceReference()} method. If this returns a
Felix Meschberger43d2a712007-09-17 08:51:36 +0000613 * non-<code>null</code> service instance the service is then considered
614 * bound to this instance.
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000615 */
616 Object getService()
617 {
Felix Meschbergere956e032009-02-19 20:09:13 +0000618 ServiceReference sr = getFrameworkServiceReference();
Felix Meschberger43d2a712007-09-17 08:51:36 +0000619 return ( sr != null ) ? getService( sr ) : null;
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000620 }
621
622
623 /**
Felix Meschberger43d2a712007-09-17 08:51:36 +0000624 * Returns an array of service instances for the service references returned
Felix Meschbergere956e032009-02-19 20:09:13 +0000625 * by the {@link #getFrameworkServiceReferences()} method. If no services
626 * match the criteria configured for this dependency <code>null</code> is
627 * returned. All services returned by this method will be considered bound
628 * after this method returns.
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000629 */
630 Object[] getServices()
631 {
Felix Meschbergerd25a63d2007-11-23 13:02:49 +0000632 ServiceReference[] sr = getFrameworkServiceReferences();
Felix Meschberger43d2a712007-09-17 08:51:36 +0000633 if ( sr == null || sr.length == 0 )
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000634 {
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000635 return null;
636 }
Felix Meschberger43d2a712007-09-17 08:51:36 +0000637
638 List services = new ArrayList();
639 for ( int i = 0; i < sr.length; i++ )
640 {
641 Object service = getService( sr[i] );
642 if ( service != null )
643 {
644 services.add( service );
645 }
646 }
647
648 return ( services.size() > 0 ) ? services.toArray() : null;
649 }
650
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000651
Felix Meschbergere956e032009-02-19 20:09:13 +0000652 /**
Felix Meschbergere956e032009-02-19 20:09:13 +0000653 * Returns the value of the <code>service.ranking</code> service property
654 * if the property exists and is of type <code>java.lang.Integer</code>. If
655 * the property does not exist or is of another type, zero is returned as
656 * the default value for service ranking.
Felix Meschberger5d89d562009-06-16 09:36:14 +0000657 *
Felix Meschbergere956e032009-02-19 20:09:13 +0000658 * @param serviceReference The Service reference whose ranking is to be
659 * returned.
660 */
661 private int getServiceRanking( ServiceReference serviceReference )
662 {
663 Object nrRankObj = serviceReference.getProperty( Constants.SERVICE_RANKING );
664 if ( nrRankObj instanceof Integer )
665 {
666 return ( ( Integer ) nrRankObj ).intValue();
667 }
668 return 0;
669 }
670
671
672 /**
673 * Returns the value of the <code>service.id</code> service property.
Felix Meschberger5d89d562009-06-16 09:36:14 +0000674 *
Felix Meschbergere956e032009-02-19 20:09:13 +0000675 * @param serviceReference The Service reference whose service id is to be
676 * returned.
Felix Meschberger5d89d562009-06-16 09:36:14 +0000677 *
Felix Meschbergere956e032009-02-19 20:09:13 +0000678 * @throws ClassCastException if the <code>service.id</code> property exists
679 * but is not a <code>java.lang.Long</code> value. This is not
680 * expected since the framework should guarantee this property and
681 * its type.
682 * @throws NullPointerException if the <code>service.id</code> property
683 * does not exist. This is not expected since the framework should
684 * guarantee this property and its type.
685 */
686 private long getServiceId( ServiceReference serviceReference )
687 {
688 return ( ( Long ) serviceReference.getProperty( Constants.SERVICE_ID ) ).longValue();
689 }
690
691
Felix Meschberger43d2a712007-09-17 08:51:36 +0000692 //---------- bound services maintenance -----------------------------------
693
694 /**
695 * Returns an array of <code>ServiceReference</code> instances of all
696 * services this instance is bound to.
697 */
698 private ServiceReference[] getBoundServiceReferences()
699 {
700 return ( ServiceReference[] ) m_bound.keySet().toArray( new ServiceReference[m_bound.size()] );
701 }
702
703
704 /**
705 * Returns <code>true</code> if at least one service has been bound
706 */
707 private boolean isBound()
708 {
709 return !m_bound.isEmpty();
710 }
711
712
Felix Meschberger38b77d72007-09-18 09:22:10 +0000713 /**
714 * Adds the {@link #BOUND_SERVICE_SENTINEL} object as a pseudo service to
715 * the map of bound services. This method allows keeping track of services
716 * which have been bound but not retrieved from the service registry, which
717 * is the case if the bind method is called with a ServiceReference instead
718 * of the service object itself.
719 * <p>
720 * We have to keep track of all services for which we called the bind
721 * method to be able to call the unbind method in case the service is
722 * unregistered.
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000723 *
Felix Meschberger38b77d72007-09-18 09:22:10 +0000724 * @param serviceReference The reference to the service being marked as
725 * bound.
726 */
Felix Meschberger9dadeef2007-09-17 10:57:44 +0000727 private void bindService( ServiceReference serviceReference )
728 {
729 m_bound.put( serviceReference, BOUND_SERVICE_SENTINEL );
730 }
731
732
Felix Meschberger43d2a712007-09-17 08:51:36 +0000733 /**
734 * Returns the bound service represented by the given service reference
735 * or <code>null</code> if this is instance is not currently bound to that
736 * service.
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000737 *
Felix Meschberger43d2a712007-09-17 08:51:36 +0000738 * @param serviceReference The reference to the bound service
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000739 *
Felix Meschberger9dadeef2007-09-17 10:57:44 +0000740 * @return the service for the reference or the {@link #BOUND_SERVICE_SENTINEL}
741 * if the service is bound or <code>null</code> if the service is not
742 * bound.
Felix Meschberger43d2a712007-09-17 08:51:36 +0000743 */
744 private Object getBoundService( ServiceReference serviceReference )
745 {
746 return m_bound.get( serviceReference );
747 }
748
749
750 /**
751 * Returns the service described by the ServiceReference. If this instance
752 * is already bound the given service, that bound service instance is
753 * returned. Otherwise the service retrieved from the service registry
754 * and kept as a bound service for future use.
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000755 *
Felix Meschberger43d2a712007-09-17 08:51:36 +0000756 * @param serviceReference The reference to the service to be returned
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000757 *
Felix Meschberger43d2a712007-09-17 08:51:36 +0000758 * @return The requested service or <code>null</code> if no service is
759 * registered for the service reference (any more).
760 */
761 Object getService( ServiceReference serviceReference )
762 {
763 // check whether we already have the service and return that one
764 Object service = getBoundService( serviceReference );
Felix Meschberger9dadeef2007-09-17 10:57:44 +0000765 if ( service != null && service != BOUND_SERVICE_SENTINEL )
Felix Meschberger43d2a712007-09-17 08:51:36 +0000766 {
767 return service;
768 }
769
770 // otherwise acquire the service and keep it
771 service = m_componentManager.getActivator().getBundleContext().getService( serviceReference );
772 if ( service != null )
773 {
774 m_bound.put( serviceReference, service );
775 }
776
777 // returne the acquired service (may be null of course)
778 return service;
779 }
780
781
782 /**
783 * Ungets the service described by the ServiceReference and removes it from
784 * the list of bound services.
785 */
786 void ungetService( ServiceReference serviceReference )
787 {
788 // check we really have this service, do nothing if not
789 Object service = m_bound.remove( serviceReference );
Felix Meschberger9dadeef2007-09-17 10:57:44 +0000790 if ( service != null && service != BOUND_SERVICE_SENTINEL )
Felix Meschberger43d2a712007-09-17 08:51:36 +0000791 {
792 m_componentManager.getActivator().getBundleContext().ungetService( serviceReference );
793 }
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000794 }
795
796
797 //---------- DependencyManager core ---------------------------------------
798
799 /**
800 * Returns the name of the service reference.
801 */
Felix Meschbergerd25a63d2007-11-23 13:02:49 +0000802 public String getName()
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000803 {
Carsten Ziegeler7cbcef52007-08-15 11:37:08 +0000804 return m_dependencyMetadata.getName();
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000805 }
806
807
808 /**
Felix Meschberger43d2a712007-09-17 08:51:36 +0000809 * Returns <code>true</code> if this dependency manager is satisfied, that
810 * is if eithern the dependency is optional or the number of services
811 * registered in the framework and available to this dependency manager is
812 * not zero.
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000813 */
Felix Meschbergerd25a63d2007-11-23 13:02:49 +0000814 public boolean isSatisfied()
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000815 {
Felix Meschbergeree3f1db2007-08-22 15:21:27 +0000816 return size() > 0 || m_dependencyMetadata.isOptional();
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000817 }
818
819
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000820 boolean open( Object instance )
821 {
822 m_componentInstance = instance;
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +0000823 initBindingMethods();
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000824 return bind();
825 }
826
827
828 /**
829 * Revoke all bindings. This method cannot throw an exception since it must
830 * try to complete all that it can
831 */
832 void close( )
833 {
834 try
835 {
836 unbind( getBoundServiceReferences() );
837 }
838 finally
839 {
840 m_componentInstance = null;
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +0000841 m_bind = null;
842 m_unbind = null;
843
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000844 }
845 }
846
847
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000848 /**
849 * initializes a dependency. This method binds all of the service
850 * occurrences to the instance object
Carsten Ziegeler64c6f7a2007-08-15 09:58:35 +0000851 *
Felix Meschberger43d2a712007-09-17 08:51:36 +0000852 * @return true if the dependency is satisfied and at least the minimum
853 * number of services could be bound. Otherwise false is returned.
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000854 */
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000855 private boolean bind()
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000856 {
857 // If no references were received, we have to check if the dependency
858 // is optional, if it is not then the dependency is invalid
Felix Meschbergerb609eca2007-09-17 12:32:57 +0000859 if ( !isSatisfied() )
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000860 {
861 return false;
862 }
863
Felix Meschberger43d2a712007-09-17 08:51:36 +0000864 // if no bind method is configured or if this is a delayed component,
865 // we have nothing to do and just signal success
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000866 if ( m_componentInstance == null || m_dependencyMetadata.getBind() == null )
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000867 {
868 return true;
869 }
870
Felix Meschberger86a336d2007-09-06 08:34:16 +0000871 // assume success to begin with: if the dependency is optional,
872 // we don't care, whether we can bind a service. Otherwise, we
Felix Meschberger43d2a712007-09-17 08:51:36 +0000873 // require at least one service to be bound, thus we require
Felix Meschberger86a336d2007-09-06 08:34:16 +0000874 // flag being set in the loop below
875 boolean success = m_dependencyMetadata.isOptional();
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000876
Felix Meschbergere956e032009-02-19 20:09:13 +0000877 // Get service reference(s)
878 if ( m_dependencyMetadata.isMultiple() )
Felix Meschberger86a336d2007-09-06 08:34:16 +0000879 {
Felix Meschbergere956e032009-02-19 20:09:13 +0000880 // bind all registered services
881 ServiceReference[] refs = getFrameworkServiceReferences();
882 if ( refs != null )
883 {
884 for ( int index = 0; index < refs.length; index++ )
885 {
886 // success is if we have the minimal required number of services bound
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000887 if ( invokeBindMethod( refs[index] ) )
Felix Meschbergere956e032009-02-19 20:09:13 +0000888 {
889 // of course, we have success if the service is bound
890 success = true;
891 }
892 }
893 }
894 }
895 else
896 {
897 // bind best matching service
898 ServiceReference ref = getFrameworkServiceReference();
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000899 if ( ref != null && invokeBindMethod( ref ) )
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000900 {
Felix Meschberger9dadeef2007-09-17 10:57:44 +0000901 // of course, we have success if the service is bound
902 success = true;
Felix Meschbergeraa5adb92007-09-06 08:37:44 +0000903 }
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000904 }
905
Felix Meschberger86a336d2007-09-06 08:34:16 +0000906 // success will be true, if the service is optional or if at least
907 // one service was available to be bound (regardless of whether the
908 // bind method succeeded or not)
909 return success;
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000910 }
911
912
913 /**
Felix Meschbergere956e032009-02-19 20:09:13 +0000914 * Revoke the given bindings. This method cannot throw an exception since
915 * it must try to complete all that it can
916 */
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000917 private void unbind( ServiceReference[] boundRefs )
Felix Meschbergere956e032009-02-19 20:09:13 +0000918 {
Felix Meschbergerc0df73b2009-02-06 15:25:13 +0000919 // only invoke the unbind method if there is an instance (might be null
920 // in the delayed component situation) and the unbind method is declared.
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000921 boolean doUnbind = m_componentInstance != null && m_dependencyMetadata.getUnbind() != null;
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000922
Felix Meschberger43d2a712007-09-17 08:51:36 +0000923 if ( boundRefs != null )
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000924 {
Felix Meschberger43d2a712007-09-17 08:51:36 +0000925 for ( int i = 0; i < boundRefs.length; i++ )
926 {
Felix Meschbergerc0df73b2009-02-06 15:25:13 +0000927 if ( doUnbind )
928 {
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000929 invokeUnbindMethod( boundRefs[i] );
Felix Meschbergerc0df73b2009-02-06 15:25:13 +0000930 }
931
932 // unget the service, we call it here since there might be a
933 // bind method (or the locateService method might have been
934 // called) but there is no unbind method to actually unbind
935 // the service (see FELIX-832)
936 ungetService( boundRefs[i] );
Felix Meschberger43d2a712007-09-17 08:51:36 +0000937 }
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000938 }
939 }
940
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000941 /**
Felix Meschberger43d2a712007-09-17 08:51:36 +0000942 * Calls the bind method. In case there is an exception while calling the
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000943 * bind method, the service is not considered to be bound to the instance
944 * object
Felix Meschberger43d2a712007-09-17 08:51:36 +0000945 * <p>
946 * If the reference is singular and a service has already been bound to the
947 * component this method has no effect and just returns <code>true</code>.
Carsten Ziegeler64c6f7a2007-08-15 09:58:35 +0000948 *
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000949 * @param ref A ServiceReference with the service that will be bound to the
950 * instance object
Felix Meschberger9dadeef2007-09-17 10:57:44 +0000951 * @return true if the service should be considered bound. If no bind
952 * method is found or the method call fails, <code>true</code> is
953 * returned. <code>false</code> is only returned if the service must
954 * be handed over to the bind method but the service cannot be
955 * retrieved using the service reference.
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000956 */
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +0000957 private boolean invokeBindMethod( final ServiceReference ref )
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000958 {
959 // The bind method is only invoked if the implementation object is not
Felix Meschberger86a336d2007-09-06 08:34:16 +0000960 // null. This is valid for both immediate and delayed components
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +0000961 if( m_componentInstance != null )
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000962 {
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +0000963 return m_bind.invoke(
964 m_componentInstance,
965 new BindMethod.Service()
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000966 {
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +0000967 public ServiceReference getReference()
Felix Meschberger9dadeef2007-09-17 10:57:44 +0000968 {
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +0000969 bindService( ref );
970 return ref;
Felix Meschberger9dadeef2007-09-17 10:57:44 +0000971 }
Felix Meschberger9b6b5092007-10-01 14:18:04 +0000972
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +0000973 public Object getInstance()
Felix Meschberger9dadeef2007-09-17 10:57:44 +0000974 {
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +0000975 return getService( ref );
Felix Meschberger9dadeef2007-09-17 10:57:44 +0000976 }
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000977 }
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +0000978 );
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000979 }
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +0000980 else if ( !m_componentManager.getComponentMetadata().isImmediate() )
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000981 {
Felix Meschberger3e26f2d2009-04-20 11:13:27 +0000982 m_componentManager.log( LogService.LOG_DEBUG,
983 "DependencyManager : Delayed component not yet created, assuming bind method call succeeded",
984 m_componentManager.getComponentMetadata(), null );
985
986 return true;
987 }
988 else if ( m_componentManager.getState() == AbstractComponentManager.STATE_ACTIVATING )
989 {
990 // when activating the method, events may be handled before the
991 // open(Object) method has been called on this instance. This is
992 // not a problem, because the open(Object) method will catch up
993 // this services any way
994 m_componentManager.log( LogService.LOG_DEBUG, "DependencyManager : Not yet open for activating component",
995 m_componentManager.getComponentMetadata(), null );
996
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000997 return true;
998 }
999 else
1000 {
1001 // this is not expected: if the component is immediate the
1002 // implementationObject is not null (asserted by the caller)
Felix Meschberger3e26f2d2009-04-20 11:13:27 +00001003
1004 m_componentManager.log( LogService.LOG_ERROR,
1005 "DependencyManager : Immediate component not yet created, bind method cannot be called",
1006 m_componentManager.getComponentMetadata(), null );
1007
Felix Meschbergerc90e3162007-03-28 14:34:01 +00001008 return false;
1009 }
1010 }
1011
1012
1013 /**
Felix Meschberger43d2a712007-09-17 08:51:36 +00001014 * Calls the unbind method.
1015 * <p>
1016 * If the reference is singular and the given service is not the one bound
1017 * to the component this method has no effect and just returns
1018 * <code>true</code>.
Carsten Ziegeler64c6f7a2007-08-15 09:58:35 +00001019 *
Felix Meschbergerc90e3162007-03-28 14:34:01 +00001020 * @param ref A service reference corresponding to the service that will be
1021 * unbound
1022 * @return true if the call was successful, false otherwise
1023 */
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +00001024 private void invokeUnbindMethod( final ServiceReference ref )
Felix Meschbergerc90e3162007-03-28 14:34:01 +00001025 {
1026 // The unbind method is only invoked if the implementation object is not
1027 // null. This is valid for both immediate and delayed components
Felix Meschberger3e26f2d2009-04-20 11:13:27 +00001028 if ( m_componentInstance != null )
Felix Meschbergerc90e3162007-03-28 14:34:01 +00001029 {
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +00001030 m_unbind.invoke(
1031 m_componentInstance,
1032 new BindMethod.Service()
Felix Meschberger9dadeef2007-09-17 10:57:44 +00001033 {
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +00001034 public ServiceReference getReference()
Felix Meschberger9dadeef2007-09-17 10:57:44 +00001035 {
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +00001036 return ref;
Felix Meschberger9dadeef2007-09-17 10:57:44 +00001037 }
Felix Meschberger9dadeef2007-09-17 10:57:44 +00001038
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +00001039 public Object getInstance()
Felix Meschberger9dadeef2007-09-17 10:57:44 +00001040 {
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +00001041 return getService( ref );
Felix Meschberger9dadeef2007-09-17 10:57:44 +00001042 }
Felix Meschbergerc90e3162007-03-28 14:34:01 +00001043 }
Felix Meschberger8c1d3ec2009-07-28 14:59:16 +00001044 );
Felix Meschbergerc90e3162007-03-28 14:34:01 +00001045 }
Felix Meschbergerc90e3162007-03-28 14:34:01 +00001046 else
1047 {
Felix Meschberger3e26f2d2009-04-20 11:13:27 +00001048 // don't care whether we can or cannot call the unbind method
1049 // if the component instance has already been cleared by the
1050 // close() method
1051 m_componentManager.log( LogService.LOG_DEBUG,
1052 "DependencyManager : Component not set, no need to call unbind method", m_componentManager
1053 .getComponentMetadata(), null );
Felix Meschbergerc90e3162007-03-28 14:34:01 +00001054 }
1055 }
1056
Felix Meschberger5d89d562009-06-16 09:36:14 +00001057
Felix Meschberger9b6b5092007-10-01 14:18:04 +00001058 //------------- Service target filter support -----------------------------
1059
1060 /**
Felix Meschbergere21cefd2009-07-28 13:58:48 +00001061 * Returns <code>true</code> if the <code>properties</code> can be
1062 * dynamically applied to the component to which the dependency manager
1063 * belongs.
1064 * <p>
1065 * This method applies the following heuristics (in the given order):
1066 * <ol>
1067 * <li>If there is no change in the target filter for this dependency, the
1068 * properties can be applied</li>
1069 * <li>If the dependency is static and there are changes in the target
1070 * filter we cannot dynamically apply the configuration because the filter
1071 * may (assume they do for simplicity here) cause the bindings to change.</li>
1072 * <li>If there is still at least one service matching the new target filter
1073 * we can apply the configuration because the depdency is dynamic.</li>
1074 * <li>If there are no more services matching the filter, we can still
1075 * apply the configuration if the dependency is optional.</li>
1076 * <li>Ultimately, if all other checks do not apply we cannot dynamically
1077 * apply.</li>
1078 * </ol>
1079 */
1080 boolean canUpdateDynamically( Dictionary properties )
1081 {
1082 // 1. no target filter change
1083 final String targetFilter = ( String ) properties.get( m_dependencyMetadata.getTargetPropertyName() );
1084 if ( ( getTarget() == null && targetFilter == null ) || getTarget().equals( targetFilter ) )
1085 {
1086 // can update if target filter is not changed, since there is
1087 // no change is service binding
1088 return true;
1089 }
1090 // invariant: target filter change
1091
1092 // 2. if static policy, cannot update dynamically
1093 // (for simplicity assuming change in target service binding)
1094 if ( m_dependencyMetadata.isStatic() )
1095 {
1096 // cannot update if services are statically bound and the target
1097 // filter is modified, since there is (potentially at least)
1098 // a change is service bindings
1099 return false;
1100 }
1101 // invariant: target filter change + dynamic policy
1102
1103 // 3. check target services matching the new filter
1104 ServiceReference[] refs = getFrameworkServiceReferences( targetFilter );
1105 if ( refs != null && refs.length > 0 )
1106 {
1107 // can update since there is at least on service matching the
1108 // new target filter and the services may be exchanged dynamically
1109 return true;
1110 }
1111 // invariant: target filter change + dynamic policy + no more matching service
1112
1113 // 4. check optionality
1114 if ( m_dependencyMetadata.isOptional() )
1115 {
1116 // can update since even if no service matches the new filter, this
1117 // makes no difference because the dependency is optional
1118 return true;
1119 }
1120 // invariant: target filter change + dynamic policy + no more matching service + required
1121
1122 // 5. cannot dynamically update because the target filter results in
1123 // no more applicable services which is not acceptable
1124 return false;
1125 }
1126
1127
1128 /**
Felix Meschberger9b6b5092007-10-01 14:18:04 +00001129 * Sets the target filter from target filter property contained in the
1130 * properties. The filter is taken from a property whose name is derived
1131 * from the dependency name and the suffix <code>.target</code> as defined
1132 * for target properties on page 302 of the Declarative Services
1133 * Specification, section 112.6.
1134 *
1135 * @param properties The properties containing the optional target service
1136 * filter property
1137 */
1138 void setTargetFilter( Dictionary properties )
1139 {
1140 setTargetFilter( ( String ) properties.get( m_dependencyMetadata.getTargetPropertyName() ) );
1141 }
1142
1143
1144 /**
1145 * Sets the target filter of this dependency to the new filter value. If the
1146 * new target filter is the same as the old target filter, this method has
1147 * not effect. Otherwise any services currently bound but not matching the
1148 * new filter are unbound. Likewise any registered services not currently
1149 * bound but matching the new filter are bound.
1150 *
1151 * @param target The new target filter to be set. This may be
1152 * <code>null</code> if no target filtering is to be used.
1153 */
1154 private void setTargetFilter( String target )
1155 {
1156 // do nothing if target filter does not change
1157 if ( ( m_target == null && target == null ) || ( m_target != null && m_target.equals( target ) ) )
1158 {
1159 return;
1160 }
1161
1162 m_target = target;
1163 if ( target != null )
1164 {
1165 try
1166 {
1167 m_targetFilter = m_componentManager.getActivator().getBundleContext().createFilter( target );
1168 }
1169 catch ( InvalidSyntaxException ise )
1170 {
1171 // log
1172 m_targetFilter = null;
1173 }
1174 }
1175 else
1176 {
1177 m_targetFilter = null;
1178 }
1179
1180 // check for services to be removed
1181 if ( m_targetFilter != null )
1182 {
1183 ServiceReference[] refs = getBoundServiceReferences();
1184 if ( refs != null )
1185 {
1186 for ( int i = 0; i < refs.length; i++ )
1187 {
1188 if ( !m_targetFilter.match( refs[i] ) )
1189 {
1190 // might want to do this asynchronously ??
1191 serviceRemoved( refs[i] );
1192 }
1193 }
1194 }
1195 }
1196
Felix Meschbergerf60039b2009-04-27 09:44:55 +00001197 // check for new services to be added and set the number of
1198 // matching services
Felix Meschbergerd25a63d2007-11-23 13:02:49 +00001199 ServiceReference[] refs = getFrameworkServiceReferences();
Felix Meschberger9b6b5092007-10-01 14:18:04 +00001200 if ( refs != null )
1201 {
1202 for ( int i = 0; i < refs.length; i++ )
1203 {
1204 if ( getBoundService( refs[i] ) == null )
1205 {
1206 // might want to do this asynchronously ??
1207 serviceAdded( refs[i] );
1208 }
1209 }
Felix Meschbergerf60039b2009-04-27 09:44:55 +00001210 m_size = refs.length;
1211 }
1212 else
1213 {
1214 // no services currently match the filter
1215 m_size = 0;
Felix Meschberger9b6b5092007-10-01 14:18:04 +00001216 }
1217 }
1218
1219
1220 /**
1221 * Returns the target filter of this dependency as a string or
1222 * <code>null</code> if this dependency has no target filter set.
1223 *
1224 * @return The target filter of this dependency or <code>null</code> if
1225 * none is set.
1226 */
Felix Meschbergerd25a63d2007-11-23 13:02:49 +00001227 public String getTarget()
Felix Meschberger9b6b5092007-10-01 14:18:04 +00001228 {
1229 return m_target;
1230 }
1231
1232
1233 /**
1234 * Checks whether the service references matches the target filter of this
1235 * dependency.
1236 *
1237 * @param ref The service reference to check
1238 * @return <code>true</code> if this dependency has no target filter or if
1239 * the target filter matches the service reference.
1240 */
1241 private boolean targetFilterMatch( ServiceReference ref )
1242 {
1243 return m_targetFilter == null || m_targetFilter.match( ref );
1244 }
Felix Meschbergerc90e3162007-03-28 14:34:01 +00001245}