blob: 8606ece9ec4a777e9f9372faed28cafdf56e0226 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.reef.tang;
import org.apache.reef.tang.exceptions.BindException;
import org.apache.reef.tang.types.ClassNode;
import org.apache.reef.tang.types.ConstructorArg;
import org.apache.reef.tang.types.NamedParameterNode;
import org.apache.reef.tang.types.Node;
import java.util.List;
import java.util.Set;
/**
* This class allows applications to register bindings with Tang. Tang
* configurations are simply sets of bindings of various types. The most
* common bindings are of interfaces (or superclasses) to implementation
* classes, and of configuration options ("NamedParameters") to values.
* <p>
* Implementations of this class type check the bindings against an underlying
* ClassHierarchy implementation. Typically, the backing ClassHierarchy will
* be delegate to the default classloader (the one that loaded the code that is
* invoking Tang), though other scenarios are possible. For instance, the
* ClassHierarchy could incorporate additional Jars, or it might not delegate
* to the default classloader at all. In fact, Tang supports ClassHierarchy
* objects that are derived from reflection data from other languages, such as
* C#. This enables cross-language injection sessions, where Java code
* configures C# code, or vice versa.
* <p>
* When possible, the methods in this interface eagerly check for these
* errors. Methods that check for configuration and other runtime or
* application-level errors are declared to throw BindException.
* <p>
* Furthermore, all methods in Tang, may throw RuntimeException if they
* encounter inconsistencies in the underlying ClassHierarchy. Such errors
* reflect problems that existed when the application was compiled or
* packaged, and cannot be corrected at runtime. Examples include
* inconsistent type hierarchies (such as version mismatches between jars),
* and unparsable default values (such as an int that defaults to "false"
* or "five"). These exceptions are analogous to the runtime exceptions
* thrown by the Java classloader; other than logging them or reporting them
* to an end user, applications have little recourse when such problems are
* encountered.
*
* @see JavaConfigurationBuilder for convenience methods that assume the
* underlying ClassHierarchy object delegates to the default
* classloader, and enable many compile time static checks.
* @see org.apache.reef.tang.formats.ConfigurationModule which pushes additional type checks to class load
* time. This allows Tint, Tang's static analysis tool, to detect a wide
* range of runtime configuration errors at build time.
*/
public interface ConfigurationBuilder {
/**
* Add all configuration parameters from the given Configuration object.
*
* @param c the configuration to be added
*/
void addConfiguration(Configuration c) throws BindException;
/**
* Each ConfigurationBuilder instance is associated with a ClassHierarchy.
* It uses this ClassHierarchy to validate the configuration options that it
* processes.
*
* @return a reference to the ClassHierarchy instance backing this
* ConfigurationBuilder. No copy is made, since ClassHierarchy objects
* are effectively immutable.
*/
ClassHierarchy getClassHierarchy();
/**
* Force Tang to treat the specified constructor as though it had an @Inject
* annotation.
* <p>
* This method takes ClassNode objects. Like all of the methods in this
* API, the ClassNode objects must come from the ClassHierarchy instance
* returned by getClassHierarchy().
*
* @param cn The class the constructor instantiates.
* @param args The types of the arguments taken by the constructor, in declaration order.
* @throws BindException if the constructor does not exist, or if it has already been bound as a legacy constructor.
*/
void registerLegacyConstructor(ClassNode<?> cn, ClassNode<?>... args)
throws BindException;
/**
* Force Tang to treat the specified constructor as though it had an @Inject
* annotation.
*
* @param cn The full name of the class the constructor instantiates.
* @param args The full names of the types of the arguments taken by the constructor, in declaration order.
* @throws BindException if the constructor does not exist, or if it has already been bound as a legacy constructor.
*/
void registerLegacyConstructor(String cn, String... args)
throws BindException;
/**
* Force Tang to treat the specified constructor as though it had an @Inject
* annotation.
* <p>
* This method takes ClassNode and ConstructorArg objects. Like all of the
* methods in this API, these objects must come from the ClassHierarchy
* instance returned by getClassHierarchy().
*
* @param c The class the constructor instantiates.
* @param args The parsed ConstructorArg objects corresponding to the types of the arguments taken by the constructor,
* in declaration order.
* @throws BindException if the constructor does not exist, or if it has already been bound as a legacy constructor.
*/
void registerLegacyConstructor(ClassNode<?> c, ConstructorArg... args)
throws BindException;
/**
* Bind classes to each other, based on their full class names; alternatively,
* bound a NamedParameter configuration option to a configuration value.
*
* @param <T> a type
* @param iface The full name of the interface that should resolve to impl,
* or the NamedParameter to be set.
* @param impl The full name of the implementation that will be used in
* place of impl, or the value the NamedParameter should be set to.
* @throws BindException If (In the case of interfaces and implementations)
* the underlying ClassHierarchy does not recognise iface and
* impl as known, valid classes, or if impl is not a in
* implementation of iface, or (in the case of NamedParameters
* and values) if iface is not a NamedParameter, or if impl
* fails to parse as the type the iface expects.
*/
<T> void bind(String iface, String impl)
throws BindException;
/**
* Bind classes to each other, based on their full class names; alternatively,
* bound a NamedParameter configuration option to a configuration value.
* <p>
* This method takes Node objects. Like all of the methods in this API,
* these objects must come from the ClassHierarchy instance returned by
* getClassHierarchy().
*
* @param iface The interface / NamedParameter to be bound.
* @param impl The implementation / value iface should be set to.
* @throws BindException if there is a type checking error
* See {@link #bind(String, String) bind(String,String)} for a more complete description.
*/
void bind(Node iface, Node impl) throws BindException;
/**
* Register an ExternalConstructor implementation with Tang.
* ExternalConstructors are proxy classes that instantiate some
* other class. They have two primary use cases: (1) adding new
* constructors to classes that you cannot modify and (2) implementing
* constructors that examine their arguments and return an instance of a
* subclass of the requested object.
* <p>
* To see how the second use case could be useful, consider a implementing a
* URI interface with a distinct subclass for each valid URI prefix (e.g.,
* http://, ssh://, etc...). An ExternalConstructor could examine the prefix
* and delegate to a constructor of the correct implementation (e.g, HttpURL,
* SshURL, etc...) which would validate the remainder of the provided string.
* URI's external constructor would return the validated subclass of URI that
* corresponds to the provided string, allowing instanceof and downcasts to
* behave as expected in the code that invoked Tang.
* <p>
* Both use cases should be avoided when possible, since they can
* unnecessarily complicate object injections and undermine Tang's ability
* to statically check a given configuration.
* <p>
* This method takes ClassNode objects. Like all of the methods in this API,
* these objects must come from the ClassHierarchy instance returned by
* getClassHierarchy().
*
* @param <T> a type
* @param iface The class or interface to be instantiated.
* @param impl The ExternalConstructor class that will be used to instantiate iface.
* @throws BindException If impl does not instantiate a subclass of iface.
*/
<T> void bindConstructor(ClassNode<T> iface,
ClassNode<? extends ExternalConstructor<? extends T>> impl)
throws BindException;
/**
* Pretty print the default implementation / value of the provided class / NamedParameter.
* This is used by Tang to produce human readable error messages.
*
* @param longName a name of class or parameter
* @return a pretty-formatted string for class or named parameter
* @throws BindException if name resolution fails
*/
String classPrettyDefaultString(String longName) throws BindException;
/**
* Pretty print the human readable documentation of the provided class / NamedParameter.
* This is used by Tang to produce human readable error messages.
*
* @param longName a name of class or parameter
* @return a pretty-formatted class description string
* @throws BindException if name resolution fails
*/
String classPrettyDescriptionString(String longName)
throws BindException;
/**
* Produce an immutable Configuration object that contains the current
* bindings and ClassHierarchy of this ConfigurationBuilder. Future
* changes to this ConfigurationBuilder will not be reflected in the
* returned Configuration.
* <p>
* Since Tang eagerly checks for configuration errors, this method does not
* perform any additional validation, and does not throw any checkable
* exceptions.
*
* @return the Configuration
*/
Configuration build();
<T> void bindSetEntry(NamedParameterNode<Set<T>> iface, Node impl)
throws BindException;
<T> void bindSetEntry(NamedParameterNode<Set<T>> iface, String impl)
throws BindException;
void bindSetEntry(String iface, String impl) throws BindException;
void bindSetEntry(String iface, Node impl) throws BindException;
/**
* Bind an list of implementations(Class or String) to an given NamedParameter.
* Unlike bindSetEntry, bindListEntry will bind a whole list to the parameter,
* not an element of the list.
* <p>
* Since ordering of the list is important, list binding cannot be repeated or
* merged unlike set binding. If the elements of the list are Classes, the objects
* created by the Classes will be injected. If the elements are Strings, the values
* will be injected directly to a given list parameter.
*
* @param <T> a type
* @param iface The list named parameter to be instantiated
* @param implList The list of class or value will be used to instantiated the named parameter
* @throws BindException if implementation class does not fit to the named parameter
*/
<T> void bindList(NamedParameterNode<List<T>> iface, List implList) throws BindException;
void bindList(String iface, List implList) throws BindException;
}