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