/*
* Copyright 2013 eXo Platform SAS
*
* 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 juzu.impl.inject.spi;
import juzu.impl.inject.ScopeController;
import java.io.Closeable;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.NoSuchElementException;
/** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
public abstract class InjectionContext<B, C> implements Closeable {
public abstract ScopeController getScopeController();
/**
* Returns the injector provider.
*
* @return the injector provider
*/
public abstract InjectorProvider getProvider();
public abstract ClassLoader getClassLoader();
public abstract B resolveBean(Class<?> type);
public abstract B resolveBean(String name);
public abstract Iterable<B> resolveBeans(Class<?> type);
/**
* Create a bean context for the specified bean.
*
* @param bean the bean
* @return the bean context
* @throws InvocationTargetException wrap any exception thrown by the bean class during its creation.
*/
public abstract C createContext(B bean) throws InvocationTargetException;
/**
* Resolve the specified bean context.
*
* @param bean the bean
* @param context the bean context
*/
public abstract void releaseContext(B bean, C context);
/**
* Get the bean object associated the bean instance.
*
* @param bean the bean
* @param context the bean instance
* @return the bean instance
* @throws InvocationTargetException wrap any exception throws,by the bean class during its creation.
*/
public abstract Object getInstance(B bean, C context) throws InvocationTargetException;
/**
* Close the manager. The implementation should care bout shutting down the existing bean in particular the
* singleton beans that are managed outside of an explicit scope.
*/
public abstract void close();
private static class BeanLifeCycleImpl<B,C,I> implements BeanLifeCycle<I> {
final Class<I> type;
final InjectionContext<B, C> manager;
final B a;
private C context;
private I instance;
private BeanLifeCycleImpl(Class<I> type, InjectionContext<B, C> manager, B a) {
this.type = type;
this.manager = manager;
this.a = a;
}
public I get() throws InvocationTargetException {
if (instance == null) {
context = manager.createContext(a);
instance = type.cast(manager.getInstance(a, context));
}
return instance;
}
public I peek() {
return instance;
}
public void close() {
if (context != null) {
manager.releaseContext(a, context);
}
}
}
public final <T> BeanLifeCycle<T> get(Class<T> type) {
final B a = resolveBean(type);
if (a == null) {
return null;
} else {
return new BeanLifeCycleImpl<B, C,T>(type, this, a);
}
}
public final <T> Iterable<BeanLifeCycle<T>> resolve(final Class<T> type) {
final Iterable<B> a = resolveBeans(type);
return new Iterable<BeanLifeCycle<T>>() {
public Iterator<BeanLifeCycle<T>> iterator() {
return new Iterator<BeanLifeCycle<T>>() {
final Iterator<B> i = a.iterator();
public boolean hasNext() {
return i.hasNext();
}
public BeanLifeCycle<T> next() {
B b = i.next();
return new BeanLifeCycleImpl<B, C,T>(type, InjectionContext.this, b);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
public final <T> T resolveInstance(Class<T> beanType) {
try {
BeanLifeCycle<T> pluginLifeCycle = get(beanType);
return pluginLifeCycle != null ? pluginLifeCycle.get() : null;
}
catch (InvocationTargetException e) {
// log.log("Could not retrieve bean of type " + beanType, e.getCause());
return null;
}
}
public final <T> Iterable<T> resolveInstances(final Class<T> beanType) {
return new Iterable<T>() {
Iterable<BeanLifeCycle<T>> lifecycles = resolve(beanType);
public Iterator<T> iterator() {
return new Iterator<T>() {
Iterator<BeanLifeCycle<T>> iterator = lifecycles.iterator();
T next = null;
public boolean hasNext() {
while (next == null && iterator.hasNext()) {
try {
BeanLifeCycle<T> pluginLifeCycle = iterator.next();
next = pluginLifeCycle.get();
}
catch (InvocationTargetException e) {
// log.log("Could not retrieve bean of type " + beanType.getName(), e);
}
}
return next != null;
}
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
} else {
T tmp = next;
next = null;
return tmp;
}
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
}