/*
* ============================================================================
* GNU Lesser General Public License
* ============================================================================
*
* Beanlet - JSE Application Container.
* Copyright (C) 2006 Leon van Zantvoort
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Leon van Zantvoort
* 243 Acalanes Drive #11
* Sunnyvale, CA 94086
* USA
*
* zantvoort@users.sourceforge.net
* http://beanlet.org
*/
package org.beanlet.impl;
import java.util.ArrayList;
import static org.beanlet.common.Beanlets.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.beanlet.BeanletApplicationContext;
import org.beanlet.BeanletApplicationException;
import org.beanlet.BeanletCreationException;
import org.beanlet.BeanletFactory;
import org.beanlet.BeanletNotFoundException;
import org.beanlet.BeanletNotOfRequiredTypeException;
import org.beanlet.BeanletReference;
import org.beanlet.Event;
import org.beanlet.FactoryBeanlet;
import org.beanlet.event.FactoryEvent;
import org.beanlet.metadata.FactoryMetaData;
import org.beanlet.plugin.BeanletEventFactory;
import org.jargo.ComponentApplicationContext;
import org.jargo.ComponentFactory;
import org.jargo.ComponentNotFoundException;
/**
*
* @author Leon van Zantvoort
*/
public final class BeanletApplicationContextImpl extends
BeanletApplicationContext {
private final BeanletEventFactory factory;
public BeanletApplicationContextImpl() {
this.factory = BeanletEventFactories.getInstance();
}
protected BeanletApplicationContext resolveInstance() throws
BeanletApplicationException {
ComponentApplicationContext.instance();
return this;
}
public void shutdown() {
ComponentApplicationContext.instance().shutdown();
}
public <T extends Event> T getEvent(Class<T> eventClass) {
return factory.getEvent(eventClass);
}
public Object getBeanlet(String beanletName) throws
BeanletNotFoundException, BeanletCreationException {
return getBeanlet(beanletName, (Class<?>) null);
}
public <T> T getBeanlet(String beanletName, Class<T> requiredType) throws
BeanletNotFoundException, BeanletCreationException,
BeanletNotOfRequiredTypeException {
return getBeanlet(beanletName, requiredType, null);
}
public Object getBeanlet(String beanletName, Map<String, ?> info) throws
BeanletNotFoundException, BeanletCreationException {
return getBeanlet(beanletName, null, info);
}
public <T> T getBeanlet(String beanletName, Class<T> requiredType,
Map<String, ?> info) throws BeanletNotFoundException,
BeanletCreationException, BeanletNotOfRequiredTypeException {
final Object beanlet;
final boolean prefix;
if (beanletName.startsWith(FACTORY_BEANLET_PREFIX)) {
beanletName = beanletName.substring(1);
prefix = true;
} else {
prefix = false;
}
BeanletReference<?> reference = getBeanletFactory(beanletName).create(info);
if (prefix) {
beanlet = reference.getBeanlet();
} else {
Object tmp = null;
FactoryEvent event = getEvent(FactoryEvent.class);
if (reference.isExecutable(event)) {
tmp = reference.execute(event);
} else {
tmp = reference.getBeanlet();
}
while (tmp instanceof FactoryBeanlet) {
Object t = ((FactoryBeanlet) tmp).getObject();
if (tmp == t) {
// Prevent infinite loop.
// PENDING: throw exception instead?
break;
}
tmp = t;
}
beanlet = tmp;
}
if (beanlet != null && requiredType != null && !requiredType.
isAssignableFrom(beanlet.getClass())) {
throw new BeanletNotOfRequiredTypeException(beanletName,
requiredType, beanlet.getClass());
}
@SuppressWarnings("unchecked")
T t = (T) beanlet;
return t;
}
public Set<String> getBeanletNames() {
Set<String> names = new HashSet<String>();
for (ComponentFactory<?> factory :
ComponentApplicationContext.instance().getComponentFactories()) {
names.add(factory.getComponentMetaData().getComponentName());
}
return Collections.unmodifiableSet(names);
}
public Set<String> getBeanletNamesForType(Class<?> type) {
Set<String> names = new HashSet<String>();
for (ComponentFactory<?> factory : ComponentApplicationContext.
instance().getComponentFactoriesForType(type)) {
names.add(factory.getComponentMetaData().getComponentName());
}
return Collections.unmodifiableSet(names);
}
public Set<String> getBeanletNamesForType(Class<?> type,
boolean factoryAware, boolean usePrefix) {
if (!factoryAware) {
return getBeanletNamesForType(type);
}
Set<String> names = new HashSet<String>();
for (ComponentFactory<?> f : ComponentApplicationContext.instance().
getComponentFactories()) {
BeanletFactory<?> factory = BeanletFactoryImpl.instance(f);
if (isFactoryBeanlet(factory)) {
if (isTypeMatch(factory, type)) {
if (usePrefix) {
names.add(FACTORY_BEANLET_PREFIX +
factory.getBeanletMetaData().getBeanletName());
} else {
names.add(factory.getBeanletMetaData().getBeanletName());
}
}
if (isFactoryTypeMatch(factory, type)) {
names.add(factory.getBeanletMetaData().getBeanletName());
}
} else {
if (isTypeMatch(factory, type)) {
names.add(factory.getBeanletMetaData().getBeanletName());
}
}
}
return Collections.unmodifiableSet(names);
}
private boolean isFactoryBeanlet(BeanletFactory<?> factory) {
return factory.getBeanletMetaData().isMetaDataPresent(
FactoryMetaData.class);
}
private boolean isFactoryTypeMatch(BeanletFactory<?> factory, Class<?> type) {
List<FactoryMetaData> m = factory.getBeanletMetaData().getMetaData(
FactoryMetaData.class);
assert m.size() == 1;
Class<?> returnType = m.get(0).getReturnType();
return !FactoryBeanlet.class.isAssignableFrom(returnType) &&
type.isAssignableFrom(returnType);
}
private boolean isTypeMatch(BeanletFactory<?> factory, Class<?> type) {
final List<Class<?>> types;
if (factory.getBeanletMetaData().isVanilla()) {
types = new ArrayList<Class<?>>(factory.getBeanletMetaData().getInterfaces());
types.add(factory.getBeanletMetaData().getType());
} else {
types = factory.getBeanletMetaData().getInterfaces();
}
for (Class<?> t : types) {
if (type.isAssignableFrom(t)) {
return true;
}
}
return false;
}
public BeanletFactory<?> getBeanletFactory(String beanletName) throws
BeanletNotFoundException {
try {
if (beanletName.startsWith(FACTORY_BEANLET_PREFIX)) {
beanletName = beanletName.substring(1);
}
return BeanletFactoryImpl.instance(
ComponentApplicationContext.instance().
getComponentFactory(beanletName));
} catch (ComponentNotFoundException e) {
throw new BeanletNotFoundException(e.getComponentName(),
CHAIN_JARGO_EXCEPTIONS ? e : e.getCause());
}
}
public <T> BeanletFactory<? extends T> getBeanletFactory(String beanletName,
Class<T> requiredType) throws BeanletNotFoundException {
BeanletFactory<?> tmp = getBeanletFactory(beanletName);
if (!isTypeMatch(tmp, requiredType)) {
throw new BeanletNotOfRequiredTypeException(beanletName,
requiredType, tmp.getBeanletMetaData().getType());
}
@SuppressWarnings("unchecked")
BeanletFactory<? extends T> factory = (BeanletFactory<? extends T>) tmp;
return factory;
}
public boolean exists(String beanletName) {
if (beanletName.startsWith(FACTORY_BEANLET_PREFIX)) {
beanletName = beanletName.substring(1);
}
return ComponentApplicationContext.instance().exists(beanletName);
}
}