Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * 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.List;
 import java.util.Map;
 import java.util.UUID;
 
The SCRDescriptorGenerator class does the hard work of generating the SCR descriptors. This class is being instantiated and configured by clients and the execute() method called to generate the descriptor files.

When using this class carefully consider calling all 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.

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 Log instance of logging.
 
     public SCRDescriptorGenerator(final Log logger) {
         this. = logger;
     }

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

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

    
Actually generates the Declarative Services and Metatype descriptors scanning the java sources provided by the setProject(org.apache.felix.scrplugin.Project)

Returns:
A list of generated file names, relative to the output directory
Throws:
SCRDescriptorException
SCRDescriptorFailureException
        this..debug("Starting SCR Descriptor Generator....");
        if (this. == null) {
            throw new SCRDescriptorFailureException("Project has not been set!");
        }
        if (this. == null) {
            // use default options
            this. = new Options();
        }
        if (this..getOutputDirectory() == null) {
            throw new SCRDescriptorFailureException("Output directory has not been set!");
        }
        this..debug("..using output directory: " + this..getOutputDirectory());
        this..debug("..using scr name: " + this..getSCRName());
        this..debug("..using metatype name: " + this..getMetaTypeName());
        this..debug("..strict mode: " + this..isStrictMode());
        this..debug("..generating accessors: " + this..isGenerateAccessors());
        this..debug("..generating separate descs: " + this..isGenerateSeparateDescriptors());
        // check speck version configuration
        SpecVersion specVersion = .getSpecVersion();
        if (specVersion == null) {
            this..debug("..auto detecting spec version");
        } else {
            this..debug("..using spec version " + specVersion.getName());
        }
        // create a log
        this. = new IssueLog(this..isStrictMode());
        // create the annotation processor manager
        final AnnotationProcessor aProcessor = new AnnotationProcessorManager(this.,
                        this..getClassLoader());
        // create the class scanner - and start scanning
        this. = new ClassScanner(aProcessor);
        final List<ClassDescriptionscannedDescriptions = .scanSources();
        // create the result to hold the list of processed source files
        final Result result = new Result();
        final List<ComponentContainerprocessedContainers = new ArrayList<ComponentContainer>();
        for (final ClassDescription desc : scannedDescriptions) {
            this..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) {
                .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);
                if (container.getComponentDescription().getSpecVersion() != null) {
                    if ( specVersion == null ) {
                        specVersion = container.getComponentDescription().getSpecVersion();
                        .debug("Setting used spec version to " + specVersion);
                    } else if (container.getComponentDescription().getSpecVersion().ordinal() > specVersion.ordinal() ) {
                        if ( this..getSpecVersion() != null) {
                            // if a spec version has been configured and a component requires a higher
                            // version, this is considered an error!
                            .addError("Component " + container + " requires spec version " + container.getComponentDescription().getSpecVersion().name()
                                            + " but plugin is configured to use version " + this..getSpecVersion(),
                                            desc.getSource());
                        } else {
                            specVersion = container.getComponentDescription().getSpecVersion();
                            .debug("Setting used spec version to " + specVersion);
                        }
                    }
                }
                processedContainers.add(container);
            }
        }
        // if spec version is still not set, we're using lowest available
        if ( specVersion == null ) {
            specVersion = .;
            .debug("Using default spec version " + specVersion);
        }
        this..debug("Generating descriptor for spec version: " + specVersion);
        .setSpecVersion(specVersion);
        final DescriptionContainer module = new DescriptionContainer(this.);
        // before we can validate we should check the references for bind/unbind method
        // in order to create them if possible
        if ( this..isGenerateAccessors() ) {
            for (final ComponentContainer container : processedContainers) {
                for (final ReferenceDescription ref : container.getReferences().values()) {
                    // 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() != . && ref.getField() != null
                        && ref.getField().getDeclaringClass().getName().equals(container.getClassDescription().getDescribedClass().getName())
                        && (ref.getCardinality() == . || ref.getCardinality() == .)) {
                        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.this.container.getClassDescription(), ref"bind") == null) {
                            // create bind method
                            createBind = true;
                        }
                        if (unbindValue == null && Validator.findMethod(this.this.container.getClassDescription(), ref"unbind") == null) {
                            // create unbind method
                            createUnbind = true;
                        }
                        if (createBind || createUnbind) {
                            // logging
                            if ( createBind && createUnbind ) {
                                this..debug("Generating bind and unbind method for " + name + " in " + container.getClassDescription().getDescribedClass().getName());
                            } else if ( createBind ) {
                                this..debug("Generating bind method for " + name + " in " + container.getClassDescription().getDescribedClass().getName());
                            } else {
                                this..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..getClassLoader(),
                                            this..getClassesDirectory(),
                                            this.);
                        }
                    }
                }
            }
        }
        // now validate
        for (final ComponentContainer container : processedContainers) {
            final int errorCount = .getNumberOfErrors();
            final Validator validator = new Validator(container);
            validator.validate();
            // ignore component if it has errors
            if (.getNumberOfErrors() == errorCount) {
                module.add(container);
            }
        }
        // log issues
        .logMessages();
        // after checking all classes, throw if there were any failures
        if (.hasErrors()) {
            throw new SCRDescriptorFailureException("SCR Descriptor parsing had failures (see log)");
        }
        // and generate files
        result.setMetatypeFiles(MetaTypeIO.generateDescriptors(modulethis.this.));
        result.setScrFiles(ComponentDescriptorIO.generateDescriptorFiles(modulethis.));
        return result;
    }

    
