Package com.cognifide.slice.core.internal.injector

Source Code of com.cognifide.slice.core.internal.injector.InjectorHierarchy

/*-
* #%L
* Slice - Core API
* $Id:$
* $HeadURL:$
* %%
* Copyright (C) 2012 Cognifide Limited
* %%
* 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.
* #L%
*/
package com.cognifide.slice.core.internal.injector;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cognifide.slice.api.injector.InjectorConfig;
import com.google.inject.CreationException;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;

/**
* This class stores injector configuration tree and creates injectors associated with these configurations.
*
* @author Tomasz Rekawek
*
*/
public class InjectorHierarchy {

  private static final Logger LOG = LoggerFactory.getLogger(InjectorHierarchy.class);

  private Map<String, Injector> injectorByName = new HashMap<String, Injector>();

  private Map<String, InjectorConfig> configByName = new HashMap<String, InjectorConfig>();

  private volatile Map<Injector, String> nameLookupMap = new HashMap<Injector, String>();

  /**
   * Register new injector configuration. If all ancestors of the new config are already registered, method
   * will create new injector. If this config is a missing ancestor of some other config, the child injector
   * (or injectors) will be created as well.
   *
   * @param config Injector configuration
   */
  public synchronized void registerInjector(InjectorConfig config) {
    configByName.put(config.getName(), config);

    List<InjectorConfig> injectorsToRefresh = getSubtree(config);
    refreshInjectors(injectorsToRefresh);
    refreshNameLookupMap();
  }

  /**
   * Unregister given injector config, destroy associated injector and all its children.
   *
   * @param config
   */
  public synchronized void unregisterInjector(InjectorConfig config) {
    List<InjectorConfig> injectorsToRemove = getSubtree(config);
    for (InjectorConfig c : injectorsToRemove) {
      injectorByName.remove(c.getName());
    }
    configByName.remove(config.getName());
    refreshNameLookupMap();
  }

  /**
   * Return injector with given name
   *
   * @param injectorName Injector name
   * @return Injector or null if there is no such injector
   */
  public synchronized Injector getInjectorByName(String injectorName) {
    return injectorByName.get(injectorName);
  }

  /**
   * Return name of the given injector
   *
   * @param injector Injector object
   * @return Injector name or null if there is no such injector
   */
  public String getRegisteredName(Injector injector) {
    return nameLookupMap.get(injector);
  }

  /**
   * Return names of all created injectors
   *
   * @return Collection with names of all successfully created injectors.
   */
  public Collection<String> getInjectorNames() {
    return nameLookupMap.values();
  }

  private List<InjectorConfig> getSubtree(InjectorConfig root) {
    List<InjectorConfig> flatSubtree = new ArrayList<InjectorConfig>();
    Deque<InjectorConfig> queue = new ArrayDeque<InjectorConfig>();
    queue.add(root);

    while (!queue.isEmpty()) {
      InjectorConfig node = queue.poll();
      if (!flatSubtree.add(node)) {
        throw new IllegalStateException("There is a cycle in the injectors graph: "
            + flatSubtree.toString());
      }
      queue.addAll(getChildren(node));
    }
    return flatSubtree;
  }

  private void refreshInjectors(List<InjectorConfig> injectors) {
    for (InjectorConfig config : injectors) {
      Injector injector = createInjector(config);
      if (injector != null) {
        injectorByName.put(config.getName(), injector);
      }
    }
  }

  private Injector createInjector(InjectorConfig config) {
    List<Module> modules = new ArrayList<Module>();
    InjectorConfig current = config;
    do {
      modules.addAll(current.getModules());
      InjectorConfig parent = null;
      if (current.hasParent()) {
        String parentName = current.getParentName();
        parent = configByName.get(parentName);
        if (parent == null) {
          LOG.info("Can't create {} as its ancestor {} can't be found",
              new Object[] { config.getName(), parentName });
          return null;
        }
      }
      current = parent;
    } while (current != null);
    try {
      return Guice.createInjector(modules);
    } catch (CreationException e) {
      LOG.error("Can't create injector " + config.getName(), e);
      return null;
    }
  }

  private Collection<InjectorConfig> getChildren(InjectorConfig parent) {
    List<InjectorConfig> children = new ArrayList<InjectorConfig>();
    String parentName = parent.getName();
    for (InjectorConfig child : configByName.values()) {
      if (parentName.equals(child.getParentName())) {
        children.add(child);
      }
    }
    return children;
  }

  private void refreshNameLookupMap() {
    Map<Injector, String> map = new HashMap<Injector, String>();
    for (Entry<String, Injector> entry : injectorByName.entrySet()) {
      map.put(entry.getValue(), entry.getKey());
    }
    nameLookupMap = map;
  }
}
TOP

Related Classes of com.cognifide.slice.core.internal.injector.InjectorHierarchy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.