Package se.jbee.inject

Source Code of se.jbee.inject.Dependency

/*
*  Copyright (c) 2012-2013, Jan Bernitt
*     
*  Licensed under the Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
*/
package se.jbee.inject;

import static se.jbee.inject.Emergence.emergence;
import static se.jbee.inject.Instance.defaultInstanceOf;
import static se.jbee.inject.Instance.instance;
import static se.jbee.inject.Type.raw;

import java.util.Arrays;
import java.util.Iterator;

import se.jbee.inject.DIRuntimeException.DependencyCycleException;
import se.jbee.inject.DIRuntimeException.MoreFrequentExpiryException;

/**
* Describes what is wanted/needed as parameter to construct a instance of T.
*
* @author Jan Bernitt (jan@jbee.se)
*/
public final class Dependency<T>
    implements Named, Parameter<T>, Iterable<Injection> {

  /**
   * A empty {@link Injection} hierarchy. It is used whenever the {@link Dependency} does not
   * depend on the actual hierarchy. This is the default.
   */
  private static final Injection[] UNTARGETED = new Injection[0];

  public static <T> Dependency<T> dependency( Class<T> type ) {
    return dependency( raw( type ) );
  }

  public static <T> Dependency<T> dependency( Type<T> type ) {
    return dependency( type, UNTARGETED );
  }

  private static <T> Dependency<T> dependency( Type<T> type, Injection[] hierarchy ) {
    return dependency( instance( Name.ANY, type ), hierarchy );
  }

  public static <T> Dependency<T> dependency( Instance<T> instance ) {
    return dependency( instance, UNTARGETED );
  }

  private static <T> Dependency<T> dependency( Instance<T> instance, Injection[] hierarchy ) {
    return new Dependency<T>( instance, hierarchy );
  }

  private final Injection[] hierarchy;
  private final Instance<T> instance;

  private Dependency( Instance<T> instance, Injection... hierarchy ) {
    this.instance = instance;
    this.hierarchy = hierarchy;
  }

  public Instance<T> getInstance() {
    return instance;
  }

  @Override
  public Type<T> getType() {
    return instance.getType();
  }

  @Override
  public Name getName() {
    return instance.getName();
  }

  @Override
  public String toString() {
    return instance.toString() + ( hierarchy.length == 0
      ? ""
      : " " + Arrays.toString( hierarchy ) );
  }

  public Dependency<?> onTypeParameter() {
    return dependency( getType().parameter( 0 ), hierarchy );
  }

  public <E> Dependency<E> instanced( Instance<E> instance ) {
    return dependency( instance, hierarchy );
  }

  @Override
  public <E> Dependency<E> typed( Type<E> type ) {
    return dependency( instance( getName(), type ), hierarchy );
  }

  public <E> Dependency<E> anyTyped( Type<E> type ) {
    return dependency( instance( Name.ANY, type ), hierarchy );
  }

  public <E> Dependency<E> anyTyped( Class<E> type ) {
    return anyTyped( raw( type ) );
  }

  public Dependency<T> named( String name ) {
    return named( Name.named( name ) );
  }

  public Dependency<T> named( Name name ) {
    return dependency( instance( name, getType() ), hierarchy );
  }

  public Dependency<T> untargeted() {
    return dependency( instance, UNTARGETED );
  }

  public Dependency<T> ignoredExpiry() {
    if ( hierarchy.length == 0 ) {
      return this;
    }
    Injection[] ignored = new Injection[hierarchy.length];
    for ( int i = 0; i < ignored.length; i++ ) {
      ignored[i] = hierarchy[i].ignoredExpiry();
    }
    return dependency( instance, ignored );
  }

  public boolean isUntargeted() {
    return hierarchy.length == 0;
  }

  public Instance<?> target() {
    return target( 0 );
  }

  public Instance<?> target( int level ) {
    return isUntargeted()
      ? Instance.ANY
      : hierarchy[hierarchy.length - 1 - level].getTarget().getResource().getInstance();
  }

  public int injectionDepth() {
    return hierarchy.length;
  }

  /**
   * Means we inject into the argument target class.
   */
  public Dependency<T> injectingInto( Class<?> target ) {
    return injectingInto( raw( target ) );
  }

  public Dependency<T> injectingInto( Type<?> target ) {
    return injectingInto( defaultInstanceOf( target ) );
  }

  public <I> Dependency<T> injectingInto( Instance<I> target ) {
    return injectingInto( emergence( new Resource<I>(target), Expiry.NEVER ) );
  }

  public Dependency<T> injectingInto( Emergence<?> target ) {
    Injection injection = new Injection( instance, target );
    if ( hierarchy.length == 0 ) {
      return new Dependency<T>( instance, injection );
    }
    ensureNotMoreFrequentExpiry( injection );
    ensureNoCycle( injection );
    return new Dependency<T>( instance, Array.append( hierarchy, injection ) );
  }

  public Dependency<T> uninject() {
    if ( hierarchy.length <= 1 ) {
      return untargeted();
    }
    return new Dependency<T>( instance, Array.copy( hierarchy, hierarchy.length - 1 ) );
  }

  private void ensureNoCycle( Injection injection )
      throws DependencyCycleException {
    for ( int i = 0; i < hierarchy.length; i++ ) {
      Injection parent = hierarchy[i];
      if ( parent.equalTo( injection ) ) {
        throw new DependencyCycleException( this, injection.getTarget().getResource() );
      }
    }
  }

  private void ensureNotMoreFrequentExpiry( Injection injection ) {
    final Expiry expiry = injection.getTarget().getExpiry();
    for ( int i = 0; i < hierarchy.length; i++ ) {
      Injection parent = hierarchy[i];
      if ( expiry.moreFrequent( parent.getTarget().getExpiry() ) ) {
        throw new MoreFrequentExpiryException( parent, injection );
      }
    }
  }

  @Override
  public boolean isAssignableTo( Type<?> type ) {
    return getType().isAssignableTo( type );
  }

  @Override
  public Iterator<Injection> iterator() {
    return Arrays.asList( hierarchy ).iterator();
  }
}
TOP

Related Classes of se.jbee.inject.Dependency

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.