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;
022import org.apache.reef.tang.types.Traversable;
023
024import java.util.Collection;
025import java.util.Collections;
026
027public abstract class InjectionPlan<T> implements Traversable<InjectionPlan<?>> {
028
029  protected final Node node;
030
031  public InjectionPlan(final Node node) {
032    this.node = node;
033  }
034
035  private static void newline(final StringBuffer pretty, final int indent) {
036    pretty.append('\n');
037    for (int j = 0; j < indent * 2; j++) {
038      pretty.append(' ');
039    }
040  }
041
042  public Node getNode() {
043    return node;
044  }
045
046  /**
047   * Get child elements of the injection plan tree.
048   * By default, returns an empty list.
049   *
050   * @return An empty list.
051   */
052  @SuppressWarnings("unchecked")
053  @Override
054  public Collection<InjectionPlan<?>> getChildren() {
055    return Collections.EMPTY_LIST;
056  }
057
058  public abstract int getNumAlternatives();
059
060  public boolean isFeasible() {
061    return getNumAlternatives() > 0;
062  }
063
064  public abstract boolean isAmbiguous();
065
066  public abstract boolean isInjectable();
067
068  protected void pad(final StringBuffer sb, final int n) {
069    for (int i = 0; i < n; i++) {
070      sb.append("  ");
071    }
072  }
073
074  public String toPrettyString() {
075    final String ugly = node.getFullName() + ":\n" + toString();
076    final StringBuffer pretty = new StringBuffer();
077    int currentIndent = 1;
078    for (int i = 0; i < ugly.length(); i++) {
079      final char c = ugly.charAt(i);
080      if (c == '(') {
081        if (ugly.charAt(i + 1) == ')') {
082          pretty.append("()");
083          i++;
084        } else {
085          newline(pretty, currentIndent);
086          currentIndent++;
087          pretty.append(c);
088          pretty.append(' ');
089        }
090      } else if (c == '[') {
091        if (ugly.charAt(i + 1) == ']') {
092          pretty.append("[]");
093          i++;
094        } else {
095          newline(pretty, currentIndent);
096          currentIndent++;
097          pretty.append(c);
098          pretty.append(' ');
099        }
100      } else if (c == ')' || c == ']') {
101        currentIndent--;
102        newline(pretty, currentIndent);
103        pretty.append(c);
104      } else if (c == '|') {
105        newline(pretty, currentIndent);
106        pretty.append(c);
107      } else if (c == ',') {
108        currentIndent--;
109        newline(pretty, currentIndent);
110        pretty.append(c);
111        currentIndent++;
112      } else {
113        pretty.append(c);
114      }
115    }
116    return pretty.toString();
117  }
118
119  /**
120   * Algorithm for generating cant inject string:
121   * <p>
122   * For infeasible plans:
123   * <p>
124   * Some node types are "leaves":
125   * <ul>
126   * <li>NamedParameterNode</li>
127   * <li>ClassNode with no @Inject constructors</li>
128   * </ul>
129   * We do a depth first search of the injection plan, starting with the left
130   * most constructor arguments. When we encounter a constructor whose arguments
131   * are all either injectable or non-injectable leaf nodes, we return the name
132   * of its parent, and the name of the non-injectable leaves.
133   * <p>
134   * For ambiguous plans:
135   * <p>
136   * We perform a depth first search of the ambiguous constructors, as above. We
137   * return the name of the first class that has multiple constructors that are
138   * feasible or ambiguous (as opposed to having a single constructor with an
139   * ambiguous argument, or a constructor with an infeasible argument and an
140   * ambiguous argument).
141   */
142  public final String toCantInjectString() {
143    if (!isFeasible()) {
144      return toInfeasibleInjectString();
145    } else if (isAmbiguous()) {
146      return toAmbiguousInjectString();
147    } else {
148      throw new IllegalArgumentException(
149          "toCantInjectString() called on injectable constructor:"
150              + this.toPrettyString());
151    }
152  }
153
154  protected abstract String toAmbiguousInjectString();
155
156  protected abstract String toInfeasibleInjectString();
157
158  protected abstract boolean isInfeasibleLeaf();
159
160  public abstract String toShallowString();
161}