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

org.javabits.yar.guice.GuiceWatchableRegistrationContainer Maven / Gradle / Ivy

There is a newer version: 3.0.1.RELEASE
Show newest version
/*
 * 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