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

se.jbee.inject.Dependency Maven / Gradle / Ivy

There is a newer version: 0.6
Show newest version
/*
 *  Copyright (c) 2012, 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 ([email protected])
 */
public final class Dependency
		implements Typed, Named, Parameter, Iterable {

	/**
	 * 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  Dependency dependency( Class type ) {
		return dependency( raw( type ) );
	}

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

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

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

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

	private final Injection[] hierarchy;
	private final Instance instance;

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

	public Instance getInstance() {
		return instance;
	}

	@Override
	public Type 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  Dependency instanced( Instance instance ) {
		return dependency( instance, hierarchy );
	}

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

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

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

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

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

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

	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().getInstance();
	}

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

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

	public Dependency injectingInto( Type target ) {
		return injectingInto( defaultInstanceOf( target ) );
	}

	public Dependency injectingInto( Instance target ) {
		return injectingInto( emergence( target, Expiry.NEVER ) );
	}

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

	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().getInstance() );
			}
		}
	}

	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 iterator() {
		return Arrays.asList( hierarchy ).iterator();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy