Package org.apache.felix.scrplugin

Source Code of org.apache.felix.scrplugin.SCRDescriptorGenerator

/*
* 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.scrplugin;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.felix.scrplugin.annotations.AnnotationProcessor;
import org.apache.felix.scrplugin.description.ClassDescription;
import org.apache.felix.scrplugin.description.ComponentConfigurationPolicy;
import org.apache.felix.scrplugin.description.ComponentDescription;
import org.apache.felix.scrplugin.description.PropertyDescription;
import org.apache.felix.scrplugin.description.PropertyType;
import org.apache.felix.scrplugin.description.PropertyUnbounded;
import org.apache.felix.scrplugin.description.ReferenceCardinality;
import org.apache.felix.scrplugin.description.ReferenceDescription;
import org.apache.felix.scrplugin.description.ReferencePolicyOption;
import org.apache.felix.scrplugin.description.ReferenceStrategy;
import org.apache.felix.scrplugin.description.ServiceDescription;
import org.apache.felix.scrplugin.helper.AnnotationProcessorManager;
import org.apache.felix.scrplugin.helper.ClassModifier;
import org.apache.felix.scrplugin.helper.ClassScanner;
import org.apache.felix.scrplugin.helper.ComponentContainer;
import org.apache.felix.scrplugin.helper.DescriptionContainer;
import org.apache.felix.scrplugin.helper.IssueLog;
import org.apache.felix.scrplugin.helper.MetatypeAttributeDefinition;
import org.apache.felix.scrplugin.helper.MetatypeContainer;
import org.apache.felix.scrplugin.helper.StringUtils;
import org.apache.felix.scrplugin.helper.Validator;
import org.apache.felix.scrplugin.xml.ComponentDescriptorIO;
import org.apache.felix.scrplugin.xml.MetaTypeIO;
import org.osgi.service.cm.ConfigurationAdmin;

/**
* The <code>SCRDescriptorGenerator</code> class does the hard work of
* generating the SCR descriptors. This class is being instantiated and
* configured by clients and the {@link #execute()} method called to generate
* the descriptor files.
* <p>
* When using this class carefully consider calling <i>all</i> setter methods to properly configure the generator. All setter
* method document, which default value is assumed for the respective property if the setter is not called.
* <p>
* Instances of this class are not thread save and should not be reused.
*/
public class SCRDescriptorGenerator {

    private final Log logger;

    /** The project. */
    private Project project;

    /** The options. */
    private Options options = new Options();

    /** The annotation scanner. */
    private ClassScanner scanner;

    /** The issue log. */
    private IssueLog iLog;

    /**
     * Create an instance of this generator using the given {@link Log} instance
     * of logging.
     */
    public SCRDescriptorGenerator(final Log logger) {
        this.logger = logger;
    }

    /**
     * Set the project. This is required.
     */
    public void setProject(final Project p) {
        this.project = p;
    }

    /**
     * Set the options.
     */
    public void setOptions(final Options p) {
        this.options = p;
    }