Create the SCR objects based on the descriptions
                    final IssueLog iLog) {
        final ComponentDescription componentDesc = desc.getDescription(ComponentDescription.class);
        // configuration pid in 1.2
        if ( componentDesc.getConfigurationPid() != null && !componentDesc.getConfigurationPid().equals(componentDesc.getName())) {
            componentDesc.setSpecVersion(.);
        }
        final ComponentContainer container = new ComponentContainer(desccomponentDesc);
        // Create metatype (if required)
        final MetatypeContainer ocd;
        if ( !componentDesc.isAbstract() && componentDesc.isCreateMetatype() ) {
            // OCD
            ocd = new MetatypeContainer();
            container.setMetatypeContainerocd );
            ocd.setIdcomponentDesc.getName() );
            if ( componentDesc.getLabel() != null ) {
                ocd.setNamecomponentDesc.getLabel() );
            } else {
                ocd.setName"%" + componentDesc.getName() + ".name");
            }
            if ( componentDesc.getDescription() != null ) {
                ocd.setDescriptioncomponentDesc.getDescription() );
            } else {
                ocd.setDescription"%" + componentDesc.getName() + ".description");
            }
            // Factory pid
            if ( componentDesc.isSetMetatypeFactoryPid() ) {
                if ( componentDesc.getFactory() == null ) {
                    ocd.setFactoryPidcomponentDesc.getName() );
                } else {
                    iLog.addWarning"Component factory " + componentDesc.getName()
                        + " should not set metatype factory pid."desc.getSource() );
                }
            }
        } else {
            ocd = null;
        }
        ClassDescription current = desc;
        boolean inherit;
        do {
            final ComponentDescription cd = current.getDescription(ComponentDescription.class);
            inherit = (cd == null ? true : cd.isInherit());
            if ( cd != null ) {
                // 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(.);
                }
                if ( componentDesc.getConfigurationPolicy() != . ) {
                    // policy requires 1.1
                    componentDesc.setSpecVersion(.);
                }
            }
            // services, properties, references
            this.processServices(currentcontainer);
            this.processProperties(currentcontainerocd);
            this.processReferences(currentcontainer);
            // go up in the class hierarchy
            if ( !inherit || current.getDescribedClass().getSuperclass() == null ) {
                current = null;
            } else {
                try {
                    current = this..getDescription(current.getDescribedClass().getSuperclass());
                } catch ( final SCRDescriptorFailureException sde) {
                    this..debug(sde.getMessage(), sde);
                    iLog.addError(sde.getMessage(), current.getSource());
                } catch ( final SCRDescriptorException sde) {
                    this..debug(sde.getSourceLocation() + " : " + sde.getMessage(), sde);
                    iLog.addError(sde.getMessage(), sde.getSourceLocation());
                }
            }
        } while ( current != null);
        // global properties
        this.processGlobalProperties(desccontainer.getProperties());
        // PID handling
        if ( componentDesc.isCreatePid() && !container.getProperties().containsKey(....)) {
            final PropertyDescription pid = new PropertyDescription(null);
            pid.setName.... );
            pid.setValuecomponentDesc.getName() );
            pid.setType(.);
            container.getProperties().put(....pid);
        }
        return container;
    }

    
