org.javabits.yar.guice.GuiceWatchableRegistrationContainer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of yar-guice Show documentation
Show all versions of yar-guice Show documentation
Yar Guice: provide a implementation / integration base on guice
/*
* Copyright 2013 Romain Gilles
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.javabits.yar.guice;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.javabits.yar.Id;
import org.javabits.yar.Registration;
import org.javabits.yar.RegistryHook;
import org.javabits.yar.TypeListener;
import javax.annotation.Nullable;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.javabits.yar.TypeEvent.newAddTypeEvent;
import static org.javabits.yar.TypeEvent.newRemoveTypeEvent;
import static org.javabits.yar.guice.AbstractExecutionStrategy.newExecutionStrategy;
import static org.javabits.yar.guice.CacheContainer.KeyConversionStrategies.TYPE_ERASURE;
import static org.javabits.yar.guice.ExecutionStrategy.Type.*;
import static org.javabits.yar.guice.Reflections.getRawType;
/**
* TODO comment
* Date: 2/20/13
* Time: 9:47 AM
*
* @author Romain Gilles
*/
public class GuiceWatchableRegistrationContainer implements WatchableRegistrationContainer {
private static final Logger LOG = Logger.getLogger(GuiceWatchableRegistrationContainer.class.getName());
private enum Action {
ADD() {
@Override
void execute(WatcherRegistration watcherRegistration, SupplierRegistration supplierRegistration) {
watcherRegistration.right().add(supplierRegistration.right());
}
}, REMOVE() {
@Override
void execute(WatcherRegistration watcherRegistration, SupplierRegistration supplierRegistration) {
watcherRegistration.right().remove(supplierRegistration.right());
}
};
abstract void execute(WatcherRegistration watcherRegistration, SupplierRegistration supplierRegistration);
}
private final Container> supplierRegistry;
private final Container> watcherRegistry;
private final ExecutionStrategy executor;
public GuiceWatchableRegistrationContainer() {
this(CacheContainer.>newConcurrentContainer(), CacheContainer.>newNonConcurrentContainer(TYPE_ERASURE), newExecutionStrategy(SERIALIZED));
}
public GuiceWatchableRegistrationContainer(Container> supplierRegistry
, Container> watcherRegistry, ExecutionStrategy executionStrategy) {
this.supplierRegistry = supplierRegistry;
this.watcherRegistry = watcherRegistry;
this.executor = executionStrategy;
}
@Override
public Set types() {
return supplierRegistry.asMap().keySet();
}
@Override
public List> getAll(Type type) {
return supplierRegistry.getAll(type);
}
@Nullable
@Override
public SupplierRegistration> getFirst(Type type) {
return supplierRegistry.getFirst(type);
}
@Override
public List> getAll(Id id) {
return getSupplierRegistrationsFor(id, supplierRegistry);
}
private List> getSupplierRegistrationsFor(Id id, Container> registry) {
List> pairs = registry.getAll(id.type());
ImmutableList.Builder> suppliersByKey = ImmutableList.builder();
for (SupplierRegistration> registryEntry : pairs) {
addSupplierIfKeyEquals(id, suppliersByKey, registryEntry);
}
return suppliersByKey.build();
}
@SuppressWarnings("unchecked")
private void addSupplierIfKeyEquals(Id id, ImmutableList.Builder> suppliersByKey, SupplierRegistration> registryEntry) {
if (isKeyCompatibleToThisRegistration(id, registryEntry))
suppliersByKey.add((SupplierRegistration) registryEntry);
}
private boolean isKeyCompatibleToThisRegistration(Id id, Registration> registryEntry) {
return id.annotationType() == null && id.type().equals(registryEntry.id().type())
|| id.equals(registryEntry.id());
}
@Nullable
@Override
@SuppressWarnings("unchecked")
public SupplierRegistration getFirst(Id id) {
List> all = supplierRegistry.getAll(id.type());
for (SupplierRegistration> pair : all) {
if (id.equals(pair.left())) {
return (SupplierRegistration) pair;
}
}
return null;
}
@Override
public boolean put(SupplierRegistration> registration, long timeout, TimeUnit unit) throws InterruptedException {
boolean added = putToRegistry(supplierRegistry, registration);
updateWatcher(registration, Action.ADD, timeout, unit);
return added;
}
private void updateWatcher(final SupplierRegistration supplierRegistration, final Action action, long timeout, TimeUnit unit) throws InterruptedException {
Id id = supplierRegistration.id();
final List> watcherRegistrations = getWatcherRegistrations(id);
LOG.log(Level.FINE, "Execute {0} on watchers: {1}, for given supplier {2}", new Object[]{ action, watcherRegistrations, supplierRegistration});
executor.execute(getUpdateActionsToExistingWatcherOnSupplierEvent(supplierRegistration, action, watcherRegistrations),timeout, unit);
}
private List> getUpdateActionsToExistingWatcherOnSupplierEvent(final SupplierRegistration supplierRegistration, final Action action, List> watcherRegistrations) {
return Lists.transform(watcherRegistrations, new Function, Callable>() {
@Nullable
@Override
public Callable apply(@Nullable WatcherRegistration watcherRegistration) {
return new UpdateWatcherOnSupplierEvent<>(watcherRegistration, supplierRegistration, action);
}
});
}
//returns all the watchers associated to the type of the given id.
@SuppressWarnings("unchecked")
private List> getWatcherRegistrations(Id id) {
return (List>)((Container)watcherRegistry).getAll(id.type());
}
private > boolean putToRegistry(Container container, T registration) {
return container.put(getRegistryKey(registration), registration);
}
@Override
public boolean remove(SupplierRegistration> registration, long timeout, TimeUnit unit) throws InterruptedException {
boolean removed = removeFromRegistry(supplierRegistry, registration);
updateWatcher(registration, Action.REMOVE, timeout, unit);
return removed;
}
private > boolean removeFromRegistry(Container container, T registration) {
return container.remove(getRegistryKey(registration), registration);
}
@Override
public boolean add(final WatcherRegistration watcherRegistration, long timeout, TimeUnit unit) throws InterruptedException {
executor.execute(getAddSupplierActionsToNewWatcher(watcherRegistration), timeout, unit);
return putToRegistry(watcherRegistry, watcherRegistration);
}
@SuppressWarnings("unchecked")
private List> getAddSupplierActionsToNewWatcher(final WatcherRegistration watcherRegistration) {
final Class> watcherRawType = getRawType(watcherRegistration.id().type());
Set watcherCompatiblesTypes = Sets.filter(types(), new Predicate() {
@Override
public boolean apply(Type type) {
return watcherRawType.equals(getRawType(type));
}
});
ImmutableList.Builder> resultBuilder = ImmutableList.builder();
for (Type watcherCompatiblesType : watcherCompatiblesTypes) {
resultBuilder.addAll((List)getAll(watcherCompatiblesType));
}
List < SupplierRegistration < T >> supplierRegistrations = resultBuilder.build();
return Lists.transform(supplierRegistrations, new Function, Callable>() {
@Nullable
@Override
public Callable apply(@Nullable SupplierRegistration supplierRegistration) {
return new AddToNewWatcher<>(watcherRegistration, supplierRegistration);
}
});
}
@Override
public void addTypeListener(TypeListener typeListener) {
supplierRegistry.addKeyListener(adapt(typeListener));
}
private static KeyListener adapt(final TypeListener typeListener) {
return new KeyListener() {
@Override
public void keyAdded(KeyEvent event) {
typeListener.typeChanged(newAddTypeEvent(event.key()));
}
@Override
public void keyRemoved(KeyEvent event) {
typeListener.typeChanged(newRemoveTypeEvent(event.key()));
}
};
}
@Override
public void removeTypeListener(TypeListener typeListener) {
supplierRegistry.removeKeyListener(adapt(typeListener));
}
@Override
public boolean hasPendingListenerUpdateTasks() {
return executor.hasPendingTasks();
}
@Override
public void addEndOfListenerUpdateTasksListener(RegistryHook.EndOfListenerUpdateTasksListener listener) {
executor.addEndOfListenerUpdateTasksListener(listener);
}
static class ActionAdapter implements Callable {
private final WatcherRegistration watcherRegistration;
private final SupplierRegistration supplierRegistration;
private final Action action;
ActionAdapter(WatcherRegistration watcherRegistration, SupplierRegistration supplierRegistration, Action action) {
this.watcherRegistration = watcherRegistration;
this.supplierRegistration = supplierRegistration;
this.action = action;
}
@Override
public Void call() throws Exception {
fireAddToWatcherIfMatches(watcherRegistration, supplierRegistration, action);
return null;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{" +
"action=" + action +
", watcherRegistration=" + watcherRegistration +
", supplierRegistration=" + supplierRegistration +
'}';
}
}
static class AddToNewWatcher extends ActionAdapter {
AddToNewWatcher(WatcherRegistration watcherRegistration, SupplierRegistration supplierRegistration) {
super(watcherRegistration, supplierRegistration, Action.ADD);
}
}
static class UpdateWatcherOnSupplierEvent extends ActionAdapter {
UpdateWatcherOnSupplierEvent(WatcherRegistration watcherRegistration, SupplierRegistration supplierRegistration, Action action) {
super(watcherRegistration, supplierRegistration, action);
}
}
static private void fireAddToWatcherIfMatches(WatcherRegistration watcherRegistration, SupplierRegistration supplierRegistration, Action action) {
if (watcherRegistration.left().matches(supplierRegistration.id())) {
action.execute(watcherRegistration, supplierRegistration);
}
}
@Override
public boolean remove(WatcherRegistration> watcherRegistration) {
return watcherRegistry.remove(getRegistryKey(watcherRegistration), watcherRegistration);
}
@Override
public void removeAll(Type type, long timeout, TimeUnit unit) throws InterruptedException {
List> all = getAll(type);
for (SupplierRegistration> supplierRegistration: all) {
remove(supplierRegistration,timeout, unit);
}
watcherRegistry.invalidate(type);
supplierRegistry.invalidate(type);
}
private Type getRegistryKey(Registration> watcherRegistration) {
return watcherRegistration.id().type();
}
static GuiceWatchableRegistrationContainer newMultimapGuiceWatchableRegistrationContainer() {
return new GuiceWatchableRegistrationContainer(ListMultimapContainer.>newSynchronizedContainer(), ListMultimapContainer.>newLockFreeContainer(), newExecutionStrategy(SERIALIZED));
}
static GuiceWatchableRegistrationContainer newLoadingCacheGuiceWatchableRegistrationContainer() {
return newLoadingCacheGuiceWatchableRegistrationContainer(newExecutionStrategy(SERIALIZED));
}
static GuiceWatchableRegistrationContainer newLoadingCacheGuiceWatchableRegistrationContainer(ExecutionStrategy executionStrategy) {
return new GuiceWatchableRegistrationContainer(CacheContainer.>newConcurrentContainer(), CacheContainer.>newNonConcurrentContainer(TYPE_ERASURE), executionStrategy);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy