001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.blueprint;
018
019import java.util.Collection;
020import java.util.HashSet;
021import java.util.LinkedHashMap;
022import java.util.Map;
023import java.util.Set;
024import java.util.concurrent.ConcurrentHashMap;
025
026import org.apache.camel.NoSuchBeanException;
027import org.apache.camel.spi.BeanRepository;
028import org.osgi.framework.Bundle;
029import org.osgi.service.blueprint.container.BlueprintContainer;
030import org.osgi.service.blueprint.container.NoSuchComponentException;
031import org.osgi.service.blueprint.reflect.BeanMetadata;
032import org.osgi.service.blueprint.reflect.ComponentMetadata;
033import org.osgi.service.blueprint.reflect.ReferenceMetadata;
034
035public class BlueprintContainerBeanRepository implements BeanRepository {
036
037    private final BlueprintContainer blueprintContainer;
038
039    private final Map<Class<?>, Map<String, Class<?>>> perBlueprintContainerCache = new ConcurrentHashMap<>();
040
041    public BlueprintContainerBeanRepository(BlueprintContainer blueprintContainer) {
042        this.blueprintContainer = blueprintContainer;
043    }
044
045    @Override
046    public Object lookupByName(String name) {
047        try {
048            return blueprintContainer.getComponentInstance(name);
049        } catch (NoSuchComponentException e) {
050            return null;
051        }
052    }
053
054    @Override
055    public <T> T lookupByNameAndType(String name, Class<T> type) {
056        Object answer;
057        try {
058            answer = blueprintContainer.getComponentInstance(name);
059        } catch (NoSuchComponentException e) {
060            return null;
061        }
062
063        // just to be safe
064        if (answer == null) {
065            return null;
066        }
067
068        try {
069            return type.cast(answer);
070        } catch (Throwable e) {
071            String msg = "Found bean: " + name + " in BlueprintContainer: " + blueprintContainer
072                    + " of type: " + answer.getClass().getName() + " expected type was: " + type;
073            throw new NoSuchBeanException(name, msg, e);
074        }
075    }
076
077    @Override
078    @SuppressWarnings("unchecked")
079    public <T> Map<String, T> findByTypeWithName(Class<T> type) {
080        if (perBlueprintContainerCache.containsKey(type)) {
081            return (Map<String, T>) perBlueprintContainerCache.get(type);
082        }
083        Map<String, T> result = lookupByType(blueprintContainer, type);
084        perBlueprintContainerCache.put(type, (Map<String, Class<?>>) result);
085        return result;
086    }
087
088    @Override
089    @SuppressWarnings("unchecked")
090    public <T> Set<T> findByType(Class<T> type) {
091        if (perBlueprintContainerCache.containsKey(type)) {
092            return new HashSet<T>((Collection<? extends T>) perBlueprintContainerCache.get(type).values());
093        }
094        Map<String, T> map = lookupByType(blueprintContainer, type);
095        perBlueprintContainerCache.put(type, (Map<String, Class<?>>) map);
096        return new HashSet<>(map.values());
097    }
098
099    public static <T> Map<String, T> lookupByType(BlueprintContainer blueprintContainer, Class<T> type) {
100        return lookupByType(blueprintContainer, type, true);
101    }
102
103    public static <T> Map<String, T> lookupByType(BlueprintContainer blueprintContainer, Class<T> type, boolean includeNonSingletons) {
104        Bundle bundle = (Bundle) blueprintContainer.getComponentInstance("blueprintBundle");
105        Map<String, T> objects = new LinkedHashMap<>();
106        Set<String> ids = blueprintContainer.getComponentIds();
107        for (String id : ids) {
108            try {
109                ComponentMetadata metadata = blueprintContainer.getComponentMetadata(id);
110                Class<?> cl = null;
111                if (metadata instanceof BeanMetadata) {
112                    BeanMetadata beanMetadata = (BeanMetadata)metadata;
113                    // should we skip the bean if its prototype and we are only looking for singletons?
114                    if (!includeNonSingletons) {
115                        String scope = beanMetadata.getScope();
116                        if (BeanMetadata.SCOPE_PROTOTYPE.equals(scope)) {
117                            continue;
118                        }
119                    }
120                    String clazz = beanMetadata.getClassName();
121                    if (clazz != null) {
122                        cl = bundle.loadClass(clazz);
123                    }
124                } else if (metadata instanceof ReferenceMetadata) {
125                    ReferenceMetadata referenceMetadata = (ReferenceMetadata)metadata;
126                    cl = bundle.loadClass(referenceMetadata.getInterface());
127                }
128                if (cl != null && type.isAssignableFrom(cl)) {
129                    Object o = blueprintContainer.getComponentInstance(metadata.getId());
130                    objects.put(metadata.getId(), type.cast(o));
131                }
132            } catch (Throwable t) {
133                // ignore
134            }
135        }
136        return objects;
137    }
138}