
org.ops4j.pax.jdbc.config.impl.ServiceTrackerHelper Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2021 OPS4J.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ops4j.pax.jdbc.config.impl;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Helper class to track multiple services in cascade.
* As it's exclusively using the ServiceTracker helper class,
* the whole tracking mechanism is thread safe.
*/
public class ServiceTrackerHelper {
public static final Logger LOGGER = LoggerFactory.getLogger(ServiceTrackerHelper.class);
private final BundleContext context;
private ServiceTrackerHelper(BundleContext context) {
this.context = context;
}
/**
* Build a ServiceTrackerHelper using the given BundleContext.
*/
public static ServiceTrackerHelper helper(BundleContext bundleContext) {
return new ServiceTrackerHelper(bundleContext);
}
/**
* Start tracking a service for class S, and chain with another service tracking call.
*
* @param clazz the service class
* @param consumer a function receiving the tracked service and chaining with another service tracking call
* @param the tracked service class
* @param the chained service tracker class
* @return an opened service tracker
*/
public > ServiceTracker track(
Class clazz,
Function consumer
) {
return track(clazz, defaultFilter(clazz), consumer, ServiceTracker::close);
}
/**
* Start tracking a service for class S with a given filter, and chain with another service tracking call.
* If a null filter is given, the service tracking is completely bypassed and a null value will be
* immediately given to the consumer.
*
* @param clazz the service class
* @param filter the filter to use
* @param consumer a function receiving the tracked service and chaining with another service tracking call
* @param the tracked service class
* @param the chained service tracker class
* @return an opened service tracker
*/
public > ServiceTracker track(
Class clazz,
String filter,
Function consumer
) {
return track(clazz, filter, consumer, ServiceTracker::close);
}
/**
* Start tracking a service for class S with a given filter, and create the final object.
*
* @param clazz the service class
* @param creator a function receiving the tracked service and creating the final object
* @param destroyer a callback to destroy the final object when the tracked service is lost
* @param the tracked service class
* @param the final object type
* @return an opened service tracker
*/
public ServiceTracker track(
Class clazz,
Function creator,
Consumer destroyer
) {
return track(clazz, defaultFilter(clazz), creator, destroyer);
}
/**
* Start tracking a service for class S with a given filter, and create the final object.
* If a null filter is given, the service tracking is completely bypassed and a null value will be
* immediately given to the consumer.
*
* @param clazz the service class
* @param filter the filter to use
* @param creator a function receiving the tracked service and creating the final object
* @param destroyer a callback to destroy the final object when the tracked service is lost
* @param the tracked service class
* @param the final object type
* @return an opened service tracker
*/
public ServiceTracker track(
Class clazz,
String filter,
Function creator,
Consumer destroyer
) {
if (filter != null) {
ServiceTracker tracker = new ServiceTracker(context, getOrCreateFilter(filter), null) {
@Override
public T addingService(ServiceReference reference) {
LOGGER.debug("Obtained service dependency: " + filter);
S s = context.getService(reference);
return creator.apply(s);
}
@Override
public void removedService(ServiceReference reference, T service) {
LOGGER.debug("Lost service dependency: " + filter);
destroyer.accept(service);
context.ungetService(reference);
}
};
tracker.open();
if (tracker.isEmpty()) {
LOGGER.debug("Waiting for service dependency: " + filter);
}
return tracker;
} else {
T t = creator.apply(null);
return new ServiceTracker(context, clazz, null) {
@Override
public void close() {
destroyer.accept(t);
}
};
}
}
/**
* Start tracking a service for class S with a given filter, and create the final object.
* If a null filter is given, the service tracking is completely bypassed and a null value will be
* immediately given to the consumer.
*
* @param clazz the service class
* @param filter the filter to use
* @param creator a function receiving the tracked service plus its {@link ServiceReference} and creating the final object
* @param destroyer a callback to destroy the final object when the tracked service is lost
* @param the tracked service class
* @param the final object type
* @return an opened service tracker
*/
public ServiceTracker track(
Class clazz,
String filter,
BiFunction, T> creator,
Consumer destroyer
) {
if (filter != null) {
ServiceTracker tracker = new ServiceTracker(context, getOrCreateFilter(filter), null) {
@Override
public T addingService(ServiceReference reference) {
LOGGER.debug("Obtained service dependency: " + filter);
S s = context.getService(reference);
return creator.apply(s, reference);
}
@Override
public void removedService(ServiceReference reference, T service) {
LOGGER.debug("Lost service dependency: " + filter);
destroyer.accept(service);
context.ungetService(reference);
}
};
tracker.open();
if (tracker.isEmpty()) {
LOGGER.debug("Waiting for service dependency: " + filter);
}
return tracker;
} else {
T t = creator.apply(null, null);
return new ServiceTracker(context, clazz, null) {
@Override
public void close() {
destroyer.accept(t);
}
};
}
}
private String defaultFilter(Class> clazz) {
return "(" + Constants.OBJECTCLASS + "=" + clazz.getName() + ")";
}
private Filter getOrCreateFilter(String filter) {
try {
return context.createFilter(filter);
} catch (InvalidSyntaxException e) {
throw new RuntimeException("Unable to create filter", e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy