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.types;
020
021import org.apache.reef.tang.exceptions.ClassHierarchyException;
022import org.apache.reef.tang.types.ClassNode;
023import org.apache.reef.tang.types.ConstructorArg;
024import org.apache.reef.tang.types.ConstructorDef;
025
026import java.util.Arrays;
027import java.util.HashMap;
028
029public class ConstructorDefImpl<T> implements ConstructorDef<T> {
030  private final ConstructorArg[] args;
031  private final String className;
032
033  public ConstructorDefImpl(final String className, final ConstructorArg[] args,
034                            final boolean injectable) throws ClassHierarchyException {
035    this.className = className;
036    this.args = args;
037    if (injectable) {
038      for (int i = 0; i < this.getArgs().length; i++) {
039        for (int j = i + 1; j < this.getArgs().length; j++) {
040          if (this.getArgs()[i].equals(this.getArgs()[j])) {
041            throw new ClassHierarchyException(
042                "Repeated constructor parameter detected.  "
043                    + "Cannot inject constructor " + toString());
044          }
045        }
046      }
047    }
048  }
049
050  @Override
051  public ConstructorArg[] getArgs() {
052    return args;
053  }
054
055  @Override
056  public String getClassName() {
057    return className;
058  }
059
060  private String join(final String sep, final Object[] vals) {
061    if (vals.length != 0) {
062      final StringBuilder sb = new StringBuilder(vals[0].toString());
063      for (int i = 1; i < vals.length; i++) {
064        sb.append(sep + vals[i]);
065      }
066      return sb.toString();
067    } else {
068      return "";
069    }
070  }
071
072  @Override
073  public String toString() {
074    final StringBuilder sb = new StringBuilder(className);
075    sb.append("(");
076    sb.append(join(",", args));
077    sb.append(")");
078    return sb.toString();
079  }
080
081  @Override
082  public boolean takesParameters(final ClassNode<?>[] paramTypes) {
083    if (paramTypes.length != args.length) {
084      return false;
085    }
086    for (int i = 0; i < paramTypes.length; i++) {
087      if (!args[i].getType().equals(paramTypes[i].getFullName())) {
088        return false;
089      }
090    }
091    return true;
092  }
093
094  /**
095   * Check to see if two boundConstructors take indistinguishable arguments. If
096   * so (and they are in the same class), then this would lead to ambiguous
097   * injection targets, and we want to fail fast.
098   *
099   * @param def
100   * @return
101   */
102  private boolean equalsIgnoreOrder(final ConstructorDef<?> def) {
103    HashMap map = new HashMap();
104    for (ConstructorArg a : def.getArgs()) {
105      map.put(a.getName(), null);
106    }
107    for (ConstructorArg a : getArgs()) {
108      if (!map.containsKey(a.getName())) {
109        return false;
110      }
111    }
112    return true;
113  }
114
115  @Override
116  public boolean equals(final Object o) {
117    if (this == o) {
118      return true;
119    }
120    if (o == null || getClass() != o.getClass()) {
121      return false;
122    }
123
124    int length = getArgs().length;
125    ConstructorDef<?> def = (ConstructorDef<?>) o;
126    if (length != def.getArgs().length) {
127      return false;
128    }
129    if (length == 0) {
130      return true;
131    }
132    if (length == 1) {
133      return getArgs()[0].getName().equals(def.getArgs()[0].getName());
134    }
135    return equalsIgnoreOrder(def);
136  }
137
138  @Override
139  public boolean isMoreSpecificThan(final ConstructorDef<?> def) {
140    // Return true if our list of args is a superset of those in def.
141
142    // Is everything in def also in this?
143    for (int i = 0; i < def.getArgs().length; i++) {
144      boolean found = false;
145      for (int j = 0; j < this.getArgs().length; j++) {
146        if (getArgs()[j].equals(def.getArgs()[i])) {
147          found = true;
148          break;
149        }
150      }
151      // If not, then argument j from def is not in our list.  Return false.
152      if (!found) {
153        return false;
154      }
155    }
156    // Everything in def's arg list is in ours.  Do we have at least one extra
157    // argument?
158    return getArgs().length > def.getArgs().length;
159  }
160
161  @Override
162  public int compareTo(final ConstructorDef<?> o) {
163    return toString().compareTo(o.toString());
164  }
165
166  @Override
167  public int hashCode() {
168    final ConstructorArg[] argsSort = getArgs().clone();
169    Arrays.sort(argsSort);
170    int result = Arrays.hashCode(argsSort);
171    result = 31 * result + (this.className == null ? 0 : this.className.hashCode());
172    return result;
173  }
174}