-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #110 from rchodava/rc/new-wiring
A fresh new and simpler approach to Wirings as a combination of a PropertySourceChain and a FactoryChain
- Loading branch information
Showing
48 changed files
with
2,576 additions
and
1,427 deletions.
There are no files selected for viewing
11 changes: 0 additions & 11 deletions
11
core/src/main/java/foundation/stack/datamill/configuration/Defaults.java
This file was deleted.
Oops, something went wrong.
29 changes: 29 additions & 0 deletions
29
core/src/main/java/foundation/stack/datamill/configuration/DelegatingPropertySource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package foundation.stack.datamill.configuration; | ||
|
||
import foundation.stack.datamill.configuration.impl.AbstractSource; | ||
|
||
import java.util.Optional; | ||
|
||
/** | ||
* @author Ravi Chodavarapu (rchodava@gmail.com) | ||
*/ | ||
public class DelegatingPropertySource extends AbstractSource { | ||
private volatile PropertySource delegate; | ||
|
||
public DelegatingPropertySource(PropertySource delegate) { | ||
setDelegate(delegate); | ||
} | ||
|
||
public DelegatingPropertySource() { | ||
this(null); | ||
} | ||
|
||
public void setDelegate(PropertySource delegate) { | ||
this.delegate = delegate; | ||
} | ||
|
||
@Override | ||
protected Optional<String> getOptional(String name) { | ||
return delegate != null ? delegate.get(name) : Optional.empty(); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
core/src/main/java/foundation/stack/datamill/configuration/Factory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package foundation.stack.datamill.configuration; | ||
|
||
import rx.functions.Func2; | ||
|
||
/** | ||
* A factory for constructing objects of particular types. Use {@link FactoryChains} to create factories and compose | ||
* them together into chains. Note that the contract of a factory is to return a fully constructed instance of the | ||
* requested type (it can use the provided {@link Wiring} to construct the instance, or return null if the factory | ||
* cannot construct an instance. | ||
* | ||
* @author Ravi Chodavarapu (rchodava@gmail.com) | ||
*/ | ||
@FunctionalInterface | ||
public interface Factory<T, R extends T> extends Func2<Wiring, Class<? extends T>, R> { | ||
static Factory<?, ?> wrap(TypeLessFactory<?> factory) { | ||
return (w, c) -> factory.call(w); | ||
} | ||
} |
74 changes: 74 additions & 0 deletions
74
core/src/main/java/foundation/stack/datamill/configuration/FactoryChain.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package foundation.stack.datamill.configuration; | ||
|
||
/** | ||
* A chain of object factories used by {@link Wiring}s to create objects. Use {@link FactoryChains} to create | ||
* {@link FactoryChain}s. | ||
* | ||
* @author Ravi Chodavarapu (rchodava@gmail.com) | ||
*/ | ||
public interface FactoryChain extends QualifyingFactory<Object, Object> { | ||
/** | ||
* Remove a factory from the chain, returning a chain without the specified factory. | ||
*/ | ||
FactoryChain exclude(QualifyingFactory<?, ?> factory); | ||
|
||
/** | ||
* Add a factory which will be used to attempt construction of instances for all types. | ||
*/ | ||
<T, R extends T> FactoryChain thenForAny(Factory<T, R> factory); | ||
|
||
/** | ||
* Add a factory which will be used to attempt construction of instances of concrete classes. | ||
*/ | ||
FactoryChain thenForAnyConcreteClass(); | ||
|
||
/** | ||
* Add a factory for a type, and it's super-classes and interfaces. Note that this factory will be invoked if the | ||
* type requested is exactly the specified type, or one of it's super-classes or interfaces. | ||
*/ | ||
<T> FactoryChain thenForSuperOf(Class<T> type, Factory<T, ?> factory); | ||
|
||
/** | ||
* Add a factory for a specific type. Note that this factory is only invoked if the type being constructed matches | ||
* the exact type specified. | ||
* | ||
* @param type Exact type for which the specified factory will be used. | ||
*/ | ||
<T, R extends T> FactoryChain thenForType(Class<T> type, Factory<T, R> factory); | ||
|
||
/** | ||
* @see #thenForAny(Factory) | ||
*/ | ||
<R> FactoryChain thenForAny(TypeLessFactory<R> factory); | ||
|
||
/** | ||
* @see #thenForSuperOf(Class, Factory) | ||
*/ | ||
<T> FactoryChain thenForSuperOf(Class<T> type, TypeLessFactory<?> factory); | ||
|
||
/** | ||
* @see #thenForType(Class, Factory) | ||
*/ | ||
<T, R extends T> FactoryChain thenForType(Class<T> type, TypeLessFactory<R> factory); | ||
|
||
/** | ||
* Add a qualifying factory which will be used to attempt construction of instances for all types. | ||
* | ||
* @see #thenForAny(Factory) | ||
*/ | ||
<T, R extends T> FactoryChain thenForAny(QualifyingFactory<T, R> factory); | ||
|
||
/** | ||
* Add a qualifying factory for a type, and it's super-classes and interfaces. | ||
* | ||
* @see #thenForSuperOf(Class, Factory) | ||
*/ | ||
<T> FactoryChain thenForSuperOf(Class<T> type, QualifyingFactory<T, ?> factory); | ||
|
||
/** | ||
* Add a qualifying factory for a specific type. | ||
* | ||
* @see #thenForType(Class, Factory) | ||
*/ | ||
<T, R extends T> FactoryChain thenForType(Class<T> type, QualifyingFactory<T, R> factory); | ||
} |
124 changes: 124 additions & 0 deletions
124
core/src/main/java/foundation/stack/datamill/configuration/FactoryChains.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package foundation.stack.datamill.configuration; | ||
|
||
import foundation.stack.datamill.configuration.impl.ConcreteClassFactory; | ||
import foundation.stack.datamill.configuration.impl.FactoryChainImpl; | ||
|
||
/** | ||
* <p> | ||
* Use this class to create{@link FactoryChain}s. For example, consider a chain composed and used as follows: | ||
* <p/> | ||
* <pre> | ||
* chain = FactoryChains.forType(DatabaseClient.class, w -> createDatabaseClient()) | ||
* .thenForSuperOf(UserRepository.class, w -> new UserRepository(...)) | ||
* .thenForAny(Core.FACTORY) | ||
* .thenForAnyConcreteClass(); | ||
* </pre> | ||
* <p> | ||
* This chain will first check if the class requested is a DatabaseClient, and if so, will construct it. Then, it will | ||
* check if the class requested is a super-class or interface of the UserRepository class, and if so will construct it. | ||
* Then, it will delegate to the Core.FACTORY factory chain. Finally, if none of those factories are able to construct | ||
* the requested instance, the chain will ask the concrete class factory to construct an instance. | ||
* <p/> | ||
* <p> | ||
* Note that if you do not add the concrete class factory at the end of a chain, your chain will only construct the | ||
* exact types for which your factories can construct instances. Thus, it is often useful to add the concrete class | ||
* factory to the end of a factory chain. | ||
* </p> | ||
* <p> | ||
* Note that it is easy to construct factory chains that result in infinite recursion. For example, consider the | ||
* following: | ||
* </p> | ||
* <pre> | ||
* chain = FactoryChains.forSuperOf(EmailService.class, w -> w.singleton(EmailService.class)) | ||
* .thenForAnyConcreteClass(); | ||
* | ||
* new Wiring(chain).singleton(EmailService.class); | ||
* </pre> | ||
* <p> | ||
* If the chain is used in this way to construct an instance of the EmailService class (a concrete class), the first | ||
* factory in the chain is used. This results in turn to a call to the wiring to construct a singleton instance of | ||
* EmailService. The Wiring will use the same chain, starting at the beginning of the chain. This will again result | ||
* in the first factory in the chain to be used, and would lead to an infinite recursion. To solve this, when a particular | ||
* factory in the chain in turn uses the Wiring to construct an instance, the factory will be excluded from the chain in | ||
* the next call. This will essentially break the infinite recursion - the call to construct the EmailService from the | ||
* first factory in the chain will go directly to the concrete class factory in the second pass through the chain. | ||
* </p> | ||
* <p> | ||
* Note that factory chains are immutable, and each of the chaining methods returns a new chain with the additional | ||
* factory added. This allows you to have common chains which you can combine in different ways, because each | ||
* of those combinations is a new chain. | ||
* </p> | ||
* | ||
* @author Ravi Chodavarapu (rchodava@gmail.com) | ||
*/ | ||
public class FactoryChains { | ||
/** | ||
* @see FactoryChain#thenForAnyConcreteClass() | ||
*/ | ||
public static FactoryChain forAnyConcreteClass() { | ||
return forAny(ConcreteClassFactory.instance()); | ||
} | ||
|
||
/** | ||
* @see FactoryChain#thenForAny(Factory) | ||
*/ | ||
public static <T, R extends T> FactoryChain forAny(Factory<T, R> factory) { | ||
return new FactoryChainImpl(FactoryChainImpl.tautology(), factory); | ||
} | ||
|
||
/** | ||
* @see FactoryChain#thenForSuperOf(Class, Factory) | ||
*/ | ||
public static FactoryChain forSuperOf(Class<?> type, Factory<?, ?> factory) { | ||
return new FactoryChainImpl(FactoryChainImpl.isSuperOf(type), factory); | ||
} | ||
|
||
/** | ||
* @see FactoryChain#thenForType(Class, Factory) | ||
*/ | ||
public static <T, R extends T> FactoryChain forType(Class<T> type, Factory<T, R> factory) { | ||
return new FactoryChainImpl(FactoryChainImpl.isExactType(type), factory); | ||
} | ||
|
||
/** | ||
* @see FactoryChain#thenForAny(QualifyingFactory) | ||
*/ | ||
public static <T, R extends T> FactoryChain forAny(QualifyingFactory<T, R> factory) { | ||
return new FactoryChainImpl(FactoryChainImpl.tautology(), factory); | ||
} | ||
|
||
/** | ||
* @see FactoryChain#thenForSuperOf(Class, QualifyingFactory) | ||
*/ | ||
public static FactoryChain forSuperOf(Class<?> type, QualifyingFactory<?, ?> factory) { | ||
return new FactoryChainImpl(FactoryChainImpl.isSuperOf(type), factory); | ||
} | ||
|
||
/** | ||
* @see FactoryChain#thenForType(Class, QualifyingFactory) | ||
*/ | ||
public static <T, R extends T> FactoryChain forType(Class<T> type, QualifyingFactory<T, R> factory) { | ||
return new FactoryChainImpl(FactoryChainImpl.isExactType(type), factory); | ||
} | ||
|
||
/** | ||
* @see FactoryChain#thenForAny(TypeLessFactory) | ||
*/ | ||
public static <R> FactoryChain forAny(TypeLessFactory<R> factory) { | ||
return new FactoryChainImpl(FactoryChainImpl.tautology(), factory); | ||
} | ||
|
||
/** | ||
* @see FactoryChain#thenForSuperOf(Class, TypeLessFactory) | ||
*/ | ||
public static FactoryChain forSuperOf(Class<?> type, TypeLessFactory<?> factory) { | ||
return new FactoryChainImpl(FactoryChainImpl.isSuperOf(type), factory); | ||
} | ||
|
||
/** | ||
* @see FactoryChain#thenForType(Class, TypeLessFactory) | ||
*/ | ||
public static <T, R extends T> FactoryChain forType(Class<T> type, TypeLessFactory<R> factory) { | ||
return new FactoryChainImpl(FactoryChainImpl.isExactType(type), factory); | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
core/src/main/java/foundation/stack/datamill/configuration/ImmediatePropertySource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package foundation.stack.datamill.configuration; | ||
|
||
/** | ||
* Used in defining an immediate immutable set of properties. | ||
* | ||
* @see PropertySources | ||
* @author Ravi Chodavarapu (rchodava@gmail.com) | ||
*/ | ||
public interface ImmediatePropertySource { | ||
ImmediatePropertySource put(String name, String value); | ||
|
||
/** | ||
* Add a formatted value to the immediate set of properties. Uses the | ||
* {@link java.text.MessageFormat#format(String, Object...)} method to format the value. | ||
*/ | ||
ImmediatePropertySource put(String name, String format, Object... arguments); | ||
} |
10 changes: 0 additions & 10 deletions
10
core/src/main/java/foundation/stack/datamill/configuration/Module.java
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 0 additions & 48 deletions
48
core/src/main/java/foundation/stack/datamill/configuration/Properties.java
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.