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.Registry;
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 BlueprintContainerRegistry implements Registry {
036
037    private final BlueprintContainer blueprintContainer;
038
039    private final Map<Class<?>, Map<String, Class<?>>> perBlueprintContainerCache = new ConcurrentHashMap<>();
040
041    public BlueprintContainerRegistry(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<T>(map.values());
097    }
098
099    @Override
100    public Object lookup(String name) {
101        return lookupByName(name);
102    }
103
104    @Override
105    public <T> T lookup(String name, Class<T> type) {
106        return lookupByNameAndType(name, type);
107    }
108
109    @Override
110    public <T> Map<String, T> lookupByType(Class<T> type) {
111        return findByTypeWithName(type);
112    }
113
114    public static <T> Map<String, T> lookupByType(BlueprintContainer blueprintContainer, Class<T> type) {
115        return lookupByType(blueprintContainer, type, true);
116    }
117
118    public static <T> Map<String, T> lookupByType(BlueprintContainer blueprintContainer, Class<T> type, boolean includeNonSingletons) {
119        Bundle bundle = (Bundle) blueprintContainer.getComponentInstance("blueprintBundle");
120        Map<String, T> objects = new LinkedHashMap<String, T>();
121        Set<String> ids = blueprintContainer.getComponentIds();
122        for (String id : ids) {
123            try {
124                ComponentMetadata metadata = blueprintContainer.getComponentMetadata(id);
125                Class<?> cl = null;
126                if (metadata instanceof BeanMetadata) {
127                    BeanMetadata beanMetadata = (BeanMetadata)metadata;
128                    // should we skip the bean if its prototype and we are only looking for singletons?
129                    if (!includeNonSingletons) {
130                        String scope = beanMetadata.getScope();
131                        if (BeanMetadata.SCOPE_PROTOTYPE.equals(scope)) {
132                            continue;
133                        }
134                    }
135                    cl = bundle.loadClass(beanMetadata.getClassName());
136                } else if (metadata instanceof ReferenceMetadata) {
137                    ReferenceMetadata referenceMetadata = (ReferenceMetadata)metadata;
138                    cl = bundle.loadClass(referenceMetadata.getInterface());
139                }
140                if (cl != null && type.isAssignableFrom(cl)) {
141                    Object o = blueprintContainer.getComponentInstance(metadata.getId());
142                    objects.put(metadata.getId(), type.cast(o));
143                }
144            } catch (Throwable t) {
145                // ignore
146            }
147        }
148        return objects;
149    }
150}