/******************************************************************************* * 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.cache; import java.util.Map; import org.eclipse.sisu.peaberry.AttributeFilter; 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; /** * Pre-filtered {@link ServiceWatcher} that handles mutable services. * * @author mcculls@gmail.com (Stuart McCulloch) */ public final class FilteredServiceWatcher<S> implements ServiceWatcher<S> { final AttributeFilter filter; final ServiceWatcher<S> watcher; public FilteredServiceWatcher(final AttributeFilter filter, final ServiceWatcher<S> watcher) { this.filter = filter; this.watcher = watcher; } public <T extends S> Export<T> add(final Import<T> service) { // service metadata can change, so must be able to re-check return new FilteredExport<T>(service); } private final class FilteredExport<T extends S> extends SimpleExport<T> { private Export<T> realExport; FilteredExport(final Import<T> service) { super(service); checkMatchingService(); } private void checkMatchingService() { if (filter.matches(super.attributes())) { if (null == realExport) { // service metadata now matches realExport = watcher.add(this); } } else if (null != realExport) { // metadata doesn't match anymore! final Export<T> temp = realExport; realExport = null; temp.unput(); } } // Export aspect is only active when service matches filter @Override public synchronized void put(final T newInstance) { super.put(newInstance); if (null != realExport) { realExport.put(newInstance); } } @Override public synchronized void attributes(final Map<String, ?> newAttributes) { super.attributes(newAttributes); if (null != realExport) { realExport.attributes(newAttributes); } checkMatchingService(); // re-check filter against latest attributes } } @Override public boolean equals(final Object rhs) { if (rhs instanceof FilteredServiceWatcher<?>) { final FilteredServiceWatcher<?> filteredWatcher = (FilteredServiceWatcher<?>) rhs; return filter.equals(filteredWatcher.filter) && watcher.equals(filteredWatcher.watcher); } return false; } @Override public int hashCode() { return filter.hashCode() ^ watcher.hashCode(); } }