All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.liferay.registry.collections.ServiceTrackerCollections Maven / Gradle / Ivy

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.registry.collections;

import com.liferay.registry.Filter;
import com.liferay.registry.Registry;
import com.liferay.registry.RegistryUtil;
import com.liferay.registry.ServiceReference;
import com.liferay.registry.ServiceRegistration;
import com.liferay.registry.ServiceTracker;
import com.liferay.registry.ServiceTrackerCustomizer;

import java.lang.reflect.Array;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author Raymond Augé
 */
public class ServiceTrackerCollections {

	public static  ServiceTrackerList openList(Class clazz) {
		return new ServiceTrackerCollectionImpl<>(
			clazz, null, null, Collections.emptyMap());
	}

	public static  ServiceTrackerList openList(
		Class clazz, Filter filter) {

		return new ServiceTrackerCollectionImpl<>(
			clazz, filter, null, Collections.emptyMap());
	}

	public static  ServiceTrackerList openList(
		Class clazz, Filter filter, Map properties) {

		return new ServiceTrackerCollectionImpl<>(
			clazz, filter, null, properties);
	}

	public static  ServiceTrackerList openList(
		Class clazz, Filter filter,
		ServiceTrackerCustomizer serviceTrackerCustomizer) {

		return new ServiceTrackerCollectionImpl<>(
			clazz, filter, serviceTrackerCustomizer,
			Collections.emptyMap());
	}

	public static  ServiceTrackerList openList(
		Class clazz, Filter filter,
		ServiceTrackerCustomizer serviceTrackerCustomizer,
		Map properties) {

		return new ServiceTrackerCollectionImpl<>(
			clazz, filter, serviceTrackerCustomizer, properties);
	}

	public static  ServiceTrackerList openList(
		Class clazz, Map properties) {

		return new ServiceTrackerCollectionImpl<>(
			clazz, null, null, properties);
	}

	public static  ServiceTrackerList openList(
		Class clazz,
		ServiceTrackerCustomizer serviceTrackerCustomizer) {

		return new ServiceTrackerCollectionImpl<>(
			clazz, null, serviceTrackerCustomizer,
			Collections.emptyMap());
	}

	public static  ServiceTrackerList openList(
		Class clazz, ServiceTrackerCustomizer serviceTrackerCustomizer,
		Map properties) {

		return new ServiceTrackerCollectionImpl<>(
			clazz, null, serviceTrackerCustomizer, properties);
	}

	public static  ServiceTrackerList openList(
		Class clazz, String filterString) {

		return new ServiceTrackerCollectionImpl<>(
			clazz, _getFilter(filterString), null,
			Collections.emptyMap());
	}

	public static  ServiceTrackerList openList(
		Class clazz, String filterString, Map properties) {

		return new ServiceTrackerCollectionImpl<>(
			clazz, _getFilter(filterString), null, properties);
	}

	public static  ServiceTrackerList openList(
		Class clazz, String filterString,
		ServiceTrackerCustomizer serviceTrackerCustomizer) {

		return new ServiceTrackerCollectionImpl<>(
			clazz, _getFilter(filterString), serviceTrackerCustomizer,
			Collections.emptyMap());
	}

	public static  ServiceTrackerList openList(
		Class clazz, String filterString,
		ServiceTrackerCustomizer serviceTrackerCustomizer,
		Map properties) {

		return new ServiceTrackerCollectionImpl<>(
			clazz, _getFilter(filterString), serviceTrackerCustomizer,
			properties);
	}

	public static  ServiceTrackerMap> openMultiValueMap(
		Class clazz, String propertyKey) {

		ServiceTrackerMapFactory serviceTrackerMapFactory =
			ServiceTrackerMapFactoryUtil.getServiceTrackerMapFactory();

		return serviceTrackerMapFactory.openMultiValueMap(clazz, propertyKey);
	}

	public static  ServiceTrackerMap> openMultiValueMap(
		Class clazz, String filterString,
		ServiceReferenceMapper serviceReferenceMapper) {

		ServiceTrackerMapFactory serviceTrackerMapFactory =
			ServiceTrackerMapFactoryUtil.getServiceTrackerMapFactory();

		return serviceTrackerMapFactory.openMultiValueMap(
			clazz, filterString, serviceReferenceMapper);
	}

	public static  ServiceTrackerMap> openMultiValueMap(
		Class clazz, String filterString,
		ServiceReferenceMapper serviceReferenceMapper,
		Comparator> comparator) {

		ServiceTrackerMapFactory serviceTrackerMapFactory =
			ServiceTrackerMapFactoryUtil.getServiceTrackerMapFactory();

		return serviceTrackerMapFactory.openMultiValueMap(
			clazz, filterString, serviceReferenceMapper, comparator);
	}

