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.ClassNode;
022import org.apache.reef.tang.types.ConstructorDef;
023
024import java.util.*;
025
026public final class Constructor<T> extends InjectionPlan<T> {
027
028  private final ConstructorDef<T> constructor;
029  private final InjectionPlan<?>[] args;
030  private final int numAlternatives;
031  private final boolean isAmbiguous;
032  private final boolean isInjectable;
033
034  public Constructor(final ClassNode<T> classNode,
035                     final ConstructorDef<T> constructor, final InjectionPlan<?>[] args) {
036    super(classNode);
037    this.constructor = constructor;
038    this.args = args;
039    int curAlternatives = 1;
040    boolean curAmbiguous = false;
041    boolean curInjectable = true;
042    for (final InjectionPlan<?> plan : args) {
043      curAlternatives *= plan.getNumAlternatives();
044      curAmbiguous |= plan.isAmbiguous();
045      curInjectable &= plan.isInjectable();
046    }
047    this.numAlternatives = curAlternatives;
048    this.isAmbiguous = curAmbiguous;
049    this.isInjectable = curInjectable;
050  }
051
052  public InjectionPlan<?>[] getArgs() {
053    return args;
054  }
055
056  /**
057   * Get child elements of the injection plan tree.
058   * This method is inherited from the Traversable interface.
059   * TODO: use ArrayList internally (and maybe for input, too).
060   *
061   * @return A list of injection plans for the constructor's arguments.
062   */
063  @Override
064  public Collection<InjectionPlan<?>> getChildren() {
065    return Collections.unmodifiableList(Arrays.asList(this.args));
066  }
067
068  public ConstructorDef<T> getConstructorDef() {
069    return constructor;
070  }
071
072  @SuppressWarnings("unchecked")
073  @Override
074  public ClassNode<T> getNode() {
075    return (ClassNode<T>) node;
076  }
077
078  @Override
079  public int getNumAlternatives() {
080    return numAlternatives;
081  }
082
083  @Override
084  public boolean isAmbiguous() {
085    return isAmbiguous;
086  }
087
088  @Override
089  public boolean isInjectable() {
090    return isInjectable;
091  }
092
093  @Override
094  public String toString() {
095    final StringBuilder sb = new StringBuilder("new " + getNode().getName() + '(');
096    if (args.length > 0) {
097      sb.append(args[0]);
098      for (int i = 1; i < args.length; i++) {
099        sb.append(", " + args[i]);
100      }
101    }
102    sb.append(')');
103    return sb.toString();
104  }
105
106  private String shallowArgString(final InjectionPlan<?> arg) {
107    if (arg instanceof Constructor || arg instanceof Subplan) {
108      return arg.getClass().getName() + ": " + arg.getNode().getName();
109    } else {
110      return arg.toShallowString();
111    }
112  }
113
114  @Override
115  public String toShallowString() {
116    final StringBuilder sb = new StringBuilder("new " + getNode().getName() + '(');
117    if (args.length > 0) {
118      sb.append(shallowArgString(args[0]));
119      for (int i = 1; i < args.length; i++) {
120        sb.append(", " + shallowArgString(args[i]));
121      }
122    }
123    sb.append(')');
124    return sb.toString();
125  }
126
127  /**
128   * @return A string describing ambiguous constructor arguments.
129   * @throws IllegalArgumentException if constructor is not ambiguous.
130   */
131  @Override
132  protected String toAmbiguousInjectString() {
133
134    if (!isAmbiguous) {
135      throw new IllegalArgumentException(getNode().getFullName() + " is NOT ambiguous.");
136    }
137
138    final StringBuilder sb = new StringBuilder(
139        getNode().getFullName() + " has ambiguous arguments: [ ");
140
141    for (final InjectionPlan<?> plan : args) {
142      if (plan.isAmbiguous()) {
143        sb.append(plan.toAmbiguousInjectString());
144      }
145    }
146
147    sb.append(']');
148    return sb.toString();
149  }
150
151  @Override
152  protected String toInfeasibleInjectString() {
153
154    final List<InjectionPlan<?>> leaves = new ArrayList<>();
155
156    for (final InjectionPlan<?> ip : args) {
157      if (!ip.isFeasible()) {
158        if (ip.isInfeasibleLeaf()) {
159          leaves.add(ip);
160        } else {
161          return ip.toInfeasibleInjectString();
162        }
163      }
164    }
165
166    if (leaves.isEmpty()) {
167      throw new IllegalArgumentException(getNode().getFullName() + " has NO infeasible leaves.");
168    }
169
170    if (leaves.size() == 1) {
171      return getNode().getFullName() + " missing argument " + leaves.get(0).getNode().getFullName();
172    } else {
173      final StringBuffer sb = new StringBuffer(getNode().getFullName() + " missing arguments: [\n\t");
174      for (final InjectionPlan<?> leaf : leaves) {
175        sb.append(leaf.getNode().getFullName() + "\n\t");
176      }
177      sb.append(']');
178      return sb.toString();
179    }
180  }
181
182  @Override
183  protected boolean isInfeasibleLeaf() {
184    return false;
185  }
186}