/**
* 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;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Shuyang Zhou
*/
public class ServiceTrackerFieldUpdaterCustomizer<S, T>
implements ServiceTrackerCustomizer<S, T> {
public ServiceTrackerFieldUpdaterCustomizer(
Field serviceField, Object serviceHolder, T dummyTrackedService) {
if (!Modifier.isVolatile(serviceField.getModifiers())) {
throw new IllegalArgumentException(
serviceField + " is not volatile");
}
_serviceField = serviceField;
if (serviceHolder == null) {
_serviceHolderReference = null;
}
else {
_serviceHolderReference = new WeakReference<>(serviceHolder);
}
_dummyTrackedService = dummyTrackedService;
}
@Override
public final T addingService(ServiceReference<S> serviceReference) {
T trackedService = doAddingService(serviceReference);
if (trackedService != null) {
_trackedServices.put(serviceReference, trackedService);
_updateService();
}
return trackedService;
}
@Override
public final void modifiedService(
ServiceReference<S> serviceReference, T service) {
doModifiedService(serviceReference, service);
_updateService();
}
@Override
public final void removedService(
ServiceReference<S> serviceReference, T service) {
if (_trackedServices.remove(serviceReference, service)) {
_updateService();
}
doRemovedService(serviceReference, service);
}
protected void afterServiceUpdate(T oldService, T newService) {
}
protected void beforeServiceUpdate(T oldService, T newService) {
}
protected T doAddingService(ServiceReference<S> serviceReference) {
Registry registry = RegistryUtil.getRegistry();
return (T)registry.getService(serviceReference);
}
protected void doModifiedService(
ServiceReference<S> serviceReference, T service) {
}
protected void doRemovedService(
ServiceReference<S> serviceReference, T service) {
Registry registry = RegistryUtil.getRegistry();
registry.ungetService(serviceReference);
}
protected void doServiceUpdate(T newService) {
Object serviceHolder = null;
if (_serviceHolderReference != null) {
serviceHolder = _serviceHolderReference.get();
if (serviceHolder == null) {
return;
}
}
try {
T oldService = (T)_serviceField.get(serviceHolder);
if (newService != oldService) {
beforeServiceUpdate(oldService, newService);
_serviceField.set(serviceHolder, newService);
afterServiceUpdate(oldService, newService);
}
}
catch (IllegalAccessException iae) {
throw new RuntimeException(iae);
}
}
private void _updateService() {
Optional<Entry<ServiceReference<S>, T>> optionalEntry =
ServiceRankingUtil.getHighestRankingEntry(_trackedServices);
Optional<T> optionalService = optionalEntry.map(Entry::getValue);
doServiceUpdate(optionalService.orElse(_dummyTrackedService));
}
private final T _dummyTrackedService;
private final Field _serviceField;
private final Reference<?> _serviceHolderReference;
private final Map<ServiceReference<S>, T> _trackedServices =
new ConcurrentHashMap<>();
}