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

com.liferay.registry.collections.internal.ServiceTrackerCollectionImpl Maven / Gradle / Ivy

There is a newer version: 5.0.1
Show newest version
/**
 * 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.internal;

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 com.liferay.registry.collections.ServiceRegistrationMap;
import com.liferay.registry.collections.ServiceRegistrationMapImpl;
import com.liferay.registry.collections.ServiceTrackerList;

import java.lang.reflect.Array;

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

/**
 * @author Raymond Augé
 */
public class ServiceTrackerCollectionImpl implements ServiceTrackerList {

	public 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));
		}
	}

	@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()) {
			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 void open() {
		_serviceTracker.open();
	}

	@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 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 {

		public DefaultServiceTrackerCustomizer(
			ServiceTrackerCustomizer serviceTrackerCustomizer) {

			_serviceTrackerCustomizer = 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 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 {

		public EntryWrapper(ServiceReference serviceReference, S service) {
			_serviceReference = serviceReference;
			_service = service;
		}

		@Override
		public int compareTo(EntryWrapper entryWrapper) {

			// The order is deliberately reversed

			return entryWrapper._serviceReference.compareTo(_serviceReference);
		}

		private final S _service;
		private final ServiceReference _serviceReference;

	}

	private class ServiceTrackerIterator implements ListIterator {

		public ServiceTrackerIterator(ListIterator listIterator) {
			_listIterator = 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 final ListIterator _listIterator;

	}

}