	public static  ServiceTrackerMap> openMultiValueMap(
		Class clazz, String filterString,
		ServiceReferenceMapper serviceReferenceMapper,
		ServiceTrackerMapListener>
			serviceTrackerMapListener) {

		ServiceTrackerMapFactory serviceTrackerMapFactory =
			ServiceTrackerMapFactoryUtil.getServiceTrackerMapFactory();

		return serviceTrackerMapFactory.openMultiValueMap(
			clazz, filterString, serviceReferenceMapper,
			serviceTrackerMapListener);
	}

	public static  ServiceTrackerMap> openMultiValueMap(
		Class clazz, String filterString,
		ServiceReferenceMapper serviceReferenceMapper,
		ServiceTrackerCustomizer serviceTrackerCustomizer) {

		ServiceTrackerMapFactory serviceTrackerMapFactory =
			ServiceTrackerMapFactoryUtil.getServiceTrackerMapFactory();

		return serviceTrackerMapFactory.openMultiValueMap(
			clazz, filterString, serviceReferenceMapper,
			serviceTrackerCustomizer);
	}

	public static  ServiceTrackerMap> openMultiValueMap(
		Class clazz, String filterString,
		ServiceReferenceMapper serviceReferenceMapper,
		ServiceTrackerCustomizer serviceTrackerCustomizer,
		Comparator> comparator) {

		ServiceTrackerMapFactory serviceTrackerMapFactory =
			ServiceTrackerMapFactoryUtil.getServiceTrackerMapFactory();

		return serviceTrackerMapFactory.openMultiValueMap(
			clazz, filterString, serviceReferenceMapper,
			serviceTrackerCustomizer, comparator);
	}

	public static  ServiceTrackerMap> openMultiValueMap(
		Class clazz, String propertyKey,
		ServiceTrackerCustomizer serviceTrackerCustomizer) {

		ServiceTrackerMapFactory serviceTrackerMapFactory =
			ServiceTrackerMapFactoryUtil.getServiceTrackerMapFactory();

		return serviceTrackerMapFactory.openMultiValueMap(
			clazz, propertyKey, serviceTrackerCustomizer);
	}

	public static  ServiceTrackerMap openSingleValueMap(
		Class clazz, String propertyKey) {

		ServiceTrackerMapFactory serviceTrackerMapFactory =
			ServiceTrackerMapFactoryUtil.getServiceTrackerMapFactory();

		return serviceTrackerMapFactory.openSingleValueMap(clazz, propertyKey);
	}

	public static  ServiceTrackerMap openSingleValueMap(
		Class clazz, String filterString,
		ServiceReferenceMapper serviceReferenceMapper) {

		ServiceTrackerMapFactory serviceTrackerMapFactory =
			ServiceTrackerMapFactoryUtil.getServiceTrackerMapFactory();

		return serviceTrackerMapFactory.openSingleValueMap(
			clazz, filterString, serviceReferenceMapper);
	}

	public static  ServiceTrackerMap openSingleValueMap(
		Class clazz, String filterString,
		ServiceReferenceMapper serviceReferenceMapper,
		Comparator> comparator) {

		ServiceTrackerMapFactory serviceTrackerMapFactory =
			ServiceTrackerMapFactoryUtil.getServiceTrackerMapFactory();

		return serviceTrackerMapFactory.openSingleValueMap(
			clazz, filterString, serviceReferenceMapper, comparator);
	}

	public static  ServiceTrackerMap openSingleValueMap(
		Class clazz, String filterString,
		ServiceReferenceMapper serviceReferenceMapper,
		ServiceTrackerCustomizer serviceTrackerCustomizer) {

		ServiceTrackerMapFactory serviceTrackerMapFactory =
			ServiceTrackerMapFactoryUtil.getServiceTrackerMapFactory();

		return serviceTrackerMapFactory.openSingleValueMap(
			clazz, filterString, serviceReferenceMapper,
			serviceTrackerCustomizer);
	}

	public static  ServiceTrackerMap openSingleValueMap(
		Class clazz, String filterString,
		ServiceReferenceMapper serviceReferenceMapper,
		ServiceTrackerCustomizer serviceTrackerCustomizer,
		Comparator> comparator) {

		ServiceTrackerMapFactory serviceTrackerMapFactory =
			ServiceTrackerMapFactoryUtil.getServiceTrackerMapFactory();

		return serviceTrackerMapFactory.openSingleValueMap(
			clazz, filterString, serviceReferenceMapper,
			serviceTrackerCustomizer, comparator);
	}

	public static  ServiceTrackerMap openSingleValueMap(
		Class clazz, String propertyKey,
		ServiceTrackerCustomizer serviceTrackerCustomizer) {

		ServiceTrackerMapFactory serviceTrackerMapFactory =
			ServiceTrackerMapFactoryUtil.getServiceTrackerMapFactory();

		return serviceTrackerMapFactory.openSingleValueMap(
			clazz, propertyKey, serviceTrackerCustomizer);
	}

