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