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; 020 021import org.apache.reef.tang.exceptions.BindException; 022import org.apache.reef.tang.types.ClassNode; 023import org.apache.reef.tang.types.ConstructorArg; 024import org.apache.reef.tang.types.NamedParameterNode; 025import org.apache.reef.tang.types.Node; 026 027import java.util.List; 028import java.util.Set; 029 030/** 031 * This class allows applications to register bindings with Tang. Tang 032 * configurations are simply sets of bindings of various types. The most 033 * common bindings are of interfaces (or superclasses) to implementation 034 * classes, and of configuration options ("NamedParameters") to values. 035 * <p> 036 * Implementations of this class type check the bindings against an underlying 037 * ClassHierarchy implementation. Typically, the backing ClassHierarchy will 038 * be delegate to the default classloader (the one that loaded the code that is 039 * invoking Tang), though other scenarios are possible. For instance, the 040 * ClassHierarchy could incorporate additional Jars, or it might not delegate 041 * to the default classloader at all. In fact, Tang supports ClassHierarchy 042 * objects that are derived from reflection data from other languages, such as 043 * C#. This enables cross-language injection sessions, where Java code 044 * configures C# code, or vice versa. 045 * <p> 046 * When possible, the methods in this interface eagerly check for these 047 * errors. Methods that check for configuration and other runtime or 048 * application-level errors are declared to throw BindException. 049 * <p> 050 * Furthermore, all methods in Tang, may throw RuntimeException if they 051 * encounter inconsistencies in the underlying ClassHierarchy. Such errors 052 * reflect problems that existed when the application was compiled or 053 * packaged, and cannot be corrected at runtime. Examples include 054 * inconsistent type hierarchies (such as version mismatches between jars), 055 * and unparsable default values (such as an int that defaults to "false" 056 * or "five"). These exceptions are analogous to the runtime exceptions 057 * thrown by the Java classloader; other than logging them or reporting them 058 * to an end user, applications have little recourse when such problems are 059 * encountered. 060 * 061 * @see JavaConfigurationBuilder for convenience methods that assume the 062 * underlying ClassHierarchy object delegates to the default 063 * classloader, and enable many compile time static checks. 064 * @see org.apache.reef.tang.formats.ConfigurationModule which pushes additional type checks to class load 065 * time. This allows Tint, Tang's static analysis tool, to detect a wide 066 * range of runtime configuration errors at build time. 067 */ 068public interface ConfigurationBuilder { 069 070 /** 071 * Add all configuration parameters from the given Configuration object. 072 * 073 * @param c the configuration to be added 074 */ 075 void addConfiguration(final Configuration c) throws BindException; 076 077 /** 078 * Each ConfigurationBuilder instance is associated with a ClassHierarchy. 079 * It uses this ClassHierarchy to validate the configuration options that it 080 * processes. 081 * 082 * @return a reference to the ClassHierarchy instance backing this 083 * ConfigurationBuilder. No copy is made, since ClassHierarchy objects 084 * are effectively immutable. 085 */ 086 ClassHierarchy getClassHierarchy(); 087 088 /** 089 * Force Tang to treat the specified constructor as though it had an @Inject 090 * annotation. 091 * <p> 092 * This method takes ClassNode objects. Like all of the methods in this 093 * API, the ClassNode objects must come from the ClassHierarchy instance 094 * returned by getClassHierarchy(). 095 * 096 * @param cn The class the constructor instantiates. 097 * @param args The types of the arguments taken by the constructor, in declaration order. 098 * @throws BindException if the constructor does not exist, or if it has already been bound as a legacy constructor. 099 */ 100 void registerLegacyConstructor(ClassNode<?> cn, ClassNode<?>... args) 101 throws BindException; 102 103 /** 104 * Force Tang to treat the specified constructor as though it had an @Inject 105 * annotation. 106 * 107 * @param cn The full name of the class the constructor instantiates. 108 * @param args The full names of the types of the arguments taken by the constructor, in declaration order. 109 * @throws BindException if the constructor does not exist, or if it has already been bound as a legacy constructor. 110 */ 111 void registerLegacyConstructor(String cn, String... args) 112 throws BindException; 113 114 /** 115 * Force Tang to treat the specified constructor as though it had an @Inject 116 * annotation. 117 * <p> 118 * This method takes ClassNode and ConstructorArg objects. Like all of the 119 * methods in this API, these objects must come from the ClassHierarchy 120 * instance returned by getClassHierarchy(). 121 * 122 * @param c The class the constructor instantiates. 123 * @param args The parsed ConstructorArg objects corresponding to the types of the arguments taken by the constructor, 124 * in declaration order. 125 * @throws BindException if the constructor does not exist, or if it has already been bound as a legacy constructor. 126 */ 127 void registerLegacyConstructor(ClassNode<?> c, ConstructorArg... args) 128 throws BindException; 129 130 /** 131 * Bind classes to each other, based on their full class names; alternatively, 132 * bound a NamedParameter configuration option to a configuration value. 133 * 134 * @param <T> a type 135 * @param iface The full name of the interface that should resolve to impl, 136 * or the NamedParameter to be set. 137 * @param impl The full name of the implementation that will be used in 138 * place of impl, or the value the NamedParameter should be set to. 139 * @throws BindException If (In the case of interfaces and implementations) 140 * the underlying ClassHierarchy does not recognise iface and 141 * impl as known, valid classes, or if impl is not a in 142 * implementation of iface, or (in the case of NamedParameters 143 * and values) if iface is not a NamedParameter, or if impl 144 * fails to parse as the type the iface expects. 145 */ 146 <T> void bind(String iface, String impl) 147 throws BindException; 148 149 /** 150 * Bind classes to each other, based on their full class names; alternatively, 151 * bound a NamedParameter configuration option to a configuration value. 152 * <p> 153 * This method takes Node objects. Like all of the methods in this API, 154 * these objects must come from the ClassHierarchy instance returned by 155 * getClassHierarchy(). 156 * 157 * @param iface The interface / NamedParameter to be bound. 158 * @param impl The implementation / value iface should be set to. 159 * @throws BindException if there is a type checking error 160 * See {@link #bind(String, String) bind(String,String)} for a more complete description. 161 */ 162 void bind(Node iface, Node impl) throws BindException; 163 164 /** 165 * Register an ExternalConstructor implementation with Tang. 166 * ExternalConstructors are proxy classes that instantiate some 167 * other class. They have two primary use cases: (1) adding new 168 * constructors to classes that you cannot modify and (2) implementing 169 * constructors that examine their arguments and return an instance of a 170 * subclass of the requested object. 171 * <p> 172 * To see how the second use case could be useful, consider a implementing a 173 * URI interface with a distinct subclass for each valid URI prefix (e.g., 174 * http://, ssh://, etc...). An ExternalConstructor could examine the prefix 175 * and delegate to a constructor of the correct implementation (e.g, HttpURL, 176 * SshURL, etc...) which would validate the remainder of the provided string. 177 * URI's external constructor would return the validated subclass of URI that 178 * corresponds to the provided string, allowing instanceof and downcasts to 179 * behave as expected in the code that invoked Tang. 180 * <p> 181 * Both use cases should be avoided when possible, since they can 182 * unnecessarily complicate object injections and undermine Tang's ability 183 * to statically check a given configuration. 184 * <p> 185 * This method takes ClassNode objects. Like all of the methods in this API, 186 * these objects must come from the ClassHierarchy instance returned by 187 * getClassHierarchy(). 188 * 189 * @param <T> a type 190 * @param iface The class or interface to be instantiated. 191 * @param impl The ExternalConstructor class that will be used to instantiate iface. 192 * @throws BindException If impl does not instantiate a subclass of iface. 193 */ 194 <T> void bindConstructor(ClassNode<T> iface, 195 ClassNode<? extends ExternalConstructor<? extends T>> impl) 196 throws BindException; 197 198 /** 199 * Pretty print the default implementation / value of the provided class / NamedParameter. 200 * This is used by Tang to produce human readable error messages. 201 * 202 * @param longName a name of class or parameter 203 * @return a pretty-formatted string for class or named parameter 204 * @throws BindException if name resolution fails 205 */ 206 String classPrettyDefaultString(String longName) throws BindException; 207 208 /** 209 * Pretty print the human readable documentation of the provided class / NamedParameter. 210 * This is used by Tang to produce human readable error messages. 211 * 212 * @param longName a name of class or parameter 213 * @return a pretty-formatted class description string 214 * @throws BindException if name resolution fails 215 */ 216 String classPrettyDescriptionString(String longName) 217 throws BindException; 218 219 /** 220 * Produce an immutable Configuration object that contains the current 221 * bindings and ClassHierarchy of this ConfigurationBuilder. Future 222 * changes to this ConfigurationBuilder will not be reflected in the 223 * returned Configuration. 224 * <p> 225 * Since Tang eagerly checks for configuration errors, this method does not 226 * perform any additional validation, and does not throw any checkable 227 * exceptions. 228 * 229 * @return the Configuration 230 */ 231 Configuration build(); 232 233 <T> void bindSetEntry(NamedParameterNode<Set<T>> iface, Node impl) 234 throws BindException; 235 236 <T> void bindSetEntry(NamedParameterNode<Set<T>> iface, String impl) 237 throws BindException; 238 239 void bindSetEntry(String iface, String impl) throws BindException; 240 241 void bindSetEntry(String iface, Node impl) throws BindException; 242 243 /** 244 * Bind an list of implementations(Class or String) to an given NamedParameter. 245 * Unlike bindSetEntry, bindListEntry will bind a whole list to the parameter, 246 * not an element of the list. 247 * <p> 248 * Since ordering of the list is important, list binding cannot be repeated or 249 * merged unlike set binding. If the elements of the list are Classes, the objects 250 * created by the Classes will be injected. If the elements are Strings, the values 251 * will be injected directly to a given list parameter. 252 * 253 * @param <T> a type 254 * @param iface The list named parameter to be instantiated 255 * @param implList The list of class or value will be used to instantiated the named parameter 256 * @throws BindException if implementation class does not fit to the named parameter 257 */ 258 <T> void bindList(NamedParameterNode<List<T>> iface, List implList) throws BindException; 259 260 void bindList(String iface, List implList) throws BindException; 261 262}