blob: 6aeafc3b0fa2068b2597ac7356891be961c48b6f [file] [log] [blame]
Pierre De Ropb9dee1a2009-12-04 22:59:03 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
3 * agreements. See the NOTICE file distributed with this work for additional information
4 * regarding copyright ownership. The ASF licenses this file to you under the Apache License,
5 * Version 2.0 (the "License"); you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless
7 * required by applicable law or agreed to in writing, software distributed under the License is
8 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
9 * or implied. See the License for the specific language governing permissions and limitations
10 * under the License.
11 */
Pierre De Ropc2429862009-12-04 23:00:03 +000012package org.apache.felix.dm.impl.dependencies;
Pierre De Ropb9dee1a2009-12-04 22:59:03 +000013
14import java.lang.reflect.InvocationHandler;
15import java.lang.reflect.Method;
16import java.lang.reflect.Proxy;
17
Pierre De Ropc2429862009-12-04 23:00:03 +000018import org.apache.felix.dm.DependencyActivatorBase;
Marcel Offermans3d921212010-08-09 13:37:02 +000019import org.apache.felix.dm.DependencyService;
Marcel Offermans8b93efa2010-07-02 18:27:21 +000020import org.apache.felix.dm.TemporalServiceDependency;
Pierre De Ropc2429862009-12-04 23:00:03 +000021import org.apache.felix.dm.impl.Logger;
Pierre De Ropb9dee1a2009-12-04 22:59:03 +000022import org.osgi.framework.BundleContext;
23import org.osgi.framework.ServiceReference;
24
25/**
Pierre De Rop7d049032010-01-20 23:03:25 +000026* Temporal Service dependency implementation.
27* (see javadoc in {@link TemporalServiceDependency}).
Pierre De Ropb9dee1a2009-12-04 22:59:03 +000028*/
Pierre De Ropc2429862009-12-04 23:00:03 +000029public class TemporalServiceDependencyImpl extends ServiceDependencyImpl implements TemporalServiceDependency, InvocationHandler {
Pierre De Ropb9dee1a2009-12-04 22:59:03 +000030 // Max millis to wait for service availability.
31 private long m_timeout = 30000;
32
33 /**
34 * Creates a new Temporal Service Dependency.
35 *
36 * @param context The bundle context of the bundle which is instantiating this dependency object
37 * @param logger the logger our Internal logger for logging events.
38 * @see DependencyActivatorBase#createTemporalServiceDependency()
39 */
Pierre De Ropc2429862009-12-04 23:00:03 +000040 public TemporalServiceDependencyImpl(BundleContext context, Logger logger) {
Pierre De Ropb9dee1a2009-12-04 22:59:03 +000041 super(context, logger);
42 super.setRequired(true);
43 }
44
45 /**
46 * Sets the timeout for this temporal dependency. Specifying a timeout value of zero means that there is no timeout period,
47 * and an invocation on a missing service will fail immediately.
48 *
49 * @param timeout the dependency timeout value greater or equals to 0
50 * @throws IllegalArgumentException if the timeout is negative
51 * @return this temporal dependency
52 */
53 public TemporalServiceDependency setTimeout(long timeout) {
54 if (timeout < 0) {
55 throw new IllegalArgumentException("Invalid timeout value: " + timeout);
56 }
57 m_timeout = timeout;
58 return this;
59 }
60
61 /**
62 * The ServiceTracker calls us here in order to inform about a service arrival.
63 */
64 public synchronized void addedService(ServiceReference ref, Object service) {
65 boolean makeAvailable = makeAvailable();
66 if (makeAvailable) {
67 m_serviceInstance = Proxy.newProxyInstance(m_trackedServiceName.getClassLoader(), new Class[] { m_trackedServiceName }, this);
68 }
69 Object[] services = m_services.toArray();
70 for (int i = 0; i < services.length; i++) {
71 DependencyService ds = (DependencyService) services[i];
72 if (makeAvailable) {
73 ds.dependencyAvailable(this);
74 }
75 }
76 if (!makeAvailable) {
77 notifyAll();
78 }
79 }
80
81 /**
82 * The ServiceTracker calls us here when a tracked service properties are modified.
83 */
84 public void modifiedService(ServiceReference ref, Object service) {
85 // We don't care.
86 }
87
88 /**
89 * The ServiceTracker calls us here when a tracked service is lost.
90 */
91 public synchronized void removedService(ServiceReference ref, Object service) {
92 // Unget what we got in addingService (see ServiceTracker 701.4.1)
93 m_context.ungetService(ref);
94 }
95
96 /**
97 * @returns our dependency instance. Unlike in ServiceDependency, we always returns our proxy.
98 */
99 public synchronized Object getService() {
100 return m_serviceInstance;
101 }
102
103 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
104 Object service = m_tracker.getService();
105 if (service == null) {
106 synchronized (this) {
107 long start = System.currentTimeMillis();
108 long waitTime = m_timeout;
109 while (service == null) {
110 if (waitTime <= 0) {
111 throw new IllegalStateException("Service unavailable: " + m_trackedServiceName.getName());
112 }
113 try {
114 wait(waitTime);
115 }
116 catch (InterruptedException e) {
117 throw new IllegalStateException("Service unavailable: " + m_trackedServiceName.getName());
118 }
119 waitTime = m_timeout - (System.currentTimeMillis() - start);
120 service = m_tracker.getService();
121 }
122 }
123 }
124 try {
125 return method.invoke(service, args);
126 }
127 catch (IllegalAccessException iae) {
128 method.setAccessible(true);
129 return method.invoke(service, args);
130 }
131 }
132}