    /**
     * Actually generates the Declarative Services and Metatype descriptors
     * scanning the java sources provided by the {@link #setProject(Project)}
     *
     * @return A list of generated file names, relative to the output directory
     *
     * @throws SCRDescriptorException
     * @throws SCRDescriptorFailureException
     */
    public Result execute() throws SCRDescriptorException, SCRDescriptorFailureException {

        this.logger.debug("Starting SCR Descriptor Generator....");
        if (this.project == null) {
            throw new SCRDescriptorFailureException("Project has not been set!");
        }
        if (this.options == null) {
            // use default options
            this.options = new Options();
        }
        if (this.options.getOutputDirectory() == null) {
            throw new SCRDescriptorFailureException("Output directory has not been set!");
        }

        this.logger.debug("..using output directory: " + this.options.getOutputDirectory());
        this.logger.debug("..strict mode: " + this.options.isStrictMode());
        this.logger.debug("..generating accessors: " + this.options.isGenerateAccessors());

        // check speck version configuration
        SpecVersion specVersion = options.getSpecVersion();
        if (specVersion == null) {
            this.logger.debug("..auto detecting spec version");
        } else {
            this.logger.debug("..using spec version " + specVersion.getName());
        }

        // create a log
        this.iLog = new IssueLog(this.options.isStrictMode());

        // create the annotation processor manager
        final AnnotationProcessor aProcessor = new AnnotationProcessorManager(this.logger,
                        this.project.getClassLoader());

        // create the class scanner - and start scanning
        this.scanner = new ClassScanner(logger, iLog, project, aProcessor);
        final List<ClassDescription> scannedDescriptions = scanner.scanSources();

        // create the result to hold the list of processed source files
        final Result result = new Result();
        final List<ComponentContainer> processedContainers = new ArrayList<ComponentContainer>();
        for (final ClassDescription desc : scannedDescriptions) {
            this.logger.debug("Processing component class " + desc.getSource());
            result.addProcessedSourceFile(desc.getSource());

            // check if there is more than one component definition
            if (desc.getDescriptions(ComponentDescription.class).size() > 1) {
                iLog.addError("Class has more than one component definition." +
                             " Check the annotations and merge the definitions to a single definition.",
                                desc.getSource());
            } else {
                final ComponentContainer container = this.createComponent(desc, iLog);

                if (container.getComponentDescription().getSpecVersion() != null) {
                    if ( specVersion == null ) {
                        specVersion = container.getComponentDescription().getSpecVersion();
                        logger.debug("Setting used spec version to " + specVersion);
                    } else if (container.getComponentDescription().getSpecVersion().ordinal() > specVersion.ordinal() ) {
                        if ( this.options.getSpecVersion() != null) {
                            // if a spec version has been configured and a component requires a higher
                            // version, this is considered an error!
                            iLog.addError("Component " + container + " requires spec version " + container.getComponentDescription().getSpecVersion().name()
                                            + " but plugin is configured to use version " + this.options.getSpecVersion(),
                                            desc.getSource());
                        } else {
                            specVersion = container.getComponentDescription().getSpecVersion();
                            logger.debug("Setting used spec version to " + specVersion);
                        }
                    }
                } else {
                    if ( this.options.getSpecVersion() != null ) {
                        container.getComponentDescription().setSpecVersion(options.getSpecVersion());
                    } else {
                        container.getComponentDescription().setSpecVersion(SpecVersion.VERSION_1_0);
                    }
                }
                processedContainers.add(container);
            }
        }
        // if spec version is still not set, we're using lowest available
        if ( specVersion == null ) {
            specVersion = SpecVersion.VERSION_1_0;
            logger.debug("Using default spec version " + specVersion);
        }
        this.logger.debug("Generating descriptor for spec version: " + specVersion);
        options.setSpecVersion(specVersion);

        // before we can validate we should check the references for bind/unbind method
        // in order to create them if possible
        if ( this.options.isGenerateAccessors() ) {
            for(final ComponentContainer container : processedContainers) {
                this.generateMethods(container);
            }
        }

        // now validate
        final DescriptionContainer module = new DescriptionContainer(this.options);
        for (final ComponentContainer container : processedContainers) {
            final int errorCount = iLog.getNumberOfErrors();

            final Validator validator = new Validator(container, project, options, iLog);
            validator.validate();

            // ignore component if it has errors
            if (iLog.getNumberOfErrors() == errorCount) {
                module.add(container);
            }
        }
        // log issues
        iLog.logMessages(logger);

        // after checking all classes, throw if there were any failures
        if (iLog.hasErrors()) {
            throw new SCRDescriptorFailureException("SCR Descriptor parsing had failures (see log)");
        }

        // and generate files
        result.setMetatypeFiles(MetaTypeIO.generateDescriptors(module, this.project, this.options, this.logger));
        result.setScrFiles(ComponentDescriptorIO.generateDescriptorFiles(module, this.options, logger));

        return result;
    }

