/*
* Copyright (C) 2015 Red Hat, Inc. and/or its affiliates.
*
* 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 org.jboss.errai.ioc.client.container;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* @see ContextManager
* @author Max Barkley <mbarkley@redhat.com>
*/
public class ContextManagerImpl implements ContextManager {
private final Map<String, Context> contextsByFactoryName = new HashMap<String, Context>();
private final Collection<Context> contexts = new ArrayList<Context>();
@Override
public void addContext(final Context context) {
if (!contexts.contains(context)) {
contexts.add(context);
context.setContextManager(this);
for (final Factory<?> factory : context.getAllFactories()) {
contextsByFactoryName.put(factory.getHandle().getFactoryName(), context);
}
}
}
@Override
public <T> T getInstance(final String factoryName) {
return getContext(factoryName).getInstance(factoryName);
}
@Override
public <T> T getContextualInstance(final String factoryName, final Class<?>[] typeArgs, final Annotation[] qualifiers) {
return getContext(factoryName)
.withContextualInstanceSupport()
.orElseThrow(() -> new RuntimeException("The scope, " + getClass().getSimpleName() + ", does not support contextual instances."))
.getContextualInstance(factoryName, typeArgs, qualifiers);
}
private Context getContext(final String factoryName) {
final Context context = contextsByFactoryName.get(factoryName);
if (context == null) {
throw new RuntimeException("Could not find a context for the factory " + factoryName);
} else {
return context;
}
}
@SuppressWarnings("unchecked")
@Override
public <T> T getEagerInstance(final String factoryName) {
final T instance = getContext(factoryName).<T>getInstance(factoryName);
if ((instance instanceof Proxy)) {
((Proxy<T>) instance).unwrap();
}
return instance;
}
@Override
public <T> T getNewInstance(final String factoryName) {
return getContext(factoryName).getNewInstance(factoryName);
}
@Override
public Collection<FactoryHandle> getAllFactoryHandles() {
final Collection<FactoryHandle> allHandles = new ArrayList<FactoryHandle>();
for (final Context context : contexts) {
for (final Factory<?> factory : context.getAllFactories()) {
allHandles.add(factory.getHandle());
}
}
return allHandles;
}
@Override
public void destroy(final Object instance) {
for (final Context context : contexts) {
context.destroyInstance(instance);
}
}
@Override
public boolean isManaged(final Object ref) {
for (final Context context : contexts) {
if (context.isManaged(ref)) {
return true;
}
}
return false;
}
@Override
public boolean addDestructionCallback(final Object instance, final DestructionCallback<?> callback) {
boolean success = false;
for (final Context context : contexts) {
success = success || context.addDestructionCallback(instance, callback);
}
return success;
}
@Override
public <P> P getInstanceProperty(final Object instance, final String propertyName, final Class<P> type) {
for (final Context context : contexts) {
if (context.isManaged(instance)) {
return context.getInstanceProperty(instance, propertyName, type);
}
}
throw new RuntimeException("The given instance, " + instance + ", is not managed.");
}
@Override
public void finishInit() {
for (final Context context : contexts) {
for (final Factory<?> factory : context.getAllFactories()) {
factory.init(context);
}
}
}
@Override
public void addFactory(final Factory<?> factory) {
final Context context = getContextForScope(factory.getHandle().getScope());
context.registerFactory(factory);
contextsByFactoryName.put(factory.getHandle().getFactoryName(), context);
factory.init(context);
}
private Context getContextForScope(final Class<? extends Annotation> scope) {
for (final Context context : contexts) {
if (context.handlesScope(scope)) {
return context;
}
}
throw new RuntimeException("Could not find context for the scope " + scope.getName());
}
}