/**
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.plugin.model;
import org.apache.aries.blueprint.plugin.handlers.Handlers;
import org.apache.aries.blueprint.plugin.spi.BlueprintConfiguration;
import org.apache.aries.blueprint.plugin.spi.ContextEnricher;
import org.apache.aries.blueprint.plugin.spi.ContextInitializationHandler;
import org.apache.aries.blueprint.plugin.spi.XmlWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
public class Blueprint implements BlueprintRegistry, ContextEnricher, XmlWriter {
private static final String NS_BLUEPRINT = "http://www.osgi.org/xmlns/blueprint/v1.0.0";
private final BeanRefStore beanRefStore = new BeanRefStore();
private final Map<String, XmlWriter> customWriters = new HashMap<>();
private final BlueprintConfiguration blueprintConfiguration;
private final List<Bean> generatedBeans = new ArrayList<>();
Blueprint(BlueprintConfiguration blueprintConfiguration, Class<?>... beanClasses) {
this(blueprintConfiguration, Arrays.asList(beanClasses));
}
public Blueprint(BlueprintConfiguration blueprintConfiguration, Collection<Class<?>> beanClasses) {
this.blueprintConfiguration = blueprintConfiguration;
initContext();
parseBeans(beanClasses);
resolveDependency();
}
private void initContext() {
for (ContextInitializationHandler contextInitializationHandler : Handlers.CONTEXT_INITIALIZATION_HANDLERS) {
contextInitializationHandler.initContext(this);
}
}
private void parseBeans(Collection<Class<?>> beanClasses) {
for (Class<?> clazz : beanClasses) {
parseBean(clazz);
}
}
private void parseBean(Class<?> clazz) {
Bean bean = new Bean(clazz, this);
beanRefStore.addBean(bean.toBeanRef());
generatedBeans.add(bean);
addBeansFromFactories(bean);
}
private void addBeansFromFactories(Bean factoryBean) {
for (Method method : factoryBean.clazz.getMethods()) {
if (!isFactoryMethod(method)) {
continue;
}
BeanFromFactory beanFromFactory = new BeanFromFactory(factoryBean, method, this);
beanRefStore.addBean(beanFromFactory.toBeanRef());
generatedBeans.add(beanFromFactory);
}
}
private boolean isFactoryMethod(Method method) {
boolean isFactoryMethod = false;
for (Class<? extends Annotation> factoryMethodAnnotationClass : Handlers.FACTORY_METHOD_ANNOTATION_CLASSES) {
Annotation annotation = AnnotationHelper.findAnnotation(method.getAnnotations(), factoryMethodAnnotationClass);
if (annotation != null) {
isFactoryMethod = true;
break;
}
}
return isFactoryMethod;
}
private void resolveDependency() {
for (Bean bean : generatedBeans) {
bean.resolveDependency(this);
}
}
public BeanRef getMatching(BeanTemplate template) {
return beanRefStore.getMatching(template);
}
Collection<Bean> getBeans() {
return generatedBeans;
}
Map<String, XmlWriter> getCustomWriters() {
return customWriters;
}
@Override
public void addBean(String id, Class<?> clazz) {
beanRefStore.addBean(new BeanRef(clazz, id, new Annotation[]{}));
}
@Override
public void addBlueprintContentWriter(String id, XmlWriter blueprintWriter) {
customWriters.put(id, blueprintWriter);
}
@Override
public BlueprintConfiguration getBlueprintConfiguration() {
return blueprintConfiguration;
}
public void write(XMLStreamWriter writer) throws XMLStreamException {
writeBlueprint(writer);
writeBeans(writer);
writeCustomWriters(writer);
writer.writeEndElement();
}
private void writeCustomWriters(XMLStreamWriter writer) throws XMLStreamException {
List<String> customWriterKeys = new ArrayList<>(customWriters.keySet());
Collections.sort(customWriterKeys);
for (String customWriterKey : customWriterKeys) {
customWriters.get(customWriterKey).write(writer);
}
}
private void writeBeans(XMLStreamWriter writer) throws XMLStreamException {
Collections.sort(generatedBeans);
for (Bean beanWriter : generatedBeans) {
beanWriter.write(writer);
}
}
private void writeBlueprint(XMLStreamWriter writer) throws XMLStreamException {
writer.writeStartElement("blueprint");
writer.writeDefaultNamespace(NS_BLUEPRINT);
if (blueprintConfiguration.getDefaultActivation() != null) {
writer.writeAttribute("default-activation", blueprintConfiguration.getDefaultActivation().name().toLowerCase());
}
}
public boolean shouldBeGenerated() {
return !getBeans().isEmpty();
}
}