    private void generateMethods(final ComponentContainer container) throws SCRDescriptorException {
        for (final ReferenceDescription ref : container.getReferences().values()) {
            // skip refs without a interface name (validate will be called next)
            if (StringUtils.isEmpty(ref.getInterfaceName())) {
                continue;
            }

            // if this is a field with a single cardinality,
            // we look for the bind/unbind methods
            // and create them if they are not availabe
            if (ref.getStrategy() != ReferenceStrategy.LOOKUP && ref.getField() != null
                && ref.getField().getDeclaringClass().getName().equals(container.getClassDescription().getDescribedClass().getName())
                && (ref.getCardinality() == ReferenceCardinality.OPTIONAL_UNARY || ref.getCardinality() == ReferenceCardinality.MANDATORY_UNARY)) {

                final String bindValue = ref.getBind();
                final String unbindValue = ref.getUnbind();
                final String name = ref.getName();
                final String type = ref.getInterfaceName();

                boolean createBind = false;
                boolean createUnbind = false;

                // Only create method if no bind name has been specified
                if (bindValue == null && Validator.findMethod(this.project, this.options, container.getClassDescription(), ref, "bind") == null) {
                    // create bind method
                    createBind = true;
                }
                if (unbindValue == null && Validator.findMethod(this.project, this.options, container.getClassDescription(), ref, "unbind") == null) {
                    // create unbind method
                    createUnbind = true;
                }
                if (createBind || createUnbind) {
                    // logging
                    if ( createBind && createUnbind ) {
                        this.logger.debug("Generating bind and unbind method for " + name + " in " + container.getClassDescription().getDescribedClass().getName());
                    } else if ( createBind ) {
                        this.logger.debug("Generating bind method for " + name + " in " + container.getClassDescription().getDescribedClass().getName());
                    } else {
                        this.logger.debug("Generating unbind method for " + name + " in " + container.getClassDescription().getDescribedClass().getName());

                    }
                    ClassModifier.addMethods(container.getClassDescription().getDescribedClass().getName(),
                                    name,
                                    ref.getField().getName(),
                                    type,
                                    createBind,
                                    createUnbind,
                                    this.project.getClassLoader(),
                                    this.project.getClassesDirectory(),
                                    this.logger);
                    // set a flag for validation
                    ref.setBindMethodCreated(createBind);
                    ref.setUnbindMethodCreated(createUnbind);
                }
            }
        }
    }

