org.openengsb.core.util.DefaultOsgiUtilsService.java Source code

Java tutorial

Introduction

Here is the source code for org.openengsb.core.util.DefaultOsgiUtilsService.java

Source

/**
 * Licensed to the Austrian Association for Software Tool Integration (AASTI)
 * under one or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership. The AASTI licenses this file to you 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.openengsb.core.util;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.openengsb.core.api.OsgiServiceNotAvailableException;
import org.openengsb.core.api.OsgiUtilsService;
import org.openengsb.core.api.context.ContextHolder;
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;

import com.google.common.base.Function;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;

public class DefaultOsgiUtilsService implements OsgiUtilsService {

    /**
     * serves as common invocation handler for proxies that resolve osgi-services dynamically. The proxy tries to
     * resolve the service for the given timeout. A timeout of 0 means that the proxy will wait for the service
     * indefinitely {@link ServiceTracker#waitForService(long)} A timeout < 0 means that the service tracker will not
     * wait for the service at all. If the service is not available immediately an
     * {@link OsgiServiceNotAvailableException} is thrown.
     *
     */
    private final class ServiceTrackerInvocationHandler implements InvocationHandler {
        private ServiceTracker tracker;
        private Long timeout = -1L;
        private final String info;

        protected ServiceTrackerInvocationHandler(Filter filter, long timeout) {
            this(filter);
            this.timeout = timeout;
        }

        protected ServiceTrackerInvocationHandler(Filter filter) {
            tracker = new ServiceTracker(bundleContext, filter, null);
            info = filter.toString();
        }

        protected ServiceTrackerInvocationHandler(String className, long timeout) {
            this(className);
            this.timeout = timeout;
        }

        protected ServiceTrackerInvocationHandler(String className) {
            tracker = new ServiceTracker(bundleContext, className, null);
            info = "Class: " + className;
        }

        protected ServiceTrackerInvocationHandler(Class<?> targetClass, long timeout) {
            this(targetClass.getName(), timeout);
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object service = getService();
            if (service == null) {
                throw new OsgiServiceNotAvailableException("could not resolve service with tracker: " + info);
            }
            try {
                return method.invoke(service, args);
            } catch (InvocationTargetException e) {
                throw e.getCause();
            }
        }

        private synchronized Object getService() throws InterruptedException {
            tracker.open();
            try {
                if (timeout < 0) {
                    return tracker.getService();
                } else {
                    return tracker.waitForService(timeout);
                }
            } finally {
                tracker.close();
            }
        }
    }

    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultOsgiUtilsService.class);
    private static final long DEFAULT_TIMEOUT = 30000L;

    private BundleContext bundleContext;

    public DefaultOsgiUtilsService() {
    }

    public DefaultOsgiUtilsService(BundleContext bundleContext) {
        this.bundleContext = bundleContext;
    }

    @Override
    public <T> T getService(Class<T> clazz) throws OsgiServiceNotAvailableException {
        return getService(clazz, DEFAULT_TIMEOUT);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T getService(Class<T> clazz, long timeout) throws OsgiServiceNotAvailableException {
        ServiceTracker tracker = new ServiceTracker(bundleContext, clazz.getName(), null);
        Object result = waitForServiceFromTracker(tracker, timeout);
        if (result == null) {
            throw new OsgiServiceNotAvailableException(
                    String.format("no service of type %s available at the time", clazz.getName()));
        }
        return (T) result;
    }

    @Override
    public Object getService(Filter filter) throws OsgiServiceNotAvailableException {
        return getService(filter, DEFAULT_TIMEOUT);
    }

    @Override
    public Object getService(Filter filter, long timeout) throws OsgiServiceNotAvailableException {
        ServiceTracker t = new ServiceTracker(bundleContext, filter, null);
        LOGGER.debug("getting service for filter {} from tracker", filter);
        Object result = waitForServiceFromTracker(t, timeout);
        if (result == null) {
            throw new OsgiServiceNotAvailableException(
                    String.format("no service matching filter \"%s\" available at the time", filter.toString()));
        }
        return result;
    }

    @Override
    public Object getService(String filterString) throws OsgiServiceNotAvailableException {
        return getService(filterString, DEFAULT_TIMEOUT);
    }

    @Override
    public Object getService(String filterString, long timeout) throws OsgiServiceNotAvailableException {
        return getService(FilterUtils.createFilter(filterString), timeout);
    }

    @Override
    public <T> T getServiceWithId(Class<? extends T> clazz, String id) throws OsgiServiceNotAvailableException {
        return getServiceWithId(clazz, id, DEFAULT_TIMEOUT);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T getServiceWithId(Class<? extends T> clazz, String id, long timeout)
            throws OsgiServiceNotAvailableException {
        return (T) getServiceWithId(clazz.getName(), id, timeout);
    }

    @Override
    public Object getServiceWithId(String className, String id) throws OsgiServiceNotAvailableException {
        return getServiceWithId(className, id, DEFAULT_TIMEOUT);
    }

    @Override
    public Object getServiceWithId(String className, String id, long timeout)
            throws OsgiServiceNotAvailableException {
        Filter filter = FilterUtils.makeFilter(className, String.format("(%s=%s)", Constants.SERVICE_PID, id));
        return getService(filter, timeout);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T getOsgiServiceProxy(final Filter filter, Class<T> targetClass, final long timeout) {
        return (T) Proxy.newProxyInstance(targetClass.getClassLoader(), new Class<?>[] { targetClass },
                new ServiceTrackerInvocationHandler(filter, timeout));
    }

    @Override
    public <T> T getOsgiServiceProxy(final String filter, Class<T> targetClass, long timeout) {
        return getOsgiServiceProxy(FilterUtils.createFilter(filter), targetClass, timeout);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T getOsgiServiceProxy(Class<T> targetClass, long timeout) {
        return (T) Proxy.newProxyInstance(targetClass.getClassLoader(), new Class<?>[] { targetClass },
                new ServiceTrackerInvocationHandler(targetClass, timeout));
    }

    @Override
    public <T> T getOsgiServiceProxy(Class<T> targetClass) {
        return getOsgiServiceProxy(targetClass, DEFAULT_TIMEOUT);
    }

    @Override
    public <T> T getOsgiServiceProxy(Filter filter, Class<T> targetClass) {
        return getOsgiServiceProxy(filter, targetClass, DEFAULT_TIMEOUT);
    }

    @Override
    public <T> T getOsgiServiceProxy(String filter, Class<T> targetClass) {
        return getOsgiServiceProxy(filter, targetClass, DEFAULT_TIMEOUT);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T getServiceForLocation(Class<T> clazz, String location, String context)
            throws OsgiServiceNotAvailableException, IllegalArgumentException {
        Filter compiled = OsgiUtils.getFilterForLocation(clazz, location, context);
        return (T) getService(compiled);
    }

    @Override
    public Object getServiceForLocation(String location, String context)
            throws OsgiServiceNotAvailableException, IllegalArgumentException {
        return getService(OsgiUtils.getFilterForLocation(location, context));
    }

    @Override
    public Object getServiceForLocation(String location)
            throws OsgiServiceNotAvailableException, IllegalArgumentException {
        LOGGER.debug("retrieve service for location: {}", location);
        return getService(OsgiUtils.getFilterForLocation(location));
    }

    @Override
    public <T> T getServiceForLocation(Class<T> clazz, String location)
            throws OsgiServiceNotAvailableException, IllegalArgumentException {
        return getServiceForLocation(clazz, location, ContextHolder.get().getCurrentContextId());
    }

    /**
     * tries to retrieve the service from the given service-tracker for the amount of milliseconds provided by the given
     * timeout.
     *
     * @throws OsgiServiceNotAvailableException if the service could not be found within the given timeout
     */
    private static Object waitForServiceFromTracker(ServiceTracker tracker, long timeout)
            throws OsgiServiceNotAvailableException {
        synchronized (tracker) {
            tracker.open();
            try {
                return tracker.waitForService(timeout);
            } catch (InterruptedException e) {
                throw new OsgiServiceNotAvailableException(e);
            } finally {
                tracker.close();
            }
        }
    }

    @Override
    public <T> List<ServiceReference<T>> listServiceReferences(Class<T> clazz) {
        return listServiceReferences(clazz, null);
    }

    @Override
    public List<ServiceReference<?>> listServiceReferences(String filter) {
        ServiceReference<?>[] serviceReferences;
        try {
            serviceReferences = bundleContext.getServiceReferences((String) null, filter);
        } catch (InvalidSyntaxException e) {
            throw new IllegalArgumentException(e);
        }
        if (serviceReferences == null) {
            return Collections.emptyList();
        }
        return Arrays.asList(serviceReferences);
    }

    @Override
    public <T> List<ServiceReference<T>> listServiceReferences(Class<T> clazz, String filter) {
        Collection<ServiceReference<T>> serviceReferences;
        try {
            serviceReferences = bundleContext.getServiceReferences(clazz, filter);
        } catch (InvalidSyntaxException e) {
            throw new IllegalArgumentException(e);
        }
        return Lists.newArrayList(serviceReferences);
    }

    @Override
    public <T> List<T> listServices(Class<T> clazz) {
        ServiceTracker tracker = new ServiceTracker(bundleContext, clazz.getName(), null);
        return getListFromTracker(tracker);
    }

    private <T> List<T> getListFromTracker(ServiceTracker tracker) {
        tracker.open();
        Object[] services = tracker.getServices();
        List<T> result = new ArrayList<T>();
        if (services != null) {
            CollectionUtils.addAll(result, services);
        }
        tracker.close();
        return result;
    }

    @Override
    public <T> List<T> listServices(Class<T> clazz, String filterString) throws IllegalArgumentException {
        Filter filter = FilterUtils.makeFilter(clazz, filterString);
        ServiceTracker tracker = new ServiceTracker(bundleContext, filter, null);
        return getListFromTracker(tracker);
    }

    @Override
    public <T> Iterator<T> getServiceIterator(Iterable<ServiceReference<T>> references) {
        return Iterators.transform(references.iterator(), new Function<ServiceReference<T>, T>() {
            @Override
            public T apply(ServiceReference<T> input) {
                return bundleContext.getService(input);
            }
        });
    }

    @Override
    public <T> Iterator<T> getServiceIterator(Iterable<ServiceReference> references, Class<T> serviceType) {
        return Iterators.transform(references.iterator(), new Function<ServiceReference, T>() {
            @Override
            public T apply(ServiceReference input) {
                return (T) bundleContext.getService(input);
            }
        });
    }

    /**
     * Any bundle-context is fine here, since it does not matter from which bundlecontext services are retrieved.
     */
    public void setBundleContext(BundleContext bundleContext) {
        this.bundleContext = bundleContext;
    }
}