/*******************************************************************************
* Copyright (c) 2008, 2014 Stuart McCulloch
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Stuart McCulloch - initial API and implementation
*******************************************************************************/
package org.eclipse.sisu.peaberry.internal;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.sisu.peaberry.Export;
import org.eclipse.sisu.peaberry.Import;
import org.eclipse.sisu.peaberry.ServiceWatcher;
import org.eclipse.sisu.peaberry.util.SimpleExport;
/**
* A {@link ServiceWatcher} with similar behaviour to {@link ConcurrentImport}.
*
* @author mcculls@gmail.com (Stuart McCulloch)
*/
final class ConcurrentServiceWatcher<S>
implements ServiceWatcher<S> {
final Iterable<Import<S>> services;
final ServiceWatcher<? super S> watcher;
// the "best" service
Import<S> currentImport;
Export<S> currentExport;
ConcurrentServiceWatcher(final Iterable<Import<S>> services,
final ServiceWatcher<? super S> watcher) {
this.services = services;
this.watcher = watcher;
}
private final class TrackingExport<T>
extends SimpleExport<T> {
private final Import<T> thisImport;
TrackingExport(final Import<T> thisImport) {
super(thisImport);
this.thisImport = thisImport;
}
// Export aspect is only active when our service is "best"
@Override
@SuppressWarnings("unchecked")
public void put(final T newInstance) {
super.put(newInstance);
synchronized (ConcurrentServiceWatcher.this) {
if (null != currentExport && thisImport.equals(currentImport)) {
currentExport.put((S) newInstance);
// is this being removed?
if (null == newInstance) {
updateBestService();
}
}
}
}
@Override
public void attributes(final Map<String, ?> newAttributes) {
super.attributes(newAttributes);
synchronized (ConcurrentServiceWatcher.this) {
if (null != currentExport && thisImport.equals(currentImport)) {
currentExport.attributes(newAttributes);
}
// has ranking changed?
updateBestService();
}
}
}
public synchronized <T extends S> Export<T> add(final Import<T> service) {
updateBestService();
// every new service has a tracker
return new TrackingExport<T>(service);
}
void updateBestService() {
// check the last-known best service is still the best
final Iterator<Import<S>> i = services.iterator();
final Import<S> bestImport = i.hasNext() ? i.next() : null;
if (null != currentImport && currentImport.equals(bestImport)) {
return; // still the same...
}
// best service has changed
if (null != currentExport) {
currentExport.unput();
}
// report service (if any)
currentImport = bestImport;
currentExport = null == bestImport ? null : watcher.add(bestImport);
}
@Override
public boolean equals(final Object rhs) {
if (rhs instanceof ConcurrentServiceWatcher<?>) {
final ConcurrentServiceWatcher<?> concurrentWatcher = (ConcurrentServiceWatcher<?>) rhs;
return services.equals(concurrentWatcher.services)
&& watcher.equals(concurrentWatcher.watcher);
}
return false;
}
@Override
public int hashCode() {
return services.hashCode() ^ watcher.hashCode();
}
}