    /**
     * Create the SCR objects based on the descriptions
     */
    private ComponentContainer createComponent(final ClassDescription desc,
                    final IssueLog iLog) {
        final ComponentDescription componentDesc = desc.getDescription(ComponentDescription.class);

        final SpecVersion intitialComponentSpecVersion = componentDesc.getSpecVersion();

        // configuration pid in 1.2
        if ( componentDesc.getConfigurationPid() != null && !componentDesc.getConfigurationPid().equals(componentDesc.getName())) {
            componentDesc.setSpecVersion(SpecVersion.VERSION_1_2);
        }

        final ComponentContainer container = new ComponentContainer(desc, componentDesc);

        // Create metatype (if required)
        final MetatypeContainer ocd;
        if ( !componentDesc.isAbstract() && componentDesc.isCreateMetatype() ) {
            // OCD
            ocd = new MetatypeContainer();
            container.setMetatypeContainer( ocd );
            ocd.setId( componentDesc.getName() );
            if ( componentDesc.getLabel() != null ) {
                ocd.setName( componentDesc.getLabel() );
            }
            if ( componentDesc.getDescription() != null ) {
                ocd.setDescription( componentDesc.getDescription() );
            }

            // Factory pid
            if ( componentDesc.isSetMetatypeFactoryPid() ) {
                if ( componentDesc.getFactory() == null ) {
                    ocd.setFactoryPid( componentDesc.getName() );
                } else {
                    iLog.addWarning( "Component factory " + componentDesc.getName()
                        + " should not set metatype factory pid.", desc.getSource() );
                }
            }
        } else {
            ocd = null;
        }
        // metatype checks if metatype is not generated (FELIX-4033)
        if ( !componentDesc.isAbstract() && !componentDesc.isCreateMetatype() ) {
            if ( componentDesc.getLabel() != null && componentDesc.getLabel().trim().length() > 0 ) {
                iLog.addWarning(" Component " + componentDesc.getName() + " has set a label. However metatype is set to false. This label is ignored.",
                        desc.getSource());
            }
            if ( componentDesc.getDescription() != null && componentDesc.getDescription().trim().length() > 0 ) {
                iLog.addWarning(" Component " + componentDesc.getName() + " has set a description. However metatype is set to false. This description is ignored.",
                        desc.getSource());
            }
        }

        ClassDescription current = desc;
        boolean inherit;
        do {
            final ComponentDescription cd = current.getDescription(ComponentDescription.class);
            inherit = (cd == null ? true : cd.isInherit());

            if ( cd != null ) {
                if ( current != desc ) {
                    iLog.addWarning(" Component " + componentDesc.getName() + " is using the " +
                                    "deprecated inheritance feature and inherits from " + current.getDescribedClass().getName() +
                                    ". This feature will be removed in future versions.",
                                    desc.getSource());
                }
                // handle enabled and immediate
                if ( componentDesc.getEnabled() == null ) {
                    componentDesc.setEnabled(cd.getEnabled());
                }
                if ( componentDesc.getImmediate() == null ) {
                    componentDesc.setImmediate(cd.getImmediate());
                }

                // lifecycle methods
                if ( componentDesc.getActivate() == null && cd.getActivate() != null ) {
                    componentDesc.setActivate(cd.getActivate());
                }
                if ( componentDesc.getDeactivate() == null && cd.getDeactivate() != null ) {
                    componentDesc.setDeactivate(cd.getDeactivate());
                }
                if ( componentDesc.getModified() == null && cd.getModified() != null ) {
                    componentDesc.setModified(cd.getModified());
                }
                if ( componentDesc.getActivate() != null || componentDesc.getDeactivate() != null || componentDesc.getModified() != null ) {
                    // spec version must be at least 1.1
                    componentDesc.setSpecVersion(SpecVersion.VERSION_1_1);
                }
                if ( componentDesc.getConfigurationPolicy() != ComponentConfigurationPolicy.OPTIONAL ) {
                    // policy requires 1.1
                    componentDesc.setSpecVersion(SpecVersion.VERSION_1_1);
                }

            }
            // services, properties, references
            this.processServices(current, container);
            this.processProperties(current, container, ocd);
            this.processReferences(current, container);


            // go up in the class hierarchy
            if ( !inherit || current.getDescribedClass().getSuperclass() == null ) {
                current = null;
            } else {
                try {
                    current = this.scanner.getDescription(current.getDescribedClass().getSuperclass());
                } catch ( final SCRDescriptorFailureException sde) {
                    this.logger.debug(sde.getMessage(), sde);
                    iLog.addError(sde.getMessage(), current.getSource());
                } catch ( final SCRDescriptorException sde) {
                    this.logger.debug(sde.getSourceLocation() + " : " + sde.getMessage(), sde);
                    iLog.addError(sde.getMessage(), sde.getSourceLocation());
                }
            }
        } while ( current != null);

        // check service interfaces for properties
        if ( container.getServiceDescription() != null ) {
            for(final String interfaceName : container.getServiceDescription().getInterfaces()) {
                try {
                    final Class<?> interfaceClass = project.getClassLoader().loadClass(interfaceName);
                    final ClassDescription interfaceDesc = this.scanner.getDescription(interfaceClass);
                    if ( interfaceDesc != null ) {
                        this.processProperties(interfaceDesc, container, ocd);
                    }
                } catch ( final SCRDescriptorFailureException sde) {
                    this.logger.debug(sde.getMessage(), sde);
                    iLog.addError(sde.getMessage(), interfaceName);
                } catch ( final SCRDescriptorException sde) {
                    this.logger.debug(sde.getSourceLocation() + " : " + sde.getMessage(), sde);
                    iLog.addError(sde.getMessage(), sde.getSourceLocation());
                } catch (ClassNotFoundException e) {
                    this.logger.debug(e.getMessage(), e);
                    iLog.addError(e.getMessage(), interfaceName);
                }
            }
        }

        // global properties
        this.processGlobalProperties(desc, container.getProperties());

        // PID handling
        if ( componentDesc.isCreatePid() && !container.getProperties().containsKey(org.osgi.framework.Constants.SERVICE_PID)) {
            final PropertyDescription pid = new PropertyDescription(null);
            pid.setName( org.osgi.framework.Constants.SERVICE_PID );
            pid.setValue( componentDesc.getName() );
            pid.setType(PropertyType.String);

            container.getProperties().put(org.osgi.framework.Constants.SERVICE_PID, pid);
        }

        // check if component has spec version configured but requires a higher one
        if ( intitialComponentSpecVersion != null && componentDesc.getSpecVersion().ordinal() > intitialComponentSpecVersion.ordinal() ) {
            iLog.addError("Component " + container + " requires spec version " + container.getComponentDescription().getSpecVersion().name()
                    + " but component is configured to use version " + intitialComponentSpecVersion.name(),
                    desc.getSource());
        }
        return container;
    }