Process service directives
    private void processServices(final ClassDescription currentfinal 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);
            }
        }
    }

    
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(currentcomponent.getProperties(), pdcurrent == component.getClassDescription()) && ocd != null) {
                // metatype - is this property private?
                final boolean isPrivate;
                if ( pd.isPrivate() != null ) {
                    isPrivate = pd.isPrivate();
                } else {
                    final String name = pd.getName();
                    if (.....equals(name)
                        || .....equals(name)
                        || .....equals(name)
                        || .....equals(name)
                        || .....equals(name)
                        || ..equals(name)
                        || ..equals(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());
                    } else {
                        ad.setName("%" + pd.getName() + ".name");
                    }
                    if (pd.getDescription() != null ) {
                        ad.setDescription(pd.getDescription());
                    } else {
                        ad.setDescription("%" + pd.getName() + ".description");
                    }
                    if ( pd.getUnbounded() == . ) {
                        if ( pd.getCardinality() != 0 ) {
                            ad.setCardinality(pd.getCardinality());
                        }
                    } else if ( pd.getUnbounded() == . ) {
                        // unlimited array
                        ad.setCardinality(new Integer(.));
                    } else {
                        // unlimited vector
                        ad.setCardinality(new Integer(.));
                    }
                    ad.setDefaultValue(pd.getValue());
                    ad.setDefaultMultiValue(pd.getMultiValue());
                    // check options
                    final String[] parameters = pd.getOptions();
                    if ( parameters != null && parameters.length > 0 ) {
                        final Map<StringStringoptions = new LinkedHashMap<StringString>();
                        for (int j=0; j < parameters.lengthj=j+2) {
                            final String optionLabel = parameters[j];
                            final String optionValue = (j < parameters.length-1) ? parameters[j+1] : null;
                            if (optionValue != null) {
                                options.put(optionLabeloptionValue);
                            }
                        }
                        ad.setOptions(options);
                    }
                }
            }
        }
    }

    
Add global properties (if not already defined in the component)
    private void processGlobalProperties(final ClassDescription desc,
                    final Map<StringPropertyDescriptionallProperties) {
        // apply pre configured global properties
        if ( this..getProperties() != null ) {
            for(final Map.Entry<StringStringentry : this..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(.);
                    allProperties.put(propNamep);
                }
            }
        }
    }

    
Test a newly found property
    private boolean testProperty(final ClassDescription current,
                    final Map<StringPropertyDescriptionallProperties,
                    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 ) {
                    .addError("Duplicate definition for property " + propName + " in class "
                                    + current.getDescribedClass().getName(), current.getSource() );
                }
                return false;
            }
            allProperties.put(propNamenewProperty);
        } else {
            // no name - generate a unique one
            allProperties.put(UUID.randomUUID().toString(), newProperty);
        }
        return true;
    }

    
Process reference directives
    private void processReferences(final ClassDescription current,
                    final ComponentContainer component) {
        for(final ReferenceDescription rd : current.getDescriptions(ReferenceDescription.class)) {
            if ( rd.getPolicyOption() != . ) {
                component.getComponentDescription().setSpecVersion(.);
            }
            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() < ..ordinal() ) {
                    component.getComponentDescription().setSpecVersion(.);
                }
            }
            this.testReference(currentcomponent.getReferences(), rdcomponent.getClassDescription() == current);
        }
    }

    
Test a newly found reference
    private void testReference(final ClassDescription current,
                    final Map<StringReferenceDescriptionallReferences,
                    final ReferenceDescription newReference,
                    final boolean isInspectedClass ) {
        String refName = newReference.getName();
        if ( refName == null) {
            refName = newReference.getInterfaceName();
        }
        if ( refName != null ) {
            if ( allReferences.containsKeyrefName ) ) {
                // if the current class is the class we are currently inspecting, we
                // have found a duplicate definition
                if ( isInspectedClass ) {
                    .addError("Duplicate definition for reference " + refName + " in class "
                        + current.getDescribedClass().getName(), current.getSource() );
                }
            } else {
                allReferences.put(refNamenewReference);
            }
        } else {
            // no name - generate a unique one
            allReferences.put(UUID.randomUUID().toString(), newReference);
        }
    }
New to GrepCode? Check out our FAQ X