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.java; 020 021import org.apache.reef.tang.Configuration; 022import org.apache.reef.tang.ExternalConstructor; 023import org.apache.reef.tang.JavaClassHierarchy; 024import org.apache.reef.tang.JavaConfigurationBuilder; 025import org.apache.reef.tang.annotations.Name; 026import org.apache.reef.tang.exceptions.BindException; 027import org.apache.reef.tang.implementation.ConfigurationBuilderImpl; 028import org.apache.reef.tang.implementation.ConfigurationImpl; 029import org.apache.reef.tang.types.ClassNode; 030import org.apache.reef.tang.types.NamedParameterNode; 031import org.apache.reef.tang.types.Node; 032import org.apache.reef.tang.util.ReflectionUtilities; 033 034import java.lang.reflect.Type; 035import java.net.URL; 036import java.util.ArrayList; 037import java.util.List; 038import java.util.Set; 039 040public class JavaConfigurationBuilderImpl extends ConfigurationBuilderImpl 041 implements JavaConfigurationBuilder { 042 043 public JavaConfigurationBuilderImpl(final URL[] jars, 044 final Configuration[] confs, 045 final Class<? extends ExternalConstructor<?>>[] parsers) 046 throws BindException { 047 super(jars, confs, parsers); 048 } 049 050 JavaConfigurationBuilderImpl() { 051 super(); 052 } 053 054 public JavaConfigurationBuilderImpl(final URL[] jars) throws BindException { 055 super(jars); 056 } 057 058 JavaConfigurationBuilderImpl(final JavaConfigurationBuilderImpl impl) { 059 super(impl); 060 } 061 062 public JavaConfigurationBuilderImpl(final Configuration[] confs) 063 throws BindException { 064 super(confs); 065 } 066 067 @Override 068 public ConfigurationImpl build() { 069 return new JavaConfigurationImpl(new JavaConfigurationBuilderImpl(this)); 070 } 071 072 private Node getNode(final Class<?> c) { 073 return ((JavaClassHierarchy) getClassHierarchy()).getNode(c); 074 } 075 076 @Override 077 public <T> JavaConfigurationBuilder bind(final Class<T> c, final Class<?> val) throws BindException { 078 super.bind(getNode(c), getNode(val)); 079 return this; 080 } 081 082 @Override 083 @SuppressWarnings("unchecked") 084 public <T> JavaConfigurationBuilder bindImplementation(final Class<T> c, final Class<? extends T> d) 085 throws BindException { 086 final Node cn = getNode(c); 087 final Node dn = getNode(d); 088 if (!(cn instanceof ClassNode)) { 089 throw new BindException( 090 "bindImplementation passed interface that resolved to " + cn 091 + " expected a ClassNode<?>"); 092 } 093 if (!(dn instanceof ClassNode)) { 094 throw new BindException( 095 "bindImplementation passed implementation that resolved to " + dn 096 + " expected a ClassNode<?>"); 097 } 098 super.bindImplementation((ClassNode<T>) cn, (ClassNode<? extends T>) dn); 099 return this; 100 } 101 102 @Override 103 public JavaConfigurationBuilder bindNamedParameter(final Class<? extends Name<?>> name, final String value) 104 throws BindException { 105 if (value == null) { 106 throw new IllegalStateException("The value null set to the named parameter is illegal: " + name); 107 } 108 final Node np = getNode(name); 109 if (np instanceof NamedParameterNode) { 110 super.bindParameter((NamedParameterNode<?>) np, value); 111 return this; 112 } else { 113 throw new BindException( 114 "Detected type mismatch when setting named parameter " + name 115 + " Expected NamedParameterNode, but namespace contains a " + np); 116 } 117 } 118 119 @Override 120 public <T> JavaConfigurationBuilder bindNamedParameter(final Class<? extends Name<T>> iface, 121 final Class<? extends T> impl) throws BindException { 122 final Node ifaceN = getNode(iface); 123 final Node implN = getNode(impl); 124 if (!(ifaceN instanceof NamedParameterNode)) { 125 throw new BindException("Type mismatch when setting named parameter " + ifaceN 126 + " Expected NamedParameterNode"); 127 } 128 bind(ifaceN, implN); 129 return this; 130 } 131 132 @SuppressWarnings({"unchecked"}) 133 public <T> JavaConfigurationBuilder bindConstructor(final Class<T> c, 134 final Class<? extends ExternalConstructor<? extends T>> v) 135 throws BindException { 136 final Node n = getNode(c); 137 final Node m = getNode(v); 138 if (!(n instanceof ClassNode)) { 139 throw new BindException("BindConstructor got class that resolved to " + n + "; expected ClassNode"); 140 } 141 if (!(m instanceof ClassNode)) { 142 throw new BindException("BindConstructor got class that resolved to " + m + "; expected ClassNode"); 143 } 144 super.bindConstructor((ClassNode<T>) n, (ClassNode<? extends ExternalConstructor<? extends T>>) m); 145 return this; 146 } 147 148 @SuppressWarnings("unchecked") 149 @Override 150 public <T> JavaConfigurationBuilder bindSetEntry(final Class<? extends Name<Set<T>>> iface, final String value) 151 throws BindException { 152 final Node n = getNode(iface); 153 154 if (!(n instanceof NamedParameterNode)) { 155 throw new BindException("BindSetEntry got an interface that resolved to " + n + "; expected a NamedParameter"); 156 } 157 final Type setType = ReflectionUtilities.getInterfaceTarget(Name.class, iface); 158 if (!ReflectionUtilities.getRawClass(setType).equals(Set.class)) { 159 throw new BindException("BindSetEntry got a NamedParameter that takes a " + setType + "; expected Set<...>"); 160 } 161// Type valType = ReflectionUtilities.getInterfaceTarget(Set.class, setType); 162 super.bindSetEntry((NamedParameterNode<Set<T>>) n, value); 163 return this; 164 } 165 166 @SuppressWarnings("unchecked") 167 @Override 168 public <T> JavaConfigurationBuilder bindSetEntry( 169 final Class<? extends Name<Set<T>>> iface, final Class<? extends T> impl) throws BindException { 170 final Node n = getNode(iface); 171 final Node m = getNode(impl); 172 173 if (!(n instanceof NamedParameterNode)) { 174 throw new BindException("BindSetEntry got an interface that resolved to " + n + "; expected a NamedParameter"); 175 } 176 final Type setType = ReflectionUtilities.getInterfaceTarget(Name.class, iface); 177 if (!ReflectionUtilities.getRawClass(setType).equals(Set.class)) { 178 throw new BindException("BindSetEntry got a NamedParameter that takes a " + setType + "; expected Set<...>"); 179 } 180 final Type valType = ReflectionUtilities.getInterfaceTarget(Set.class, setType); 181 if (!ReflectionUtilities.getRawClass(valType).isAssignableFrom(impl)) { 182 throw new BindException("BindSetEntry got implementation " + impl + 183 " that is incompatible with expected type " + valType); 184 } 185 186 super.bindSetEntry((NamedParameterNode<Set<T>>) n, m); 187 return this; 188 } 189 190 /** 191 * Binding list method for JavaConfigurationBuilder. It checks the type of a given named parameter, 192 * and whether all the list's elements can be applied to the named parameter. The elements' type 193 * should be either java Class or String. 194 * <p> 195 * It does not check whether the list's String values can be parsed to T, like bindSetEntry. 196 * 197 * @param iface target named parameter to be instantiated 198 * @param implList implementation list used to instantiate the named parameter 199 * @param <T> type of the list 200 * @return bound JavaConfigurationBuilder object 201 * @throws BindException 202 */ 203 @SuppressWarnings("unchecked") 204 @Override 205 public <T> JavaConfigurationBuilder bindList(final Class<? extends Name<List<T>>> iface, final List implList) 206 throws BindException { 207 final Node n = getNode(iface); 208 final List<Object> result = new ArrayList<>(); 209 210 if (!(n instanceof NamedParameterNode)) { 211 throw new BindException("BindList got an interface that resolved to " + n + "; expected a NamedParameter"); 212 } 213 final Type listType = ReflectionUtilities.getInterfaceTarget(Name.class, iface); 214 if (!ReflectionUtilities.getRawClass(listType).equals(List.class)) { 215 throw new BindException("BindList got a NamedParameter that takes a " + listType + "; expected List<...>"); 216 } 217 if (!implList.isEmpty()) { 218 final Type valType = ReflectionUtilities.getInterfaceTarget(List.class, listType); 219 for (final Object item : implList) { 220 if (item instanceof Class) { 221 if (!ReflectionUtilities.getRawClass(valType).isAssignableFrom((Class) item)) { 222 throw new BindException("BindList got a list element which is not assignable to the given Type; " + 223 "expected: " + valType); 224 } 225 result.add(getNode((Class) item)); 226 } else if (item instanceof String) { 227 result.add(item); 228 } else { 229 throw new BindException("BindList got an list element with unsupported type; expected Class or String " + 230 "object"); 231 } 232 } 233 } 234 235 super.bindList((NamedParameterNode<List<T>>) n, result); 236 return this; 237 } 238 239 private class JavaConfigurationImpl extends ConfigurationImpl { 240 JavaConfigurationImpl(final JavaConfigurationBuilderImpl builder) { 241 super(builder); 242 } 243 } 244}