    /**
     * Process service directives
     */
    private void processServices(final ClassDescription current, final ComponentContainer component) {

        final ServiceDescription serviceDesc = current.getDescription(ServiceDescription.class);
        if ( serviceDesc != null ) {
            ServiceDescription service = component.getServiceDescription();
            if ( service == null ) {
                service = new ServiceDescription(serviceDesc.getAnnotation());
                service.setServiceFactory(false);
                component.setServiceDescription(service);
            }
            if ( serviceDesc.isServiceFactory() ) {
                service.setServiceFactory(true);
            }
            for(final String className : serviceDesc.getInterfaces()) {
                service.addInterface(className);
            }
        }
    }

    private boolean isPrivateProperty(final String name) {
        final boolean isPrivate;
        if (org.osgi.framework.Constants.SERVICE_RANKING.equals(name)
                || org.osgi.framework.Constants.SERVICE_PID.equals(name)
                || org.osgi.framework.Constants.SERVICE_DESCRIPTION.equals(name)
                || org.osgi.framework.Constants.SERVICE_VENDOR.equals(name)
                || ConfigurationAdmin.SERVICE_BUNDLELOCATION.equals(name)
                || ConfigurationAdmin.SERVICE_FACTORYPID.equals(name) ) {
                isPrivate = true;
            } else {
                isPrivate = false;
            }
        return isPrivate;
    }

    /**
     * Process property directives
     */
    private void processProperties(
                    final ClassDescription current,
                    final ComponentContainer component,
                    final MetatypeContainer ocd) {
        for(final PropertyDescription pd : current.getDescriptions(PropertyDescription.class)) {

            if ( this.testProperty(current, component.getProperties(), pd, current == component.getClassDescription()) ) {
                final String name = pd.getName();
                if ( org.osgi.framework.Constants.SERVICE_ID.equals(name) ) {
                    iLog.addError("Class " + current.getDescribedClass().getName() + " is declaring " +
                                  "the protected property 'service.id'.", current.getSource() );
                    continue;

                }
                if ( ocd != null) {

                    // metatype - is this property private?
                    final boolean isPrivate;
                    if ( pd.isPrivate() != null ) {
                        isPrivate = pd.isPrivate();
                    } else {
                        if (isPrivateProperty(name) ) {
                            isPrivate = true;
                        } else {
                            isPrivate = false;
                        }
                    }
                    if ( !isPrivate ) {
                        final MetatypeAttributeDefinition ad = new MetatypeAttributeDefinition();
                        ocd.getProperties().add(ad);
                        ad.setId(pd.getName());
                        ad.setType(pd.getType().name());

                        if (pd.getLabel() != null ) {
                            ad.setName(pd.getLabel());
                        }
                        if (pd.getDescription() != null ) {
                            ad.setDescription(pd.getDescription());
                        }

                        if ( pd.getUnbounded() == PropertyUnbounded.DEFAULT ) {
                            if ( pd.getCardinality() != 0 ) {
                                ad.setCardinality(pd.getCardinality());
                            }
                        } else if ( pd.getUnbounded() == PropertyUnbounded.ARRAY ) {
                            // unlimited array
                            ad.setCardinality(new Integer(Integer.MAX_VALUE));
                        } else {
                            // unlimited vector
                            ad.setCardinality(new Integer(Integer.MIN_VALUE));
                        }

                        ad.setDefaultValue(pd.getValue());
                        ad.setDefaultMultiValue(pd.getMultiValue());

                        // check options
                        final String[] parameters = pd.getOptions();
                        if ( parameters != null && parameters.length > 0 ) {
                            final Map<String, String> options = new LinkedHashMap<String, String>();
                            for (int j=0; j < parameters.length; j=j+2) {
                                final String optionLabel = parameters[j];
                                final String optionValue = (j < parameters.length-1) ? parameters[j+1] : null;
                                if (optionValue != null) {
                                    options.put(optionLabel, optionValue);
                                }
                            }
                            ad.setOptions(options);
                        }
                    }
                } else {
                    // additional metatype checks (FELIX-4033)
                    if ( pd.isPrivate() != null && pd.isPrivate() ) {
                        iLog.addWarning("Property " + pd.getName() + " in class "
                                + current.getDescribedClass().getName() + " is set as private. " +
                                "This is redundant as no metatype will be generated.", current.getSource() );
                    }
                }
            }
        }
    }

