/*
* Copyright 2012 The Solmix Project
*
* This 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 software 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 may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.gnu.org/licenses/
* or see the FSF site: http://www.fsf.org.
*/
package org.solmix.runtime.support.spring;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.solmix.runtime.Container;
import org.solmix.runtime.bean.ConfiguredBeanProvider;
import org.solmix.runtime.extension.ExtensionManagerImpl;
import org.springframework.beans.Mergeable;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
/**
*
* @author solmix.f@gmail.com
* @version $Id$ 2013-11-4
*/
public class SpringBeanProvider implements ConfiguredBeanProvider
{
private final ApplicationContext context;
private ConfiguredBeanProvider original;
private final Set<String> passThroughs = new HashSet<String>();
public SpringBeanProvider(ApplicationContext context)
{
this(context, null);
}
/**
* @param applicationContext
* @param systemContext
*/
public SpringBeanProvider(ApplicationContext applicationContext, Container system)
{
this.context = applicationContext;
if (system != null) {
original = system.getExtension(ConfiguredBeanProvider.class);
if(original instanceof ExtensionManagerImpl){
List<String> names = new ArrayList<String>();
for (String s : context.getBeanDefinitionNames()) {
names.add(s);
for (String s2 : context.getAliases(s)) {
names.add(s2);
}
}
((ExtensionManagerImpl)original).removeBeansOfNames(names);
}
}
}
/**
* {@inheritDoc}
*
* @see org.solmix.api.bean.ConfiguredBeanProvider#getBeanNamesOfType(java.lang.Class)
*/
@Override
public List<String> getBeanNamesOfType(Class<?> type) {
Set<String> s = new LinkedHashSet<String>(Arrays.asList(context.getBeanNamesForType(type, false, false)));
if(context.getParent()!=null){
s.addAll(_doGetBeanNamesOfType(context.getParent(),type));
}
s.removeAll(passThroughs);
if (original != null) {
List<String> origs = original.getBeanNamesOfType(type);
if (origs != null)
s.addAll(original.getBeanNamesOfType(type));
}
return new ArrayList<String>(s);
}
private Set<String> _doGetBeanNamesOfType(ApplicationContext context,Class<?> type) {
Set<String> s = new LinkedHashSet<String>(Arrays.asList(context.getBeanNamesForType(type, false, false)));
if(context.getParent()!=null){
s.addAll(_doGetBeanNamesOfType(context.getParent(),type));
}
return s;
}
/**
* {@inheritDoc}
*
* @see org.solmix.api.bean.ConfiguredBeanProvider#getBeanOfType(java.lang.String, java.lang.Class)
*/
@Override
public <T> T getBeanOfType(String name, Class<T> type) {
T t = null;
try {
t = type.cast(context.getBean(name, type));
} catch (NoSuchBeanDefinitionException nsbde) {
// ignore
}
if(t==null&&context.getParent()!=null){
t=_dogetBeanOfType(context.getParent(),name,type);
}
if (t == null && original != null) {
t = original.getBeanOfType(name, type);
}
return t;
}
//get bean from parent;
private <T> T _dogetBeanOfType(ApplicationContext context,String name, Class<T> type){
T t = null;
if(context!=null){
t = type.cast(context.getBean(name, type));
if(t==null&&context.getParent()!=null)
t=_dogetBeanOfType(context.getParent(),name,type);
}
return t;
}
/**
* {@inheritDoc}
*
* @see org.solmix.api.bean.ConfiguredBeanProvider#getBeansOfType(java.lang.Class)
*/
@Override
public <T> Collection<? extends T> getBeansOfType(Class<T> type) {
Set<String> s = new LinkedHashSet<String>(Arrays.asList(context.getBeanNamesForType(type, false, false)));
s.removeAll(passThroughs);
List<T> lst = new LinkedList<T>();
for (String n : s) {
lst.add(type.cast(context.getBean(n, type)));
}
if(context.getParent()!=null){
lst.addAll(_doGetBeansOfType(context.getParent(),type));
}
if(original!=null){
Collection<? extends T> origs= original.getBeansOfType(type);
if(origs!=null)
lst.addAll(origs);
}
return lst;
}
//get bean from parent;
private <T> Collection<? extends T> _doGetBeansOfType(ApplicationContext context,Class<T> type){
if(context!=null){
Set<String> s = new LinkedHashSet<String>(Arrays.asList(context.getBeanNamesForType(type, false, false)));
s.removeAll(passThroughs);
List<T> lst = new LinkedList<T>();
for (String n : s) {
lst.add(type.cast(context.getBean(n, type)));
}
if(context.getParent()!=null){
lst.addAll(_doGetBeansOfType(context.getParent(),type));
}
return lst;
}
return null;
}
/**
* {@inheritDoc}
*
* @see org.solmix.api.bean.ConfiguredBeanProvider#loadBeansOfType(java.lang.Class,
* org.solmix.api.bean.ConfiguredBeanProvider.BeanLoaderListener)
*/
@Override
public <T> boolean loadBeansOfType(Class<T> type, BeanLoaderListener<T> listener) {
List<String> list = new ArrayList<String>(Arrays.asList(context.getBeanNamesForType(type, false, false)));
list.removeAll(passThroughs);
Collections.reverse(list);
boolean loaded = false;
for (String s : list) {
Class<?> beanType = context.getType(s);
Class<? extends T> t = beanType.asSubclass(type);
if (listener.loadBean(s, t)) {
Object o = context.getBean(s);
if (listener.beanLoaded(s, type.cast(o))) {
return true;
}
loaded = true;
}
}
return loaded || original.loadBeansOfType(type, listener);
}
/**
* {@inheritDoc}
*
* @see org.solmix.api.bean.ConfiguredBeanProvider#hasBeanOfName(java.lang.String)
*/
@Override
public boolean hasBeanOfName(String name) {
if (context.containsBean(name)) {
return true;
}
return original.hasBeanOfName(name);
}
public boolean hasConfiguredPropertyValue(String beanName, String propertyName, String searchValue) {
if (context.containsBean(beanName) && !passThroughs.contains(beanName)) {
ConfigurableApplicationContext ctxt = (ConfigurableApplicationContext)context;
BeanDefinition def = ctxt.getBeanFactory().getBeanDefinition(beanName);
if (!ctxt.getBeanFactory().isSingleton(beanName) || def.isAbstract()) {
return false;
}
Collection<?> ids = null;
PropertyValue pv = def.getPropertyValues().getPropertyValue(propertyName);
if (pv != null) {
Object value = pv.getValue();
if (!(value instanceof Collection)) {
throw new RuntimeException("The property " + propertyName + " must be a collection!");
}
if (value instanceof Mergeable) {
if (!((Mergeable)value).isMergeEnabled()) {
ids = (Collection<?>)value;
}
} else {
ids = (Collection<?>)value;
}
}
if (ids != null) {
for (Iterator<?> itr = ids.iterator(); itr.hasNext();) {
Object o = itr.next();
if (o instanceof TypedStringValue) {
if (searchValue.equals(((TypedStringValue) o).getValue())) {
return true;
}
} else {
if (searchValue.equals(o)) {
return true;
}
}
}
}
}
return false;
// return orig.hasConfiguredPropertyValue(beanName, propertyName, searchValue);
}
}