/*
* 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.blueprint;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.aries.blueprint.ExtendedBeanMetadata;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.blueprint.container.BlueprintContainer;
import org.osgi.service.blueprint.container.NoSuchComponentException;
import org.osgi.service.blueprint.reflect.BeanMetadata;
import org.osgi.service.blueprint.reflect.ComponentMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.solmix.commons.util.Reflection;
import org.solmix.runtime.bean.ConfiguredBeanProvider;
import org.solmix.runtime.extension.ExtensionManagerImpl;
/**
*
* @author solmix.f@gmail.com
* @version $Id$ 2013-11-5
*/
public class BlueprintBeanProvider implements ConfiguredBeanProvider
{
private static final Logger LOG = LoggerFactory.getLogger(BlueprintConfigurer.class);
BundleContext bundleContext;
BlueprintContainer blueprintContainer;
ConfiguredBeanProvider original;
public BlueprintBeanProvider(ConfiguredBeanProvider original, BlueprintContainer blueprintContainer, BundleContext bundleContext)
{
this.bundleContext = bundleContext;
this.blueprintContainer = blueprintContainer;
this.original = original;
if(original instanceof ExtensionManagerImpl){
List<String> names = new ArrayList<String>(blueprintContainer.getComponentIds());
((ExtensionManagerImpl)original).removeBeansOfNames(names);
}
}
private ComponentMetadata getComponentMetadata(String id) {
try {
return blueprintContainer.getComponentMetadata(id);
} catch (NoSuchComponentException nsce) {
return null;
}
}
static Class<?> getClassForMetaData(BlueprintContainer container, ComponentMetadata cmd) {
Class<?> cls = null;
if (cmd instanceof BeanMetadata) {
BeanMetadata bm = (BeanMetadata) cmd;
if (bm instanceof ExtendedBeanMetadata) {
cls = ((ExtendedBeanMetadata)bm).getRuntimeClass();
}
if (cls == null) {
try {
Method m = Reflection.findMethod(container.getClass().getName(), "loadClass", String.class);
cls = (Class<?>) m.invoke(container, bm.getClassName());
} catch (Exception e) {
// ignore
}
}
}
return cls;
}
private Class<?> getClassForMetaData(ComponentMetadata cmd) {
return getClassForMetaData(blueprintContainer, cmd);
}
@Override
public List<String> getBeanNamesOfType(Class<?> type) {
Set<String> names = new LinkedHashSet<String>();
for (String s : blueprintContainer.getComponentIds()) {
ComponentMetadata cmd = blueprintContainer.getComponentMetadata(s);
Class<?> cls = getClassForMetaData(cmd);
if (cls != null && type.isAssignableFrom(cls)) {
names.add(s);
}
}
if (original != null) {
List<String> origs = original.getBeanNamesOfType(type);
if (origs != null)
names.addAll(original.getBeanNamesOfType(type));
}
return new ArrayList<String>(names);
}
@Override
public <T> T getBeanOfType(String name, Class<T> type) {
ComponentMetadata cmd = getComponentMetadata(name);
Class<?> cls = getClassForMetaData(cmd);
if (cls != null && type.isAssignableFrom(cls)) {
return type.cast(blueprintContainer.getComponentInstance(name));
}
if(original!=null){
return original.getBeanOfType(name, type);
}
return null;
}
@Override
public <T> Collection<? extends T> getBeansOfType(Class<T> type) {
List<T> list = new ArrayList<T>();
for (String s : blueprintContainer.getComponentIds()) {
ComponentMetadata cmd = blueprintContainer.getComponentMetadata(s);
Class<?> cls = getClassForMetaData(cmd);
if (cls != null && type.isAssignableFrom(cls)) {
list.add(type.cast(blueprintContainer.getComponentInstance(s)));
}
}
if(original!=null){
Collection<? extends T> origs= original.getBeansOfType(type);
if(origs!=null)
list.addAll(origs);
}
if (list.isEmpty()) {
try {
ServiceReference<?> refs[] = bundleContext.getServiceReferences(type.getName(), null);
if (refs != null) {
for (ServiceReference<?> r : refs) {
list.add(type.cast(bundleContext.getService(r)));
}
}
} catch (Exception ex) {
// ignore, just don't support the OSGi services
LOG.info("Try to find the Bean with type:" + type + " from OSGi services and get error: " + ex);
}
}
return list;
}
@Override
public <T> boolean loadBeansOfType(Class<T> type, BeanLoaderListener<T> listener) {
List<String> names = new ArrayList<String>();
boolean loaded = false;
for (String s : blueprintContainer.getComponentIds()) {
ComponentMetadata cmd = blueprintContainer.getComponentMetadata(s);
Class<?> cls = getClassForMetaData(cmd);
if (cls != null && type.isAssignableFrom(cls)) {
names.add(s);
}
}
Collections.reverse(names);
for (String s : names) {
ComponentMetadata cmd = blueprintContainer.getComponentMetadata(s);
Class<?> beanType = getClassForMetaData(cmd);
Class<? extends T> t = beanType.asSubclass(type);
if (listener.loadBean(s, t)) {
Object o = blueprintContainer.getComponentInstance(s);
if (listener.beanLoaded(s, type.cast(o))) {
return true;
}
loaded = true;
}
}
return loaded || original.loadBeansOfType(type, listener);
}
@Override
public boolean hasBeanOfName(String name) {
ComponentMetadata cmd = getComponentMetadata(name);
if (cmd instanceof BeanMetadata) {
return true;
}
return original.hasBeanOfName(name);
}
}