| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.aries.blueprint.container; |
| |
| import org.apache.aries.blueprint.ComponentDefinitionRegistry; |
| import org.apache.aries.blueprint.ExtendedBeanMetadata; |
| import org.apache.aries.blueprint.PassThroughMetadata; |
| import org.apache.aries.blueprint.di.*; |
| import org.apache.aries.blueprint.ext.ComponentFactoryMetadata; |
| import org.apache.aries.blueprint.ext.DependentComponentFactoryMetadata; |
| import org.apache.aries.blueprint.reflect.MetadataUtil; |
| import org.apache.aries.blueprint.utils.ServiceListener; |
| import org.osgi.service.blueprint.reflect.*; |
| |
| import java.util.*; |
| |
| public class NoOsgiRecipeBuilder { |
| |
| private final Set<String> names = new HashSet<String>(); |
| private final BlueprintContainerImpl blueprintContainer; |
| private final ComponentDefinitionRegistry registry; |
| private final IdSpace recipeIdSpace; |
| |
| public NoOsgiRecipeBuilder(BlueprintContainerImpl blueprintContainer, IdSpace recipeIdSpace) { |
| this.recipeIdSpace = recipeIdSpace; |
| this.blueprintContainer = blueprintContainer; |
| this.registry = blueprintContainer.getComponentDefinitionRegistry(); |
| } |
| |
| public BlueprintRepository createRepository() { |
| BlueprintRepository repository = new NoOsgiBlueprintRepository(blueprintContainer); |
| // Create component recipes |
| for (String name : registry.getComponentDefinitionNames()) { |
| ComponentMetadata component = registry.getComponentDefinition(name); |
| Recipe recipe = createRecipe(component); |
| repository.putRecipe(recipe.getName(), recipe); |
| } |
| repository.validate(); |
| return repository; |
| } |
| |
| public Recipe createRecipe(ComponentMetadata component) { |
| |
| // Custom components should be handled before built-in ones |
| // in case we have a custom component that also implements a built-in metadata |
| |
| if (component instanceof DependentComponentFactoryMetadata) { |
| return createDependentComponentFactoryMetadata((DependentComponentFactoryMetadata) component); |
| } else if (component instanceof ComponentFactoryMetadata) { |
| return createComponentFactoryMetadata((ComponentFactoryMetadata) component); |
| } else if (component instanceof BeanMetadata) { |
| return createBeanRecipe((BeanMetadata) component); |
| } else if (component instanceof ServiceMetadata) { |
| throw new IllegalArgumentException("OSGi services are not supported"); |
| } else if (component instanceof ReferenceMetadata) { |
| throw new IllegalArgumentException("OSGi references are not supported"); |
| } else if (component instanceof ReferenceListMetadata) { |
| throw new IllegalArgumentException("OSGi references are not supported"); |
| } else if (component instanceof PassThroughMetadata) { |
| return createPassThroughRecipe((PassThroughMetadata) component); |
| } else { |
| throw new IllegalStateException("Unsupported component type " + component.getClass()); |
| } |
| } |
| |
| private Recipe createComponentFactoryMetadata(ComponentFactoryMetadata metadata) { |
| return new ComponentFactoryRecipe<ComponentFactoryMetadata>( |
| metadata.getId(), metadata, blueprintContainer, getDependencies(metadata)); |
| } |
| |
| private Recipe createDependentComponentFactoryMetadata(DependentComponentFactoryMetadata metadata) { |
| return new DependentComponentFactoryRecipe( |
| metadata.getId(), metadata, blueprintContainer, getDependencies(metadata)); |
| } |
| |
| private List<Recipe> getDependencies(ComponentMetadata metadata) { |
| List<Recipe> deps = new ArrayList<Recipe>(); |
| for (String name : metadata.getDependsOn()) { |
| deps.add(new RefRecipe(getName(null), name)); |
| } |
| return deps; |
| } |
| |
| private Recipe createPassThroughRecipe(PassThroughMetadata passThroughMetadata) { |
| return new PassThroughRecipe(getName(passThroughMetadata.getId()), |
| passThroughMetadata.getObject()); |
| } |
| |
| private Object getBeanClass(BeanMetadata beanMetadata) { |
| if (beanMetadata instanceof ExtendedBeanMetadata) { |
| ExtendedBeanMetadata extBeanMetadata = (ExtendedBeanMetadata) beanMetadata; |
| if (extBeanMetadata.getRuntimeClass() != null) { |
| return extBeanMetadata.getRuntimeClass(); |
| } |
| } |
| return beanMetadata.getClassName(); |
| } |
| |
| private boolean allowsFieldInjection(BeanMetadata beanMetadata) { |
| if (beanMetadata instanceof ExtendedBeanMetadata) { |
| return ((ExtendedBeanMetadata) beanMetadata).getFieldInjection(); |
| } |
| return false; |
| } |
| |
| private BeanRecipe createBeanRecipe(BeanMetadata beanMetadata) { |
| BeanRecipe recipe = new BeanRecipe( |
| getName(beanMetadata.getId()), |
| blueprintContainer, |
| getBeanClass(beanMetadata), |
| allowsFieldInjection(beanMetadata)); |
| // Create refs for explicit dependencies |
| recipe.setExplicitDependencies(getDependencies(beanMetadata)); |
| recipe.setPrototype(MetadataUtil.isPrototypeScope(beanMetadata) || MetadataUtil.isCustomScope(beanMetadata)); |
| recipe.setInitMethod(beanMetadata.getInitMethod()); |
| recipe.setDestroyMethod(beanMetadata.getDestroyMethod()); |
| recipe.setInterceptorLookupKey(beanMetadata); |
| List<BeanArgument> beanArguments = beanMetadata.getArguments(); |
| if (beanArguments != null && !beanArguments.isEmpty()) { |
| boolean hasIndex = (beanArguments.get(0).getIndex() >= 0); |
| if (hasIndex) { |
| List<BeanArgument> beanArgumentsCopy = new ArrayList<BeanArgument>(beanArguments); |
| Collections.sort(beanArgumentsCopy, MetadataUtil.BEAN_COMPARATOR); |
| beanArguments = beanArgumentsCopy; |
| } |
| List<Object> arguments = new ArrayList<Object>(); |
| List<String> argTypes = new ArrayList<String>(); |
| for (BeanArgument argument : beanArguments) { |
| Recipe value = getValue(argument.getValue(), null); |
| arguments.add(value); |
| argTypes.add(argument.getValueType()); |
| } |
| recipe.setArguments(arguments); |
| recipe.setArgTypes(argTypes); |
| recipe.setReorderArguments(!hasIndex); |
| } |
| recipe.setFactoryMethod(beanMetadata.getFactoryMethod()); |
| if (beanMetadata.getFactoryComponent() != null) { |
| recipe.setFactoryComponent(getValue(beanMetadata.getFactoryComponent(), null)); |
| } |
| for (BeanProperty property : beanMetadata.getProperties()) { |
| Recipe value = getValue(property.getValue(), null); |
| recipe.setProperty(property.getName(), value); |
| } |
| return recipe; |
| } |
| |
| private Recipe createRecipe(RegistrationListener listener) { |
| BeanRecipe recipe = new BeanRecipe(getName(null), blueprintContainer, ServiceListener.class, false); |
| recipe.setProperty("listener", getValue(listener.getListenerComponent(), null)); |
| if (listener.getRegistrationMethod() != null) { |
| recipe.setProperty("registerMethod", listener.getRegistrationMethod()); |
| } |
| if (listener.getUnregistrationMethod() != null) { |
| recipe.setProperty("unregisterMethod", listener.getUnregistrationMethod()); |
| } |
| recipe.setProperty("blueprintContainer", blueprintContainer); |
| return recipe; |
| } |
| |
| private Recipe createRecipe(ReferenceListener listener) { |
| BeanRecipe recipe = new BeanRecipe(getName(null), blueprintContainer, AbstractServiceReferenceRecipe.Listener.class, false); |
| recipe.setProperty("listener", getValue(listener.getListenerComponent(), null)); |
| recipe.setProperty("metadata", listener); |
| recipe.setProperty("blueprintContainer", blueprintContainer); |
| return recipe; |
| } |
| |
| private Recipe getValue(Metadata v, Object groupingType) { |
| if (v instanceof NullMetadata) { |
| return null; |
| } else if (v instanceof ComponentMetadata) { |
| return createRecipe((ComponentMetadata) v); |
| } else if (v instanceof ValueMetadata) { |
| ValueMetadata stringValue = (ValueMetadata) v; |
| Object type = stringValue.getType(); |
| type = (type == null) ? groupingType : type; |
| ValueRecipe vr = new ValueRecipe(getName(null), stringValue, type); |
| return vr; |
| } else if (v instanceof RefMetadata) { |
| // TODO: make it work with property-placeholders? |
| String componentName = ((RefMetadata) v).getComponentId(); |
| RefRecipe rr = new RefRecipe(getName(null), componentName); |
| return rr; |
| } else if (v instanceof CollectionMetadata) { |
| CollectionMetadata collectionMetadata = (CollectionMetadata) v; |
| Class<?> cl = collectionMetadata.getCollectionClass(); |
| String type = collectionMetadata.getValueType(); |
| if (cl == Object[].class) { |
| ArrayRecipe ar = new ArrayRecipe(getName(null), type); |
| for (Metadata lv : collectionMetadata.getValues()) { |
| ar.add(getValue(lv, type)); |
| } |
| return ar; |
| } else { |
| CollectionRecipe cr = new CollectionRecipe(getName(null), cl != null ? cl : ArrayList.class, type); |
| for (Metadata lv : collectionMetadata.getValues()) { |
| cr.add(getValue(lv, type)); |
| } |
| return cr; |
| } |
| } else if (v instanceof MapMetadata) { |
| return createMapRecipe((MapMetadata) v); |
| } else if (v instanceof PropsMetadata) { |
| PropsMetadata mapValue = (PropsMetadata) v; |
| MapRecipe mr = new MapRecipe(getName(null), Properties.class, String.class, String.class); |
| for (MapEntry entry : mapValue.getEntries()) { |
| Recipe key = getValue(entry.getKey(), String.class); |
| Recipe val = getValue(entry.getValue(), String.class); |
| mr.put(key, val); |
| } |
| return mr; |
| } else if (v instanceof IdRefMetadata) { |
| // TODO: make it work with property-placeholders? |
| String componentName = ((IdRefMetadata) v).getComponentId(); |
| IdRefRecipe rnr = new IdRefRecipe(getName(null), componentName); |
| return rnr; |
| } else { |
| throw new IllegalStateException("Unsupported value: " + v.getClass().getName()); |
| } |
| } |
| |
| private MapRecipe createMapRecipe(MapMetadata mapValue) { |
| String keyType = mapValue.getKeyType(); |
| String valueType = mapValue.getValueType(); |
| MapRecipe mr = new MapRecipe(getName(null), HashMap.class, keyType, valueType); |
| for (MapEntry entry : mapValue.getEntries()) { |
| Recipe key = getValue(entry.getKey(), keyType); |
| Recipe val = getValue(entry.getValue(), valueType); |
| mr.put(key, val); |
| } |
| return mr; |
| } |
| |
| private String getName(String name) { |
| if (name == null) { |
| do { |
| name = "#recipe-" + recipeIdSpace.nextId(); |
| } while (names.contains(name) || registry.containsComponentDefinition(name)); |
| } |
| names.add(name); |
| return name; |
| } |
| |
| } |