com.microsoft.windowsazure.services.core.DefaultBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of microsoft-windowsazure-api Show documentation
Show all versions of microsoft-windowsazure-api Show documentation
API for Microsoft Windows Azure Clients
/**
* Copyright Microsoft Corporation
*
* Licensed 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 com.microsoft.windowsazure.services.core;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import javax.inject.Inject;
import javax.inject.Named;
public class DefaultBuilder implements Builder, Builder.Registry {
Map, Factory>> factories;
Map, List>> alterations;
public DefaultBuilder() {
factories = new HashMap, Factory>>();
alterations = new HashMap, List>>();
}
public static DefaultBuilder create() {
DefaultBuilder builder = new DefaultBuilder();
for (Builder.Exports exports : ServiceLoader.load(Builder.Exports.class)) {
exports.register(builder);
}
return builder;
}
void addFactory(Class> service, Factory> factory) {
factories.put(service, factory);
}
public Builder.Registry add(Class service) {
return add(service, service);
}
Constructor> findInjectConstructor(Class> implementation) {
Constructor> withInject = null;
Constructor> withoutInject = null;
int count = 0;
for (Constructor> ctor : implementation.getConstructors()) {
if (ctor.getAnnotation(Inject.class) != null) {
if (withInject != null) {
throw new RuntimeException("Class must not have multple @Inject annotations: "
+ implementation.getName());
}
withInject = ctor;
}
else {
++count;
withoutInject = ctor;
}
}
if (withInject != null) {
return withInject;
}
if (count != 1) {
throw new RuntimeException("Class without @Inject annotation must have one constructor: "
+ implementation.getName());
}
return withoutInject;
}
public Builder.Registry add(Class service, final Class implementation) {
final Constructor> ctor = findInjectConstructor(implementation);
final Class>[] parameterTypes = ctor.getParameterTypes();
final Annotation[][] parameterAnnotations = ctor.getParameterAnnotations();
addFactory(service, new Builder.Factory() {
@SuppressWarnings("unchecked")
public T create(String profile, Builder builder, Map properties) {
Object[] initargs = new Object[parameterTypes.length];
for (int i = 0; i != parameterTypes.length; ++i) {
boolean located = false;
String named = findNamedAnnotation(parameterAnnotations[i]);
String fullName = dotCombine(profile, named);
boolean probeProperties = fullName != null && fullName != "";
int startingIndex = 0;
while (!located && probeProperties) {
String probeName = fullName.substring(startingIndex);
if (!located && named != null && properties.containsKey(probeName)) {
located = true;
initargs[i] = properties.get(probeName);
}
else {
startingIndex = fullName.indexOf('.', startingIndex) + 1;
if (startingIndex == 0) {
probeProperties = false;
}
}
}
if (!located) {
located = true;
initargs[i] = builder.build(fullName, parameterTypes[i], properties);
}
}
try {
return (T) ctor.newInstance(initargs);
}
catch (InstantiationException e) {
throw new ConfigurationException(e);
}
catch (IllegalAccessException e) {
throw new ConfigurationException(e);
}
catch (InvocationTargetException e) {
throw new ConfigurationException(e);
}
}
});
return this;
}
protected String dotCombine(String profile, String named) {
boolean noProfile = profile == null || profile == "";
boolean noName = named == null || named == "";
if (noName)
return profile;
if (noProfile)
return named;
return profile + "." + named;
}
protected String findNamedAnnotation(Annotation[] annotations) {
for (Annotation annotation : annotations) {
if (Named.class.isAssignableFrom(annotation.getClass())) {
return ((Named) annotation).value();
}
}
return null;
}
public Registry add(Factory factory) {
for (Type genericInterface : factory.getClass().getGenericInterfaces()) {
ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
if (parameterizedType.getRawType().equals(Builder.Factory.class)) {
Type typeArgument = parameterizedType.getActualTypeArguments()[0];
addFactory((Class>) typeArgument, factory);
}
}
return this;
}
@SuppressWarnings("unchecked")
public T build(String profile, Class service, Map properties) {
Factory factory = (Factory) factories.get(service);
if (factory == null) {
throw new RuntimeException("Service or property not registered: " + profile + " " + service.getName());
}
T instance = factory.create(profile, this, properties);
List> alterationList = alterations.get(service);
if (alterationList != null) {
for (Alteration> alteration : alterationList) {
instance = ((Alteration) alteration).alter(instance, this, properties);
}
}
return instance;
}
public void alter(Class service, Alteration alteration) {
if (!this.alterations.containsKey(service)) {
this.alterations.put(service, new ArrayList>());
}
this.alterations.get(service).add(alteration);
}
}