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}