1549e6b26a4d715d70dbe31b1c4a1f9891fd9301
[controller.git] / opendaylight / config / config-api / src / main / java / org / opendaylight / controller / config / api / osgi / WaitingServiceTracker.java
1 /*
2  * Copyright (c) 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.config.api.osgi;
9
10 import java.util.concurrent.TimeUnit;
11 import javax.annotation.Nonnull;
12 import org.osgi.framework.BundleContext;
13 import org.osgi.framework.Constants;
14 import org.osgi.framework.InvalidSyntaxException;
15 import org.osgi.util.tracker.ServiceTracker;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 /**
20  * Tracker that waits for an OSGi service.
21  *
22  * @author Thomas Pantelis
23  */
24 public final class WaitingServiceTracker<T> implements AutoCloseable {
25     private static final Logger LOG = LoggerFactory.getLogger(WaitingServiceTracker.class);
26     public static final long FIVE_MINUTES = TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES);
27
28     private final ServiceTracker<T, ?> tracker;
29     private final Class<T> serviceInterface;
30
31     private WaitingServiceTracker(Class<T> serviceInterface, ServiceTracker<T, ?> tracker) {
32         this.tracker = tracker;
33         this.serviceInterface = serviceInterface;
34     }
35
36     /**
37      * Waits for an OSGi services.
38      *
39      * @param timeoutInMillis the timeout in millis
40      * @return the service instance
41      * @throws ServiceNotFoundException if it times out or is interrupted
42      */
43     @SuppressWarnings("unchecked")
44     public T waitForService(long timeoutInMillis) throws ServiceNotFoundException {
45         try {
46             T service = (T) tracker.waitForService(timeoutInMillis);
47             if(service == null) {
48                 throw new ServiceNotFoundException(String.format("OSGi Service %s was not found after %d ms",
49                         serviceInterface, timeoutInMillis));
50             }
51
52             return service;
53         } catch(InterruptedException e) {
54             throw new ServiceNotFoundException(String.format("Wait for OSGi service %s was interrrupted",
55                     serviceInterface));
56         }
57     }
58
59     /**
60      * Creates an instance.
61      *
62      * @param serviceInterface the service interface
63      * @param context the BundleContext
64      * @return new WaitingServiceTracker instance
65      */
66     public static <T> WaitingServiceTracker<T> create(@Nonnull Class<T> serviceInterface, @Nonnull BundleContext context) {
67         ServiceTracker<T, ?> tracker = new ServiceTracker<>(context, serviceInterface, null);
68         tracker.open();
69         return new WaitingServiceTracker<T>(serviceInterface, tracker);
70     }
71
72     /**
73      * Creates an instance.
74      *
75      * @param serviceInterface the service interface
76      * @param context the BundleContext
77      * @param filter the OSGi service filter
78      * @return new WaitingServiceTracker instance
79      */
80     public static <T> WaitingServiceTracker<T> create(@Nonnull Class<T> serviceInterface, @Nonnull BundleContext context,
81             @Nonnull String filter) {
82         String newFilter = String.format("(&(%s=%s)%s)", Constants.OBJECTCLASS, serviceInterface.getName(), filter);
83         try {
84             ServiceTracker<T, ?> tracker = new ServiceTracker<>(context, context.createFilter(newFilter), null);
85             tracker.open();
86             return new WaitingServiceTracker<T>(serviceInterface, tracker);
87         } catch(InvalidSyntaxException e) {
88             throw new IllegalArgumentException(String.format("Invalid OSGi filter %s", newFilter), e);
89         }
90     }
91
92     @Override
93     public void close() {
94         try {
95             tracker.close();
96         } catch(RuntimeException e) {
97             // The ServiceTracker could throw IllegalStateException if the BundleContext is already closed.
98             // This is benign so ignore it.
99             LOG.debug("Error closing ServiceTracker", e);
100         }
101     }
102 }