    /**
     * Add global properties (if not already defined in the component)
     */
    private void processGlobalProperties(final ClassDescription desc,
                    final Map<String, PropertyDescription> allProperties) {
        // apply pre configured global properties
        if ( this.options.getProperties() != null ) {
            for(final Map.Entry<String, String> entry : this.options.getProperties().entrySet()) {
                final String propName = entry.getKey();
                final String value = entry.getValue();
                // check if the service already provides this property
                if ( value != null && !allProperties.containsKey(propName) ) {

                    final PropertyDescription p = new PropertyDescription(null);
                    p.setName(propName);
                    p.setValue(value);
                    p.setType(PropertyType.String);

                    allProperties.put(propName, p);
                }
            }
        }
    }

    /**
     * Test a newly found property
     */
    private boolean testProperty(final ClassDescription current,
                    final Map<String, PropertyDescription> allProperties,
                    final PropertyDescription newProperty,
                    final boolean isInspectedClass ) {
        final String propName = newProperty.getName();

        if ( !StringUtils.isEmpty(propName) ) {
            if ( allProperties.containsKey(propName) ) {
                // if the current class is the class we are currently inspecting, we
                // have found a duplicate definition
                if ( isInspectedClass ) {
                    iLog.addError("Duplicate definition for property " + propName + " in class "
                                    + current.getDescribedClass().getName(), current.getSource() );
                }
                return false;
            }
            allProperties.put(propName, newProperty);

        } else {
            // no name - generate a unique one
            allProperties.put(UUID.randomUUID().toString(), newProperty);
        }
        return true;
    }

    /**
     * Process reference directives
     * @throws SCRDescriptorException
     */
    private void processReferences(final ClassDescription current,
                    final ComponentContainer component) {
        for(final ReferenceDescription rd : current.getDescriptions(ReferenceDescription.class)) {
            if ( rd.getPolicyOption() != ReferencePolicyOption.RELUCTANT ) {
                component.getComponentDescription().setSpecVersion(SpecVersion.VERSION_1_2);
            }
            if ( rd.getUpdated() != null ) {
                // updated requires 1.2 or 1.1_FELIX, if nothing is set, we use 1.2
                if ( component.getComponentDescription().getSpecVersion() == null
                     || component.getComponentDescription().getSpecVersion().ordinal() < SpecVersion.VERSION_1_1_FELIX.ordinal() ) {
                    component.getComponentDescription().setSpecVersion(SpecVersion.VERSION_1_2);
                }
            }

            this.testReference(current, component.getReferences(), rd, component.getClassDescription() == current);

            // check for method signature - if interface name is set (empty interface name will fail during validate)
            if (!StringUtils.isEmpty(rd.getInterfaceName())) {

                try {
                    final Validator.MethodResult bindMethod = Validator.findMethod(this.project, this.options, current, rd,
                            rd.getBind() == null ? "bind" : rd.getBind());
                    if ( bindMethod != null ) {
                        component.getComponentDescription().setSpecVersion(bindMethod.requiredSpecVersion);
                    }

                    final Validator.MethodResult unbindMethod = Validator.findMethod(this.project, this.options, current, rd,
                            rd.getUnbind() == null ? "unbind" : rd.getUnbind());
                    if ( unbindMethod != null ) {
                        component.getComponentDescription().setSpecVersion(unbindMethod.requiredSpecVersion);
                    }

                } catch (final SCRDescriptorException sde) {
                    // this happens only if a class not found exception occurs, so we can ignore this at this point!
                }
            }
        }
    }

    /**
     * Test a newly found reference
     */
    private void testReference(final ClassDescription current,
                    final Map<String, ReferenceDescription> allReferences,
                    final ReferenceDescription newReference,
                    final boolean isInspectedClass ) {
        String refName = newReference.getName();
        if ( refName == null) {
            refName = newReference.getInterfaceName();
        }

        if ( refName != null ) {
            if ( allReferences.containsKey( refName ) ) {
                // if the current class is the class we are currently inspecting, we
                // have found a duplicate definition
                if ( isInspectedClass ) {
                    iLog.addError("Duplicate definition for reference " + refName + " in class "
                        + current.getDescribedClass().getName(), current.getSource() );
                }
            } else {
                allReferences.put(refName, newReference);
            }
        } else {
            // no name - generate a unique one
            allReferences.put(UUID.randomUUID().toString(), newReference);
        }
    }
}
TOP

Related Classes of org.apache.felix.scrplugin.SCRDescriptorGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.