You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@reef.apache.org by we...@apache.org on 2015/01/23 00:46:45 UTC
[12/51] [partial] incubator-reef git commit: [REEF-93] Move java
sources to lang/java
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/AbstractNode.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/AbstractNode.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/AbstractNode.java
new file mode 100644
index 0000000..fb34bbb
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/AbstractNode.java
@@ -0,0 +1,127 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.implementation.types;
+
+import org.apache.reef.tang.types.Node;
+import org.apache.reef.tang.util.MonotonicTreeMap;
+
+import java.util.Collection;
+import java.util.Map;
+
+public abstract class AbstractNode implements Node {
+ protected final Map<String, Node> children = new MonotonicTreeMap<>();
+ private final Node parent;
+ private final String name;
+ private final String fullName;
+
+ public AbstractNode(Node parent, String name, String fullName) {
+ this.parent = parent;
+ this.name = name;
+ this.fullName = fullName;
+ if (parent != null) {
+ if (name.length() == 0) {
+ throw new IllegalArgumentException(
+ "Zero length child name means bad news");
+ }
+ parent.put(this);
+ }
+ }
+
+ @Override
+ public Collection<Node> getChildren() {
+ return children.values();
+ }
+
+ @Override
+ public String getFullName() {
+ return fullName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) return false;
+ if (o == this) return true;
+
+ AbstractNode n = (AbstractNode) o;
+ final boolean parentsEqual;
+ if (n.parent == this.parent) {
+ parentsEqual = true;
+ } else if (n.parent == null) {
+ parentsEqual = false;
+ } else if (this.parent == null) {
+ parentsEqual = false;
+ } else {
+ parentsEqual = n.parent.equals(this.parent);
+ }
+ if (!parentsEqual) {
+ return false;
+ }
+ return this.name.equals(n.name);
+ }
+
+ @Override
+ public Node getParent() {
+ return parent;
+ }
+
+ @Override
+ public boolean contains(String key) {
+ return children.containsKey(key);
+ }
+
+ @Override
+ public Node get(String key) {
+ return children.get(key);
+ }
+
+ @Override
+ public void put(Node n) {
+ children.put(n.getName(), n);
+ }
+
+ @SuppressWarnings("unused")
+ private String toIndentedString(int level) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < level; i++) {
+ sb.append("\t");
+ }
+ sb.append(toString() + "\n");
+ if (children != null) {
+ for (Node n : children.values()) {
+ sb.append(((AbstractNode) n).toIndentedString(level + 1));
+ }
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return "[" + this.getClass().getSimpleName() + " '" + getFullName() + "']";
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public int compareTo(Node n) {
+ return getFullName().compareTo(n.getFullName());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ClassNodeImpl.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ClassNodeImpl.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ClassNodeImpl.java
new file mode 100644
index 0000000..672f37a
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ClassNodeImpl.java
@@ -0,0 +1,141 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.implementation.types;
+
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.types.ClassNode;
+import org.apache.reef.tang.types.ConstructorDef;
+import org.apache.reef.tang.types.Node;
+import org.apache.reef.tang.util.MonotonicSet;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class ClassNodeImpl<T> extends AbstractNode implements ClassNode<T> {
+ private final boolean injectable;
+ private final boolean unit;
+ private final boolean externalConstructor;
+ private final ConstructorDef<T>[] injectableConstructors;
+ private final ConstructorDef<T>[] allConstructors;
+ private final MonotonicSet<ClassNode<T>> knownImpls;
+ private final String defaultImpl;
+
+ public ClassNodeImpl(Node parent, String simpleName, String fullName,
+ boolean unit, boolean injectable, boolean externalConstructor,
+ ConstructorDef<T>[] injectableConstructors,
+ ConstructorDef<T>[] allConstructors,
+ String defaultImplementation) {
+ super(parent, simpleName, fullName);
+ this.unit = unit;
+ this.injectable = injectable;
+ this.externalConstructor = externalConstructor;
+ this.injectableConstructors = injectableConstructors;
+ this.allConstructors = allConstructors;
+ this.knownImpls = new MonotonicSet<>();
+ this.defaultImpl = defaultImplementation;
+ }
+
+ @Override
+ public ConstructorDef<T>[] getInjectableConstructors() {
+ return injectableConstructors;
+ }
+
+ @Override
+ public ConstructorDef<T>[] getAllConstructors() {
+ return allConstructors;
+ }
+
+ @Override
+ public boolean isInjectionCandidate() {
+ return injectable;
+ }
+
+ @Override
+ public boolean isExternalConstructor() {
+ return externalConstructor;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(super.toString() + ": ");
+ if (getInjectableConstructors() != null) {
+ for (ConstructorDef<T> c : getInjectableConstructors()) {
+ sb.append(c.toString() + ", ");
+ }
+ } else {
+ sb.append("OBJECT BUILD IN PROGRESS! BAD NEWS!");
+ }
+ return sb.toString();
+ }
+
+ public ConstructorDef<T> getConstructorDef(ClassNode<?>... paramTypes)
+ throws BindException {
+ if (!isInjectionCandidate()) {
+ throw new BindException("Cannot @Inject non-static member/local class: "
+ + getFullName());
+ }
+ for (ConstructorDef<T> c : getAllConstructors()) {
+ if (c.takesParameters(paramTypes)) {
+ return c;
+ }
+ }
+ throw new BindException("Could not find requested constructor for class "
+ + getFullName());
+ }
+
+ @Override
+ public void putImpl(ClassNode<T> impl) {
+ knownImpls.add(impl);
+ }
+
+ @Override
+ public Set<ClassNode<T>> getKnownImplementations() {
+ return new MonotonicSet<>(knownImpls);
+ }
+
+ @Override
+ public boolean isUnit() {
+ return unit;
+ }
+
+ @Override
+ public boolean isImplementationOf(ClassNode<?> inter) {
+ List<ClassNode<?>> worklist = new ArrayList<>();
+ if (this.equals(inter)) {
+ return true;
+ }
+ worklist.add(inter);
+ while (!worklist.isEmpty()) {
+ ClassNode<?> cn = worklist.remove(worklist.size() - 1);
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ Set<ClassNode<?>> impls = (Set) cn.getKnownImplementations();
+ if (impls.contains(this)) {
+ return true;
+ }
+ worklist.addAll(impls);
+ }
+ return false;
+ }
+
+ @Override
+ public String getDefaultImplementation() {
+ return defaultImpl;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorArgImpl.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorArgImpl.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorArgImpl.java
new file mode 100644
index 0000000..8232339
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorArgImpl.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.implementation.types;
+
+import org.apache.reef.tang.types.ConstructorArg;
+
+public class ConstructorArgImpl implements ConstructorArg {
+ private final String type;
+ private final String name;
+ private final boolean isInjectionFuture;
+
+ public ConstructorArgImpl(String type, String namedParameterName, boolean isInjectionFuture) {
+ this.type = type;
+ this.name = namedParameterName;
+ this.isInjectionFuture = isInjectionFuture;
+ }
+
+ @Override
+ public String getName() {
+ return name == null ? type : name;
+ }
+
+ @Override
+ public String getNamedParameterName() {
+ return name;
+ }
+
+ @Override
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return name == null ? type : type + " " + name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ ConstructorArgImpl arg = (ConstructorArgImpl) o;
+ if (!type.equals(arg.type)) {
+ return false;
+ }
+ if (name == null && arg.name == null) {
+ return true;
+ }
+ if (name == null && arg.name != null) {
+ return false;
+ }
+ if (name != null && arg.name == null) {
+ return false;
+ }
+ return name.equals(arg.name);
+
+ }
+
+ @Override
+ public boolean isInjectionFuture() {
+ return isInjectionFuture;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorDefImpl.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorDefImpl.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorDefImpl.java
new file mode 100644
index 0000000..2c27eb1
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorDefImpl.java
@@ -0,0 +1,150 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.implementation.types;
+
+import org.apache.reef.tang.exceptions.ClassHierarchyException;
+import org.apache.reef.tang.types.ClassNode;
+import org.apache.reef.tang.types.ConstructorArg;
+import org.apache.reef.tang.types.ConstructorDef;
+
+public class ConstructorDefImpl<T> implements ConstructorDef<T> {
+ private final ConstructorArg[] args;
+ private final String className;
+
+ public ConstructorDefImpl(String className, ConstructorArg[] args,
+ boolean injectable) throws ClassHierarchyException {
+ this.className = className;
+ this.args = args;
+ if (injectable) {
+ for (int i = 0; i < this.getArgs().length; i++) {
+ for (int j = i + 1; j < this.getArgs().length; j++) {
+ if (this.getArgs()[i].equals(this.getArgs()[j])) {
+ throw new ClassHierarchyException(
+ "Repeated constructor parameter detected. "
+ + "Cannot inject constructor " + toString());
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public ConstructorArg[] getArgs() {
+ return args;
+ }
+
+ @Override
+ public String getClassName() {
+ return className;
+ }
+
+ private String join(String sep, Object[] vals) {
+ if (vals.length != 0) {
+ StringBuilder sb = new StringBuilder(vals[0].toString());
+ for (int i = 1; i < vals.length; i++) {
+ sb.append(sep + vals[i]);
+ }
+ return sb.toString();
+ } else {
+ return "";
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(className);
+ sb.append("(");
+ sb.append(join(",", args));
+ sb.append(")");
+ return sb.toString();
+ }
+
+ @Override
+ public boolean takesParameters(ClassNode<?>[] paramTypes) {
+ if (paramTypes.length != args.length) {
+ return false;
+ }
+ for (int i = 0; i < paramTypes.length; i++) {
+ if (!args[i].getType().equals(paramTypes[i].getFullName())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Check to see if two boundConstructors take indistinguishable arguments. If
+ * so (and they are in the same class), then this would lead to ambiguous
+ * injection targets, and we want to fail fast.
+ * <p/>
+ * TODO could be faster. Currently O(n^2) in number of parameters.
+ *
+ * @param def
+ * @return
+ */
+ private boolean equalsIgnoreOrder(ConstructorDef<?> def) {
+ if (getArgs().length != def.getArgs().length) {
+ return false;
+ }
+ for (int i = 0; i < getArgs().length; i++) {
+ boolean found = false;
+ for (int j = 0; j < def.getArgs().length; j++) {
+ if (getArgs()[i].getName().equals(def.getArgs()[j].getName())) {
+ found = true;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return equalsIgnoreOrder((ConstructorDef<?>) o);
+ }
+
+ @Override
+ public boolean isMoreSpecificThan(ConstructorDef<?> def) {
+ // Return true if our list of args is a superset of those in def.
+
+ // Is everything in def also in this?
+ for (int i = 0; i < def.getArgs().length; i++) {
+ boolean found = false;
+ for (int j = 0; j < this.getArgs().length; j++) {
+ if (getArgs()[j].equals(def.getArgs()[i])) {
+ found = true;
+ break;
+ }
+ }
+ // If not, then argument j from def is not in our list. Return false.
+ if (found == false)
+ return false;
+ }
+ // Everything in def's arg list is in ours. Do we have at least one extra
+ // argument?
+ return getArgs().length > def.getArgs().length;
+ }
+
+ @Override
+ public int compareTo(ConstructorDef<?> o) {
+ return toString().compareTo(o.toString());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/NamedParameterNodeImpl.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/NamedParameterNodeImpl.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/NamedParameterNodeImpl.java
new file mode 100644
index 0000000..f2e796d
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/NamedParameterNodeImpl.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.implementation.types;
+
+import org.apache.reef.tang.types.NamedParameterNode;
+import org.apache.reef.tang.types.Node;
+
+public class NamedParameterNodeImpl<T> extends AbstractNode implements
+ NamedParameterNode<T> {
+ private final String fullArgName;
+ private final String simpleArgName;
+ private final String documentation;
+ private final String shortName;
+ private final String[] defaultInstanceAsStrings;
+ private final boolean isSet;
+ private final boolean isList;
+
+ public NamedParameterNodeImpl(Node parent, String simpleName,
+ String fullName, String fullArgName, String simpleArgName, boolean isSet, boolean isList,
+ String documentation, String shortName, String[] defaultInstanceAsStrings) {
+ super(parent, simpleName, fullName);
+ this.fullArgName = fullArgName;
+ this.simpleArgName = simpleArgName;
+ this.isSet = isSet;
+ this.isList = isList;
+ this.documentation = documentation;
+ this.shortName = shortName;
+ this.defaultInstanceAsStrings = defaultInstanceAsStrings;
+ }
+
+ @Override
+ public String toString() {
+ return getSimpleArgName() + " " + getName();
+ }
+
+ @Override
+ public String getSimpleArgName() {
+ return simpleArgName;
+ }
+
+ @Override
+ public String getFullArgName() {
+ return fullArgName;
+ }
+
+ @Override
+ public String getDocumentation() {
+ return documentation;
+ }
+
+ @Override
+ public String getShortName() {
+ return shortName;
+ }
+
+ @Override
+ public String[] getDefaultInstanceAsStrings() {
+ return defaultInstanceAsStrings;
+ }
+
+ @Override
+ public boolean isSet() {
+ return isSet;
+ }
+
+ @Override
+ public boolean isList() {
+ return isList;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/PackageNodeImpl.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/PackageNodeImpl.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/PackageNodeImpl.java
new file mode 100644
index 0000000..16ee0aa
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/PackageNodeImpl.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.implementation.types;
+
+import org.apache.reef.tang.types.Node;
+import org.apache.reef.tang.types.PackageNode;
+
+public class PackageNodeImpl extends AbstractNode implements PackageNode {
+ public PackageNodeImpl(Node parent, String name, String fullName) {
+ super(parent, name, fullName);
+ }
+
+ public PackageNodeImpl() {
+ this(null, "", "[root node]");
+ }
+
+ /**
+ * Unlike normal nodes, the root node needs to take the package name of its
+ * children into account. Therefore, we use the full name as the key when
+ * we insert nodes into the root.
+ */
+ @Override
+ public void put(Node n) {
+ super.children.put(n.getFullName(), n);
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/package-info.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/package-info.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/package-info.java
new file mode 100644
index 0000000..9b0f605
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/package-info.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/**
+ * Implementations of the ClassHierarchy type system. These classes encode
+ * language independent data. Java specializations of these types are in
+ * org.apache.reef.tang.implementation.java.
+ */
+
+package org.apache.reef.tang.implementation.types;
+
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/package-info.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/package-info.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/package-info.java
new file mode 100644
index 0000000..23b203f
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/package-info.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/**
+ * Public interfaces and factories for Tang's core API.
+ *
+ * Other packages that are of interest to typical Tang use-cases are
+ * org.apache.reef.tang.annotations which contains Java annotations that encode
+ * Tang configuration metadata, and org.apache.reef.tang.formats, which
+ * contains classes that import and export data from Tang in various formats.
+ */
+package org.apache.reef.tang;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ClassNode.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ClassNode.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ClassNode.java
new file mode 100644
index 0000000..8c5c19b
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ClassNode.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.types;
+
+import org.apache.reef.tang.exceptions.BindException;
+
+import java.util.Set;
+
+public interface ClassNode<T> extends Node {
+
+ public ConstructorDef<T>[] getInjectableConstructors();
+
+ public ConstructorDef<T> getConstructorDef(ClassNode<?>... args)
+ throws BindException;
+
+ public ConstructorDef<T>[] getAllConstructors();
+
+ public void putImpl(ClassNode<T> impl);
+
+ public Set<ClassNode<T>> getKnownImplementations();
+
+ public String getDefaultImplementation();
+
+ public boolean isUnit();
+
+ public boolean isInjectionCandidate();
+
+ public boolean isExternalConstructor();
+
+ public boolean isImplementationOf(ClassNode<?> inter);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorArg.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorArg.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorArg.java
new file mode 100644
index 0000000..811af9e
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorArg.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.types;
+
+public interface ConstructorArg {
+
+ public String getName();
+
+ public String getType();
+
+ public boolean isInjectionFuture();
+
+ public String getNamedParameterName();
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorDef.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorDef.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorDef.java
new file mode 100644
index 0000000..92922c7
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorDef.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.types;
+
+public interface ConstructorDef<T> extends Comparable<ConstructorDef<?>> {
+ public String getClassName();
+
+ public ConstructorArg[] getArgs();
+
+ public boolean isMoreSpecificThan(ConstructorDef<?> def);
+
+ public boolean takesParameters(ClassNode<?>[] paramTypes);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/NamedParameterNode.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/NamedParameterNode.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/NamedParameterNode.java
new file mode 100644
index 0000000..94d0f9c
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/NamedParameterNode.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.types;
+
+public interface NamedParameterNode<T> extends Node {
+
+ public String getDocumentation();
+
+ public String getShortName();
+
+ public String[] getDefaultInstanceAsStrings();
+
+ public String getSimpleArgName();
+
+ public String getFullArgName();
+
+ public boolean isSet();
+
+ public boolean isList();
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Node.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Node.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Node.java
new file mode 100644
index 0000000..53d5ac5
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Node.java
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.types;
+
+import java.util.Collection;
+
+public interface Node extends Comparable<Node>, Traversable<Node> {
+
+ String getName();
+
+ String getFullName();
+
+ boolean contains(String key);
+
+ Node get(String key);
+
+ Node getParent();
+
+ void put(Node node);
+
+ @Override
+ Collection<Node> getChildren();
+
+ @Override
+ String toString();
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/PackageNode.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/PackageNode.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/PackageNode.java
new file mode 100644
index 0000000..5e7f20d
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/PackageNode.java
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.types;
+
+public interface PackageNode extends Node {
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Traversable.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Traversable.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Traversable.java
new file mode 100644
index 0000000..445435c
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Traversable.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.types;
+
+import java.util.Collection;
+
+public interface Traversable<T extends Traversable<T>> {
+
+ Collection<T> getChildren();
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/package-info.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/package-info.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/package-info.java
new file mode 100644
index 0000000..c76fe0e
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/package-info.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/**
+ * The interfaces that define Tang's ClassHierarchy objects. ClassHierarchies
+ * can be thought of as read-only caches of the reflection data that is
+ * produced when applications are compiled.
+ */
+
+package org.apache.reef.tang.types;
+
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/AbstractMonotonicMultiMap.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/AbstractMonotonicMultiMap.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/AbstractMonotonicMultiMap.java
new file mode 100644
index 0000000..31c023d
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/AbstractMonotonicMultiMap.java
@@ -0,0 +1,206 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.util;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public abstract class AbstractMonotonicMultiMap<K, V> implements Collection<Entry<K, V>> {
+ protected Map<K, Set<V>> map;
+ private int size = 0;
+
+ public AbstractMonotonicMultiMap(Map<K, Set<V>> map) {
+ this.map = map;
+ }
+
+ public void put(K key, V v) {
+ Set<V> vals = map.get(key);
+ if (vals == null) {
+ vals = new MonotonicHashSet<V>();
+ map.put(key, vals);
+ }
+ vals.add(v);
+ size++;
+ }
+
+ public Set<K> keySet() {
+ return map.keySet();
+ }
+
+ public Set<V> getValuesForKey(K key) {
+ Set<V> ret = map.get(key);
+ if (ret == null) {
+ return new MonotonicHashSet<V>();
+ } else {
+ return ret;
+ }
+ }
+
+ public boolean contains(K key, V v) {
+ Set<V> vals = map.get(key);
+ if (vals != null) {
+ return vals.contains(v);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean add(Entry<K, V> e) {
+ put(e.getKey(), e.getValue());
+ return true;
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends Entry<K, V>> c) {
+ boolean ret = false;
+ for (Entry<K, V> e : c) {
+ add(e);
+ ret = true;
+ }
+ return ret;
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException("MonotonicMultiMap cannot be cleared!");
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean contains(Object o) {
+ Entry<?, ?> e = (Entry<?, ?>) o;
+ return contains((K) e.getKey(), (V) e.getValue());
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ for (Object o : c) {
+ if (!contains(o)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ @Override
+ public Iterator<Entry<K, V>> iterator() {
+ final Iterator<Entry<K, Set<V>>> it = map.entrySet().iterator();
+ return new Iterator<Entry<K, V>>() {
+ Iterator<V> cur;
+ K curKey;
+
+ @Override
+ public boolean hasNext() {
+ return it.hasNext() || (cur != null && cur.hasNext());
+ }
+
+ @Override
+ public Entry<K, V> next() {
+ if (cur == null) {
+ if (it.hasNext()) {
+ Entry<K, Set<V>> e = it.next();
+ curKey = e.getKey();
+ cur = e.getValue().iterator();
+ }
+ }
+ final K k = curKey;
+ final V v = cur.next();
+ if (!cur.hasNext()) {
+ cur = null;
+ }
+
+ return new Entry<K, V>() {
+
+ @Override
+ public K getKey() {
+ return k;
+ }
+
+ @Override
+ public V getValue() {
+ return v;
+ }
+
+ @Override
+ public V setValue(V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ };
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ };
+ }
+
+ public Set<V> values() {
+ Set<V> s = new HashSet<>();
+ for (Entry<K, V> e : this) {
+ s.add(e.getValue());
+ }
+ return s;
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException("MonotonicMultiMap does not support non-monotonic method remove!");
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ throw new UnsupportedOperationException("MonotonicMultiMap does not support non-monotonic method removeAll!");
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ throw new UnsupportedOperationException("MonotonicMultiMap does not support non-monotonic method retainAll!");
+ }
+
+ @Override
+ public int size() {
+ return size;
+ }
+
+ @Override
+ public Entry<K, V>[] toArray() {
+ throw new UnsupportedOperationException("No toArray() for MonotonicMulitMap (yet)");
+ }
+
+ @Override
+ public <T> T[] toArray(T[] a) {
+ throw new UnsupportedOperationException("No toArray() for MonotonicMulitMap (yet)");
+ }
+
+ public boolean containsKey(K k) {
+ if (map.containsKey(k)) {
+ return !getValuesForKey(k).isEmpty();
+ } else {
+ return false;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashMap.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashMap.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashMap.java
new file mode 100644
index 0000000..8c5cc6d
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashMap.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MonotonicHashMap<T, U> extends HashMap<T, U> {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public U put(T key, U value) {
+ U old = super.get(key);
+ if (old != null) {
+ throw new IllegalArgumentException("Attempt to re-add: [" + key
+ + "] old value: " + old + " new value " + value);
+ }
+ return super.put(key, value);
+ }
+
+ @Override
+ public void putAll(Map<? extends T, ? extends U> m) {
+ for (T t : m.keySet()) {
+ if (containsKey(t)) {
+ put(t, m.get(t)); // guaranteed to throw.
+ }
+ }
+ for (T t : m.keySet()) {
+ put(t, m.get(t));
+ }
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public U remove(Object o) {
+ throw new UnsupportedOperationException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashSet.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashSet.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashSet.java
new file mode 100644
index 0000000..aa9b12e
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashSet.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.util;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+
+public class MonotonicHashSet<T> extends HashSet<T> {
+ private static final long serialVersionUID = 1L;
+
+ public MonotonicHashSet() {
+ super();
+ }
+
+ public MonotonicHashSet(Collection<T> c) {
+ super(c);
+ }
+
+ @SafeVarargs
+ public MonotonicHashSet(T... c) {
+ super(Arrays.asList(c));
+ }
+
+ @Override
+ public boolean add(T e) {
+ if (super.contains(e)) {
+ throw new IllegalArgumentException("Attempt to re-add " + e
+ + " to MonotonicSet!");
+ }
+ return super.add(e);
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException("Attempt to clear MonotonicSet!");
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException("Attempt to remove " + o
+ + " from MonotonicSet!");
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ throw new UnsupportedOperationException(
+ "removeAll() doesn't make sense for MonotonicSet!");
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ throw new UnsupportedOperationException(
+ "retainAll() doesn't make sense for MonotonicSet!");
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends T> c) {
+ for (T t : c) {
+ add(t);
+ }
+ return c.size() != 0;
+ }
+
+ public boolean addAllIgnoreDuplicates(Collection<? extends T> c) {
+ boolean ret = false;
+ for (T t : c) {
+ if (!contains(t)) {
+ add(t);
+ ret = true;
+ }
+ }
+ return ret;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiHashMap.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiHashMap.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiHashMap.java
new file mode 100644
index 0000000..34cdeea
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiHashMap.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.util;
+
+public class MonotonicMultiHashMap<K, V> extends AbstractMonotonicMultiMap<K, V> {
+ public MonotonicMultiHashMap() {
+ super(new MonotonicHashMap<K, java.util.Set<V>>());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiMap.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiMap.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiMap.java
new file mode 100644
index 0000000..3eb7ecb
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiMap.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.util;
+
+public class MonotonicMultiMap<K, V> extends AbstractMonotonicMultiMap<K, V> {
+ public MonotonicMultiMap() {
+ super(new MonotonicTreeMap<K, java.util.Set<V>>());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicSet.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicSet.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicSet.java
new file mode 100644
index 0000000..c272e4f
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicSet.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.util;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.TreeSet;
+
+public class MonotonicSet<T> extends TreeSet<T> {
+ private static final long serialVersionUID = 1L;
+
+ public MonotonicSet() {
+ super();
+ }
+
+ public MonotonicSet(TreeSet<T> c) {
+ super(c.comparator());
+ addAll(c);
+ }
+
+ public MonotonicSet(Comparator<T> c) {
+ super(c);
+ }
+
+ @Override
+ public boolean add(T e) {
+ if (super.contains(e)) {
+ throw new IllegalArgumentException("Attempt to re-add " + e
+ + " to MonotonicSet!");
+ }
+ return super.add(e);
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException("Attempt to clear MonotonicSet!");
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException("Attempt to remove " + o
+ + " from MonotonicSet!");
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ throw new UnsupportedOperationException(
+ "removeAll() doesn't make sense for MonotonicSet!");
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ throw new UnsupportedOperationException(
+ "retainAll() doesn't make sense for MonotonicSet!");
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends T> c) {
+ for (T t : c) {
+ add(t);
+ }
+ return c.size() != 0;
+ }
+
+ public boolean addAllIgnoreDuplicates(Collection<? extends T> c) {
+ boolean ret = false;
+ for (T t : c) {
+ if (!contains(t)) {
+ add(t);
+ ret = true;
+ }
+ }
+ return ret;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicTreeMap.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicTreeMap.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicTreeMap.java
new file mode 100644
index 0000000..3b84311
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicTreeMap.java
@@ -0,0 +1,119 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.util;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+public final class MonotonicTreeMap<T, U> implements Map<T, U> {
+ private static final long serialVersionUID = 1L;
+
+ private final TreeMap<T, U> innerMap = new TreeMap<>();
+
+
+ @Override
+ public int size() {
+ return innerMap.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return innerMap.isEmpty();
+ }
+
+ @Override
+ public boolean containsKey(final Object o) {
+ return innerMap.containsKey(o);
+ }
+
+ @Override
+ public boolean containsValue(final Object o) {
+ return innerMap.containsValue(o);
+ }
+
+ @Override
+ public U get(final Object o) {
+ return innerMap.get(o);
+ }
+
+ @Override
+ public U put(T key, U value) {
+ U old = innerMap.get(key);
+ if (old != null) {
+ throw new IllegalArgumentException("Attempt to re-add: [" + key
+ + "]\n old value: " + old + " new value " + value);
+ }
+ return innerMap.put(key, value);
+ }
+
+ @Override
+ public void putAll(Map<? extends T, ? extends U> m) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<T> keySet() {
+ return innerMap.keySet();
+ }
+
+ @Override
+ public Collection<U> values() {
+ return innerMap.values();
+ }
+
+ @Override
+ public Set<Entry<T, U>> entrySet() {
+ return innerMap.entrySet();
+ }
+
+ @Override
+ public U remove(Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final MonotonicTreeMap that = (MonotonicTreeMap) o;
+
+ if (!innerMap.equals(that.innerMap)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return innerMap.hashCode();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/ReflectionUtilities.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/ReflectionUtilities.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/ReflectionUtilities.java
new file mode 100644
index 0000000..3157ba8
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/ReflectionUtilities.java
@@ -0,0 +1,397 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.tang.util;
+
+import org.apache.reef.tang.annotations.Name;
+import org.apache.reef.tang.annotations.NamedParameter;
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.exceptions.ClassHierarchyException;
+
+import javax.inject.Inject;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.*;
+import java.util.*;
+
+public class ReflectionUtilities {
+ /**
+ * This is used to split Java classnames. Currently, we split on . and on $
+ */
+ public final static String regexp = "[\\.\\$]";
+ /**
+ * A map from numeric classes to the number of bits used by their representations.
+ */
+ private final static Map<Class<?>, Integer> sizeof = new HashMap<>();
+
+ static {
+ sizeof.put(Byte.class, Byte.SIZE);
+ sizeof.put(Short.class, Short.SIZE);
+ sizeof.put(Integer.class, Integer.SIZE);
+ sizeof.put(Long.class, Long.SIZE);
+ sizeof.put(Float.class, Float.SIZE);
+ sizeof.put(Double.class, Double.SIZE);
+ }
+
+ /**
+ * Given a primitive type, return its boxed representation.
+ * <p/>
+ * Examples:
+ * boxClass(int.class) -> Integer.class
+ * boxClass(String.class) -> String.class
+ *
+ * @param c The class to be boxed.
+ * @return The boxed version of c, or c if it is not a primitive type.
+ */
+ public static Class<?> boxClass(Class<?> c) {
+ if (c.isPrimitive() && c != Class.class) {
+ if (c == boolean.class) {
+ return Boolean.class;
+ } else if (c == byte.class) {
+ return Byte.class;
+ } else if (c == char.class) {
+ return Character.class;
+ } else if (c == short.class) {
+ return Short.class;
+ } else if (c == int.class) {
+ return Integer.class;
+ } else if (c == long.class) {
+ return Long.class;
+ } else if (c == float.class) {
+ return Float.class;
+ } else if (c == double.class) {
+ return Double.class;
+ } else if (c == void.class) {
+ return Void.class;
+ } else {
+ throw new UnsupportedOperationException(
+ "Encountered unknown primitive type!");
+ }
+ } else {
+ return c;
+ }
+ }
+
+ /**
+ * Given a Type, return all of the classes it extends and interfaces it implements (including the class itself).
+ * <p/>
+ * Examples:
+ * Integer.class -> {Integer.class, Number.class, Object.class}
+ * T -> Object
+ * ? -> Object
+ * HashSet<T> -> {HashSet<T>, Set<T>, Collection<T>, Object}
+ * FooEventHandler -> {FooEventHandler, EventHandler<Foo>, Object}
+ */
+ public static Iterable<Type> classAndAncestors(Type c) {
+ List<Type> workQueue = new ArrayList<>();
+
+ workQueue.add(c);
+ if (getRawClass(c).isInterface()) {
+ workQueue.add(Object.class);
+ }
+ for (int i = 0; i < workQueue.size(); i++) {
+ c = workQueue.get(i);
+
+ if (c instanceof Class) {
+ Class<?> clz = (Class<?>) c;
+ final Type sc = clz.getSuperclass();
+ if (sc != null) workQueue.add(sc); //c.getSuperclass());
+ workQueue.addAll(Arrays.asList(clz.getGenericInterfaces()));
+ } else if (c instanceof ParameterizedType) {
+ ParameterizedType pt = (ParameterizedType) c;
+ Class<?> rawPt = (Class<?>) pt.getRawType();
+ final Type sc = rawPt.getSuperclass();
+// workQueue.add(pt);
+// workQueue.add(rawPt);
+ if (sc != null) workQueue.add(sc);
+ workQueue.addAll(Arrays.asList(rawPt.getGenericInterfaces()));
+ } else if (c instanceof WildcardType) {
+ workQueue.add(Object.class); // XXX not really correct, but close enough?
+ } else if (c instanceof TypeVariable) {
+ workQueue.add(Object.class); // XXX not really correct, but close enough?
+ } else {
+ throw new RuntimeException(c.getClass() + " " + c + " is of unknown type!");
+ }
+ }
+ return workQueue;
+ }
+
+ /**
+ * Check to see if one class can be coerced into another. A class is
+ * coercable to another if, once both are boxed, the target class is a
+ * superclass or implemented interface of the source class.
+ * <p/>
+ * If both classes are numeric types, then this method returns true iff
+ * the conversion will not result in a loss of precision.
+ * <p/>
+ * TODO: Float and double are currently coercible to int and long. This is a bug.
+ */
+ public static boolean isCoercable(Class<?> to, Class<?> from) {
+ to = boxClass(to);
+ from = boxClass(from);
+ if (Number.class.isAssignableFrom(to)
+ && Number.class.isAssignableFrom(from)) {
+ return sizeof.get(from) <= sizeof.get(to);
+ }
+ return to.isAssignableFrom(from);
+ }
+
+ /**
+ * Lookup the provided name using the provided classloader. This method
+ * includes special handling for primitive types, which can be looked up
+ * by short name (all other types need to be looked up by long name).
+ *
+ * @throws ClassNotFoundException
+ */
+ public static Class<?> classForName(String name, ClassLoader loader)
+ throws ClassNotFoundException {
+ if (name.startsWith("[")) {
+ throw new UnsupportedOperationException("No support for arrays, etc. Name was: " + name);
+ } else if (name.equals("boolean")) {
+ return boolean.class;
+ } else if (name.equals("byte")) {
+ return byte.class;
+ } else if (name.equals("char")) {
+ return char.class;
+ } else if (name.equals("short")) {
+ return short.class;
+ } else if (name.equals("int")) {
+ return int.class;
+ } else if (name.equals("long")) {
+ return long.class;
+ } else if (name.equals("float")) {
+ return float.class;
+ } else if (name.equals("double")) {
+ return double.class;
+ } else if (name.equals("void")) {
+ return void.class;
+ } else {
+ return loader.loadClass(name);
+ }
+ }
+
+ /**
+ * Get the simple name of the class. This varies from the one in Class, in
+ * that it returns "1" for Classes like java.lang.String$1 In contrast,
+ * String.class.getSimpleName() returns "", which is not unique if
+ * java.lang.String$2 exists, causing all sorts of strange bugs.
+ *
+ * @param name
+ * @return
+ */
+ public static String getSimpleName(Type name) {
+ final Class<?> clazz = getRawClass(name);
+ final String[] nameArray = clazz.getName().split(regexp);
+ final String ret = nameArray[nameArray.length - 1];
+ if (ret.length() == 0) {
+ throw new IllegalArgumentException("Class " + name + " has zero-length simple name. Can't happen?!?");
+ }
+ return ret;
+ }
+
+ /**
+ * Return the full name of the raw type of the provided Type.
+ * <p/>
+ * Examples:
+ * <p/>
+ * java.lang.String.class -> "java.lang.String"
+ * Set<String> -> "java.util.Set" // such types can occur as constructor arguments, for example
+ *
+ * @param name
+ * @return
+ */
+ public static String getFullName(Type name) {
+ return getRawClass(name).getName();
+ }
+
+ /**
+ * Return the full name of the provided field. This will be globally
+ * unique. Following Java semantics, the full name will have all the
+ * generic parameters stripped out of it.
+ * <p/>
+ * Example:
+ * <p/>
+ * Set<X> { int size; } -> java.util.Set.size
+ */
+ public static String getFullName(Field f) {
+ return getFullName(f.getDeclaringClass()) + "." + f.getName();
+ }
+
+ /**
+ * This method takes a class called clazz that *directly* implements a generic interface or generic class, iface.
+ * Iface should take a single parameter, which this method will return.
+ * <p/>
+ * TODO This is only tested for interfaces, and the type parameters associated with method arguments.
+ * TODO Not sure what we should do in the face of deeply nested generics (eg: Set<Set<String>)
+ * TODO Recurse up the class hierarchy in case there are intermediate interfaces
+ *
+ * @param iface A generic interface; we're looking up it's first (and only) parameter.
+ * @param type A type that is more specific than clazz, or clazz if no such type is available.
+ * @return The class implemented by the interface, or null(?) if the instantiation was not generic.
+ * @throws IllegalArgumentException if clazz does not directly implement iface.
+ */
+ static public Type getInterfaceTarget(final Class<?> iface, final Type type) throws IllegalArgumentException {
+ if (type instanceof ParameterizedType) {
+ final ParameterizedType pt = (ParameterizedType) type;
+ if (iface.isAssignableFrom((Class<?>) pt.getRawType())) {
+ Type t = pt.getActualTypeArguments()[0];
+ return t;
+ } else {
+ throw new IllegalArgumentException("Parameterized type " + type + " does not extend " + iface);
+ }
+ } else if (type instanceof Class) {
+ final Class<?> clazz = (Class<?>) type;
+
+ if (!clazz.equals(type)) {
+ throw new IllegalArgumentException();
+ }
+
+ ArrayList<Type> al = new ArrayList<>();
+ al.addAll(Arrays.asList(clazz.getGenericInterfaces()));
+ Type sc = clazz.getGenericSuperclass();
+ if (sc != null) al.add(sc);
+
+ final Type[] interfaces = al.toArray(new Type[0]);
+
+ for (Type genericNameType : interfaces) {
+ if (genericNameType instanceof ParameterizedType) {
+ ParameterizedType ptype = (ParameterizedType) genericNameType;
+ if (ptype.getRawType().equals(iface)) {
+ Type t = ptype.getActualTypeArguments()[0];
+ return t;
+ }
+ }
+ }
+ throw new IllegalArgumentException(clazz + " does not directly implement " + iface);
+ } else {
+ throw new UnsupportedOperationException("Do not know how to get interface target of " + type);
+ }
+ }
+
+ /**
+ * @param clazz
+ * @return T if clazz implements Name<T>, null otherwise
+ * @throws BindException If clazz's definition incorrectly uses Name or @NamedParameter
+ */
+ static public Type getNamedParameterTargetOrNull(Class<?> clazz)
+ throws ClassHierarchyException {
+ Annotation npAnnotation = clazz.getAnnotation(NamedParameter.class);
+ boolean hasSuperClass = (clazz.getSuperclass() != Object.class);
+
+ boolean isInjectable = false;
+ boolean hasConstructor = false;
+ // TODO Figure out how to properly differentiate between default and
+ // non-default zero-arg constructors?
+ Constructor<?>[] constructors = clazz.getDeclaredConstructors();
+ if (constructors.length > 1) {
+ hasConstructor = true;
+ }
+ if (constructors.length == 1) {
+ Constructor<?> c = constructors[0];
+ Class<?>[] p = c.getParameterTypes();
+ if (p.length > 1) {
+ // Multiple args. Definitely not implicit.
+ hasConstructor = true;
+ } else if (p.length == 1) {
+ // One arg. Could be an inner class, in which case the compiler
+ // included an implicit one parameter constructor that takes the
+ // enclosing type.
+ if (p[0] != clazz.getEnclosingClass()) {
+ hasConstructor = true;
+ }
+ }
+ }
+ for (Constructor<?> c : constructors) {
+ for (Annotation a : c.getDeclaredAnnotations()) {
+ if (a instanceof Inject) {
+ isInjectable = true;
+ }
+ }
+ }
+
+ Class<?>[] allInterfaces = clazz.getInterfaces();
+
+ boolean hasMultipleInterfaces = (allInterfaces.length > 1);
+ boolean implementsName;
+ Type parameterClass = null;
+ try {
+ parameterClass = getInterfaceTarget(Name.class, clazz);
+ implementsName = true;
+ } catch (IllegalArgumentException e) {
+ implementsName = false;
+ }
+
+ if (npAnnotation == null) {
+ if (implementsName) {
+ throw new ClassHierarchyException("Named parameter " + getFullName(clazz)
+ + " is missing its @NamedParameter annotation.");
+ } else {
+ return null;
+ }
+ } else {
+ if (!implementsName) {
+ throw new ClassHierarchyException("Found illegal @NamedParameter " + getFullName(clazz)
+ + " does not implement Name<?>");
+ }
+ if (hasSuperClass) {
+ throw new ClassHierarchyException("Named parameter " + getFullName(clazz)
+ + " has a superclass other than Object.");
+ }
+ if (hasConstructor || isInjectable) {
+ throw new ClassHierarchyException("Named parameter " + getFullName(clazz) + " has "
+ + (isInjectable ? "an injectable" : "a") + " constructor. "
+ + " Named parameters must not declare any constructors.");
+ }
+ if (hasMultipleInterfaces) {
+ throw new ClassHierarchyException("Named parameter " + getFullName(clazz) + " implements "
+ + "multiple interfaces. It is only allowed to implement Name<T>");
+ }
+ if (parameterClass == null) {
+ throw new ClassHierarchyException(
+ "Missing type parameter in named parameter declaration. " + getFullName(clazz)
+ + " implements raw type Name, but must implement"
+ + " generic type Name<T>.");
+ }
+ return parameterClass;
+ }
+ }
+
+ /**
+ * Coerce a Type into a Class. This strips out any generic paramters, and
+ * resolves wildcards and free parameters to Object.
+ * <p/>
+ * Examples:
+ * java.util.Set<String> -> java.util.Set
+ * ? extends T -> Object
+ * T -> Object
+ * ? -> Object
+ */
+ public static Class<?> getRawClass(Type clazz) {
+ if (clazz instanceof Class) {
+ return (Class<?>) clazz;
+ } else if (clazz instanceof ParameterizedType) {
+ return (Class<?>) ((ParameterizedType) clazz).getRawType();
+ } else if (clazz instanceof WildcardType) {
+ return Object.class; // XXX not really correct, but close enough?
+ } else if (clazz instanceof TypeVariable) {
+ return Object.class; // XXX not really correct, but close enough?
+ } else {
+ System.err.println("Can't getRawClass for " + clazz + " of unknown type " + clazz.getClass());
+ throw new IllegalArgumentException("Can't getRawClass for " + clazz + " of unknown type " + clazz.getClass());
+ }
+ }
+}