Carsten Ziegeler | 64c6f7a | 2007-08-15 09:58:35 +0000 | [diff] [blame] | 1 | /* |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 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 | */ |
Felix Meschberger | 9c77865 | 2009-07-09 13:02:12 +0000 | [diff] [blame] | 19 | package org.apache.felix.scr.impl.manager; |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 20 | |
| 21 | |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 22 | import java.util.ArrayList; |
| 23 | import java.util.Collections; |
| 24 | import java.util.Dictionary; |
| 25 | import java.util.HashMap; |
| 26 | import java.util.List; |
| 27 | import java.util.Map; |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 28 | |
Felix Meschberger | d25a63d | 2007-11-23 13:02:49 +0000 | [diff] [blame] | 29 | import org.apache.felix.scr.Reference; |
Felix Meschberger | 9c77865 | 2009-07-09 13:02:12 +0000 | [diff] [blame] | 30 | import org.apache.felix.scr.impl.metadata.ReferenceMetadata; |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 31 | import org.osgi.framework.BundleContext; |
| 32 | import org.osgi.framework.Constants; |
| 33 | import org.osgi.framework.Filter; |
| 34 | import org.osgi.framework.InvalidSyntaxException; |
| 35 | import org.osgi.framework.ServiceEvent; |
| 36 | import org.osgi.framework.ServiceListener; |
| 37 | import org.osgi.framework.ServiceReference; |
Felix Meschberger | ba3da7a | 2009-07-09 12:26:58 +0000 | [diff] [blame] | 38 | import org.osgi.service.component.ComponentConstants; |
Felix Meschberger | 29e04e3 | 2007-08-30 14:53:12 +0000 | [diff] [blame] | 39 | import org.osgi.service.log.LogService; |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 40 | |
| 41 | |
| 42 | /** |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 43 | * The <code>DependencyManager</code> manages the references to services |
| 44 | * declared by a single <code><reference></code element in component |
| 45 | * descriptor. |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 46 | */ |
Felix Meschberger | 9c77865 | 2009-07-09 13:02:12 +0000 | [diff] [blame] | 47 | public class DependencyManager implements ServiceListener, Reference |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 48 | { |
| 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 Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 53 | |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 54 | // the ServiceReference class instance |
| 55 | private static final Class SERVICE_REFERENCE_CLASS = ServiceReference.class; |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 56 | |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 57 | // pseudo service to mark a bound service without actual service instance |
| 58 | private static final Object BOUND_SERVICE_SENTINEL = new Object(); |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 59 | |
| 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 Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 66 | // The map of bound services indexed by their ServiceReference |
| 67 | private Map m_bound; |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 68 | |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 69 | // the number of matching services registered in the system |
| 70 | private int m_size; |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 71 | |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 72 | // the object on which the bind/undind methods are to be called |
| 73 | private transient Object m_componentInstance; |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 74 | |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 75 | // the bind method |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 76 | private BindMethod m_bind; |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 77 | |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 78 | // whether the bind method takes a service reference |
| 79 | private boolean m_bindUsesReference; |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 80 | |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 81 | // the unbind method |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 82 | private UnbindMethod m_unbind; |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 83 | |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 84 | // whether the unbind method takes a service reference |
| 85 | private boolean m_unbindUsesReference; |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 86 | |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 87 | // the target service filter string |
| 88 | private String m_target; |
| 89 | |
| 90 | // the target service filter |
| 91 | private Filter m_targetFilter; |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 92 | |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 93 | |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 94 | /** |
| 95 | * Constructor that receives several parameters. |
Carsten Ziegeler | 64c6f7a | 2007-08-15 09:58:35 +0000 | [diff] [blame] | 96 | * |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 97 | * @param dependency An object that contains data about the dependency |
| 98 | */ |
| 99 | DependencyManager( AbstractComponentManager componentManager, ReferenceMetadata dependency ) |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 100 | { |
Carsten Ziegeler | 7cbcef5 | 2007-08-15 11:37:08 +0000 | [diff] [blame] | 101 | m_componentManager = componentManager; |
| 102 | m_dependencyMetadata = dependency; |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 103 | m_bound = Collections.synchronizedMap( new HashMap() ); |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 104 | |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 105 | // setup the target filter from component descriptor |
| 106 | setTargetFilter( m_dependencyMetadata.getTarget() ); |
| 107 | |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 108 | m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager " + getName() + " created: filter=" |
Felix Meschberger | c732560 | 2009-05-25 21:07:04 +0000 | [diff] [blame] | 109 | + getTarget() + ", interface=" + m_dependencyMetadata.getInterface(), m_componentManager |
| 110 | .getComponentMetadata(), null ); |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 111 | } |
| 112 | |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 113 | /** |
| 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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 146 | |
| 147 | //---------- ServiceListener interface ------------------------------------ |
| 148 | |
Felix Meschberger | 38b77d7 | 2007-09-18 09:22:10 +0000 | [diff] [blame] | 149 | /** |
| 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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 153 | public void serviceChanged( ServiceEvent event ) |
| 154 | { |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 155 | final ServiceReference ref = event.getServiceReference(); |
| 156 | final String serviceString = "Service " + m_dependencyMetadata.getInterface() + "/" |
| 157 | + ref.getProperty( Constants.SERVICE_ID ); |
| 158 | |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 159 | switch ( event.getType() ) |
| 160 | { |
| 161 | case ServiceEvent.REGISTERED: |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 162 | m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager: Adding " + serviceString, |
| 163 | m_componentManager.getComponentMetadata(), null ); |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 164 | |
Felix Meschberger | f60039b | 2009-04-27 09:44:55 +0000 | [diff] [blame] | 165 | // 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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 177 | break; |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 178 | |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 179 | case ServiceEvent.MODIFIED: |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 180 | m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager: Updating " + serviceString, |
| 181 | m_componentManager.getComponentMetadata(), null ); |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 182 | |
Felix Meschberger | f60039b | 2009-04-27 09:44:55 +0000 | [diff] [blame] | 183 | // remove the service first |
Felix Meschberger | afbd25f | 2009-07-31 15:55:42 +0000 | [diff] [blame^] | 184 | // 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 Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 193 | |
Felix Meschberger | afbd25f | 2009-07-31 15:55:42 +0000 | [diff] [blame^] | 194 | // 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 Meschberger | f60039b | 2009-04-27 09:44:55 +0000 | [diff] [blame] | 201 | |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 202 | break; |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 203 | |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 204 | case ServiceEvent.UNREGISTERING: |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 205 | m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager: Removing " + serviceString, |
| 206 | m_componentManager.getComponentMetadata(), null ); |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 207 | |
Felix Meschberger | f60039b | 2009-04-27 09:44:55 +0000 | [diff] [blame] | 208 | // 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 Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 223 | serviceRemoved( ref ); |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 224 | |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 225 | break; |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | |
Felix Meschberger | 38b77d7 | 2007-09-18 09:22:10 +0000 | [diff] [blame] | 230 | /** |
| 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 Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 237 | * |
Felix Meschberger | 38b77d7 | 2007-09-18 09:22:10 +0000 | [diff] [blame] | 238 | * @param reference The reference to the service newly registered or |
| 239 | * modified. |
| 240 | */ |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 241 | private void serviceAdded( ServiceReference reference ) |
| 242 | { |
| 243 | // if the component is currently unsatisfied, it may become satisfied |
Felix Meschberger | 8b3d464 | 2009-05-25 21:13:24 +0000 | [diff] [blame] | 244 | // by adding this service, try to activate (also schedule activation |
| 245 | // if the component is pending deactivation) |
Felix Meschberger | d3fc8bf | 2009-06-02 14:43:54 +0000 | [diff] [blame] | 246 | if ( m_componentManager.getState() == AbstractComponentManager.STATE_ENABLED ) |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 247 | { |
Felix Meschberger | 1f928f2 | 2008-05-30 19:56:02 +0000 | [diff] [blame] | 248 | m_componentManager.log( LogService.LOG_INFO, "Dependency Manager: Service " |
Felix Meschberger | 8b3d464 | 2009-05-25 21:13:24 +0000 | [diff] [blame] | 249 | + m_dependencyMetadata.getName() + " registered, activate component", m_componentManager |
Felix Meschberger | 1f928f2 | 2008-05-30 19:56:02 +0000 | [diff] [blame] | 250 | .getComponentMetadata(), null ); |
Felix Meschberger | 3f87087 | 2007-09-20 11:05:51 +0000 | [diff] [blame] | 251 | |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 252 | 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 Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 258 | |
Felix Meschberger | afbd25f | 2009-07-31 15:55:42 +0000 | [diff] [blame^] | 259 | // 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 Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 262 | if ( m_dependencyMetadata.isStatic() ) |
| 263 | { |
Felix Meschberger | afbd25f | 2009-07-31 15:55:42 +0000 | [diff] [blame^] | 264 | 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 Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 267 | } |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 268 | |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 269 | // otherwise bind if we have a bind method and the service needs |
| 270 | // be bound |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 271 | else if ( m_dependencyMetadata.getBind() != null ) |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 272 | { |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 273 | // multiple bindings or not bound at all yet |
| 274 | if ( m_dependencyMetadata.isMultiple() || !isBound() ) |
| 275 | { |
| 276 | // bind the service, getting it if required |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 277 | invokeBindMethod( reference ); |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 278 | } |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 279 | } |
| 280 | } |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 281 | |
| 282 | else |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 283 | { |
Felix Meschberger | d3fc8bf | 2009-06-02 14:43:54 +0000 | [diff] [blame] | 284 | m_componentManager.log( LogService.LOG_DEBUG, |
| 285 | "Dependency Manager: Ignoring service addition, wrong state " |
| 286 | + m_componentManager.state(), |
| 287 | m_componentManager.getComponentMetadata(), null ); |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 288 | } |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 289 | } |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 290 | |
| 291 | |
Felix Meschberger | 38b77d7 | 2007-09-18 09:22:10 +0000 | [diff] [blame] | 292 | /** |
| 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 Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 300 | * |
Felix Meschberger | 38b77d7 | 2007-09-18 09:22:10 +0000 | [diff] [blame] | 301 | * @param reference The reference to the service unregistering or being |
| 302 | * modified. |
Felix Meschberger | afbd25f | 2009-07-31 15:55:42 +0000 | [diff] [blame^] | 303 | * |
| 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 Meschberger | 38b77d7 | 2007-09-18 09:22:10 +0000 | [diff] [blame] | 309 | */ |
Felix Meschberger | afbd25f | 2009-07-31 15:55:42 +0000 | [diff] [blame^] | 310 | private boolean serviceRemoved( ServiceReference reference ) |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 311 | { |
Felix Meschberger | aed494d | 2007-11-28 17:50:22 +0000 | [diff] [blame] | 312 | // check whether we are bound to that service, do nothing if not |
| 313 | if ( getBoundService( reference ) == null ) |
| 314 | { |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 315 | 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 Meschberger | afbd25f | 2009-07-31 15:55:42 +0000 | [diff] [blame^] | 318 | |
| 319 | // service was not bound, we can continue without interruption |
| 320 | return true; |
Felix Meschberger | aed494d | 2007-11-28 17:50:22 +0000 | [diff] [blame] | 321 | } |
| 322 | |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 323 | // otherwise check whether the component is in a state to handle the event |
| 324 | else if ( handleServiceEvent() ) |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 325 | { |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 326 | |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 327 | // if the dependency is not satisfied anymore, we have to |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 328 | // deactivate the component |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 329 | 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 Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 337 | |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 338 | // deactivate the component now |
Felix Meschberger | ba3da7a | 2009-07-09 12:26:58 +0000 | [diff] [blame] | 339 | m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE ); |
Felix Meschberger | afbd25f | 2009-07-31 15:55:42 +0000 | [diff] [blame^] | 340 | |
| 341 | // component is deactivated, this does all for this service |
| 342 | return false; |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 343 | } |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 344 | |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 345 | // 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 Meschberger | 1f928f2 | 2008-05-30 19:56:02 +0000 | [diff] [blame] | 351 | m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager: Static dependency on " |
| 352 | + m_dependencyMetadata.getName() + "/" + m_dependencyMetadata.getInterface() + " is broken", |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 353 | m_componentManager.getComponentMetadata(), null ); |
Felix Meschberger | ba3da7a | 2009-07-09 12:26:58 +0000 | [diff] [blame] | 354 | m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE ); |
| 355 | m_componentManager.activate(); |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 356 | } |
| 357 | catch ( Exception ex ) |
| 358 | { |
Felix Meschberger | 1f928f2 | 2008-05-30 19:56:02 +0000 | [diff] [blame] | 359 | m_componentManager.log( LogService.LOG_ERROR, "Exception while recreating dependency ", |
| 360 | m_componentManager.getComponentMetadata(), ex ); |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 361 | } |
Felix Meschberger | afbd25f | 2009-07-31 15:55:42 +0000 | [diff] [blame^] | 362 | |
| 363 | // static reference removal causes reactivation, nothing more to do |
| 364 | return false; |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 365 | } |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 366 | |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 367 | // dynamic dependency, multiple or single but this service is the bound one |
| 368 | else |
| 369 | { |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 370 | |
Felix Meschberger | 38b77d7 | 2007-09-18 09:22:10 +0000 | [diff] [blame] | 371 | // try to bind a replacement service first if this is a unary |
| 372 | // cardinality reference and a replacement is available. |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 373 | if ( !m_dependencyMetadata.isMultiple() ) |
| 374 | { |
Felix Meschberger | 38b77d7 | 2007-09-18 09:22:10 +0000 | [diff] [blame] | 375 | // if the dependency is mandatory and no replacement is |
| 376 | // available, bind returns false and we deactivate |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 377 | if ( !bind() ) |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 378 | { |
Felix Meschberger | 1f928f2 | 2008-05-30 19:56:02 +0000 | [diff] [blame] | 379 | m_componentManager.log( LogService.LOG_DEBUG, |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 380 | "Dependency Manager: Deactivating component due to mandatory dependency on " |
| 381 | + m_dependencyMetadata.getName() + "/" + m_dependencyMetadata.getInterface() |
| 382 | + " not satisfied", m_componentManager.getComponentMetadata(), null ); |
Felix Meschberger | ba3da7a | 2009-07-09 12:26:58 +0000 | [diff] [blame] | 383 | m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE ); |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 384 | |
Felix Meschberger | afbd25f | 2009-07-31 15:55:42 +0000 | [diff] [blame^] | 385 | // required service could not be replaced, component |
| 386 | // is deactivated and we are done |
| 387 | return false; |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 388 | } |
| 389 | } |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 390 | |
Felix Meschberger | 38b77d7 | 2007-09-18 09:22:10 +0000 | [diff] [blame] | 391 | // call the unbind method if one is defined |
| 392 | if ( m_dependencyMetadata.getUnbind() != null ) |
| 393 | { |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 394 | invokeUnbindMethod( reference ); |
Felix Meschberger | 38b77d7 | 2007-09-18 09:22:10 +0000 | [diff] [blame] | 395 | } |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 396 | |
Felix Meschberger | 514de15 | 2009-05-26 08:03:25 +0000 | [diff] [blame] | 397 | // make sure the service is returned |
| 398 | ungetService( reference ); |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 399 | } |
| 400 | } |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 401 | |
| 402 | else |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 403 | { |
Felix Meschberger | d3fc8bf | 2009-06-02 14:43:54 +0000 | [diff] [blame] | 404 | m_componentManager.log( LogService.LOG_DEBUG, |
| 405 | "Dependency Manager: Ignoring service removal, wrong state " |
| 406 | + m_componentManager.state(), |
| 407 | m_componentManager.getComponentMetadata(), null ); |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 408 | } |
Felix Meschberger | afbd25f | 2009-07-31 15:55:42 +0000 | [diff] [blame^] | 409 | |
| 410 | // everything is fine, the component is still active and we continue |
| 411 | return true; |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 412 | } |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 413 | |
| 414 | |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 415 | private boolean handleServiceEvent() |
| 416 | { |
| 417 | return ( m_componentManager.getState() & STATE_MASK ) != 0; |
Felix Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 418 | } |
| 419 | |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 420 | |
Felix Meschberger | d25a63d | 2007-11-23 13:02:49 +0000 | [diff] [blame] | 421 | //---------- Reference interface ------------------------------------------ |
| 422 | |
Felix Meschberger | d25a63d | 2007-11-23 13:02:49 +0000 | [diff] [blame] | 423 | 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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 465 | //---------- Service tracking support ------------------------------------- |
| 466 | |
| 467 | /** |
Felix Meschberger | 73a39e6 | 2009-05-25 12:38:48 +0000 | [diff] [blame] | 468 | * 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 Meschberger | c732560 | 2009-05-25 21:07:04 +0000 | [diff] [blame] | 474 | // get the current number of registered services available |
| 475 | ServiceReference refs[] = getFrameworkServiceReferences(); |
| 476 | m_size = ( refs == null ) ? 0 : refs.length; |
| 477 | |
Felix Meschberger | 73a39e6 | 2009-05-25 12:38:48 +0000 | [diff] [blame] | 478 | // register the service listener |
| 479 | String filterString = "(" + Constants.OBJECTCLASS + "=" + m_dependencyMetadata.getInterface() + ")"; |
| 480 | m_componentManager.getActivator().getBundleContext().addServiceListener( this, filterString ); |
Felix Meschberger | c732560 | 2009-05-25 21:07:04 +0000 | [diff] [blame] | 481 | |
| 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 Meschberger | 73a39e6 | 2009-05-25 12:38:48 +0000 | [diff] [blame] | 484 | } |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 485 | |
Felix Meschberger | 73a39e6 | 2009-05-25 12:38:48 +0000 | [diff] [blame] | 486 | /** |
Felix Meschberger | 38b77d7 | 2007-09-18 09:22:10 +0000 | [diff] [blame] | 487 | * 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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 491 | */ |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 492 | void dispose() |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 493 | { |
Carsten Ziegeler | 7cbcef5 | 2007-08-15 11:37:08 +0000 | [diff] [blame] | 494 | BundleContext context = m_componentManager.getActivator().getBundleContext(); |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 495 | context.removeServiceListener( this ); |
| 496 | |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 497 | m_size = 0; |
| 498 | |
| 499 | // unget all services we once got |
| 500 | ServiceReference[] boundRefs = getBoundServiceReferences(); |
| 501 | if ( boundRefs != null ) |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 502 | { |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 503 | for ( int i = 0; i < boundRefs.length; i++ ) |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 504 | { |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 505 | ungetService( boundRefs[i] ); |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 506 | } |
| 507 | } |
| 508 | } |
| 509 | |
| 510 | |
| 511 | /** |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 512 | * 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 Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 518 | * |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 519 | * @see #isValid() |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 520 | */ |
| 521 | int size() |
| 522 | { |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 523 | return m_size; |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 524 | } |
| 525 | |
| 526 | |
| 527 | /** |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 528 | * 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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 537 | */ |
Felix Meschberger | d25a63d | 2007-11-23 13:02:49 +0000 | [diff] [blame] | 538 | ServiceReference[] getFrameworkServiceReferences() |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 539 | { |
Felix Meschberger | e21cefd | 2009-07-28 13:58:48 +0000 | [diff] [blame] | 540 | return getFrameworkServiceReferences( getTarget() ); |
| 541 | } |
| 542 | |
| 543 | |
| 544 | private ServiceReference[] getFrameworkServiceReferences( String targetFilter ) |
| 545 | { |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 546 | try |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 547 | { |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 548 | return m_componentManager.getActivator().getBundleContext().getServiceReferences( |
Felix Meschberger | e21cefd | 2009-07-28 13:58:48 +0000 | [diff] [blame] | 549 | m_dependencyMetadata.getInterface(), targetFilter ); |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 550 | } |
| 551 | catch ( InvalidSyntaxException ise ) |
| 552 | { |
Felix Meschberger | e21cefd | 2009-07-28 13:58:48 +0000 | [diff] [blame] | 553 | m_componentManager.log( LogService.LOG_ERROR, "Unexpected problem with filter '" + targetFilter + "'", |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 554 | m_componentManager.getComponentMetadata(), ise ); |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 555 | return null; |
| 556 | } |
| 557 | } |
| 558 | |
| 559 | |
| 560 | /** |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 561 | * 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 Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 611 | * Returns the service instance for the service reference returned by the |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 612 | * {@link #getFrameworkServiceReference()} method. If this returns a |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 613 | * non-<code>null</code> service instance the service is then considered |
| 614 | * bound to this instance. |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 615 | */ |
| 616 | Object getService() |
| 617 | { |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 618 | ServiceReference sr = getFrameworkServiceReference(); |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 619 | return ( sr != null ) ? getService( sr ) : null; |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 620 | } |
| 621 | |
| 622 | |
| 623 | /** |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 624 | * Returns an array of service instances for the service references returned |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 625 | * 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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 629 | */ |
| 630 | Object[] getServices() |
| 631 | { |
Felix Meschberger | d25a63d | 2007-11-23 13:02:49 +0000 | [diff] [blame] | 632 | ServiceReference[] sr = getFrameworkServiceReferences(); |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 633 | if ( sr == null || sr.length == 0 ) |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 634 | { |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 635 | return null; |
| 636 | } |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 637 | |
| 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 Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 651 | |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 652 | /** |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 653 | * 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 Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 657 | * |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 658 | * @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 Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 674 | * |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 675 | * @param serviceReference The Service reference whose service id is to be |
| 676 | * returned. |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 677 | * |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 678 | * @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 Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 692 | //---------- 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 Meschberger | 38b77d7 | 2007-09-18 09:22:10 +0000 | [diff] [blame] | 713 | /** |
| 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 Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 723 | * |
Felix Meschberger | 38b77d7 | 2007-09-18 09:22:10 +0000 | [diff] [blame] | 724 | * @param serviceReference The reference to the service being marked as |
| 725 | * bound. |
| 726 | */ |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 727 | private void bindService( ServiceReference serviceReference ) |
| 728 | { |
| 729 | m_bound.put( serviceReference, BOUND_SERVICE_SENTINEL ); |
| 730 | } |
| 731 | |
| 732 | |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 733 | /** |
| 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 Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 737 | * |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 738 | * @param serviceReference The reference to the bound service |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 739 | * |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 740 | * @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 Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 743 | */ |
| 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 Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 755 | * |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 756 | * @param serviceReference The reference to the service to be returned |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 757 | * |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 758 | * @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 Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 765 | if ( service != null && service != BOUND_SERVICE_SENTINEL ) |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 766 | { |
| 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 Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 790 | if ( service != null && service != BOUND_SERVICE_SENTINEL ) |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 791 | { |
| 792 | m_componentManager.getActivator().getBundleContext().ungetService( serviceReference ); |
| 793 | } |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 794 | } |
| 795 | |
| 796 | |
| 797 | //---------- DependencyManager core --------------------------------------- |
| 798 | |
| 799 | /** |
| 800 | * Returns the name of the service reference. |
| 801 | */ |
Felix Meschberger | d25a63d | 2007-11-23 13:02:49 +0000 | [diff] [blame] | 802 | public String getName() |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 803 | { |
Carsten Ziegeler | 7cbcef5 | 2007-08-15 11:37:08 +0000 | [diff] [blame] | 804 | return m_dependencyMetadata.getName(); |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 805 | } |
| 806 | |
| 807 | |
| 808 | /** |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 809 | * 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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 813 | */ |
Felix Meschberger | d25a63d | 2007-11-23 13:02:49 +0000 | [diff] [blame] | 814 | public boolean isSatisfied() |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 815 | { |
Felix Meschberger | ee3f1db | 2007-08-22 15:21:27 +0000 | [diff] [blame] | 816 | return size() > 0 || m_dependencyMetadata.isOptional(); |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 817 | } |
| 818 | |
| 819 | |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 820 | boolean open( Object instance ) |
| 821 | { |
| 822 | m_componentInstance = instance; |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 823 | initBindingMethods(); |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 824 | 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 Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 841 | m_bind = null; |
| 842 | m_unbind = null; |
| 843 | |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 844 | } |
| 845 | } |
| 846 | |
| 847 | |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 848 | /** |
| 849 | * initializes a dependency. This method binds all of the service |
| 850 | * occurrences to the instance object |
Carsten Ziegeler | 64c6f7a | 2007-08-15 09:58:35 +0000 | [diff] [blame] | 851 | * |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 852 | * @return true if the dependency is satisfied and at least the minimum |
| 853 | * number of services could be bound. Otherwise false is returned. |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 854 | */ |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 855 | private boolean bind() |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 856 | { |
| 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 Meschberger | b609eca | 2007-09-17 12:32:57 +0000 | [diff] [blame] | 859 | if ( !isSatisfied() ) |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 860 | { |
| 861 | return false; |
| 862 | } |
| 863 | |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 864 | // if no bind method is configured or if this is a delayed component, |
| 865 | // we have nothing to do and just signal success |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 866 | if ( m_componentInstance == null || m_dependencyMetadata.getBind() == null ) |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 867 | { |
| 868 | return true; |
| 869 | } |
| 870 | |
Felix Meschberger | 86a336d | 2007-09-06 08:34:16 +0000 | [diff] [blame] | 871 | // assume success to begin with: if the dependency is optional, |
| 872 | // we don't care, whether we can bind a service. Otherwise, we |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 873 | // require at least one service to be bound, thus we require |
Felix Meschberger | 86a336d | 2007-09-06 08:34:16 +0000 | [diff] [blame] | 874 | // flag being set in the loop below |
| 875 | boolean success = m_dependencyMetadata.isOptional(); |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 876 | |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 877 | // Get service reference(s) |
| 878 | if ( m_dependencyMetadata.isMultiple() ) |
Felix Meschberger | 86a336d | 2007-09-06 08:34:16 +0000 | [diff] [blame] | 879 | { |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 880 | // 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 Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 887 | if ( invokeBindMethod( refs[index] ) ) |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 888 | { |
| 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 Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 899 | if ( ref != null && invokeBindMethod( ref ) ) |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 900 | { |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 901 | // of course, we have success if the service is bound |
| 902 | success = true; |
Felix Meschberger | aa5adb9 | 2007-09-06 08:37:44 +0000 | [diff] [blame] | 903 | } |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 904 | } |
| 905 | |
Felix Meschberger | 86a336d | 2007-09-06 08:34:16 +0000 | [diff] [blame] | 906 | // 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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 910 | } |
| 911 | |
| 912 | |
| 913 | /** |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 914 | * Revoke the given bindings. This method cannot throw an exception since |
| 915 | * it must try to complete all that it can |
| 916 | */ |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 917 | private void unbind( ServiceReference[] boundRefs ) |
Felix Meschberger | e956e03 | 2009-02-19 20:09:13 +0000 | [diff] [blame] | 918 | { |
Felix Meschberger | c0df73b | 2009-02-06 15:25:13 +0000 | [diff] [blame] | 919 | // 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 Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 921 | boolean doUnbind = m_componentInstance != null && m_dependencyMetadata.getUnbind() != null; |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 922 | |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 923 | if ( boundRefs != null ) |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 924 | { |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 925 | for ( int i = 0; i < boundRefs.length; i++ ) |
| 926 | { |
Felix Meschberger | c0df73b | 2009-02-06 15:25:13 +0000 | [diff] [blame] | 927 | if ( doUnbind ) |
| 928 | { |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 929 | invokeUnbindMethod( boundRefs[i] ); |
Felix Meschberger | c0df73b | 2009-02-06 15:25:13 +0000 | [diff] [blame] | 930 | } |
| 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 Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 937 | } |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 938 | } |
| 939 | } |
| 940 | |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 941 | /** |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 942 | * Calls the bind method. In case there is an exception while calling the |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 943 | * bind method, the service is not considered to be bound to the instance |
| 944 | * object |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 945 | * <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 Ziegeler | 64c6f7a | 2007-08-15 09:58:35 +0000 | [diff] [blame] | 948 | * |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 949 | * @param ref A ServiceReference with the service that will be bound to the |
| 950 | * instance object |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 951 | * @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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 956 | */ |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 957 | private boolean invokeBindMethod( final ServiceReference ref ) |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 958 | { |
| 959 | // The bind method is only invoked if the implementation object is not |
Felix Meschberger | 86a336d | 2007-09-06 08:34:16 +0000 | [diff] [blame] | 960 | // null. This is valid for both immediate and delayed components |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 961 | if( m_componentInstance != null ) |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 962 | { |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 963 | return m_bind.invoke( |
| 964 | m_componentInstance, |
| 965 | new BindMethod.Service() |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 966 | { |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 967 | public ServiceReference getReference() |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 968 | { |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 969 | bindService( ref ); |
| 970 | return ref; |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 971 | } |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 972 | |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 973 | public Object getInstance() |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 974 | { |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 975 | return getService( ref ); |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 976 | } |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 977 | } |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 978 | ); |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 979 | } |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 980 | else if ( !m_componentManager.getComponentMetadata().isImmediate() ) |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 981 | { |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 982 | 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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 997 | 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 Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 1003 | |
| 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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 1008 | return false; |
| 1009 | } |
| 1010 | } |
| 1011 | |
| 1012 | |
| 1013 | /** |
Felix Meschberger | 43d2a71 | 2007-09-17 08:51:36 +0000 | [diff] [blame] | 1014 | * 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 Ziegeler | 64c6f7a | 2007-08-15 09:58:35 +0000 | [diff] [blame] | 1019 | * |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 1020 | * @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 Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 1024 | private void invokeUnbindMethod( final ServiceReference ref ) |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 1025 | { |
| 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 Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 1028 | if ( m_componentInstance != null ) |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 1029 | { |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 1030 | m_unbind.invoke( |
| 1031 | m_componentInstance, |
| 1032 | new BindMethod.Service() |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 1033 | { |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 1034 | public ServiceReference getReference() |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 1035 | { |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 1036 | return ref; |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 1037 | } |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 1038 | |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 1039 | public Object getInstance() |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 1040 | { |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 1041 | return getService( ref ); |
Felix Meschberger | 9dadeef | 2007-09-17 10:57:44 +0000 | [diff] [blame] | 1042 | } |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 1043 | } |
Felix Meschberger | 8c1d3ec | 2009-07-28 14:59:16 +0000 | [diff] [blame] | 1044 | ); |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 1045 | } |
Felix Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 1046 | else |
| 1047 | { |
Felix Meschberger | 3e26f2d | 2009-04-20 11:13:27 +0000 | [diff] [blame] | 1048 | // 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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 1054 | } |
| 1055 | } |
| 1056 | |
Felix Meschberger | 5d89d56 | 2009-06-16 09:36:14 +0000 | [diff] [blame] | 1057 | |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 1058 | //------------- Service target filter support ----------------------------- |
| 1059 | |
| 1060 | /** |
Felix Meschberger | e21cefd | 2009-07-28 13:58:48 +0000 | [diff] [blame] | 1061 | * 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 Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 1129 | * 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 Meschberger | f60039b | 2009-04-27 09:44:55 +0000 | [diff] [blame] | 1197 | // check for new services to be added and set the number of |
| 1198 | // matching services |
Felix Meschberger | d25a63d | 2007-11-23 13:02:49 +0000 | [diff] [blame] | 1199 | ServiceReference[] refs = getFrameworkServiceReferences(); |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 1200 | 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 Meschberger | f60039b | 2009-04-27 09:44:55 +0000 | [diff] [blame] | 1210 | m_size = refs.length; |
| 1211 | } |
| 1212 | else |
| 1213 | { |
| 1214 | // no services currently match the filter |
| 1215 | m_size = 0; |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 1216 | } |
| 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 Meschberger | d25a63d | 2007-11-23 13:02:49 +0000 | [diff] [blame] | 1227 | public String getTarget() |
Felix Meschberger | 9b6b509 | 2007-10-01 14:18:04 +0000 | [diff] [blame] | 1228 | { |
| 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 Meschberger | c90e316 | 2007-03-28 14:34:01 +0000 | [diff] [blame] | 1245 | } |