com.speedment.common.injector.internal.InjectorBuilderImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of runtime-deploy Show documentation
Show all versions of runtime-deploy Show documentation
A Speedment bundle that shades all dependencies into one jar. This is
useful when deploying an application on a server.
/**
*
* Copyright (c) 2006-2019, Speedment, Inc. All Rights Reserved.
*
* 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.speedment.common.injector.internal;
import com.speedment.common.injector.InjectBundle;
import com.speedment.common.injector.Injector;
import com.speedment.common.injector.InjectorBuilder;
import com.speedment.common.injector.State;
import com.speedment.common.injector.annotation.Config;
import com.speedment.common.injector.annotation.Inject;
import com.speedment.common.injector.annotation.InjectKey;
import com.speedment.common.injector.annotation.WithState;
import com.speedment.common.injector.dependency.DependencyGraph;
import com.speedment.common.injector.dependency.DependencyNode;
import com.speedment.common.injector.exception.NoDefaultConstructorException;
import com.speedment.common.injector.exception.NotInjectableException;
import com.speedment.common.injector.execution.Execution;
import com.speedment.common.injector.execution.Execution.ClassMapper;
import com.speedment.common.injector.execution.ExecutionBuilder;
import com.speedment.common.injector.internal.dependency.DependencyGraphImpl;
import static com.speedment.common.injector.internal.util.InjectorUtil.findIn;
import static com.speedment.common.injector.internal.util.PrintUtil.horizontalLine;
import static com.speedment.common.injector.internal.util.PrintUtil.limit;
import static com.speedment.common.injector.internal.util.PropertiesUtil.loadProperties;
import static com.speedment.common.injector.internal.util.ReflectionUtil.newInstance;
import static com.speedment.common.injector.internal.util.ReflectionUtil.traverseAncestors;
import static com.speedment.common.injector.internal.util.ReflectionUtil.traverseFields;
import com.speedment.common.logger.Level;
import com.speedment.common.logger.Logger;
import com.speedment.common.logger.LoggerManager;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import static java.util.Objects.requireNonNull;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toSet;
/**
* Default implementation of the {@link InjectorBuilder}-interface.
*
* @author Emil Forslund
* @since 1.2.0
*/
public final class InjectorBuilderImpl implements InjectorBuilder {
public final static Logger LOGGER_INSTANCE =
LoggerManager.getLogger(InjectorBuilderImpl.class);
private final ClassLoader classLoader;
private final Map>> injectables;
private final List> executions;
private final Map overriddenParams;
private Path configFileLocation;
InjectorBuilderImpl() {
this(defaultClassLoader(), Collections.emptySet());
}
InjectorBuilderImpl(ClassLoader classLoader) {
this(classLoader, Collections.emptySet());
}
InjectorBuilderImpl(Set> injectables) {
this(defaultClassLoader(), injectables);
}
InjectorBuilderImpl(ClassLoader classLoader, Set> injectables) {
requireNonNull(injectables);
this.classLoader = requireNonNull(classLoader);
this.injectables = new LinkedHashMap<>();
this.executions = new LinkedList<>();
this.overriddenParams = new HashMap<>();
this.configFileLocation = Paths.get("settings.properties");
injectables.forEach(this::withComponent);
}
@Override
public InjectorBuilder withComponent(Class injectableType) {
requireNonNull(injectableType);
// Store the injectable under every superclass in the map, as well
// as under every inherited InjectorKey value.
traverseAncestors(injectableType)
// only include classes that has an ancestor with the
// InjectorKey-annotation, or that are the original class.
.filter(c -> c == injectableType || traverseAncestors(c)
.anyMatch(c2 -> c2.isAnnotationPresent(InjectKey.class))
)
.forEachOrdered(c -> {
// Store it under the class name itself
appendInjectable(c.getName(), injectableType, true);
// Include InjectorKey value
if (c.isAnnotationPresent(InjectKey.class)) {
final InjectKey key = c.getAnnotation(InjectKey.class);
appendInjectable(
key.value().getName(),
injectableType,
key.overwrite()
);
}
});
return this;
}
@Override
public InjectorBuilder withBundle(Class bundleClass) {
try {
final InjectBundle bundle = bundleClass.newInstance();
bundle.injectables().forEach(this::withComponent);
} catch (IllegalAccessException | InstantiationException e) {
throw new NoDefaultConstructorException(e);
}
return this;
}
@Override
public InjectorBuilder withConfigFileLocation(Path configFile) {
this.configFileLocation = requireNonNull(configFile);
return this;
}
@Override
public InjectorBuilder withParam(String name, String value) {
overriddenParams.put(name, value);
return this;
}
@Override
public InjectorBuilder before(ExecutionBuilder executionBuilder) {
executions.add(requireNonNull(executionBuilder));
return this;
}
@Override
public Injector build()
throws InstantiationException, NoDefaultConstructorException {
// Load settings
final File configFile = configFileLocation.toFile();
final Properties properties = loadProperties(LOGGER_INSTANCE, configFile);
overriddenParams.forEach(properties::setProperty);
final Set> injectablesSet = unmodifiableSet(
injectables.values().stream()
.flatMap(List::stream)
.collect(toCollection(() -> new LinkedHashSet<>()))
);
final DependencyGraph graph =
DependencyGraphImpl.create(injectablesSet);
final LinkedList