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.BindException; 022import org.apache.reef.tang.types.ClassNode; 023import org.apache.reef.tang.types.ConstructorDef; 024import org.apache.reef.tang.types.Node; 025import org.apache.reef.tang.util.MonotonicSet; 026 027import java.util.ArrayList; 028import java.util.List; 029import java.util.Set; 030 031public class ClassNodeImpl<T> extends AbstractNode implements ClassNode<T> { 032 private final boolean injectable; 033 private final boolean unit; 034 private final boolean externalConstructor; 035 private final ConstructorDef<T>[] injectableConstructors; 036 private final ConstructorDef<T>[] allConstructors; 037 private final MonotonicSet<ClassNode<T>> knownImpls; 038 private final String defaultImpl; 039 040 public ClassNodeImpl(final Node parent, final String simpleName, final String fullName, 041 final boolean unit, final boolean injectable, final boolean externalConstructor, 042 final ConstructorDef<T>[] injectableConstructors, 043 final ConstructorDef<T>[] allConstructors, 044 final String defaultImplementation) { 045 super(parent, simpleName, fullName); 046 this.unit = unit; 047 this.injectable = injectable; 048 this.externalConstructor = externalConstructor; 049 this.injectableConstructors = injectableConstructors; 050 this.allConstructors = allConstructors; 051 this.knownImpls = new MonotonicSet<>(); 052 this.defaultImpl = defaultImplementation; 053 } 054 055 @Override 056 public ConstructorDef<T>[] getInjectableConstructors() { 057 return injectableConstructors; 058 } 059 060 @Override 061 public ConstructorDef<T>[] getAllConstructors() { 062 return allConstructors; 063 } 064 065 @Override 066 public boolean isInjectionCandidate() { 067 return injectable; 068 } 069 070 @Override 071 public boolean isExternalConstructor() { 072 return externalConstructor; 073 } 074 075 @Override 076 public String toString() { 077 final StringBuilder sb = new StringBuilder(super.toString() + ": "); 078 if (getInjectableConstructors() != null) { 079 for (final ConstructorDef<T> c : getInjectableConstructors()) { 080 sb.append(c.toString() + ", "); 081 } 082 } else { 083 sb.append("OBJECT BUILD IN PROGRESS! BAD NEWS!"); 084 } 085 return sb.toString(); 086 } 087 088 public ConstructorDef<T> getConstructorDef(final ClassNode<?>... paramTypes) 089 throws BindException { 090 if (!isInjectionCandidate()) { 091 throw new BindException("Cannot @Inject non-static member/local class: " 092 + getFullName()); 093 } 094 for (final ConstructorDef<T> c : getAllConstructors()) { 095 if (c.takesParameters(paramTypes)) { 096 return c; 097 } 098 } 099 throw new BindException("Could not find requested constructor for class " 100 + getFullName()); 101 } 102 103 @Override 104 public void putImpl(final ClassNode<T> impl) { 105 knownImpls.add(impl); 106 } 107 108 @Override 109 public Set<ClassNode<T>> getKnownImplementations() { 110 return new MonotonicSet<>(knownImpls); 111 } 112 113 @Override 114 public boolean isUnit() { 115 return unit; 116 } 117 118 @Override 119 public boolean isImplementationOf(final ClassNode<?> inter) { 120 final List<ClassNode<?>> worklist = new ArrayList<>(); 121 if (this.equals(inter)) { 122 return true; 123 } 124 worklist.add(inter); 125 while (!worklist.isEmpty()) { 126 final ClassNode<?> cn = worklist.remove(worklist.size() - 1); 127 @SuppressWarnings({"rawtypes", "unchecked"}) final 128 Set<ClassNode<?>> impls = (Set) cn.getKnownImplementations(); 129 if (impls.contains(this)) { 130 return true; 131 } 132 worklist.addAll(impls); 133 } 134 return false; 135 } 136 137 @Override 138 public String getDefaultImplementation() { 139 return defaultImpl; 140 } 141}