	private static Filter _getFilter(String filterString) {
		Registry registry = RegistryUtil.getRegistry();

		return registry.getFilter(filterString);
	}

	private ServiceTrackerCollections() {
	}

	private static class ServiceTrackerCollectionImpl
		implements ServiceTrackerList {

		@Override
		public void add(int index, S service) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean add(S service) {
			if (service == null) {
				throw new IllegalArgumentException("Service is null");
			}

			if ((_filter != null) && !_filter.matches(_properties)) {
				throw new IllegalStateException();
			}

			Map properties = new HashMap<>(_properties);

			Registry registry = RegistryUtil.getRegistry();

			ServiceRegistration serviceRegistration =
				registry.registerService(_clazz, service, properties);

			_serviceRegistrations.put(service, serviceRegistration);

			return true;
		}

		@Override
		public boolean add(S service, Map properties) {
			if (service == null) {
				throw new IllegalArgumentException("Service is null");
			}

			properties = new HashMap<>(properties);

			properties.putAll(_properties);

			if ((_filter != null) && !_filter.matches(properties)) {
				throw new IllegalArgumentException(
					"Filter does not match properties " + properties);
			}

			Registry registry = RegistryUtil.getRegistry();

			ServiceRegistration serviceRegistration =
				registry.registerService(_clazz, service, properties);

			_serviceRegistrations.put(service, serviceRegistration);

			return true;
		}

		@Override
		public boolean addAll(Collection services) {
			boolean modified = false;

			for (S service : services) {
				if (add(service)) {
					modified = true;
				}
			}

			return modified;
		}

		@Override
		public boolean addAll(int index, Collection services) {
			throw new UnsupportedOperationException();
		}

		@Override
		public void clear() {
			Set>> set =
				_serviceRegistrations.entrySet();

			Iterator>> iterator =
				set.iterator();

			while (iterator.hasNext()) {
				Map.Entry> entry = iterator.next();

				ServiceRegistration serviceRegistration = entry.getValue();

				serviceRegistration.unregister();

				iterator.remove();
			}
		}

		@Override
		public void close() {
			clear();

			_serviceTracker.close();
		}

		@Override
		public boolean contains(Object service) {
			return _services.contains(service);
		}

		@Override
		public boolean containsAll(Collection services) {
			throw new UnsupportedOperationException();
		}

		@Override
		public S get(int index) {
			EntryWrapper entryWrapper = _services.get(index);

			return entryWrapper._service;
		}

		@Override
		public int indexOf(Object service) {
			return _services.indexOf(service);
		}

		@Override
		public boolean isEmpty() {
			return _services.isEmpty();
		}

		@Override
		public Iterator iterator() {
			return new ServiceTrackerIterator(_services.listIterator());
		}

		@Override
		public int lastIndexOf(Object service) {
			return _services.lastIndexOf(service);
		}

		@Override
		public ListIterator listIterator() {
			return new ServiceTrackerIterator(_services.listIterator());
		}

		@Override
		public ListIterator listIterator(int index) {
			return new ServiceTrackerIterator(_services.listIterator(index));
		}

		@Override
		public S remove(int index) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean remove(Object service) {
			ServiceRegistration serviceRegistration =
				_serviceRegistrations.remove(service);

			if (serviceRegistration == null) {
				return false;
			}

			serviceRegistration.unregister();

			return true;
		}

		@Override
		public boolean removeAll(Collection services) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean retainAll(Collection services) {
			throw new UnsupportedOperationException();
		}

		@Override
		public S set(int index, S service) {
			throw new UnsupportedOperationException();
		}

		@Override
		public int size() {
			return _services.size();
		}

		@Override
		public List subList(int fromIndex, int toIndex) {
			List list = new ArrayList<>();

			List sublist = _services.subList(fromIndex, toIndex);

			for (EntryWrapper entryWrapper : sublist) {
				list.add(entryWrapper._service);
			}

			return list;
		}

		@Override
		public Object[] toArray() {
			return toArray(new Object[0]);
		}

		@Override
		public  T[] toArray(T[] services) {
			if (services.length < _services.size()) {
				Class clazz = services.getClass();

				services = (T[])Array.newInstance(
					clazz.getComponentType(), _services.size());
			}

			for (int i = 0; i < _services.size(); i++) {
				EntryWrapper entryWrapper = _services.get(i);

				services[i] = (T)entryWrapper._service;
			}

			if (services.length > _services.size()) {
				services[_services.size()] = null;
			}

			return services;
		}

		private ServiceTrackerCollectionImpl(
			Class clazz, Filter filter,
			ServiceTrackerCustomizer serviceTrackerCustomizer,
			Map properties) {

			_clazz = clazz;
			_filter = filter;

			_properties = Collections.unmodifiableMap(properties);

			Registry registry = RegistryUtil.getRegistry();

			if (filter != null) {
				filter = _getFilter(filter, _clazz);

				_serviceTracker = registry.trackServices(
					filter,
					new DefaultServiceTrackerCustomizer(
						serviceTrackerCustomizer));
			}
			else {
				_serviceTracker = registry.trackServices(
					clazz,
					new DefaultServiceTrackerCustomizer(
						serviceTrackerCustomizer));
			}

			_serviceTracker.open();
		}

		private Filter _getFilter(Filter filter, Class clazz) {
			Map properties =
				Collections.singletonMap(
					"objectClass", clazz.getName());

			if (filter.matches(properties)) {
				return filter;
			}

			Registry registry = RegistryUtil.getRegistry();

			StringBuilder sb = new StringBuilder(5);

			sb.append("(&(objectClass=");
			sb.append(clazz.getName());
			sb.append(")");
			sb.append(filter.toString());
			sb.append(")");

			return registry.getFilter(sb.toString());
		}

		private final Class _clazz;
		private final Filter _filter;
		private final Map _properties;
		private final ServiceRegistrationMap _serviceRegistrations =
			new ServiceRegistrationMapImpl<>();
		private final List _services =
			new CopyOnWriteArrayList<>();
		private final ServiceTracker _serviceTracker;

		private class DefaultServiceTrackerCustomizer
			implements ServiceTrackerCustomizer {

			@Override
			public S addingService(ServiceReference serviceReference) {
				S service = null;

				if (_serviceTrackerCustomizer != null) {
					service = _serviceTrackerCustomizer.addingService(
						serviceReference);
				}
				else {
					Registry registry = RegistryUtil.getRegistry();

					service = registry.getService(serviceReference);
				}

				_update(serviceReference, service, false);

				return service;
			}

			@Override
			public void modifiedService(
				ServiceReference serviceReference, S service) {

				if (_serviceTrackerCustomizer != null) {
					_serviceTrackerCustomizer.modifiedService(
						serviceReference, service);
				}

				_update(serviceReference, service, false);
			}

			@Override
			public void removedService(
				ServiceReference serviceReference, S service) {

				if (_serviceTrackerCustomizer != null) {
					_serviceTrackerCustomizer.removedService(
						serviceReference, service);
				}

				_update(serviceReference, service, true);

				Registry registry = RegistryUtil.getRegistry();

				registry.ungetService(serviceReference);
			}

			private DefaultServiceTrackerCustomizer(
				ServiceTrackerCustomizer serviceTrackerCustomizer) {

				_serviceTrackerCustomizer = serviceTrackerCustomizer;
			}

			private void _update(
				ServiceReference serviceReference, S service,
				boolean remove) {

				if (service == null) {
					return;
				}

				EntryWrapper entryWrapper = new EntryWrapper(
					serviceReference, service);

				synchronized (_services) {
					int index = Collections.binarySearch(
						_services, entryWrapper);

					if (remove) {
						if (index >= 0) {
							_services.remove(index);
						}
					}
					else if (index < 0) {
						_services.add(-index - 1, entryWrapper);
					}
				}
			}

			private final ServiceTrackerCustomizer
				_serviceTrackerCustomizer;

		}

		private class EntryWrapper implements Comparable {

			@Override
			public int compareTo(EntryWrapper entryWrapper) {

				// The order is deliberately reversed

				return entryWrapper._serviceReference.compareTo(
					_serviceReference);
			}

			private EntryWrapper(
				ServiceReference serviceReference, S service) {

				_serviceReference = serviceReference;
				_service = service;
			}

			private final S _service;
			private final ServiceReference _serviceReference;

		}

		private class ServiceTrackerIterator implements ListIterator {

			@Override
			public void add(S service) {
				throw new UnsupportedOperationException();
			}

			@Override
			public boolean hasNext() {
				return _listIterator.hasNext();
			}

			@Override
			public boolean hasPrevious() {
				return _listIterator.hasPrevious();
			}

			@Override
			public S next() {
				EntryWrapper entryWrapper = _listIterator.next();

				return entryWrapper._service;
			}

			@Override
			public int nextIndex() {
				return _listIterator.nextIndex();
			}

			@Override
			public S previous() {
				EntryWrapper entryWrapper = _listIterator.previous();

				return entryWrapper._service;
			}

			@Override
			public int previousIndex() {
				return _listIterator.previousIndex();
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}

			@Override
			public void set(S service) {
				throw new UnsupportedOperationException();
			}

			private ServiceTrackerIterator(
				ListIterator listIterator) {

				_listIterator = listIterator;
			}

			private final ListIterator _listIterator;

		}

	}

}