blob: 6e611120e96d5c8020431fbd3d7bfc1e0a054761 [file] [log] [blame]
/*
* 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.felix.ipojo;
import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
import org.apache.felix.ipojo.metadata.Attribute;
import org.apache.felix.ipojo.metadata.Element;
import org.apache.felix.ipojo.parser.PojoMetadata;
import org.osgi.framework.Bundle;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Set;
/**
* This class defines the description of primitive (non-composite) component
* types. An instance of this class will be returned when invoking the
* {@link org.apache.felix.ipojo.ComponentFactory#getComponentDescription()} method.
*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
final class PrimitiveTypeDescription extends ComponentTypeDescription {
/**
* Set to keep component's all super-class class-names.
*/
private Set<String> m_superClasses = new HashSet<String>();
/**
* Set to keep component's all interface class-names.
*/
private Set<String> m_interfaces = new HashSet<String>();
/**
* The described component factory.
*/
private ComponentFactory m_factory;
/**
* Creates a PrimitiveTypeDescription object.
*
* @param factory the m_factory attached to this component type description.
*/
public PrimitiveTypeDescription(ComponentFactory factory) {
super(factory);
this.m_factory = factory;
try {
// The inspection can be done only for primitive components
if (factory.getClassName() != null) {
// Read inherited classes and interfaces into given Sets.
new InheritanceInspector(factory.getPojoMetadata(), getBundleContext().getBundle()).
computeInterfacesAndSuperClasses(m_interfaces, m_superClasses);
}
} catch (ClassNotFoundException e) {
m_interfaces.clear();
m_superClasses.clear();
}
}
/**
* Computes the properties to publish.
* The <code>component.class</code> property contains the implementation class name.
*
* @return the dictionary of properties to publish
* @see org.apache.felix.ipojo.architecture.ComponentTypeDescription#getPropertiesToPublish()
*/
public Dictionary<String, Object> getPropertiesToPublish() {
Dictionary<String, Object> dict = super.getPropertiesToPublish();
if (m_factory.getClassName() != null) {
dict.put("component.class", m_factory.getClassName());
}
return dict;
}
/**
* Adds the "implementation-class" attribute to the type description.
*
* @return the component type description.
* @see org.apache.felix.ipojo.architecture.ComponentTypeDescription#getDescription()
*/
public Element getDescription() {
Element elem = super.getDescription();
elem.addAttribute(new Attribute("Implementation-Class", m_factory.getClassName()));
/* Adding interfaces and super-classes of component into description */
Element inheritance = new Element("Inherited", "");
inheritance.addAttribute(new Attribute("Interfaces", m_interfaces.toString()));
inheritance.addAttribute(new Attribute("SuperClasses", m_superClasses.toString()));
elem.addElement(inheritance);
return elem;
}
/**
* This class is used to collect interfaces and super-classes of given component in specified Sets.
*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
private final class InheritanceInspector {
/*
* PojoMetadata of target Component.
*/
private PojoMetadata m_pojoMetadata;
/*
* Bundle exposing target component.
*/
private Bundle m_bundle;
/**
* Creates a TypeCollector object
*
* @param pojoMetadata PojoMetadata describing Component.
* @param bundle Bundle which has been exposed the intended Component.
*/
public InheritanceInspector(PojoMetadata pojoMetadata, Bundle bundle) {
m_pojoMetadata = pojoMetadata;
m_bundle = bundle;
}
/**
* Collect interfaces implemented by the POJO into given Sets.
*
* @param interfaces : the set of implemented interfaces
* @param classes : the set of extended classes
* @throws ClassNotFoundException : occurs when an interface cannot be loaded.
*/
public void computeInterfacesAndSuperClasses(Set<String> interfaces, Set<String> classes) throws ClassNotFoundException {
String[] immediateInterfaces = m_pojoMetadata.getInterfaces();
String parentClass = m_pojoMetadata.getSuperClass();
// First iterate on found specification in manipulation metadata
for (String immediateInterface : immediateInterfaces) {
interfaces.add(immediateInterface);
// Iterate on interfaces implemented by the current interface
Class<?> clazz = m_bundle.loadClass(immediateInterface);
collectInterfaces(clazz, interfaces, m_bundle);
}
// Look for parent class.
if (parentClass != null) {
Class clazz = m_bundle.loadClass(parentClass);
collectInterfacesFromClass(clazz, interfaces, m_bundle);
classes.add(parentClass);
collectParentClassesFromClass(clazz, classes, m_bundle);
}
// Removing Object Class from the inherited classes list.
classes.remove(Object.class.getName());
}
/**
* Look for inherited interfaces.
*
* @param clazz : interface name to explore (class object)
* @param acc : set (accumulator)
* @param bundle : bundle
* @throws ClassNotFoundException : occurs when an interface cannot be loaded.
*/
private void collectInterfaces(Class<?> clazz, Set<String> acc, Bundle bundle) throws ClassNotFoundException {
Class[] clazzes = clazz.getInterfaces();
for (Class clazze : clazzes) {
acc.add(clazze.getName());
collectInterfaces(clazze, acc, bundle);
}
}
/**
* Collect interfaces for the given class.
* This method explores super class to.
*
* @param clazz : class object.
* @param acc : set of implemented interface (accumulator)
* @param bundle : bundle.
* @throws ClassNotFoundException : occurs if an interface cannot be load.
*/
private void collectInterfacesFromClass(Class<?> clazz, Set<String> acc,
Bundle bundle) throws ClassNotFoundException {
Class[] clazzes = clazz.getInterfaces();
for (Class clazze : clazzes) {
acc.add(clazze.getName());
collectInterfaces(clazze, acc, bundle);
}
// Iterate on parent classes
Class sup = clazz.getSuperclass();
if (sup != null) {
collectInterfacesFromClass(sup, acc, bundle);
}
}
/**
* Collect parent classes for the given class.
*
* @param clazz : class object.
* @param acc : set of extended classes (accumulator)
* @param bundle : bundle.
* @throws ClassNotFoundException : occurs if an interface cannot be load.
*/
private void collectParentClassesFromClass(Class<?> clazz, Set<String> acc, Bundle bundle) throws ClassNotFoundException {
Class<?> parent = clazz.getSuperclass();
if (parent != null) {
acc.add(parent.getName());
collectParentClassesFromClass(parent, acc, bundle);
}
}
}
}