This project has retired. For details please refer to its Attic page.
Source code
001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.reef.tang.implementation;
020
021import org.apache.reef.tang.types.Node;
022
023import java.util.*;
024
025public final class Subplan<T> extends InjectionPlan<T> {
026  final InjectionPlan<? extends T>[] alternatives;
027  final int numAlternatives;
028  final int selectedIndex;
029
030  @SafeVarargs
031  public Subplan(final Node node, final int selectedIndex, final InjectionPlan<T>... alternatives) {
032    super(node);
033    this.alternatives = alternatives;
034    if (selectedIndex < -1 || selectedIndex >= alternatives.length) {
035      throw new ArrayIndexOutOfBoundsException("Actual value of selectedIndex is " + selectedIndex
036      + ". The length of the 'alternatives' vararg is " + alternatives.length);
037    }
038    this.selectedIndex = selectedIndex;
039    if (selectedIndex != -1) {
040      this.numAlternatives = alternatives[selectedIndex].getNumAlternatives();
041    } else {
042      int numAlternativesSum = 0;
043      for (final InjectionPlan<? extends T> a : alternatives) {
044        numAlternativesSum += a.getNumAlternatives();
045      }
046      this.numAlternatives = numAlternativesSum;
047    }
048  }
049
050  @SafeVarargs
051  public Subplan(final Node node, final InjectionPlan<T>... alternatives) {
052    this(node, -1, alternatives);
053  }
054
055  /**
056   * Get child elements of the injection plan tree.
057   * TODO: use ArrayList internally (and maybe for input, too).
058   *
059   * @return A list of injection sub-plans.
060   */
061  @SuppressWarnings({"unchecked", "rawtypes"})
062  @Override
063  public Collection<InjectionPlan<?>> getChildren() {
064    return (Collection) Collections.unmodifiableCollection(Arrays.asList(this.alternatives));
065  }
066
067  @Override
068  public int getNumAlternatives() {
069    return this.numAlternatives;
070  }
071
072  /**
073   * Even if there is only one sub-plan, it was registered as a default plan,
074   * and is therefore ambiguous.
075   */
076  @Override
077  public boolean isAmbiguous() {
078    if (selectedIndex == -1) {
079      return true;
080    }
081    return alternatives[selectedIndex].isAmbiguous();
082  }
083
084  @Override
085  public boolean isInjectable() {
086    if (selectedIndex == -1) {
087      return false;
088    } else {
089      return alternatives[selectedIndex].isInjectable();
090    }
091  }
092
093  @Override
094  public String toString() {
095    if (alternatives.length == 1) {
096      return getNode().getName() + " = " + alternatives[0];
097    } else if (alternatives.length == 0) {
098      return getNode().getName() + ": no injectable constructors";
099    }
100    final StringBuilder sb = new StringBuilder("[");
101    sb.append(getNode().getName() + " = " + alternatives[0]);
102    for (int i = 1; i < alternatives.length; i++) {
103      sb.append(" | " + alternatives[i]);
104    }
105    sb.append("]");
106    return sb.toString();
107  }
108
109  @Override
110  public String toShallowString() {
111    if (alternatives.length == 1) {
112      return getNode().getName() + " = " + alternatives[0].toShallowString();
113    } else if (alternatives.length == 0) {
114      return getNode().getName() + ": no injectable constructors";
115    }
116    final StringBuilder sb = new StringBuilder("[");
117    sb.append(getNode().getName() + " = " + alternatives[0].toShallowString());
118    for (int i = 1; i < alternatives.length; i++) {
119      sb.append(" | " + alternatives[i].toShallowString());
120    }
121    sb.append("]");
122    return sb.toString();
123  }
124
125  public int getSelectedIndex() {
126    return selectedIndex;
127  }
128
129  public InjectionPlan<? extends T> getDelegatedPlan() {
130    if (selectedIndex == -1) {
131      throw new IllegalStateException("selectedIndex equals -1");
132    } else {
133      return alternatives[selectedIndex];
134    }
135  }
136
137  @Override
138  protected String toAmbiguousInjectString() {
139    if (alternatives.length == 1) {
140      return alternatives[0].toAmbiguousInjectString();
141    } else if (selectedIndex != -1) {
142      return alternatives[selectedIndex].toAmbiguousInjectString();
143    } else {
144      final List<InjectionPlan<?>> alts = new ArrayList<>();
145      final List<InjectionPlan<?>> ambig = new ArrayList<>();
146      for (final InjectionPlan<?> alt : alternatives) {
147        if (alt.isFeasible()) {
148          alts.add(alt);
149        }
150        if (alt.isAmbiguous()) {
151          ambig.add(alt);
152        }
153      }
154      final StringBuffer sb = new StringBuffer("Ambiguous subplan " + getNode().getFullName());
155      for (final InjectionPlan<?> alt : alts) {
156        sb.append("\n  " + alt.toShallowString() + " ");
157      }
158      for (final InjectionPlan<?> alt : ambig) {
159        sb.append("\n  " + alt.toShallowString() + " ");
160      }
161      sb.append("\n]");
162      return sb.toString();
163    }
164  }
165
166  @Override
167  protected String toInfeasibleInjectString() {
168    if (alternatives.length == 1) {
169      return alternatives[0].toInfeasibleInjectString();
170    } else if (alternatives.length == 0) {
171      return "No known implementations / injectable constructors for "
172          + this.getNode().getFullName();
173    } else if (selectedIndex != -1) {
174      return alternatives[selectedIndex].toInfeasibleInjectString();
175    } else {
176      return "Multiple infeasible plans: " + toPrettyString();
177    }
178  }
179
180  @Override
181  protected boolean isInfeasibleLeaf() {
182    return false;
183  }
184
185  public InjectionPlan<?>[] getPlans() {
186    return Arrays.copyOf(alternatives, alternatives.length);
187  }
188
189}