FELIX-1684 Refactor plugin for non-Maven reuse. Everything maven specific
is in the o.a.f.scrplugin.mojo package. Everything else has no dependency
on Maven anymore.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@820997 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java
index 9dff339..06dab72 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java
@@ -21,9 +21,11 @@
 import java.io.File;
 
 /**
- * Constants
+ * The <code>Constants</code> interface provides use full constants for various
+ * values used for processing SCR annotations and JavaDoc tags into SCR
+ * descriptors.
  */
-public class Constants {
+public interface Constants {
 
     /** Version 1.0 (R4.1) */
     public static final int VERSION_1_0 = 0;
@@ -31,6 +33,11 @@
     /** Version 1.1 (R4.2) */
     public static final int VERSION_1_1 = 1;
 
+    /**
+     * The name of the Bundle manifest header providing the list of service
+     * component descriptor files.
+     */
+    public static final String SERVICE_COMPONENT = "Service-Component";
 
     public static final String COMPONENT = "scr.component";
 
@@ -144,8 +151,8 @@
 
     public static final String ABSTRACT_DESCRIPTOR_FILENAME = "scrinfo.xml";
 
-    public static final String ABSTRACT_DESCRIPTOR_RELATIVE_PATH = "OSGI-INF" + File.separator + "scr-plugin" + File.separator + ABSTRACT_DESCRIPTOR_FILENAME;
-
     public static final String ABSTRACT_DESCRIPTOR_ARCHIV_PATH = "OSGI-INF/scr-plugin/" + ABSTRACT_DESCRIPTOR_FILENAME;
 
+    public static final String ABSTRACT_DESCRIPTOR_RELATIVE_PATH = ABSTRACT_DESCRIPTOR_ARCHIV_PATH.replace( '/',
+        File.separatorChar );
 }
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/JavaClassDescriptorManager.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/JavaClassDescriptorManager.java
new file mode 100644
index 0000000..b9e1794
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/JavaClassDescriptorManager.java
@@ -0,0 +1,224 @@
+/*
+ * 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.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.felix.scrplugin.om.Component;
+import org.apache.felix.scrplugin.om.Components;
+import org.apache.felix.scrplugin.tags.ClassUtil;
+import org.apache.felix.scrplugin.tags.JavaClassDescription;
+import org.apache.felix.scrplugin.tags.annotation.AnnotationJavaClassDescription;
+import org.apache.felix.scrplugin.tags.annotation.AnnotationTagProviderManager;
+import org.apache.felix.scrplugin.tags.cl.ClassLoaderJavaClassDescription;
+import org.apache.felix.scrplugin.tags.qdox.QDoxJavaClassDescription;
+import org.apache.felix.scrplugin.xml.ComponentDescriptorIO;
+import com.thoughtworks.qdox.model.JavaClass;
+import com.thoughtworks.qdox.model.JavaSource;
+
+/**
+ * The <code>JavaClassDescriptorManager</code>
+ */
+public abstract class JavaClassDescriptorManager {
+
+    /** The maven log. */
+    protected final Log log;
+
+    /** The classloader used to compile the classes. */
+    private final ClassLoader classloader;
+
+    /** A cache containing the java class descriptions hashed by classname. */
+    private final Map<String, JavaClassDescription> javaClassDescriptions = new HashMap<String, JavaClassDescription>();
+
+    /**
+     * Supports mapping of built-in and custom java anntoations to {@link JavaTag} implementations.
+     */
+    private final AnnotationTagProviderManager annotationTagProviderManager;
+
+    /** Parse Javadocs? */
+    private final boolean parseJavadocs;
+
+    /** Process Annotations? */
+    private final boolean processAnnotations;
+
+    /**
+     * Construct a new manager.
+     * @param log
+     * @param project
+     * @param annotationTagProviders List of annotation tag providers
+     * @param excludeString The exclude information for sources
+     * @param parseJavadocs Should the javadocs be parsed?
+     * @param processAnnotations Should the annotations be processed?
+     * @throws SCRDescriptorFailureException
+     * @throws SCRDescriptorException
+     */
+    public JavaClassDescriptorManager(final Log          log,
+                                      final ClassLoader        classLoader,
+                                      final String[]     annotationTagProviders,
+                                      final boolean      parseJavadocs,
+                                      final boolean      processAnnotations)
+    throws SCRDescriptorFailureException {
+        this.processAnnotations = processAnnotations;
+        this.parseJavadocs = parseJavadocs;
+        this.log = log;
+        this.annotationTagProviderManager = new AnnotationTagProviderManager(annotationTagProviders);
+        this.classloader = classLoader;
+        ClassUtil.classLoader = this.classloader;
+    }
+
+    /**
+     * Return the log.
+     */
+    public Log getLog() {
+        return this.log;
+    }
+
+    /**
+     * Return the class laoder.
+     */
+    public ClassLoader getClassLoader() {
+        return this.classloader;
+    }
+
+    /**
+     * @return Annotation tag provider manager
+     */
+    public AnnotationTagProviderManager getAnnotationTagProviderManager() {
+        return this.annotationTagProviderManager;
+    }
+
+    /**
+     * Returns <code>true</code> if this class descriptor manager is parsing
+     * JavaDoc tags.
+     */
+    public boolean isParseJavadocs()
+    {
+        return parseJavadocs;
+    }
+
+    /**
+     * Returns <code>true</code> if this class descriptor manager is parsing
+     * Java 5 annotations.
+     */
+    public boolean isProcessAnnotations()
+    {
+        return processAnnotations;
+    }
+
+    protected Components parseServiceComponentDescriptor(InputStream file)
+    throws SCRDescriptorException {
+        final Components list = ComponentDescriptorIO.read(file);
+        return list;
+    }
+
+    /**
+     * Get the absolute path to the target directory where the class files are
+     * compiled to.
+     */
+    public abstract String getOutputDirectory();
+
+
+    /**
+     * Return all source descriptions of this project.
+     * @return All contained java class descriptions.
+     */
+    public JavaClassDescription[] getSourceDescriptions() throws SCRDescriptorException {
+        final JavaClass[] javaClasses = getJavaClassesFromSources();
+        final JavaClassDescription[] descs = new JavaClassDescription[javaClasses.length];
+        for(int i=0; i<javaClasses.length; i++) {
+            descs[i] = this.getJavaClassDescription(javaClasses[i].getFullyQualifiedName());
+        }
+        return descs;
+    }
+
+    /**
+     * Get a java class description for the class.
+     * @param className
+     * @return The java class description.
+     * @throws SCRDescriptorException
+     */
+    public JavaClassDescription getJavaClassDescription(String className)
+    throws SCRDescriptorException {
+        JavaClassDescription result = this.javaClassDescriptions.get(className);
+        if ( result == null ) {
+            this.log.debug("Searching description for: " + className);
+            int index = 0;
+            final JavaClass[] javaClasses = getJavaClassesFromSources();
+            while ( result == null && index < javaClasses.length) {
+                final JavaClass javaClass = javaClasses[index];
+                if ( javaClass.getFullyQualifiedName().equals(className) ) {
+                    try {
+                        // check for java annotation descriptions - fallback to QDox if none found
+                        Class<?> clazz = this.classloader.loadClass(className);
+                        if (this.processAnnotations && getAnnotationTagProviderManager().hasScrPluginAnnotation(javaClass)) {
+                            this.log.debug("Found java annotation description for: " + className);
+                            result = new AnnotationJavaClassDescription(clazz, javaClasses[index], this);
+                        } else if ( this.parseJavadocs ) {
+                            this.log.debug("Found qdox description for: " + className);
+                            result = new QDoxJavaClassDescription(clazz, javaClasses[index], this);
+                        }
+                    } catch (ClassNotFoundException e) {
+                        throw new SCRDescriptorException("Unable to load class " + className);
+                    }
+                } else {
+                    index++;
+                }
+            }
+            if ( result == null ) {
+                try {
+                    this.log.debug("Generating classloader description for: " + className);
+                    result = new ClassLoaderJavaClassDescription(this.classloader.loadClass(className), this.getComponentDescriptors().get(className), this);
+                } catch (ClassNotFoundException e) {
+                    throw new SCRDescriptorException("Unable to load class " + className);
+                }
+            }
+            this.javaClassDescriptions.put(className, result);
+        }
+        return result;
+    }
+
+
+    protected abstract JavaSource[] getSources() throws SCRDescriptorException;
+    protected abstract Map<String, Component> getComponentDescriptors() throws SCRDescriptorException;
+
+
+    /**
+     * Get a list of all {@link JavaClass} definitions four all source files (including nested/inner classes)
+     * @return List of {@link JavaClass} definitions
+     */
+    private JavaClass[] getJavaClassesFromSources() throws SCRDescriptorException {
+        final JavaSource[] sources = this.getSources();
+        final List<JavaClass> classes = new ArrayList<JavaClass>();
+        for(int i=0; i<sources.length; i++) {
+            for(int j=0; j<sources[i].getClasses().length; j++) {
+                final JavaClass clazz = sources[i].getClasses()[j];
+                classes.add(clazz);
+                for (int k=0; k<clazz.getNestedClasses().length; k++) {
+                    final JavaClass nestedClass = clazz.getNestedClasses()[k];
+                    classes.add(nestedClass);
+                }
+            }
+        }
+        return classes.toArray(new JavaClass[classes.size()]);
+    }
+
+}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/Log.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/Log.java
new file mode 100644
index 0000000..3398928
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/Log.java
@@ -0,0 +1,167 @@
+/*
+ * 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;
+
+
+/**
+ * This interface supplies the API for providing feedback to the user from
+ * SCR descriptor generation process using whatever means is implemented. There
+ * should be no big surprises here.
+ */
+public interface Log
+{
+    /**
+     * @return true if the <b>debug</b> error level is enabled
+     */
+    boolean isDebugEnabled();
+
+
+    /**
+     * Send a message to the user in the <b>debug</b> error level.
+     *
+     * @param content
+     */
+    void debug( String content );
+
+
+    /**
+     * Send a message (and accompanying exception) to the user in the <b>debug</b> error level.
+     * <br/>
+     * The error's stacktrace will be output when this error level is enabled.
+     *
+     * @param content
+     * @param error
+     */
+    void debug( String content, Throwable error );
+
+
+    /**
+     * Send an exception to the user in the <b>debug</b> error level.
+     * <br/>
+     * The stack trace for this exception will be output when this error level is enabled.
+     *
+     * @param error
+     */
+    void debug( Throwable error );
+
+
+    /**
+     * @return true if the <b>info</b> error level is enabled
+     */
+    boolean isInfoEnabled();
+
+
+    /**
+     * Send a message to the user in the <b>info</b> error level.
+     *
+     * @param content
+     */
+    void info( String content );
+
+
+    /**
+     * Send a message (and accompanying exception) to the user in the <b>info</b> error level.
+     * <br/>
+     * The error's stacktrace will be output when this error level is enabled.
+     *
+     * @param content
+     * @param error
+     */
+    void info( String content, Throwable error );
+
+
+    /**
+     * Send an exception to the user in the <b>info</b> error level.
+     * <br/>
+     * The stack trace for this exception will be output when this error level is enabled.
+     *
+     * @param error
+     */
+    void info( Throwable error );
+
+
+    /**
+     * @return true if the <b>warn</b> error level is enabled
+     */
+    boolean isWarnEnabled();
+
+
+    /**
+     * Send a message to the user in the <b>warn</b> error level.
+     *
+     * @param content
+     */
+    void warn( String content );
+
+
+    /**
+     * Send a message (and accompanying exception) to the user in the <b>warn</b> error level.
+     * <br/>
+     * The error's stacktrace will be output when this error level is enabled.
+     *
+     * @param content
+     * @param error
+     */
+    void warn( String content, Throwable error );
+
+
+    /**
+     * Send an exception to the user in the <b>warn</b> error level.
+     * <br/>
+     * The stack trace for this exception will be output when this error level is enabled.
+     *
+     * @param error
+     */
+    void warn( Throwable error );
+
+
+    /**
+     * @return true if the <b>error</b> error level is enabled
+     */
+    boolean isErrorEnabled();
+
+
+    /**
+     * Send a message to the user in the <b>error</b> error level.
+     *
+     * @param content
+     */
+    void error( String content );
+
+
+    /**
+     * Send a message (and accompanying exception) to the user in the <b>error</b> error level.
+     * <br/>
+     * The error's stacktrace will be output when this error level is enabled.
+     *
+     * @param content
+     * @param error
+     */
+    void error( String content, Throwable error );
+
+
+    /**
+     * Send an exception to the user in the <b>error</b> error level.
+     * <br/>
+     * The stack trace for this exception will be output when this error level is enabled.
+     *
+     * @param error
+     */
+    void error( Throwable error );
+}
\ No newline at end of file
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorException.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorException.java
new file mode 100644
index 0000000..13fa575
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorException.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+public class SCRDescriptorException extends Exception
+{
+
+    private static final long serialVersionUID = 1L;
+
+    public SCRDescriptorException(String message) {
+        super(message);
+    }
+
+    public SCRDescriptorException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorFailureException.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorFailureException.java
new file mode 100644
index 0000000..4b2ce6a
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorFailureException.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+
+public class SCRDescriptorFailureException extends Exception
+{
+
+    private static final long serialVersionUID = 1L;
+
+
+    public SCRDescriptorFailureException( String message )
+    {
+        super( message );
+    }
+
+
+    public SCRDescriptorFailureException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java
new file mode 100644
index 0000000..35155ca
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java
@@ -0,0 +1,862 @@
+/*
+ * 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.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.scrplugin.helper.IssueLog;
+import org.apache.felix.scrplugin.helper.PropertyHandler;
+import org.apache.felix.scrplugin.helper.StringUtils;
+import org.apache.felix.scrplugin.om.Component;
+import org.apache.felix.scrplugin.om.Components;
+import org.apache.felix.scrplugin.om.Implementation;
+import org.apache.felix.scrplugin.om.Interface;
+import org.apache.felix.scrplugin.om.Property;
+import org.apache.felix.scrplugin.om.Reference;
+import org.apache.felix.scrplugin.om.Service;
+import org.apache.felix.scrplugin.om.metatype.Designate;
+import org.apache.felix.scrplugin.om.metatype.MTObject;
+import org.apache.felix.scrplugin.om.metatype.MetaData;
+import org.apache.felix.scrplugin.om.metatype.OCD;
+import org.apache.felix.scrplugin.tags.JavaClassDescription;
+import org.apache.felix.scrplugin.tags.JavaClassDescriptionInheritanceComparator;
+import org.apache.felix.scrplugin.tags.JavaField;
+import org.apache.felix.scrplugin.tags.JavaTag;
+import org.apache.felix.scrplugin.tags.ModifiableJavaClassDescription;
+import org.apache.felix.scrplugin.tags.qdox.QDoxJavaClassDescription;
+import org.apache.felix.scrplugin.xml.ComponentDescriptorIO;
+import org.apache.felix.scrplugin.xml.MetaTypeIO;
+import org.osgi.service.metatype.MetaTypeService;
+
+/**
+ * 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.
+ */
+public class SCRDescriptorGenerator
+{
+
+    private final Log logger;
+
+    private File outputDirectory = null;
+
+    private JavaClassDescriptorManager descriptorManager;
+
+    private String finalName = "serviceComponents.xml";
+
+    private String metaTypeName = "metatype.xml";
+
+    private boolean generateAccessors = true;
+
+    protected boolean strictMode = false;
+
+    private Map<String, String> properties = new HashMap<String, String>();
+
+    private String specVersion = null;
+
+
+    public SCRDescriptorGenerator( Log logger )
+    {
+        this.logger = logger;
+    }
+
+
+    //---------- property setup (write-only for now)
+
+    public void setOutputDirectory( File outputDirectory )
+    {
+        this.outputDirectory = outputDirectory;
+    }
+
+
+    /**
+     * Sets the class path used for resolving tags and annotations. The first
+     * entry in the class path is assumed to be the build target location.
+     */
+    public void setDescriptorManager( JavaClassDescriptorManager descriptorManager )
+    {
+        this.descriptorManager = descriptorManager;
+    }
+
+    public void setFinalName( String finalName )
+    {
+        this.finalName = finalName;
+    }
+
+
+    public void setMetaTypeName( String metaTypeName )
+    {
+        this.metaTypeName = metaTypeName;
+    }
+
+
+    public void setGenerateAccessors( boolean generateAccessors )
+    {
+        this.generateAccessors = generateAccessors;
+    }
+
+
+    public void setStrictMode( boolean strictMode )
+    {
+        this.strictMode = strictMode;
+    }
+
+
+    public void setProperties( Map<String, String> properties )
+    {
+        this.properties = new HashMap<String, String>( properties );
+    }
+
+
+    public void setSpecVersion( String specVersion )
+    {
+        this.specVersion = specVersion;
+    }
+
+    //---------- descriptor generation
+
+    public boolean execute() throws SCRDescriptorException, SCRDescriptorFailureException
+    {
+        this.logger.debug( "Starting SCRDescriptorMojo...." );
+        this.logger.debug( "..generating accessors: " + this.generateAccessors );
+        this.logger.debug( "..parsing javadocs: " + this.descriptorManager.isParseJavadocs() );
+        this.logger.debug( "..processing annotations: " + this.descriptorManager.isProcessAnnotations() );
+
+        // check speck version configuration
+        int specVersion = Constants.VERSION_1_0;
+        if ( this.specVersion != null )
+        {
+            if ( this.specVersion.equals( "1.1" ) )
+            {
+                specVersion = Constants.VERSION_1_1;
+            }
+            else if ( !this.specVersion.equals( "1.0" ) )
+            {
+                throw new SCRDescriptorException( "Unknown configuration for spec version: " + this.specVersion );
+            }
+        }
+        else
+        {
+            this.logger.debug( "..auto detecting spec version" );
+        }
+        final IssueLog iLog = new IssueLog( this.strictMode );
+
+        final MetaData metaData = new MetaData();
+        metaData.setLocalization( MetaTypeService.METATYPE_DOCUMENTS_LOCATION + "/metatype" );
+
+        // iterate through all source classes and check for component tag
+        final JavaClassDescription[] javaSources = descriptorManager.getSourceDescriptions();
+        Arrays.sort( javaSources, new JavaClassDescriptionInheritanceComparator() );
+
+        final List<Component> scannedComponents = new ArrayList<Component>();
+        for ( int i = 0; i < javaSources.length; i++ )
+        {
+            this.logger.debug( "Testing source " + javaSources[i].getName() );
+            final JavaTag tag = javaSources[i].getTagByName( Constants.COMPONENT );
+            if ( tag != null )
+            {
+                this.logger.debug( "Processing service class " + javaSources[i].getName() );
+                // check if there is more than one component tag!
+                if ( javaSources[i].getTagsByName( Constants.COMPONENT, false ).length > 1 )
+                {
+                    iLog.addError( "Class " + javaSources[i].getName() + " has more than one " + Constants.COMPONENT
+                        + " tag." + " Merge the tags to a single tag." );
+                }
+                else
+                {
+                    final Component comp = this.createComponent( javaSources[i], tag, metaData, iLog );
+                    if ( comp.getSpecVersion() > specVersion )
+                    {
+                        // if a spec version has been configured and a component requires a higher
+                        // version, this is considered an error!
+                        if ( this.specVersion != null )
+                        {
+                            String v = "1.0";
+                            if ( comp.getSpecVersion() == Constants.VERSION_1_1 )
+                            {
+                                v = "1.1";
+                            }
+                            iLog.addError( "Component " + comp + " requires spec version " + v
+                                + " but plugin is configured to use version " + this.specVersion );
+                        }
+                        specVersion = comp.getSpecVersion();
+                    }
+                    scannedComponents.add( comp );
+                }
+            }
+        }
+        this.logger.debug( "..generating descriptor for spec version: " + this.specVersion );
+
+        // now check for abstract components and fill components objects
+        final Components components = new Components();
+        final Components abstractComponents = new Components();
+        components.setSpecVersion( specVersion );
+        abstractComponents.setSpecVersion( specVersion );
+
+        for ( final Component comp : scannedComponents )
+        {
+            final int errorCount = iLog.getNumberOfErrors();
+            // before we can validate we should check the references for bind/unbind method
+            // in order to create them if possible
+
+            for ( final Reference ref : comp.getReferences() )
+            {
+                // 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 ( this.generateAccessors && !ref.isLookupStrategy() )
+                {
+                    if ( ref.getJavaTag().getField() != null
+                        && comp.getJavaClassDescription() instanceof ModifiableJavaClassDescription )
+                    {
+                        if ( ref.getCardinality().equals( "0..1" ) || ref.getCardinality().equals( "1..1" ) )
+                        {
+                            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 && ref.findMethod( specVersion, "bind" ) == null )
+                            {
+                                // create bind method
+                                createBind = true;
+                            }
+                            if ( unbindValue == null && ref.findMethod( specVersion, "unbind" ) == null )
+                            {
+                                // create unbind method
+                                createUnbind = true;
+                            }
+                            if ( createBind || createUnbind )
+                            {
+                                ( ( ModifiableJavaClassDescription ) comp.getJavaClassDescription() ).addMethods( name,
+                                    type, createBind, createUnbind );
+                            }
+                        }
+                    }
+                }
+            }
+            comp.validate( specVersion, iLog );
+            // ignore component if it has errors
+            if ( iLog.getNumberOfErrors() == errorCount )
+            {
+                if ( !comp.isDs() )
+                {
+                    logger.debug( "Ignoring descriptor " + comp );
+                }
+                else if ( comp.isAbstract() )
+                {
+                    this.logger.debug( "Adding abstract descriptor " + comp );
+                    abstractComponents.addComponent( comp );
+                }
+                else
+                {
+                    this.logger.debug( "Adding descriptor " + comp );
+                    components.addComponent( comp );
+                    abstractComponents.addComponent( comp );
+                }
+            }
+        }
+
+        // log issues
+        logMessages( iLog );
+
+        // after checking all classes, throw if there were any failures
+        if ( iLog.hasErrors() )
+        {
+            throw new SCRDescriptorFailureException( "SCR Descriptor parsing had failures (see log)" );
+        }
+
+        boolean addResources = false;
+        // write meta type info if there is a file name
+        if ( !StringUtils.isEmpty( this.metaTypeName ) )
+        {
+            File mtFile = new File( this.outputDirectory, "OSGI-INF" + File.separator + "metatype" + File.separator
+                + this.metaTypeName );
+            final int size = metaData.getOCDs().size() + metaData.getDesignates().size();
+            if ( size > 0 )
+            {
+                this.logger.info( "Generating " + size + " MetaType Descriptors to " + mtFile );
+                mtFile.getParentFile().mkdirs();
+                MetaTypeIO.write( metaData, mtFile );
+                addResources = true;
+            }
+            else
+            {
+                if ( mtFile.exists() )
+                {
+                    mtFile.delete();
+                }
+            }
+
+        }
+        else
+        {
+            this.logger.info( "Meta type file name is not set: meta type info is not written." );
+        }
+
+        // if we have descriptors, write them in our scr private file (for component inheritance)
+        final File adFile = new File( this.outputDirectory, Constants.ABSTRACT_DESCRIPTOR_RELATIVE_PATH );
+        if ( !abstractComponents.getComponents().isEmpty() )
+        {
+            this.logger.info( "Writing abstract service descriptor " + adFile + " with "
+                + abstractComponents.getComponents().size() + " entries." );
+            adFile.getParentFile().mkdirs();
+            ComponentDescriptorIO.write( abstractComponents, adFile, true );
+            addResources = true;
+        }
+        else
+        {
+            this.logger.debug( "No abstract SCR Descriptors found in project." );
+            // remove file
+            if ( adFile.exists() )
+            {
+                this.logger.debug( "Removing obsolete abstract service descriptor " + adFile );
+                adFile.delete();
+            }
+        }
+
+        // check descriptor file
+        final File descriptorFile = StringUtils.isEmpty( this.finalName ) ? null : new File( new File(
+            this.outputDirectory, "OSGI-INF" ), this.finalName );
+
+        // terminate if there is nothing else to write
+        if ( components.getComponents().isEmpty() )
+        {
+            this.logger.debug( "No SCR Descriptors found in project." );
+            // remove file if it exists
+            if ( descriptorFile != null && descriptorFile.exists() )
+            {
+                this.logger.debug( "Removing obsolete service descriptor " + descriptorFile );
+                descriptorFile.delete();
+            }
+        }
+        else
+        {
+            if ( descriptorFile == null )
+            {
+                throw new SCRDescriptorFailureException( "Descriptor file name must not be empty." );
+            }
+
+            // finally the descriptors have to be written ....
+            descriptorFile.getParentFile().mkdirs(); // ensure parent dir
+
+            this.logger.info( "Generating " + components.getComponents().size() + " Service Component Descriptors to "
+                + descriptorFile );
+
+            ComponentDescriptorIO.write( components, descriptorFile, false );
+            addResources = true;
+        }
+
+        return addResources;
+    }
+
+
+    /**
+     * Create a component for the java class description.
+     * @param description
+     * @return The generated component descriptor or null if any error occurs.
+     * @throws SCRDescriptorException
+     */
+    protected Component createComponent( JavaClassDescription description, JavaTag componentTag, MetaData metaData,
+        final IssueLog iLog ) throws SCRDescriptorException
+    {
+        // create a new component
+        final Component component = new Component( componentTag );
+
+        // set implementation
+        component.setImplementation( new Implementation( description.getName() ) );
+
+        final OCD ocd = this.doComponent( componentTag, component, metaData, iLog );
+
+        boolean inherited = getBoolean( componentTag, Constants.COMPONENT_INHERIT, true );
+        this.doServices( description.getTagsByName( Constants.SERVICE, inherited ), component, description );
+
+        // collect references from class tags and fields
+        final Map<String, Object[]> references = new HashMap<String, Object[]>();
+        // Utility handler for propertie
+        final PropertyHandler propertyHandler = new PropertyHandler( component, ocd );
+
+        JavaClassDescription currentDescription = description;
+        do
+        {
+            // properties
+            final JavaTag[] props = currentDescription.getTagsByName( Constants.PROPERTY, false );
+            for ( int i = 0; i < props.length; i++ )
+            {
+                propertyHandler.testProperty( props[i], null, description == currentDescription );
+            }
+
+            // references
+            final JavaTag[] refs = currentDescription.getTagsByName( Constants.REFERENCE, false );
+            for ( int i = 0; i < refs.length; i++ )
+            {
+                this.testReference( references, refs[i], null, description == currentDescription );
+            }
+
+            // fields
+            final JavaField[] fields = currentDescription.getFields();
+            for ( int i = 0; i < fields.length; i++ )
+            {
+                JavaTag tag = fields[i].getTagByName( Constants.REFERENCE );
+                if ( tag != null )
+                {
+                    this.testReference( references, tag, fields[i].getName(), description == currentDescription );
+                }
+
+                propertyHandler.handleField( fields[i], description == currentDescription );
+            }
+
+            currentDescription = currentDescription.getSuperClass();
+        }
+        while ( inherited && currentDescription != null );
+
+        // process properties
+        propertyHandler.processProperties( this.properties, iLog );
+
+        // process references
+        final Iterator<Map.Entry<String, Object[]>> refIter = references.entrySet().iterator();
+        while ( refIter.hasNext() )
+        {
+            final Map.Entry<String, Object[]> entry = refIter.next();
+            final String refName = entry.getKey();
+            final Object[] values = entry.getValue();
+            final JavaTag tag = ( JavaTag ) values[0];
+            this.doReference( tag, refName, component, values[1].toString() );
+        }
+
+        // pid handling
+        final boolean createPid = getBoolean( componentTag, Constants.COMPONENT_CREATE_PID, true );
+        if ( createPid )
+        {
+            // check for an existing pid first
+            boolean found = false;
+            final Iterator<Property> iter = component.getProperties().iterator();
+            while ( !found && iter.hasNext() )
+            {
+                final Property prop = iter.next();
+                found = org.osgi.framework.Constants.SERVICE_PID.equals( prop.getName() );
+            }
+            if ( !found )
+            {
+                final Property pid = new Property();
+                component.addProperty( pid );
+                pid.setName( org.osgi.framework.Constants.SERVICE_PID );
+                pid.setValue( component.getName() );
+            }
+        }
+        return component;
+    }
+
+
+    /**
+     * Fill the component object with the information from the tag.
+     * @param tag
+     * @param component
+     */
+    protected OCD doComponent( JavaTag tag, Component component, MetaData metaData, final IssueLog iLog )
+    {
+
+        // check if this is an abstract definition
+        final String abstractType = tag.getNamedParameter( Constants.COMPONENT_ABSTRACT );
+        if ( abstractType != null )
+        {
+            component.setAbstract( "yes".equalsIgnoreCase( abstractType ) || "true".equalsIgnoreCase( abstractType ) );
+        }
+        else
+        {
+            // default true for abstract classes, false otherwise
+            component.setAbstract( tag.getJavaClassDescription().isAbstract() );
+        }
+
+        // check if this is a definition to ignore
+        final String ds = tag.getNamedParameter( Constants.COMPONENT_DS );
+        component.setDs( ( ds == null ) ? true : ( "yes".equalsIgnoreCase( ds ) || "true".equalsIgnoreCase( ds ) ) );
+
+        String name = tag.getNamedParameter( Constants.COMPONENT_NAME );
+        component.setName( StringUtils.isEmpty( name ) ? component.getImplementation().getClassame() : name );
+
+        component.setEnabled( Boolean.valueOf( getBoolean( tag, Constants.COMPONENT_ENABLED, true ) ) );
+        component.setFactory( tag.getNamedParameter( Constants.COMPONENT_FACTORY ) );
+
+        // FELIX-593: immediate attribute does not default to true all the
+        // times hence we only set it if declared in the tag
+        if ( tag.getNamedParameter( Constants.COMPONENT_IMMEDIATE ) != null )
+        {
+            component.setImmediate( Boolean.valueOf( getBoolean( tag, Constants.COMPONENT_IMMEDIATE, true ) ) );
+        }
+
+        // check for V1.1 attributes: configuration policy
+        if ( tag.getNamedParameter( Constants.COMPONENT_CONFIG_POLICY ) != null )
+        {
+            component.setSpecVersion( Constants.VERSION_1_1 );
+            component.setConfigurationPolicy( tag.getNamedParameter( Constants.COMPONENT_CONFIG_POLICY ) );
+        }
+        // check for V1.1 attributes: activate, deactivate
+        if ( tag.getNamedParameter( Constants.COMPONENT_ACTIVATE ) != null )
+        {
+            component.setSpecVersion( Constants.VERSION_1_1 );
+            component.setActivate( tag.getNamedParameter( Constants.COMPONENT_ACTIVATE ) );
+        }
+        if ( tag.getNamedParameter( Constants.COMPONENT_DEACTIVATE ) != null )
+        {
+            component.setSpecVersion( Constants.VERSION_1_1 );
+            component.setDeactivate( tag.getNamedParameter( Constants.COMPONENT_DEACTIVATE ) );
+        }
+        if ( tag.getNamedParameter( Constants.COMPONENT_MODIFIED ) != null )
+        {
+            component.setSpecVersion( Constants.VERSION_1_1 );
+            component.setModified( tag.getNamedParameter( Constants.COMPONENT_MODIFIED ) );
+        }
+
+        // whether metatype information is to generated for the component
+        final String metaType = tag.getNamedParameter( Constants.COMPONENT_METATYPE );
+        final boolean hasMetaType = metaType == null || "yes".equalsIgnoreCase( metaType )
+            || "true".equalsIgnoreCase( metaType );
+        if ( hasMetaType )
+        {
+            // ocd
+            final OCD ocd = new OCD();
+            metaData.addOCD( ocd );
+            ocd.setId( component.getName() );
+            String ocdName = tag.getNamedParameter( Constants.COMPONENT_LABEL );
+            if ( ocdName == null )
+            {
+                ocdName = "%" + component.getName() + ".name";
+            }
+            ocd.setName( ocdName );
+            String ocdDescription = tag.getNamedParameter( Constants.COMPONENT_DESCRIPTION );
+            if ( ocdDescription == null )
+            {
+                ocdDescription = "%" + component.getName() + ".description";
+            }
+            ocd.setDescription( ocdDescription );
+            // designate
+            final Designate designate = new Designate();
+            metaData.addDesignate( designate );
+            designate.setPid( component.getName() );
+
+            // factory pid
+            final String setFactoryPidValue = tag.getNamedParameter( Constants.COMPONENT_SET_METATYPE_FACTORY_PID );
+            final boolean setFactoryPid = setFactoryPidValue != null
+                && ( "yes".equalsIgnoreCase( setFactoryPidValue ) || "true".equalsIgnoreCase( setFactoryPidValue ) );
+            if ( setFactoryPid )
+            {
+                if ( component.getFactory() == null )
+                {
+                    designate.setFactoryPid( component.getName() );
+                }
+                else
+                {
+                    iLog.addWarning( "Component factory " + component.getName()
+                        + " should not set metatype factory pid." );
+                }
+            }
+            // designate.object
+            final MTObject mtobject = new MTObject();
+            designate.setObject( mtobject );
+            mtobject.setOcdref( component.getName() );
+            return ocd;
+        }
+        return null;
+    }
+
+
+    /**
+     * Process the service annotations
+     * @param services
+     * @param component
+     * @param description
+     * @throws SCRDescriptorException
+     */
+    protected void doServices( JavaTag[] services, Component component, JavaClassDescription description )
+        throws SCRDescriptorException
+    {
+        // no services, hence certainly no service factory
+        if ( services == null || services.length == 0 )
+        {
+            return;
+        }
+
+        final Service service = new Service();
+        component.setService( service );
+        boolean serviceFactory = false;
+        for ( int i = 0; i < services.length; i++ )
+        {
+            final String name = services[i].getNamedParameter( Constants.SERVICE_INTERFACE );
+            if ( StringUtils.isEmpty( name ) )
+            {
+
+                this.addInterfaces( service, services[i], description );
+            }
+            else
+            {
+                String interfaceName = name;
+                // check if the value points to a class/interface
+                // and search through the imports
+                // but only for local services
+                if ( description instanceof QDoxJavaClassDescription )
+                {
+                    final JavaClassDescription serviceClass = description.getReferencedClass( name );
+                    if ( serviceClass == null )
+                    {
+                        throw new SCRDescriptorException( "Interface '" + name + "' in class " + description.getName()
+                            + " does not point to a valid class/interface." );
+                    }
+                    interfaceName = serviceClass.getName();
+                }
+                final Interface interf = new Interface( services[i] );
+                interf.setInterfacename( interfaceName );
+                service.addInterface( interf );
+            }
+
+            serviceFactory |= getBoolean( services[i], Constants.SERVICE_FACTORY, false );
+        }
+
+        service.setServicefactory( serviceFactory );
+    }
+
+
+    /**
+     * Recursively add interfaces to the service.
+     */
+    protected void addInterfaces( final Service service, final JavaTag serviceTag,
+        final JavaClassDescription description ) throws SCRDescriptorException
+    {
+        if ( description != null )
+        {
+            JavaClassDescription[] interfaces = description.getImplementedInterfaces();
+            for ( int j = 0; j < interfaces.length; j++ )
+            {
+                final Interface interf = new Interface( serviceTag );
+                interf.setInterfacename( interfaces[j].getName() );
+                service.addInterface( interf );
+                // recursivly add interfaces implemented by this interface
+                this.addInterfaces( service, serviceTag, interfaces[j] );
+            }
+
+            // try super class
+            this.addInterfaces( service, serviceTag, description.getSuperClass() );
+        }
+    }
+
+
+    /**
+     * Test a newly found reference
+     * @param references
+     * @param reference
+     * @param defaultName
+     * @param isInspectedClass
+     * @throws SCRDescriptorException
+     */
+    protected void testReference( Map<String, Object[]> references, JavaTag reference, String defaultName,
+        boolean isInspectedClass ) throws SCRDescriptorException
+    {
+        final String refName = this.getReferenceName( reference, defaultName );
+
+        if ( refName != null )
+        {
+            if ( references.containsKey( refName ) )
+            {
+                // if the current class is the class we are currently inspecting, we
+                // have found a duplicate definition
+                if ( isInspectedClass )
+                {
+                    throw new SCRDescriptorException( "Duplicate definition for reference " + refName + " in class "
+                        + reference.getJavaClassDescription().getName() );
+                }
+            }
+            else
+            {
+                // ensure interface
+                String type = reference.getNamedParameter( Constants.REFERENCE_INTERFACE );
+                if ( StringUtils.isEmpty( type ) )
+                {
+                    if ( reference.getField() != null )
+                    {
+                        type = reference.getField().getType();
+                    }
+                    else
+                    {
+                        throw new SCRDescriptorException( "Interface missing for reference " + refName + " in class "
+                            + reference.getJavaClassDescription().getName() );
+                    }
+                }
+                else if ( isInspectedClass )
+                {
+                    // check if the value points to a class/interface
+                    // and search through the imports
+                    final JavaClassDescription serviceClass = reference.getJavaClassDescription().getReferencedClass(
+                        type );
+                    if ( serviceClass == null )
+                    {
+                        throw new SCRDescriptorException( "Interface '" + type + "' in class "
+                            + reference.getJavaClassDescription().getName()
+                            + " does not point to a valid class/interface." );
+                    }
+                    type = serviceClass.getName();
+                }
+                references.put( refName, new Object[]
+                    { reference, type } );
+            }
+        }
+    }
+
+
+    protected String getReferenceName( JavaTag reference, String defaultName ) throws SCRDescriptorException
+    {
+        String name = reference.getNamedParameter( Constants.REFERENCE_NAME );
+        if ( !StringUtils.isEmpty( name ) )
+        {
+            return name;
+        }
+        name = reference.getNamedParameter( Constants.REFERENCE_NAME_REF );
+        if ( !StringUtils.isEmpty( name ) )
+        {
+            final JavaField refField = this.getReferencedField( reference, name );
+            final String[] values = refField.getInitializationExpression();
+            if ( values == null || values.length == 0 )
+            {
+                throw new SCRDescriptorException( "Referenced field for " + name
+                    + " has no values for a reference name." );
+            }
+            if ( values.length > 1 )
+            {
+                throw new SCRDescriptorException( "Referenced field " + name
+                    + " has more than one value for a reference name." );
+            }
+            name = values[0];
+        }
+
+        return defaultName;
+    }
+
+
+    protected JavaField getReferencedField( final JavaTag tag, String ref ) throws SCRDescriptorException
+    {
+        int classSep = ref.lastIndexOf( '.' );
+        JavaField field = null;
+        if ( classSep == -1 )
+        {
+            // local variable
+            field = tag.getJavaClassDescription().getFieldByName( ref );
+        }
+        if ( field == null )
+        {
+            field = tag.getJavaClassDescription().getExternalFieldByName( ref );
+        }
+        if ( field == null )
+        {
+            throw new SCRDescriptorException( "Reference references unknown field " + ref + " in class "
+                + tag.getJavaClassDescription().getName() );
+        }
+        return field;
+    }
+
+
+    /**
+     * @param reference
+     * @param defaultName
+     * @param component
+     */
+    protected void doReference( JavaTag reference, String name, Component component, String type )
+        throws SCRDescriptorException
+    {
+        final Reference ref = new Reference( reference, component.getJavaClassDescription() );
+        ref.setName( name );
+        ref.setInterfacename( type );
+        ref.setCardinality( reference.getNamedParameter( Constants.REFERENCE_CARDINALITY ) );
+        if ( ref.getCardinality() == null )
+        {
+            ref.setCardinality( "1..1" );
+        }
+        ref.setPolicy( reference.getNamedParameter( Constants.REFERENCE_POLICY ) );
+        if ( ref.getPolicy() == null )
+        {
+            ref.setPolicy( "static" );
+        }
+        ref.setTarget( reference.getNamedParameter( Constants.REFERENCE_TARGET ) );
+        final String bindValue = reference.getNamedParameter( Constants.REFERENCE_BIND );
+        if ( bindValue != null )
+        {
+            ref.setBind( bindValue );
+        }
+        final String unbindValue = reference.getNamedParameter( Constants.REFERENCE_UNDBIND );
+        if ( unbindValue != null )
+        {
+            ref.setUnbind( unbindValue );
+        }
+        final String isChecked = reference.getNamedParameter( Constants.REFERENCE_CHECKED );
+        if ( isChecked != null )
+        {
+            ref.setChecked( Boolean.valueOf( isChecked ).booleanValue() );
+        }
+        final String strategy = reference.getNamedParameter( Constants.REFERENCE_STRATEGY );
+        if ( strategy != null )
+        {
+            ref.setStrategy( strategy );
+        }
+
+        component.addReference( ref );
+    }
+
+
+    public static boolean getBoolean( JavaTag tag, String name, boolean defaultValue )
+    {
+        String value = tag.getNamedParameter( name );
+        return ( value == null ) ? defaultValue : Boolean.valueOf( value ).booleanValue();
+    }
+
+
+    private void logMessages( final IssueLog iLog )
+    {
+        final Log log = logger;
+
+        // now log warnings and errors (warnings first)
+        // in strict mode everything is an error!
+        final Iterator<String> warnings = iLog.getWarnings();
+        while ( warnings.hasNext() )
+        {
+            if ( strictMode )
+            {
+                log.error( warnings.next() );
+            }
+            else
+            {
+                log.warn( warnings.next() );
+            }
+        }
+
+        final Iterator<String> errors = iLog.getErrors();
+        while ( errors.hasNext() )
+        {
+            log.error( errors.next() );
+        }
+    }
+}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java
deleted file mode 100644
index 2662880..0000000
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java
+++ /dev/null
@@ -1,727 +0,0 @@
-/*
- * 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.io.File;
-import java.util.*;
-
-import org.apache.felix.scrplugin.om.*;
-import org.apache.felix.scrplugin.om.metatype.*;
-import org.apache.felix.scrplugin.tags.*;
-import org.apache.felix.scrplugin.tags.qdox.QDoxJavaClassDescription;
-import org.apache.felix.scrplugin.xml.ComponentDescriptorIO;
-import org.apache.felix.scrplugin.xml.MetaTypeIO;
-import org.apache.maven.model.Resource;
-import org.apache.maven.plugin.*;
-import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.StringUtils;
-import org.osgi.service.metatype.MetaTypeService;
-
-/**
- * The <code>SCRDescriptorMojo</code>
- * generates a service descriptor file based on annotations found in the sources.
- *
- * @goal scr
- * @phase process-classes
- * @description Build Service Descriptors from Java Source
- * @requiresDependencyResolution compile
- */
-public class SCRDescriptorMojo extends AbstractMojo {
-
-    /**
-     * @parameter expression="${project.build.directory}/scr-plugin-generated"
-     * @required
-     * @readonly
-     */
-    private File outputDirectory;
-
-    /**
-     * The Maven project.
-     *
-     * @parameter expression="${project}"
-     * @required
-     * @readonly
-     */
-    private MavenProject project;
-
-    /**
-     * Name of the generated descriptor.
-     *
-     * @parameter expression="${scr.descriptor.name}" default-value="serviceComponents.xml"
-     */
-    private String finalName;
-
-    /**
-     * Name of the generated meta type file.
-     *
-     * @parameter default-value="metatype.xml"
-     */
-    private String metaTypeName;
-
-    /**
-     * This flag controls the generation of the bind/unbind methods.
-     * @parameter default-value="true"
-     */
-    private boolean generateAccessors;
-
-    /**
-     * This flag controls whether the javadoc source code will be scanned for
-     * tags.
-     * @parameter default-value="true"
-     */
-    protected boolean parseJavadoc;
-
-    /**
-     * This flag controls whether the annotations in the sources will be
-     * processed.
-     * @parameter default-value="true"
-     */
-    protected boolean processAnnotations;
-
-    /**
-     * In strict mode the plugin even fails on warnings.
-     * @parameter default-value="false"
-     */
-    protected boolean strictMode;
-
-    /**
-     * The comma separated list of tokens to exclude when processing sources.
-     *
-     * @parameter alias="excludes"
-     */
-    private String sourceExcludes;
-
-    /**
-     * Predefined properties.
-     *
-     * @parameter
-     */
-    private Map<String, String> properties = new HashMap<String, String>();
-
-    /**
-     * Allows to define additional implementations of the interface
-     * {@link org.apache.felix.scrplugin.tags.annotation.AnnotationTagProvider}
-     * that provide mappings from custom annotations to
-     * {@link org.apache.felix.scrplugin.tags.JavaTag} implementations.
-     * List of full qualified class file names.
-     *
-     * @parameter
-     */
-    private String[] annotationTagProviders = {};
-
-    /**
-     * The version of the DS spec this plugin generates a descriptor for.
-     * By default the version is detected by the used tags.
-     * @parameter
-     */
-    private String specVersion;
-
-    /**
-     * @see org.apache.maven.plugin.AbstractMojo#execute()
-     */
-    public void execute() throws MojoExecutionException, MojoFailureException {
-        this.getLog().debug("Starting SCRDescriptorMojo....");
-        this.getLog().debug("..generating accessors: " + this.generateAccessors);
-        this.getLog().debug("..parsing javadocs: " + this.parseJavadoc);
-        this.getLog().debug("..processing annotations: " + this.processAnnotations);
-
-        // check speck version configuration
-        int specVersion = Constants.VERSION_1_0;
-        if ( this.specVersion != null ) {
-            if ( this.specVersion.equals("1.1") ) {
-                specVersion = Constants.VERSION_1_1;
-            } else if ( !this.specVersion.equals("1.0") ) {
-                throw new MojoExecutionException("Unknown configuration for spec version: " + this.specVersion);
-            }
-        } else {
-            this.getLog().debug("..auto detecting spec version");
-        }
-        JavaClassDescriptorManager jManager = new JavaClassDescriptorManager(this.getLog(),
-                                                                             this.project,
-                                                                             this.annotationTagProviders,
-                                                                             this.sourceExcludes,
-                                                                             this.parseJavadoc,
-                                                                             this.processAnnotations);
-        final IssueLog iLog = new IssueLog(this.strictMode);
-
-        final MetaData metaData = new MetaData();
-        metaData.setLocalization(MetaTypeService.METATYPE_DOCUMENTS_LOCATION + "/metatype");
-
-        // iterate through all source classes and check for component tag
-        final JavaClassDescription[] javaSources = jManager.getSourceDescriptions();
-        Arrays.sort(javaSources, new JavaClassDescriptionInheritanceComparator());
-
-        final List<Component> scannedComponents = new ArrayList<Component>();
-        for (int i = 0; i < javaSources.length; i++) {
-            this.getLog().debug("Testing source " + javaSources[i].getName());
-            final JavaTag tag = javaSources[i].getTagByName(Constants.COMPONENT);
-            if (tag != null) {
-                this.getLog().debug("Processing service class " + javaSources[i].getName());
-                // check if there is more than one component tag!
-                if ( javaSources[i].getTagsByName(Constants.COMPONENT, false).length > 1 ) {
-                    iLog.addError("Class " + javaSources[i].getName() + " has more than one " + Constants.COMPONENT + " tag." +
-                            " Merge the tags to a single tag.");
-                } else {
-                    final Component comp = this.createComponent(javaSources[i], tag, metaData, iLog);
-                    if ( comp.getSpecVersion() > specVersion ) {
-                        // if a spec version has been configured and a component requires a higher
-                        // version, this is considered an error!
-                        if ( this.specVersion != null ) {
-                            String v = "1.0";
-                            if ( comp.getSpecVersion() == Constants.VERSION_1_1 ) {
-                                v = "1.1";
-                            }
-                            iLog.addError("Component " + comp + " requires spec version " + v + " but plugin is configured to use version " + this.specVersion);
-                        }
-                        specVersion = comp.getSpecVersion();
-                    }
-                    scannedComponents.add(comp);
-                }
-            }
-        }
-        this.getLog().debug("..generating descriptor for spec version: " + this.specVersion);
-
-        // now check for abstract components and fill components objects
-        final Components components = new Components();
-        final Components abstractComponents = new Components();
-        components.setSpecVersion(specVersion);
-        abstractComponents.setSpecVersion(specVersion);
-
-        for(final Component comp : scannedComponents ) {
-            final int errorCount = iLog.getNumberOfErrors();
-            // before we can validate we should check the references for bind/unbind method
-            // in order to create them if possible
-
-            for(final Reference ref : comp.getReferences() ) {
-                // 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 ( this.generateAccessors && !ref.isLookupStrategy() ) {
-                    if ( ref.getJavaTag().getField() != null && comp.getJavaClassDescription() instanceof ModifiableJavaClassDescription ) {
-                        if ( ref.getCardinality().equals("0..1") || ref.getCardinality().equals("1..1") ) {
-                            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 && ref.findMethod(specVersion, "bind") == null ) {
-                                // create bind method
-                                createBind = true;
-                            }
-                            if ( unbindValue == null && ref.findMethod(specVersion, "unbind") == null ) {
-                                // create unbind method
-                                createUnbind = true;
-                            }
-                            if ( createBind || createUnbind ) {
-                                ((ModifiableJavaClassDescription)comp.getJavaClassDescription()).addMethods(name, type, createBind, createUnbind);
-                            }
-                        }
-                    }
-                }
-            }
-            comp.validate(specVersion, iLog);
-            // ignore component if it has errors
-            if ( iLog.getNumberOfErrors() == errorCount ) {
-                if ( !comp.isDs() ) {
-                    getLog().debug("Ignoring descriptor " + comp);
-                } else if ( comp.isAbstract() ) {
-                    this.getLog().debug("Adding abstract descriptor " + comp);
-                    abstractComponents.addComponent(comp);
-                } else {
-                    this.getLog().debug("Adding descriptor " + comp);
-                    components.addComponent(comp);
-                    abstractComponents.addComponent(comp);
-                }
-            }
-        }
-
-        // log issues
-        iLog.log(this.getLog());
-
-        // after checking all classes, throw if there were any failures
-        if ( iLog.hasErrors() ) {
-            throw new MojoFailureException("SCR Descriptor parsing had failures (see log)");
-        }
-
-        boolean addResources = false;
-        // write meta type info if there is a file name
-        if (!StringUtils.isEmpty(this.metaTypeName)) {
-            File mtFile = new File(this.outputDirectory, "OSGI-INF" + File.separator + "metatype" + File.separator + this.metaTypeName);
-            final int size = metaData.getOCDs().size() + metaData.getDesignates().size();
-            if (size > 0 ) {
-                this.getLog().info("Generating "
-                    + size
-                    + " MetaType Descriptors to " + mtFile);
-                mtFile.getParentFile().mkdirs();
-                MetaTypeIO.write(metaData, mtFile);
-                addResources = true;
-            } else {
-                if ( mtFile.exists() ) {
-                    mtFile.delete();
-                }
-            }
-
-        } else {
-            this.getLog().info("Meta type file name is not set: meta type info is not written.");
-        }
-
-        // if we have descriptors, write them in our scr private file (for component inheritance)
-        final File adFile = new File(this.outputDirectory, Constants.ABSTRACT_DESCRIPTOR_RELATIVE_PATH);
-        if ( !abstractComponents.getComponents().isEmpty() ) {
-            this.getLog().info("Writing abstract service descriptor " + adFile + " with " + abstractComponents.getComponents().size() + " entries.");
-            adFile.getParentFile().mkdirs();
-            ComponentDescriptorIO.write(abstractComponents, adFile, true);
-            addResources = true;
-        } else {
-            this.getLog().debug("No abstract SCR Descriptors found in project.");
-            // remove file
-            if ( adFile.exists() ) {
-                this.getLog().debug("Removing obsolete abstract service descriptor " + adFile);
-                adFile.delete();
-            }
-        }
-
-        // check descriptor file
-        final File descriptorFile = StringUtils.isEmpty(this.finalName) ? null : new File(new File(this.outputDirectory, "OSGI-INF"), this.finalName);
-
-        // terminate if there is nothing else to write
-        if (components.getComponents().isEmpty()) {
-            this.getLog().debug("No SCR Descriptors found in project.");
-            // remove file if it exists
-            if ( descriptorFile != null && descriptorFile.exists() ) {
-                this.getLog().debug("Removing obsolete service descriptor " + descriptorFile);
-                descriptorFile.delete();
-            }
-        } else {
-
-            if (descriptorFile == null) {
-                throw new MojoFailureException("Descriptor file name must not be empty.");
-            }
-
-            // finally the descriptors have to be written ....
-            descriptorFile.getParentFile().mkdirs(); // ensure parent dir
-
-            this.getLog().info("Generating " + components.getComponents().size()
-                    + " Service Component Descriptors to " + descriptorFile);
-
-            ComponentDescriptorIO.write(components, descriptorFile, false);
-            addResources = true;
-
-            // and set include accordingly
-            String svcComp = project.getProperties().getProperty("Service-Component");
-            svcComp= (svcComp == null) ? "OSGI-INF/" + finalName : svcComp + ", " + "OSGI-INF/" + finalName;
-            project.getProperties().setProperty("Service-Component", svcComp);
-        }
-
-        // now add the descriptor directory to the maven resources
-        if (addResources) {
-            final String ourRsrcPath = this.outputDirectory.getAbsolutePath();
-            boolean found = false;
-            @SuppressWarnings("unchecked")
-            final Iterator<Resource> rsrcIterator = this.project.getResources().iterator();
-            while ( !found && rsrcIterator.hasNext() ) {
-                final Resource rsrc = rsrcIterator.next();
-                found = rsrc.getDirectory().equals(ourRsrcPath);
-            }
-            if ( !found ) {
-                final Resource resource = new Resource();
-                resource.setDirectory(this.outputDirectory.getAbsolutePath());
-                this.project.addResource(resource);
-            }
-        }
-    }
-
-    /**
-     * Create a component for the java class description.
-     * @param description
-     * @return The generated component descriptor or null if any error occurs.
-     * @throws MojoExecutionException
-     */
-    protected Component createComponent(JavaClassDescription description,
-                                        JavaTag componentTag,
-                                        MetaData metaData,
-                                        final IssueLog iLog)
-    throws MojoExecutionException {
-        // create a new component
-        final Component component = new Component(componentTag);
-
-        // set implementation
-        component.setImplementation(new Implementation(description.getName()));
-
-        final OCD ocd = this.doComponent(componentTag, component, metaData, iLog);
-
-        boolean inherited = getBoolean(componentTag, Constants.COMPONENT_INHERIT, true);
-        this.doServices(description.getTagsByName(Constants.SERVICE, inherited), component, description);
-
-        // collect references from class tags and fields
-        final Map<String, Object[]> references = new HashMap<String, Object[]>();
-        // Utility handler for propertie
-        final PropertyHandler propertyHandler = new PropertyHandler(component, ocd);
-
-        JavaClassDescription currentDescription = description;
-        do {
-            // properties
-            final JavaTag[] props = currentDescription.getTagsByName(Constants.PROPERTY, false);
-            for (int i=0; i < props.length; i++) {
-                propertyHandler.testProperty(props[i], null, description == currentDescription);
-            }
-
-            // references
-            final JavaTag[] refs = currentDescription.getTagsByName(Constants.REFERENCE, false);
-            for (int i=0; i < refs.length; i++) {
-                this.testReference(references, refs[i], null, description == currentDescription);
-            }
-
-            // fields
-            final JavaField[] fields = currentDescription.getFields();
-            for (int i=0; i < fields.length; i++) {
-                JavaTag tag = fields[i].getTagByName(Constants.REFERENCE);
-                if (tag != null) {
-                    this.testReference(references, tag, fields[i].getName(), description == currentDescription);
-                }
-
-                propertyHandler.handleField(fields[i], description == currentDescription);
-            }
-
-            currentDescription = currentDescription.getSuperClass();
-        } while (inherited && currentDescription != null);
-
-        // process properties
-        propertyHandler.processProperties(this.properties, iLog);
-
-        // process references
-        final Iterator<Map.Entry<String, Object[]>> refIter = references.entrySet().iterator();
-        while ( refIter.hasNext() ) {
-            final Map.Entry<String, Object[]> entry = refIter.next();
-            final String refName = entry.getKey();
-            final Object[] values = entry.getValue();
-            final JavaTag tag = (JavaTag)values[0];
-            this.doReference(tag, refName, component, values[1].toString());
-        }
-
-        // pid handling
-        final boolean createPid = getBoolean(componentTag, Constants.COMPONENT_CREATE_PID, true);
-        if ( createPid ) {
-            // check for an existing pid first
-            boolean found = false;
-            final Iterator<Property> iter = component.getProperties().iterator();
-            while ( !found && iter.hasNext() ) {
-                final Property prop = iter.next();
-                found = org.osgi.framework.Constants.SERVICE_PID.equals( prop.getName() );
-            }
-            if ( !found ) {
-                final Property pid = new Property();
-                component.addProperty(pid);
-                pid.setName(org.osgi.framework.Constants.SERVICE_PID);
-                pid.setValue(component.getName());
-            }
-        }
-        return component;
-    }
-
-    /**
-     * Fill the component object with the information from the tag.
-     * @param tag
-     * @param component
-     */
-    protected OCD doComponent(JavaTag tag, Component component, MetaData metaData,
-            final IssueLog iLog) {
-
-        // check if this is an abstract definition
-        final String abstractType = tag.getNamedParameter(Constants.COMPONENT_ABSTRACT);
-        if (abstractType != null) {
-            component.setAbstract("yes".equalsIgnoreCase(abstractType) || "true".equalsIgnoreCase(abstractType));
-        } else {
-            // default true for abstract classes, false otherwise
-            component.setAbstract(tag.getJavaClassDescription().isAbstract());
-        }
-
-        // check if this is a definition to ignore
-        final String ds = tag.getNamedParameter(Constants.COMPONENT_DS);
-        component.setDs((ds == null) ? true : ("yes".equalsIgnoreCase(ds) || "true".equalsIgnoreCase(ds)));
-
-        String name = tag.getNamedParameter(Constants.COMPONENT_NAME);
-        component.setName(StringUtils.isEmpty(name) ? component.getImplementation().getClassame() : name);
-
-        component.setEnabled(Boolean.valueOf(getBoolean(tag, Constants.COMPONENT_ENABLED, true)));
-        component.setFactory(tag.getNamedParameter(Constants.COMPONENT_FACTORY));
-
-        // FELIX-593: immediate attribute does not default to true all the
-        // times hence we only set it if declared in the tag
-        if (tag.getNamedParameter(Constants.COMPONENT_IMMEDIATE) != null) {
-            component.setImmediate(Boolean.valueOf(getBoolean(tag,
-                Constants.COMPONENT_IMMEDIATE, true)));
-        }
-
-        // check for V1.1 attributes: configuration policy
-        if ( tag.getNamedParameter(Constants.COMPONENT_CONFIG_POLICY) != null ) {
-            component.setSpecVersion(Constants.VERSION_1_1);
-            component.setConfigurationPolicy(tag.getNamedParameter(Constants.COMPONENT_CONFIG_POLICY));
-        }
-        // check for V1.1 attributes: activate, deactivate
-        if ( tag.getNamedParameter(Constants.COMPONENT_ACTIVATE) != null ) {
-            component.setSpecVersion(Constants.VERSION_1_1);
-            component.setActivate(tag.getNamedParameter(Constants.COMPONENT_ACTIVATE));
-        }
-        if ( tag.getNamedParameter(Constants.COMPONENT_DEACTIVATE) != null ) {
-            component.setSpecVersion(Constants.VERSION_1_1);
-            component.setDeactivate(tag.getNamedParameter(Constants.COMPONENT_DEACTIVATE));
-        }
-        if ( tag.getNamedParameter(Constants.COMPONENT_MODIFIED) != null ) {
-            component.setSpecVersion(Constants.VERSION_1_1);
-            component.setModified(tag.getNamedParameter(Constants.COMPONENT_MODIFIED));
-        }
-
-        // whether metatype information is to generated for the component
-        final String metaType = tag.getNamedParameter(Constants.COMPONENT_METATYPE);
-        final boolean hasMetaType = metaType == null || "yes".equalsIgnoreCase(metaType)
-            || "true".equalsIgnoreCase(metaType);
-        if ( hasMetaType ) {
-            // ocd
-            final OCD ocd = new OCD();
-            metaData.addOCD(ocd);
-            ocd.setId(component.getName());
-            String ocdName = tag.getNamedParameter(Constants.COMPONENT_LABEL);
-            if ( ocdName == null ) {
-                ocdName = "%" + component.getName() + ".name";
-            }
-            ocd.setName(ocdName);
-            String ocdDescription = tag.getNamedParameter(Constants.COMPONENT_DESCRIPTION);
-            if ( ocdDescription == null ) {
-                ocdDescription = "%" + component.getName() + ".description";
-            }
-            ocd.setDescription(ocdDescription);
-            // designate
-            final Designate designate = new Designate();
-            metaData.addDesignate(designate);
-            designate.setPid(component.getName());
-
-            // factory pid
-            final String setFactoryPidValue = tag.getNamedParameter(Constants.COMPONENT_SET_METATYPE_FACTORY_PID);
-            final boolean setFactoryPid = setFactoryPidValue != null &&
-                ("yes".equalsIgnoreCase(setFactoryPidValue) || "true".equalsIgnoreCase(setFactoryPidValue));
-            if ( setFactoryPid ) {
-                if ( component.getFactory() == null ) {
-                    designate.setFactoryPid( component.getName() );
-                } else {
-                    iLog.addError("Component factory " + component.getName() + " should not set metatype factory pid.");
-                }
-            }
-            // designate.object
-            final MTObject mtobject = new MTObject();
-            designate.setObject(mtobject);
-            mtobject.setOcdref(component.getName());
-            return ocd;
-        }
-        return null;
-    }
-
-    /**
-     * Process the service annotations
-     * @param services
-     * @param component
-     * @param description
-     * @throws MojoExecutionException
-     */
-    protected void doServices(JavaTag[] services, Component component, JavaClassDescription description)
-    throws MojoExecutionException {
-        // no services, hence certainly no service factory
-        if (services == null || services.length == 0) {
-            return;
-        }
-
-        final Service service = new Service();
-        component.setService(service);
-        boolean serviceFactory = false;
-        for (int i=0; i < services.length; i++) {
-            final String name = services[i].getNamedParameter(Constants.SERVICE_INTERFACE);
-            if (StringUtils.isEmpty(name)) {
-
-                this.addInterfaces(service, services[i], description);
-            } else {
-                String interfaceName = name;
-                // check if the value points to a class/interface
-                // and search through the imports
-                // but only for local services
-                if ( description instanceof QDoxJavaClassDescription ) {
-                    final JavaClassDescription serviceClass = description.getReferencedClass(name);
-                    if ( serviceClass == null ) {
-                        throw new MojoExecutionException("Interface '"+ name + "' in class " + description.getName() + " does not point to a valid class/interface.");
-                    }
-                    interfaceName = serviceClass.getName();
-                }
-                final Interface interf = new Interface(services[i]);
-                interf.setInterfacename(interfaceName);
-                service.addInterface(interf);
-            }
-
-            serviceFactory |= getBoolean(services[i], Constants.SERVICE_FACTORY, false);
-        }
-
-        service.setServicefactory(serviceFactory);
-    }
-
-    /**
-     * Recursively add interfaces to the service.
-     */
-    protected void addInterfaces(final Service service, final JavaTag serviceTag, final JavaClassDescription description)
-    throws MojoExecutionException {
-        if ( description != null ) {
-            JavaClassDescription[] interfaces = description.getImplementedInterfaces();
-            for (int j=0; j < interfaces.length; j++) {
-                final Interface interf = new Interface(serviceTag);
-                interf.setInterfacename(interfaces[j].getName());
-                service.addInterface(interf);
-                // recursivly add interfaces implemented by this interface
-                this.addInterfaces(service, serviceTag, interfaces[j]);
-            }
-
-            // try super class
-            this.addInterfaces(service, serviceTag, description.getSuperClass());
-        }
-    }
-
-    /**
-     * Test a newly found reference
-     * @param references
-     * @param reference
-     * @param defaultName
-     * @param isInspectedClass
-     * @throws MojoExecutionException
-     */
-    protected void testReference(Map<String, Object[]> references, JavaTag reference, String defaultName, boolean isInspectedClass)
-    throws MojoExecutionException {
-        final String refName = this.getReferenceName(reference, defaultName);
-
-        if ( refName != null ) {
-            if ( references.containsKey(refName) ) {
-                // if the current class is the class we are currently inspecting, we
-                // have found a duplicate definition
-                if ( isInspectedClass ) {
-                    throw new MojoExecutionException("Duplicate definition for reference " + refName + " in class " + reference.getJavaClassDescription().getName());
-                }
-            } else {
-                // ensure interface
-                String type = reference.getNamedParameter(Constants.REFERENCE_INTERFACE);
-                if (StringUtils.isEmpty(type)) {
-                    if ( reference.getField() != null ) {
-                        type = reference.getField().getType();
-                    } else {
-                        throw new MojoExecutionException("Interface missing for reference " + refName + " in class " + reference.getJavaClassDescription().getName());
-                    }
-                } else if ( isInspectedClass ) {
-                    // check if the value points to a class/interface
-                    // and search through the imports
-                    final JavaClassDescription serviceClass = reference.getJavaClassDescription().getReferencedClass(type);
-                    if ( serviceClass == null ) {
-                        throw new MojoExecutionException("Interface '"+ type + "' in class " + reference.getJavaClassDescription().getName() + " does not point to a valid class/interface.");
-                    }
-                    type = serviceClass.getName();
-                }
-                references.put(refName, new Object[] {reference, type});
-            }
-        }
-    }
-
-    protected String getReferenceName(JavaTag reference, String defaultName)
-    throws MojoExecutionException {
-        String name = reference.getNamedParameter(Constants.REFERENCE_NAME);
-        if (!StringUtils.isEmpty(name)) {
-            return name;
-        }
-        name = reference.getNamedParameter(Constants.REFERENCE_NAME_REF);
-        if (!StringUtils.isEmpty(name)) {
-            final JavaField refField = this.getReferencedField(reference, name);
-            final String[] values = refField.getInitializationExpression();
-            if ( values == null || values.length == 0 ) {
-                throw new MojoExecutionException("Referenced field for " + name + " has no values for a reference name.");
-            }
-            if ( values.length > 1 ) {
-                throw new MojoExecutionException("Referenced field " + name + " has more than one value for a reference name.");
-            }
-            name = values[0];
-        }
-
-        return defaultName;
-    }
-
-    protected JavaField getReferencedField(final JavaTag tag, String ref)
-    throws MojoExecutionException {
-        int classSep = ref.lastIndexOf('.');
-        JavaField field = null;
-        if ( classSep == -1 ) {
-            // local variable
-            field = tag.getJavaClassDescription().getFieldByName(ref);
-        }
-        if ( field == null ) {
-            field = tag.getJavaClassDescription().getExternalFieldByName(ref);
-        }
-        if ( field == null ) {
-            throw new MojoExecutionException("Reference references unknown field " + ref + " in class " + tag.getJavaClassDescription().getName());
-        }
-        return field;
-    }
-
-    /**
-     * @param reference
-     * @param defaultName
-     * @param component
-     */
-    protected void doReference(JavaTag reference, String name, Component component, String type)
-    throws MojoExecutionException {
-        final Reference ref = new Reference(reference, component.getJavaClassDescription());
-        ref.setName(name);
-        ref.setInterfacename(type);
-        ref.setCardinality(reference.getNamedParameter(Constants.REFERENCE_CARDINALITY));
-        if ( ref.getCardinality() == null ) {
-            ref.setCardinality("1..1");
-        }
-        ref.setPolicy(reference.getNamedParameter(Constants.REFERENCE_POLICY));
-        if ( ref.getPolicy() == null ) {
-            ref.setPolicy("static");
-        }
-        ref.setTarget(reference.getNamedParameter(Constants.REFERENCE_TARGET));
-        final String bindValue = reference.getNamedParameter(Constants.REFERENCE_BIND);
-        if ( bindValue != null ) {
-            ref.setBind(bindValue);
-        }
-        final String unbindValue = reference.getNamedParameter(Constants.REFERENCE_UNDBIND);
-        if ( unbindValue != null ) {
-            ref.setUnbind(unbindValue);
-        }
-        final String isChecked = reference.getNamedParameter(Constants.REFERENCE_CHECKED);
-        if ( isChecked != null ) {
-            ref.setChecked(Boolean.valueOf(isChecked).booleanValue());
-        }
-        final String strategy = reference.getNamedParameter(Constants.REFERENCE_STRATEGY);
-        if ( strategy != null ) {
-            ref.setStrategy(strategy);
-        }
-
-        component.addReference(ref);
-    }
-
-    public static boolean getBoolean(JavaTag tag, String name, boolean defaultValue) {
-        String value = tag.getNamedParameter(name);
-        return (value == null) ? defaultValue : Boolean.valueOf(value).booleanValue();
-    }
-}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/IssueLog.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/helper/IssueLog.java
similarity index 76%
rename from scrplugin/src/main/java/org/apache/felix/scrplugin/IssueLog.java
rename to scrplugin/src/main/java/org/apache/felix/scrplugin/helper/IssueLog.java
index 756821b..bc5e40a 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/IssueLog.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/helper/IssueLog.java
@@ -16,13 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.felix.scrplugin;
+package org.apache.felix.scrplugin.helper;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
-import org.apache.maven.plugin.logging.Log;
-
 /**
  * Utility class for handling errors and warnings
  */
@@ -54,19 +53,11 @@
         warnings.add(e);
     }
 
-    public void log(final Log log) {
-        // now log warnings and errors (warnings first)
-        // in strict mode everything is an error!
-        for(String warn : warnings) {
-            if ( strictMode ) {
-                log.error(warn);
-            } else {
-                log.warn(warn);
-            }
-        }
-        for(String err : errors) {
-            log.error(err);
-        }
+    public Iterator<String> getWarnings() {
+        return warnings.iterator();
+    }
 
+    public Iterator<String> getErrors() {
+        return errors.iterator();
     }
 }
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/PropertyHandler.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/helper/PropertyHandler.java
similarity index 93%
rename from scrplugin/src/main/java/org/apache/felix/scrplugin/PropertyHandler.java
rename to scrplugin/src/main/java/org/apache/felix/scrplugin/helper/PropertyHandler.java
index 1671831..6728389 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/PropertyHandler.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/helper/PropertyHandler.java
@@ -16,18 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.felix.scrplugin;
+package org.apache.felix.scrplugin.helper;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
 
+import org.apache.felix.scrplugin.Constants;
+import org.apache.felix.scrplugin.SCRDescriptorException;
+import org.apache.felix.scrplugin.SCRDescriptorGenerator;
 import org.apache.felix.scrplugin.om.Component;
 import org.apache.felix.scrplugin.om.Property;
 import org.apache.felix.scrplugin.om.metatype.AttributeDefinition;
 import org.apache.felix.scrplugin.om.metatype.OCD;
 import org.apache.felix.scrplugin.tags.JavaField;
 import org.apache.felix.scrplugin.tags.JavaTag;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.codehaus.plexus.util.StringUtils;
 import org.osgi.service.cm.ConfigurationAdmin;
 
 /**
@@ -62,7 +67,7 @@
                                    String    name,
                                    JavaField javaField,
                                    final IssueLog iLog)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         final Property prop = new Property(tag);
         prop.setName(name);
         prop.setType(tag.getNamedParameter(Constants.PROPERTY_TYPE));
@@ -109,7 +114,7 @@
 
         // property is private if explicitly marked or a well known
         // service property such as service.pid
-        final boolean isPrivate = SCRDescriptorMojo.getBoolean(tag,
+        final boolean isPrivate = SCRDescriptorGenerator.getBoolean(tag,
             Constants.PROPERTY_PRIVATE, false)
             || name.equals(org.osgi.framework.Constants.SERVICE_PID)
             || name.equals(org.osgi.framework.Constants.SERVICE_DESCRIPTION)
@@ -200,7 +205,7 @@
      * @return The name of the property or the defaultName
      */
     protected String getPropertyName(JavaTag tag, JavaField field)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         // check name property
         String name = tag.getNamedParameter(Constants.PROPERTY_NAME);
 
@@ -211,10 +216,10 @@
                 final JavaField refField = this.getReferencedField(tag, name);
                 final String[] values = refField.getInitializationExpression();
                 if ( values == null || values.length == 0 ) {
-                    throw new MojoExecutionException("Referenced field for " + name + " has no values for a property name.");
+                    throw new SCRDescriptorException("Referenced field for " + name + " has no values for a property name.");
                 }
                 if ( values.length > 1 ) {
-                    throw new MojoExecutionException("Referenced field " + name + " has more than one value for a property name.");
+                    throw new SCRDescriptorException("Referenced field " + name + " has more than one value for a property name.");
                 }
                 name = values[0];
             }
@@ -238,7 +243,7 @@
     }
 
     protected void setPropertyValueRef(final JavaTag tag, Property property, String valueRef)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         final String[] values = this.getPropertyValueRef(tag, property, valueRef);
         if ( values != null && values.length == 1 ) {
             property.setValue(values[0]);
@@ -248,7 +253,7 @@
     }
 
     protected JavaField getReferencedField(final JavaTag tag, String ref)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         int classSep = ref.lastIndexOf('.');
         JavaField field = null;
         if ( classSep == -1 ) {
@@ -259,13 +264,13 @@
             field = tag.getJavaClassDescription().getExternalFieldByName(ref);
         }
         if ( field == null ) {
-            throw new MojoExecutionException("Property references unknown field " + ref + " in class " + tag.getJavaClassDescription().getName());
+            throw new SCRDescriptorException("Property references unknown field " + ref + " in class " + tag.getJavaClassDescription().getName());
         }
         return field;
     }
 
     protected String[] getPropertyValueRef(final JavaTag tag, Property prop, String valueRef)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         final JavaField field = this.getReferencedField(tag, valueRef);
 
         // determine type (if not set explicitly)
@@ -300,12 +305,12 @@
      * @param property The tag.
      * @param field
      * @param isInspectedClass
-     * @throws MojoExecutionException
+     * @throws SCRDescriptorException
      */
     public void testProperty(JavaTag   property,
                              JavaField field,
                              boolean   isInspectedClass)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         final String propName = this.getPropertyName(property, field);
 
         if ( propName != null ) {
@@ -313,18 +318,18 @@
                 // if the current class is the class we are currently inspecting, we
                 // have found a duplicate definition
                 if ( isInspectedClass ) {
-                    throw new MojoExecutionException("Duplicate definition for property " + propName + " in class " + property.getJavaClassDescription().getName());
+                    throw new SCRDescriptorException("Duplicate definition for property " + propName + " in class " + property.getJavaClassDescription().getName());
                 }
             } else {
                 properties.put(propName, new PropertyDescription(property, field));
             }
         } else {
-            throw new MojoExecutionException("Property has no name " + property.getSourceLocation());
+            throw new SCRDescriptorException("Property has no name " + property.getSourceLocation());
         }
     }
 
     public void handleField(JavaField javaField, boolean isInspectedClass)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         final JavaTag tag = javaField.getTagByName(Constants.PROPERTY);
         if (tag != null) {
             this.testProperty(tag, javaField, isInspectedClass);
@@ -335,11 +340,11 @@
      * Process all found properties for the component.
      * @param globalProperties Global properties are set on all components.
      * @param iLog The issue log.
-     * @throws MojoExecutionException
+     * @throws SCRDescriptorException
      */
     public void processProperties(final Map<String, String> globalProperties,
                                   final IssueLog iLog)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         final Iterator<Map.Entry<String, PropertyDescription>> propIter = properties.entrySet().iterator();
         while ( propIter.hasNext() ) {
             final Map.Entry<String, PropertyDescription> entry = propIter.next();
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/helper/StringUtils.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/helper/StringUtils.java
new file mode 100644
index 0000000..efee6d3
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/helper/StringUtils.java
@@ -0,0 +1,52 @@
+/*
+ * 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.helper;
+
+
+public class StringUtils
+{
+
+    public static String[] split( String value, String sep )
+    {
+        return value.split( sep );
+    }
+
+
+    public static boolean isEmpty( final String string )
+    {
+        return string == null || string.length() == 0;
+    }
+
+
+    public static String leftPad( final String base, final int width, final String pad )
+    {
+        StringBuilder builder = new StringBuilder( width );
+
+        int missing = width - base.length();
+        while ( missing > 0 )
+        {
+            builder.append( pad );
+            missing -= pad.length();
+        }
+
+        builder.append( base );
+
+        return builder.toString();
+    }
+}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/mojo/MavenJavaClassDescriptorManager.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/mojo/MavenJavaClassDescriptorManager.java
new file mode 100644
index 0000000..0978e80
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/mojo/MavenJavaClassDescriptorManager.java
@@ -0,0 +1,423 @@
+/*
+ * 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.mojo;
+
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import org.apache.felix.scrplugin.Constants;
+import org.apache.felix.scrplugin.JavaClassDescriptorManager;
+import org.apache.felix.scrplugin.Log;
+import org.apache.felix.scrplugin.SCRDescriptorException;
+import org.apache.felix.scrplugin.SCRDescriptorFailureException;
+import org.apache.felix.scrplugin.helper.StringUtils;
+import org.apache.felix.scrplugin.om.Component;
+import org.apache.felix.scrplugin.om.Components;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.DirectoryScanner;
+import com.thoughtworks.qdox.JavaDocBuilder;
+import com.thoughtworks.qdox.model.JavaSource;
+
+
+public class MavenJavaClassDescriptorManager extends JavaClassDescriptorManager
+{
+
+    private final MavenProject project;
+
+    private final String excludeString;
+
+    private JavaSource[] sources;
+
+    /** The component definitions from other bundles hashed by classname. */
+    private Map<String, Component> componentDescriptions;
+
+
+    public MavenJavaClassDescriptorManager( MavenProject project, Log log, ClassLoader classLoader,
+        String[] annotationTagProviders, String excludeString, boolean parseJavadocs, boolean processAnnotations )
+        throws SCRDescriptorFailureException
+    {
+        super( log, classLoader, annotationTagProviders, parseJavadocs, processAnnotations );
+
+        this.project = project;
+        this.excludeString = excludeString;
+    }
+
+
+    public String getOutputDirectory()
+    {
+        return this.project.getBuild().getOutputDirectory();
+    }
+
+
+    protected JavaSource[] getSources() throws SCRDescriptorException
+    {
+        if ( this.sources == null )
+        {
+
+            this.log.debug( "Setting up QDox" );
+
+            JavaDocBuilder builder = new JavaDocBuilder();
+            builder.getClassLibrary().addClassLoader( this.getClassLoader() );
+
+            @SuppressWarnings("unchecked")
+            final Iterator<String> i = project.getCompileSourceRoots().iterator();
+            // FELIX-509: check for excludes
+            if ( excludeString != null )
+            {
+                final String[] excludes = StringUtils.split( excludeString, "," );
+                final String[] includes = new String[]
+                    { "**/*.java" };
+
+                while ( i.hasNext() )
+                {
+                    final String tree = i.next();
+                    this.log.debug( "Scanning source tree " + tree );
+                    final File directory = new File( tree );
+                    final DirectoryScanner scanner = new DirectoryScanner();
+                    scanner.setBasedir( directory );
+
+                    if ( excludes != null && excludes.length > 0 )
+                    {
+                        scanner.setExcludes( excludes );
+                    }
+                    scanner.addDefaultExcludes();
+                    scanner.setIncludes( includes );
+
+                    scanner.scan();
+
+                    final String[] files = scanner.getIncludedFiles();
+                    if ( files != null )
+                    {
+                        for ( int m = 0; m < files.length; m++ )
+                        {
+                            this.log.debug( "Adding source file " + files[m] );
+                            try
+                            {
+                                builder.addSource( new File( directory, files[m] ) );
+                            }
+                            catch ( FileNotFoundException e )
+                            {
+                                throw new SCRDescriptorException( "Unable to scan directory.", e );
+                            }
+                            catch ( IOException e )
+                            {
+                                throw new SCRDescriptorException( "Unable to scan directory.", e );
+                            }
+                        }
+                    }
+                }
+            }
+            else
+            {
+                while ( i.hasNext() )
+                {
+                    final String tree = i.next();
+                    this.log.debug( "Adding source tree " + tree );
+                    final File directory = new File( tree );
+                    builder.addSourceTree( directory );
+                }
+            }
+            this.sources = builder.getSources();
+        }
+
+        return this.sources;
+    }
+
+
+    protected Map<String, Component> getComponentDescriptors() throws SCRDescriptorException
+    {
+        if ( this.componentDescriptions == null )
+        {
+            this.componentDescriptions = new HashMap<String, Component>();
+
+            // and now scan artifacts
+            final List<Component> components = new ArrayList<Component>();
+            @SuppressWarnings("unchecked")
+            final Map<String, Artifact> resolved = project.getArtifactMap();
+            @SuppressWarnings("unchecked")
+            final Set<Artifact> artifacts = project.getDependencyArtifacts();
+            final Iterator<Artifact> it = artifacts.iterator();
+            while ( it.hasNext() )
+            {
+                final Artifact declared = it.next();
+                this.log.debug( "Checking artifact " + declared );
+                if ( this.isJavaArtifact( declared ) )
+                {
+                    if ( Artifact.SCOPE_COMPILE.equals( declared.getScope() )
+                        || Artifact.SCOPE_RUNTIME.equals( declared.getScope() )
+                        || Artifact.SCOPE_PROVIDED.equals( declared.getScope() ) )
+                    {
+                        this.log.debug( "Resolving artifact " + declared );
+                        final Artifact artifact = resolved.get( ArtifactUtils.versionlessKey( declared ) );
+                        if ( artifact != null )
+                        {
+                            this.log.debug( "Trying to get manifest from artifact " + artifact );
+                            try
+                            {
+                                final Manifest manifest = this.getManifest( artifact );
+                                if ( manifest != null )
+                                {
+                                    // read Service-Component entry
+                                    if ( manifest.getMainAttributes().getValue( Constants.SERVICE_COMPONENT ) != null )
+                                    {
+                                        final String serviceComponent = manifest.getMainAttributes().getValue(
+                                            Constants.SERVICE_COMPONENT );
+                                        this.log.debug( "Found Service-Component: " + serviceComponent
+                                            + " in artifact " + artifact );
+                                        final StringTokenizer st = new StringTokenizer( serviceComponent, "," );
+                                        while ( st.hasMoreTokens() )
+                                        {
+                                            final String entry = st.nextToken().trim();
+                                            if ( entry.length() > 0 )
+                                            {
+                                                final Components c = this.readServiceComponentDescriptor( artifact,
+                                                    entry );
+                                                if ( c != null )
+                                                {
+                                                    components.addAll( c.getComponents() );
+                                                }
+                                            }
+                                        }
+                                    }
+                                    else
+                                    {
+                                        this.log.debug( "Artifact has no service component entry in manifest "
+                                            + artifact );
+                                    }
+                                }
+                                else
+                                {
+                                    this.log.debug( "Unable to get manifest from artifact " + artifact );
+                                }
+                            }
+                            catch ( IOException ioe )
+                            {
+                                throw new SCRDescriptorException( "Unable to get manifest from artifact " + artifact,
+                                    ioe );
+                            }
+                            this.log.debug( "Trying to get scrinfo from artifact " + artifact );
+                            // now read the scr private file - components stored there overwrite components already
+                            // read from the service component section.
+                            InputStream scrInfoFile = null;
+                            try
+                            {
+                                scrInfoFile = this.getFile( artifact, Constants.ABSTRACT_DESCRIPTOR_ARCHIV_PATH );
+                                if ( scrInfoFile != null )
+                                {
+                                    components.addAll( this.parseServiceComponentDescriptor( scrInfoFile )
+                                        .getComponents() );
+                                }
+                                else
+                                {
+                                    this.log.debug( "Artifact has no scrinfo file (it's optional): " + artifact );
+                                }
+                            }
+                            catch ( IOException ioe )
+                            {
+                                throw new SCRDescriptorException( "Unable to get scrinfo from artifact " + artifact,
+                                    ioe );
+                            }
+                            finally
+                            {
+                                if ( scrInfoFile != null )
+                                {
+                                    try
+                                    {
+                                        scrInfoFile.close();
+                                    }
+                                    catch ( IOException ignore )
+                                    {
+                                    }
+                                }
+                            }
+                        }
+                        else
+                        {
+                            this.log.debug( "Unable to resolve artifact " + declared );
+                        }
+                    }
+                    else
+                    {
+                        this.log.debug( "Artifact " + declared + " has not scope compile or runtime, but "
+                            + declared.getScope() );
+                    }
+                }
+                else
+                {
+                    this.log.debug( "Artifact " + declared + " is not a java artifact, type is " + declared.getType() );
+                }
+            }
+            // now create map with component descriptions
+            for ( final Component component : components )
+            {
+                this.componentDescriptions.put( component.getImplementation().getClassame(), component );
+            }
+        }
+
+        return this.componentDescriptions;
+    }
+
+
+    /**
+     * Check if the artifact is a java artifact (jar or bundle)
+     */
+    private boolean isJavaArtifact( Artifact artifact )
+    {
+        if ( "jar".equals( artifact.getType() ) )
+        {
+            return true;
+        }
+        if ( "bundle".equals( artifact.getType() ) )
+        {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Read the service component description.
+     * @param artifact
+     * @param entry
+     * @throws IOException
+     * @throws SCRDescriptorException
+     */
+    protected Components readServiceComponentDescriptor(Artifact artifact, String entry) {
+        this.log.debug("Reading " + entry + " from " + artifact);
+        InputStream xml = null;
+        try {
+            xml = this.getFile(artifact, entry);
+            if ( xml == null ) {
+                throw new SCRDescriptorException("Artifact " + artifact + " does not contain declared service component descriptor " + entry);
+            }
+            return this.parseServiceComponentDescriptor(xml);
+        } catch (IOException mee) {
+            this.log.warn("Unable to read SCR descriptor file from artifact " + artifact + " at " + entry);
+            this.log.debug("Exception occurred during reading: " + mee.getMessage(), mee);
+        } catch (SCRDescriptorException mee) {
+            this.log.warn("Unable to read SCR descriptor file from artifact " + artifact + " at " + entry);
+            this.log.debug("Exception occurred during reading: " + mee.getMessage(), mee);
+        }
+        finally
+        {
+            if ( xml != null )
+            {
+                try
+                {
+                    xml.close();
+                }
+                catch ( IOException ignore )
+                {
+                }
+            }
+        }
+       return null;
+    }
+
+    protected Manifest getManifest(Artifact artifact) throws IOException {
+        JarFile file = null;
+        try {
+            file = new JarFile(artifact.getFile());
+            return file.getManifest();
+        } finally {
+            if (file != null) {
+                try {
+                    file.close();
+                } catch (IOException ignore) {
+                }
+            }
+        }
+    }
+
+    protected InputStream getFile(Artifact artifact, String path) throws IOException {
+        JarFile file = null;
+        try {
+            file = new JarFile(artifact.getFile());
+            final JarEntry entry = file.getJarEntry(path);
+            if ( entry != null ) {
+                final InputStream stream = new ArtifactFileInputStream( file, entry);
+                file = null; // prevent file from being closed now
+                return stream;
+            }
+            return null;
+        } finally {
+            if (file != null) {
+                try {
+                    file.close();
+                } catch (IOException ignore) {
+                }
+            }
+        }
+    }
+
+    private static class ArtifactFileInputStream extends FilterInputStream
+    {
+        final JarFile jarFile;
+
+
+        ArtifactFileInputStream( JarFile jarFile, JarEntry jarEntry ) throws IOException
+        {
+            super( jarFile.getInputStream( jarEntry ) );
+            this.jarFile = jarFile;
+        }
+
+
+        @Override
+        public void close() throws IOException
+        {
+            try
+            {
+                super.close();
+            }
+            catch ( IOException ioe )
+            {
+            }
+            jarFile.close();
+        }
+
+
+        @Override
+        protected void finalize() throws Throwable
+        {
+            try
+            {
+                close();
+            }
+            finally
+            {
+                super.finalize();
+            }
+        }
+    }
+}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/mojo/MavenLog.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/mojo/MavenLog.java
new file mode 100644
index 0000000..e5312c1
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/mojo/MavenLog.java
@@ -0,0 +1,135 @@
+/*
+ * 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.mojo;
+
+
+import org.apache.felix.scrplugin.Log;
+
+
+/**
+ * The <code>MavenLog</code> class implements the {@link Log} interface using
+ * the Maven logger created on instantiation.
+ */
+public class MavenLog implements Log
+{
+
+    private final org.apache.maven.plugin.logging.Log mavenLog;
+
+
+    MavenLog( org.apache.maven.plugin.logging.Log mavenLog )
+    {
+        this.mavenLog = mavenLog;
+    }
+
+
+    public void debug( String content, Throwable error )
+    {
+        mavenLog.debug( content, error );
+    }
+
+
+    public void debug( String content )
+    {
+        mavenLog.debug( content );
+    }
+
+
+    public void debug( Throwable error )
+    {
+        mavenLog.debug( error );
+    }
+
+
+    public void error( String content, Throwable error )
+    {
+        mavenLog.error( content, error );
+    }
+
+
+    public void error( String content )
+    {
+        mavenLog.error( content );
+    }
+
+
+    public void error( Throwable error )
+    {
+        mavenLog.error( error );
+    }
+
+
+    public void info( String content, Throwable error )
+    {
+        mavenLog.info( content, error );
+    }
+
+
+    public void info( String content )
+    {
+        mavenLog.info( content );
+    }
+
+
+    public void info( Throwable error )
+    {
+        mavenLog.info( error );
+    }
+
+
+    public boolean isDebugEnabled()
+    {
+        return mavenLog.isDebugEnabled();
+    }
+
+
+    public boolean isErrorEnabled()
+    {
+        return mavenLog.isErrorEnabled();
+    }
+
+
+    public boolean isInfoEnabled()
+    {
+        return mavenLog.isInfoEnabled();
+    }
+
+
+    public boolean isWarnEnabled()
+    {
+        return mavenLog.isWarnEnabled();
+    }
+
+
+    public void warn( String content, Throwable error )
+    {
+        mavenLog.warn( content, error );
+    }
+
+
+    public void warn( String content )
+    {
+        mavenLog.warn( content );
+    }
+
+
+    public void warn( Throwable error )
+    {
+        mavenLog.warn( error );
+    }
+}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/mojo/SCRDescriptorMojo.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/mojo/SCRDescriptorMojo.java
new file mode 100644
index 0000000..40af222
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/mojo/SCRDescriptorMojo.java
@@ -0,0 +1,242 @@
+/*
+ * 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.mojo;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.scrplugin.JavaClassDescriptorManager;
+import org.apache.felix.scrplugin.SCRDescriptorException;
+import org.apache.felix.scrplugin.SCRDescriptorFailureException;
+import org.apache.felix.scrplugin.SCRDescriptorGenerator;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.model.Resource;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * The <code>SCRDescriptorMojo</code>
+ * generates a service descriptor file based on annotations found in the sources.
+ *
+ * @goal scr
+ * @phase process-classes
+ * @description Build Service Descriptors from Java Source
+ * @requiresDependencyResolution compile
+ */
+public class SCRDescriptorMojo extends AbstractMojo {
+
+    /**
+     * @parameter expression="${project.build.directory}/scr-plugin-generated"
+     * @required
+     * @readonly
+     */
+    private File outputDirectory;
+
+    /**
+     * The Maven project.
+     *
+     * @parameter expression="${project}"
+     * @required
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * Name of the generated descriptor.
+     *
+     * @parameter expression="${scr.descriptor.name}" default-value="serviceComponents.xml"
+     */
+    private String finalName;
+
+    /**
+     * Name of the generated meta type file.
+     *
+     * @parameter default-value="metatype.xml"
+     */
+    private String metaTypeName;
+
+    /**
+     * This flag controls the generation of the bind/unbind methods.
+     * @parameter default-value="true"
+     */
+    private boolean generateAccessors;
+
+    /**
+     * This flag controls whether the javadoc source code will be scanned for
+     * tags.
+     * @parameter default-value="true"
+     */
+    protected boolean parseJavadoc;
+
+    /**
+     * This flag controls whether the annotations in the sources will be
+     * processed.
+     * @parameter default-value="true"
+     */
+    protected boolean processAnnotations;
+
+    /**
+     * In strict mode the plugin even fails on warnings.
+     * @parameter default-value="false"
+     */
+    protected boolean strictMode;
+
+    /**
+     * The comma separated list of tokens to exclude when processing sources.
+     *
+     * @parameter alias="excludes"
+     */
+    private String sourceExcludes;
+
+    /**
+     * Predefined properties.
+     *
+     * @parameter
+     */
+    private Map<String, String> properties = new HashMap<String, String>();
+
+    /**
+     * Allows to define additional implementations of the interface
+     * {@link org.apache.felix.scrplugin.tags.annotation.AnnotationTagProvider}
+     * that provide mappings from custom annotations to
+     * {@link org.apache.felix.scrplugin.tags.JavaTag} implementations.
+     * List of full qualified class file names.
+     *
+     * @parameter
+     */
+    private String[] annotationTagProviders = {};
+
+    /**
+     * The version of the DS spec this plugin generates a descriptor for.
+     * By default the version is detected by the used tags.
+     * @parameter
+     */
+    private String specVersion;
+
+
+    public void execute() throws MojoExecutionException, MojoFailureException
+    {
+        try
+        {
+            final org.apache.felix.scrplugin.Log scrLog = new MavenLog( getLog() );
+
+            final ClassLoader classLoader = new URLClassLoader( getClassPath(), this.getClass().getClassLoader() );
+            final JavaClassDescriptorManager jManager = new MavenJavaClassDescriptorManager( project, scrLog,
+                classLoader, this.annotationTagProviders, this.sourceExcludes, this.parseJavadoc,
+                this.processAnnotations );
+
+            final SCRDescriptorGenerator generator = new SCRDescriptorGenerator( scrLog );
+
+            // setup from plugin configuration
+            generator.setOutputDirectory( outputDirectory );
+            generator.setDescriptorManager( jManager );
+            generator.setFinalName( finalName );
+            generator.setMetaTypeName( metaTypeName );
+            generator.setGenerateAccessors( generateAccessors );
+            generator.setStrictMode( strictMode );
+            generator.setProperties( properties );
+            generator.setSpecVersion( specVersion );
+
+            if ( generator.execute() )
+            {
+                setServiceComponentHeader();
+                addResources();
+            }
+        }
+        catch ( SCRDescriptorException sde )
+        {
+            throw new MojoExecutionException( sde.getMessage(), sde.getCause() );
+        }
+        catch ( SCRDescriptorFailureException sdfe )
+        {
+            throw ( MojoFailureException ) new MojoFailureException( sdfe.getMessage() ).initCause( sdfe );
+        }
+    }
+
+    private URL[] getClassPath() throws MojoFailureException{
+        @SuppressWarnings("unchecked")
+        List<Artifact> artifacts = this.project.getCompileArtifacts();
+        ArrayList<URL> path = new ArrayList<URL>();
+
+        try
+        {
+            path.add(new File( this.project.getBuild().getOutputDirectory() ).toURI().toURL());
+        }
+        catch ( IOException ioe )
+        {
+            throw new MojoFailureException( "Unable to add target directory to classloader.");
+        }
+
+        int i = 1;
+        for (Iterator<Artifact> ai=artifacts.iterator(); ai.hasNext(); ) {
+            Artifact a = ai.next();
+            try {
+                path.add(a.getFile().toURI().toURL());
+            } catch (IOException ioe) {
+                throw new MojoFailureException("Unable to get compile class loader.");
+            }
+        }
+
+        return path.toArray( new URL[path.size()] );
+    }
+
+
+    private void setServiceComponentHeader()
+    {
+        final File descriptorFile = StringUtils.isEmpty( this.finalName ) ? null : new File( new File(
+            this.outputDirectory, "OSGI-INF" ), this.finalName );
+        if ( descriptorFile.exists() )
+        {
+            String svcComp = project.getProperties().getProperty( "Service-Component" );
+            svcComp = ( svcComp == null ) ? "OSGI-INF/" + finalName : svcComp + ", " + "OSGI-INF/" + finalName;
+            project.getProperties().setProperty( "Service-Component", svcComp );
+        }
+    }
+
+
+    private void addResources()
+    {
+        // now add the descriptor directory to the maven resources
+        final String ourRsrcPath = this.outputDirectory.getAbsolutePath();
+        boolean found = false;
+        @SuppressWarnings("unchecked")
+        final Iterator<Resource> rsrcIterator = this.project.getResources().iterator();
+        while ( !found && rsrcIterator.hasNext() )
+        {
+            final Resource rsrc = rsrcIterator.next();
+            found = rsrc.getDirectory().equals( ourRsrcPath );
+        }
+        if ( !found )
+        {
+            final Resource resource = new Resource();
+            resource.setDirectory( this.outputDirectory.getAbsolutePath() );
+            this.project.addResource( resource );
+        }
+    }
+}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Component.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Component.java
index 7a3dab6..e69ff07 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Component.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Component.java
@@ -22,9 +22,11 @@
 import java.util.List;
 
 import org.apache.felix.scrplugin.Constants;
-import org.apache.felix.scrplugin.IssueLog;
-import org.apache.felix.scrplugin.tags.*;
-import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.felix.scrplugin.SCRDescriptorException;
+import org.apache.felix.scrplugin.helper.IssueLog;
+import org.apache.felix.scrplugin.tags.JavaClassDescription;
+import org.apache.felix.scrplugin.tags.JavaMethod;
+import org.apache.felix.scrplugin.tags.JavaTag;
 
 /**
  * <code>Component</code>
@@ -255,7 +257,7 @@
      * warnings can be added to the warnings list.
      */
     public void validate(final int specVersion, final IssueLog iLog)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         final int currentIssueCount = iLog.getNumberOfErrors();
 
         // nothing to check if this is ignored
@@ -374,7 +376,7 @@
                                         final String methodName,
                                         final boolean isActivate,
                                         final IssueLog iLog)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         // first candidate is (de)activate(ComponentContext)
         JavaMethod method = javaClass.getMethodBySignature(methodName, new String[] {TYPE_COMPONENT_CONTEXT});
         if ( method == null ) {
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Interface.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Interface.java
index d3997ba..281a483 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Interface.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Interface.java
@@ -18,10 +18,10 @@
  */
 package org.apache.felix.scrplugin.om;
 
-import org.apache.felix.scrplugin.IssueLog;
+import org.apache.felix.scrplugin.SCRDescriptorException;
+import org.apache.felix.scrplugin.helper.IssueLog;
 import org.apache.felix.scrplugin.tags.JavaClassDescription;
 import org.apache.felix.scrplugin.tags.JavaTag;
-import org.apache.maven.plugin.MojoExecutionException;
 
 /**
  * <code>Interface.java</code>...
@@ -59,7 +59,7 @@
      * warnings can be added to the warnings list.
      */
     public void validate(final int specVersion, final IssueLog iLog)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         final JavaClassDescription javaClass = this.tag.getJavaClassDescription();
         if (javaClass == null) {
             iLog.addError(this.getMessage("Must be declared in a Java class"));
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Property.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Property.java
index 7ba0703..a70ecf5 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Property.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Property.java
@@ -19,7 +19,7 @@
 package org.apache.felix.scrplugin.om;
 
 import org.apache.felix.scrplugin.Constants;
-import org.apache.felix.scrplugin.IssueLog;
+import org.apache.felix.scrplugin.helper.IssueLog;
 import org.apache.felix.scrplugin.tags.JavaTag;
 
 /**
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Reference.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Reference.java
index 261a53f..901d883 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Reference.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Reference.java
@@ -19,10 +19,12 @@
 package org.apache.felix.scrplugin.om;
 
 import org.apache.felix.scrplugin.Constants;
-import org.apache.felix.scrplugin.IssueLog;
-import org.apache.felix.scrplugin.tags.*;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.codehaus.plexus.util.StringUtils;
+import org.apache.felix.scrplugin.SCRDescriptorException;
+import org.apache.felix.scrplugin.helper.IssueLog;
+import org.apache.felix.scrplugin.helper.StringUtils;
+import org.apache.felix.scrplugin.tags.JavaClassDescription;
+import org.apache.felix.scrplugin.tags.JavaMethod;
+import org.apache.felix.scrplugin.tags.JavaTag;
 
 /**
  * <code>Reference.java</code>...
@@ -149,7 +151,7 @@
     public void validate(final int specVersion,
                          final boolean componentIsAbstract,
                          final IssueLog iLog)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         // if this reference is already checked, return immediately
         if ( this.checked ) {
             return;
@@ -225,7 +227,7 @@
                                     final String   methodName,
                                     final boolean  componentIsAbstract,
                                     final IssueLog iLog)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         final JavaMethod method = this.findMethod(specVersion, methodName);
         if (method == null) {
             if ( !componentIsAbstract ) {
@@ -251,7 +253,7 @@
 
     public JavaMethod findMethod(final int    specVersion,
                                  final String methodName)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         final String[] sig = new String[]{ TYPE_SERVICE_REFERENCE };
         final String[] sig2 = new String[]{ this.getInterfacename() };
         final String[] sig3 = new String[]{ this.getInterfacename(), TYPE_MAP};
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Service.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Service.java
index 7d80258..49354ac 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Service.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Service.java
@@ -18,10 +18,12 @@
  */
 package org.apache.felix.scrplugin.om;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 
-import org.apache.felix.scrplugin.IssueLog;
-import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.felix.scrplugin.SCRDescriptorException;
+import org.apache.felix.scrplugin.helper.IssueLog;
 
 /**
  * <code>Service</code>...
@@ -92,7 +94,7 @@
      * warnings can be added to the warnings list.
      */
     public void validate(final int specVersion, final IssueLog iLog)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         for(final Interface interf : this.getInterfaces()) {
             interf.validate(specVersion, iLog);
         }
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/JavaClassDescription.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/JavaClassDescription.java
index af008e4..db299d1 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/JavaClassDescription.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/JavaClassDescription.java
@@ -18,7 +18,7 @@
  */
 package org.apache.felix.scrplugin.tags;
 
-import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.felix.scrplugin.SCRDescriptorException;
 
 /**
  * <code>JavaClassDescription.java</code>...
@@ -41,18 +41,18 @@
      * @param name
      * @param inherited If true, parent classes are searched as well.
      * @return An array of tags or the empty array.
-     * @throws MojoExecutionException
+     * @throws SCRDescriptorException
      */
     JavaTag[] getTagsByName(String name, boolean inherited)
-    throws MojoExecutionException;
+    throws SCRDescriptorException;
 
     /**
      * Get the description for the parent class.
      * @return The description or <code>null</code> if this class is the
      *         Object class.
-     * @throws MojoExecutionException
+     * @throws SCRDescriptorException
      */
-    JavaClassDescription getSuperClass() throws MojoExecutionException;
+    JavaClassDescription getSuperClass() throws SCRDescriptorException;
 
     /**
      * Get the name of the described class.
@@ -70,29 +70,29 @@
      * Get the field with the name.
      * @param name The name of the field
      * @return The field with the name or null.
-     * @throws MojoExecutionException
+     * @throws SCRDescriptorException
      */
-    JavaField getFieldByName(String name) throws MojoExecutionException;
+    JavaField getFieldByName(String name) throws SCRDescriptorException;
 
-    JavaField getExternalFieldByName(String name) throws MojoExecutionException;
+    JavaField getExternalFieldByName(String name) throws SCRDescriptorException;
 
     /**
      * Returns an array of the implemented interfaces of this class.
      * @return An array containing the interfaces or an empty array
      *         if this class does not implement any interface.
-     * @throws MojoExecutionException
+     * @throws SCRDescriptorException
      */
-    JavaClassDescription[] getImplementedInterfaces() throws MojoExecutionException;
+    JavaClassDescription[] getImplementedInterfaces() throws SCRDescriptorException;
 
     /**
      * Search for a method with the given signature.
      * @param name
      * @param parameters
      * @return A descriptor for the method or <code>null</code>
-     * @throws MojoExecutionException
+     * @throws SCRDescriptorException
      */
     JavaMethod getMethodBySignature(String name, String[] parameters)
-    throws MojoExecutionException;
+    throws SCRDescriptorException;
 
     /**
      * Is this class public?
@@ -122,9 +122,9 @@
      * Is this class of the type?
      * @param type
      * @return True if this class is of the type.
-     * @throws MojoExecutionException
+     * @throws SCRDescriptorException
      */
-    boolean isA(String type) throws MojoExecutionException;
+    boolean isA(String type) throws SCRDescriptorException;
 
     /**
      * Search for the class.
@@ -132,8 +132,8 @@
      * of the class are searched.
      * @param referencedName
      * @return The java class description or null
-     * @throws MojoExecutionException
+     * @throws SCRDescriptorException
      */
     JavaClassDescription getReferencedClass(String referencedName)
-    throws MojoExecutionException;
+    throws SCRDescriptorException;
 }
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/JavaClassDescriptionInheritanceComparator.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/JavaClassDescriptionInheritanceComparator.java
index 80a9cbe..e48cacd 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/JavaClassDescriptionInheritanceComparator.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/JavaClassDescriptionInheritanceComparator.java
@@ -21,7 +21,7 @@
 
 import java.util.Comparator;
 
-import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.felix.scrplugin.SCRDescriptorException;
 
 
 /**
@@ -88,7 +88,7 @@
                 return 1;
             }
         }
-        catch ( MojoExecutionException mee )
+        catch ( SCRDescriptorException mee )
         {
             // what shall we do ??
         }
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/JavaClassDescriptorManager.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/JavaClassDescriptorManager.java
deleted file mode 100644
index 99c06eb..0000000
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/JavaClassDescriptorManager.java
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * 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.tags;
-
-import java.io.*;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.*;
-import java.util.jar.*;
-
-import org.apache.felix.scrplugin.Constants;
-import org.apache.felix.scrplugin.om.Component;
-import org.apache.felix.scrplugin.om.Components;
-import org.apache.felix.scrplugin.tags.annotation.AnnotationJavaClassDescription;
-import org.apache.felix.scrplugin.tags.annotation.AnnotationTagProviderManager;
-import org.apache.felix.scrplugin.tags.cl.ClassLoaderJavaClassDescription;
-import org.apache.felix.scrplugin.tags.qdox.QDoxJavaClassDescription;
-import org.apache.felix.scrplugin.xml.ComponentDescriptorIO;
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.ArtifactUtils;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.*;
-
-import com.thoughtworks.qdox.JavaDocBuilder;
-import com.thoughtworks.qdox.model.JavaClass;
-import com.thoughtworks.qdox.model.JavaSource;
-
-/**
- * <code>JavaClassDescriptorManager.java</code>...
- *
- */
-public class JavaClassDescriptorManager {
-
-    protected static final String SERVICE_COMPONENT = "Service-Component";
-
-    /** The sources read by qdox. */
-    protected final JavaSource[] sources;
-
-    /** The maven log. */
-    protected final Log log;
-
-    /** The classloader used to compile the classes. */
-    protected final ClassLoader classloader;
-
-    /** A cache containing the java class descriptions hashed by classname. */
-    protected final Map<String, JavaClassDescription> javaClassDescriptions = new HashMap<String, JavaClassDescription>();
-
-    /** The component definitions from other bundles hashed by classname. */
-    protected final Map<String, Component> componentDescriptions = new HashMap<String, Component>();
-
-    /** The maven project. */
-    protected final MavenProject project;
-
-    /**
-     * Supports mapping of built-in and custom java anntoations to {@link JavaTag} implementations.
-     */
-    protected final AnnotationTagProviderManager annotationTagProviderManager;
-
-    /** Parse Javadocs? */
-    protected final boolean parseJavadocs;
-
-    /** Process Annotations? */
-    protected final boolean processAnnotations;
-
-    /**
-     * Construct a new manager.
-     * @param log
-     * @param project
-     * @param annotationTagProviders List of annotation tag providers
-     * @param excludeString The exclude information for sources
-     * @param parseJavadocs Should the javadocs be parsed?
-     * @param processAnnotations Should the annotations be processed?
-     * @throws MojoFailureException
-     * @throws MojoExecutionException
-     */
-    public JavaClassDescriptorManager(final Log          log,
-                                      final MavenProject project,
-                                      final String[]     annotationTagProviders,
-                                      final String       excludeString,
-                                      final boolean      parseJavadocs,
-                                      final boolean      processAnnotations)
-    throws MojoFailureException, MojoExecutionException {
-        this.processAnnotations = processAnnotations;
-        this.parseJavadocs = parseJavadocs;
-        this.log = log;
-        this.project = project;
-        this.annotationTagProviderManager = new AnnotationTagProviderManager(annotationTagProviders);
-        this.classloader = this.getCompileClassLoader();
-        ClassUtil.classLoader = this.classloader;
-
-        // get all the class sources through qdox
-        this.log.debug("Setting up QDox");
-        JavaDocBuilder builder = new JavaDocBuilder();
-        builder.getClassLibrary().addClassLoader(this.classloader);
-        @SuppressWarnings("unchecked")
-        final Iterator<String> i = project.getCompileSourceRoots().iterator();
-        // FELIX-509: check for excludes
-        if ( excludeString != null ) {
-            final String[] excludes = StringUtils.split(excludeString, ",");
-            final String[] includes = new String[] {"**/*.java"};
-
-            while ( i.hasNext() ) {
-                final String tree = i.next();
-                this.log.debug("Scanning source tree " + tree);
-                final File directory = new File(tree);
-                final DirectoryScanner scanner = new DirectoryScanner();
-                scanner.setBasedir( directory );
-
-                if ( excludes != null && excludes.length > 0 ) {
-                    scanner.setExcludes( excludes );
-                }
-                scanner.addDefaultExcludes();
-                scanner.setIncludes( includes );
-
-                scanner.scan();
-
-                final String[] files = scanner.getIncludedFiles();
-                if ( files != null ) {
-                    for(int m=0; m<files.length; m++) {
-                        this.log.debug("Adding source file " + files[m]);
-                        try {
-                            builder.addSource(new File(directory, files[m]));
-                        } catch (FileNotFoundException e) {
-                            throw new MojoExecutionException("Unable to scan directory.", e);
-                        } catch (IOException e) {
-                            throw new MojoExecutionException("Unable to scan directory.", e);
-                        }
-                    }
-                }
-            }
-        } else {
-            while ( i.hasNext() ) {
-                final String tree = i.next();
-                this.log.debug("Adding source tree " + tree);
-                final File directory = new File(tree);
-                builder.addSourceTree(directory);
-            }
-        }
-        this.sources = builder.getSources();
-
-        // and now scan artifacts
-        final List<Component> components = new ArrayList<Component>();
-        @SuppressWarnings("unchecked")
-        final Map<String, Artifact> resolved = project.getArtifactMap();
-        @SuppressWarnings("unchecked")
-        final Set<Artifact> artifacts = project.getDependencyArtifacts();
-        final Iterator<Artifact> it = artifacts.iterator();
-        while ( it.hasNext() ) {
-            final Artifact declared = it.next();
-            this.log.debug("Checking artifact " + declared);
-            if ( this.isJavaArtifact(declared)) {
-                if (Artifact.SCOPE_COMPILE.equals(declared.getScope())
-                    || Artifact.SCOPE_RUNTIME.equals(declared.getScope())
-                    || Artifact.SCOPE_PROVIDED.equals(declared.getScope())) {
-                    this.log.debug("Resolving artifact " + declared);
-                    final Artifact artifact = resolved.get(ArtifactUtils.versionlessKey(declared));
-                    if (artifact != null) {
-                        this.log.debug("Trying to get manifest from artifact " + artifact);
-                        try {
-                            final Manifest manifest = this.getManifest(artifact);
-                            if ( manifest != null ) {
-                                // read Service-Component entry
-                                if ( manifest.getMainAttributes().getValue(JavaClassDescriptorManager.SERVICE_COMPONENT) != null ) {
-                                    final String serviceComponent = manifest.getMainAttributes().getValue(JavaClassDescriptorManager.SERVICE_COMPONENT);
-                                    this.log.debug("Found Service-Component: " + serviceComponent + " in artifact " + artifact);
-                                    final StringTokenizer st = new StringTokenizer(serviceComponent, ",");
-                                    while ( st.hasMoreTokens() ) {
-                                        final String entry = st.nextToken().trim();
-                                        if ( entry.length() > 0 ) {
-                                            final Components c = this.readServiceComponentDescriptor(artifact, entry);
-                                            if ( c != null ) {
-                                                components.addAll(c.getComponents());
-                                            }
-                                        }
-                                    }
-                                } else {
-                                    this.log.debug("Artifact has no service component entry in manifest " + artifact);
-                                }
-                            } else {
-                                this.log.debug("Unable to get manifest from artifact " + artifact);
-                            }
-                        } catch (IOException ioe) {
-                            throw new MojoExecutionException("Unable to get manifest from artifact " + artifact, ioe);
-                        }
-                        this.log.debug("Trying to get scrinfo from artifact " + artifact);
-                        // now read the scr private file - components stored there overwrite components already
-                        // read from the service component section.
-                        try {
-                            final File scrInfoFile = this.getFile(artifact, Constants.ABSTRACT_DESCRIPTOR_ARCHIV_PATH);
-                            if ( scrInfoFile != null ) {
-                                components.addAll(this.parseServiceComponentDescriptor(artifact, scrInfoFile).getComponents());
-                            } else {
-                                this.log.debug("Artifact has no scrinfo file (it's optional): " + artifact);
-                            }
-                        } catch (IOException ioe) {
-                            throw new MojoExecutionException("Unable to get scrinfo from artifact " + artifact, ioe);
-                        }
-                    } else {
-                        this.log.debug("Unable to resolve artifact " + declared);
-                    }
-                } else {
-                    this.log.debug("Artifact " + declared + " has not scope compile or runtime, but " + declared.getScope());
-                }
-            } else {
-                this.log.debug("Artifact " + declared + " is not a java artifact, type is " + declared.getType());
-            }
-        }
-        // now create map with component descriptions
-        for(final Component component : components) {
-            this.componentDescriptions.put(component.getImplementation().getClassame(), component);
-        }
-    }
-
-    /**
-     * Check if the artifact is a java artifact (jar or bundle)
-     */
-    private boolean isJavaArtifact(Artifact artifact) {
-        if ( "jar".equals(artifact.getType()) ) {
-            return true;
-        }
-        if ( "bundle".equals(artifact.getType()) ) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Return the log.
-     */
-    public Log getLog() {
-        return this.log;
-    }
-
-    /**
-     * Return the class laoder.
-     */
-    public ClassLoader getClassLoader() {
-        return this.classloader;
-    }
-
-    /**
-     * Return the project.
-     */
-    public MavenProject getProject() {
-        return this.project;
-    }
-
-    /**
-     * @return Annotation tag provider manager
-     */
-    public AnnotationTagProviderManager getAnnotationTagProviderManager() {
-        return this.annotationTagProviderManager;
-    }
-
-    /**
-     * Read the service component description.
-     * @param artifact
-     * @param entry
-     * @throws IOException
-     * @throws MojoExecutionException
-     */
-    protected Components readServiceComponentDescriptor(Artifact artifact, String entry) {
-        this.log.debug("Reading " + entry + " from " + artifact);
-        try {
-            final File xml = this.getFile(artifact, entry);
-            if ( xml == null ) {
-                throw new MojoExecutionException("Artifact " + artifact + " does not contain declared service component descriptor " + entry);
-            }
-            return this.parseServiceComponentDescriptor(artifact, xml);
-        } catch (IOException mee) {
-            this.log.warn("Unable to read SCR descriptor file from artifact " + artifact + " at " + entry);
-            this.log.debug("Exception occurred during reading: " + mee.getMessage(), mee);
-        } catch (MojoExecutionException mee) {
-            this.log.warn("Unable to read SCR descriptor file from artifact " + artifact + " at " + entry);
-            this.log.debug("Exception occurred during reading: " + mee.getMessage(), mee);
-        }
-        return null;
-    }
-
-    protected Components parseServiceComponentDescriptor(Artifact artifact, File file)
-    throws MojoExecutionException {
-        this.log.debug("Parsing " + file);
-        final Components list = ComponentDescriptorIO.read(file);
-        return list;
-    }
-
-    /**
-     * Get the url for the target directory
-     */
-    protected URL getOutputDirectory()
-    throws MojoFailureException {
-        final String targetDirectory = this.getProject().getBuild().getOutputDirectory();
-        try {
-            return new File(targetDirectory).toURI().toURL();
-        } catch (IOException ioe) {
-            throw new MojoFailureException("Unable to add target directory to classloader.");
-        }
-    }
-
-    /**
-     * Create a class loader containing all compile artifacts including
-     * the target/class directory of the current project
-     * @return The class loader
-     * @throws MojoFailureException
-     */
-    protected ClassLoader getCompileClassLoader()
-    throws MojoFailureException {
-        @SuppressWarnings("unchecked")
-        List<Artifact> artifacts = this.getProject().getCompileArtifacts();
-        URL[] path = new URL[artifacts.size() + 1];
-        int i = 0;
-        for (Iterator<Artifact> ai=artifacts.iterator(); ai.hasNext(); ) {
-            Artifact a = ai.next();
-            try {
-                path[i++] = a.getFile().toURI().toURL();
-            } catch (IOException ioe) {
-                throw new MojoFailureException("Unable to get compile class loader.");
-            }
-        }
-        path[path.length - 1] = this.getOutputDirectory();
-
-        return new URLClassLoader(path, this.getClass().getClassLoader());
-    }
-
-    protected Manifest getManifest(Artifact artifact) throws IOException {
-        JarFile file = null;
-        try {
-            file = new JarFile(artifact.getFile());
-            return file.getManifest();
-        } finally {
-            if (file != null) {
-                try {
-                    file.close();
-                } catch (IOException ignore) {
-                }
-            }
-        }
-    }
-
-    protected File getFile(Artifact artifact, String path) throws IOException {
-        final int pos = path.lastIndexOf('.');
-        final String suffix = path.substring(pos + 1);
-        JarFile file = null;
-        File tmpFile = null;
-        try {
-            file = new JarFile(artifact.getFile());
-            final JarEntry entry = file.getJarEntry(path);
-            if ( entry != null ) {
-                tmpFile = File.createTempFile("scrjcdm" + artifact.getArtifactId(), suffix);
-                tmpFile.deleteOnExit();
-                final FileOutputStream fos = new FileOutputStream(tmpFile);
-                IOUtil.copy(file.getInputStream(entry), fos);
-                IOUtil.close(fos);
-                return tmpFile;
-            }
-            return null;
-        } finally {
-            if (file != null) {
-                try {
-                    file.close();
-                } catch (IOException ignore) {
-                }
-            }
-        }
-    }
-
-    /**
-     * Return all source descriptions of this project.
-     * @return All contained java class descriptions.
-     */
-    public JavaClassDescription[] getSourceDescriptions() throws MojoExecutionException {
-        final JavaClass[] javaClasses = getJavaClassesFromSources();
-        final JavaClassDescription[] descs = new JavaClassDescription[javaClasses.length];
-        for(int i=0; i<javaClasses.length; i++) {
-            descs[i] = this.getJavaClassDescription(javaClasses[i].getFullyQualifiedName());
-        }
-        return descs;
-    }
-
-    /**
-     * Get a java class description for the class.
-     * @param className
-     * @return The java class description.
-     * @throws MojoExecutionException
-     */
-    public JavaClassDescription getJavaClassDescription(String className)
-    throws MojoExecutionException {
-        JavaClassDescription result = this.javaClassDescriptions.get(className);
-        if ( result == null ) {
-            this.log.debug("Searching description for: " + className);
-            int index = 0;
-            final JavaClass[] javaClasses = getJavaClassesFromSources();
-            while ( result == null && index < javaClasses.length) {
-                final JavaClass javaClass = javaClasses[index];
-                if ( javaClass.getFullyQualifiedName().equals(className) ) {
-                    try {
-                        // check for java annotation descriptions - fallback to QDox if none found
-                        Class<?> clazz = this.classloader.loadClass(className);
-                        if (this.processAnnotations && getAnnotationTagProviderManager().hasScrPluginAnnotation(javaClass)) {
-                            this.log.debug("Found java annotation description for: " + className);
-                            result = new AnnotationJavaClassDescription(clazz, javaClasses[index], this);
-                        } else if ( this.parseJavadocs ) {
-                            this.log.debug("Found qdox description for: " + className);
-                            result = new QDoxJavaClassDescription(clazz, javaClasses[index], this);
-                        }
-                    } catch (ClassNotFoundException e) {
-                        throw new MojoExecutionException("Unable to load class " + className);
-                    }
-                } else {
-                    index++;
-                }
-            }
-            if ( result == null ) {
-                try {
-                    this.log.debug("Generating classloader description for: " + className);
-                    result = new ClassLoaderJavaClassDescription(this.classloader.loadClass(className), this.componentDescriptions.get(className), this);
-                } catch (ClassNotFoundException e) {
-                    throw new MojoExecutionException("Unable to load class " + className);
-                }
-            }
-            this.javaClassDescriptions.put(className, result);
-        }
-        return result;
-    }
-    
-    /**
-     * Get a list of all {@link JavaClass} definitions four all source files (including nested/inner classes)
-     * @return List of {@link JavaClass} definitions
-     */
-    private JavaClass[] getJavaClassesFromSources() {
-        final List<JavaClass> classes = new ArrayList<JavaClass>();
-        for(int i=0; i<this.sources.length; i++) {
-            for(int j=0; j<this.sources[i].getClasses().length; j++) {
-                final JavaClass clazz = this.sources[i].getClasses()[j];
-                classes.add(clazz);
-                for (int k=0; k<clazz.getNestedClasses().length; k++) {
-                    final JavaClass nestedClass = clazz.getNestedClasses()[k];
-                    classes.add(nestedClass);
-                }
-            }
-        }
-        return classes.toArray(new JavaClass[classes.size()]);
-    }
-    
-}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/ModifiableJavaClassDescription.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/ModifiableJavaClassDescription.java
index 91a39fa..a3f5a79 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/ModifiableJavaClassDescription.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/ModifiableJavaClassDescription.java
@@ -18,11 +18,11 @@
  */
 package org.apache.felix.scrplugin.tags;
 
-import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.felix.scrplugin.SCRDescriptorException;
 
 
 public interface ModifiableJavaClassDescription {
 
     void addMethods(String propertyName, String className, boolean createBind, boolean createUnbind)
-    throws MojoExecutionException;
+    throws SCRDescriptorException;
 }
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/AnnotationJavaClassDescription.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/AnnotationJavaClassDescription.java
index 1cf785d..4881308 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/AnnotationJavaClassDescription.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/AnnotationJavaClassDescription.java
@@ -18,11 +18,15 @@
  */
 package org.apache.felix.scrplugin.tags.annotation;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
-import org.apache.felix.scrplugin.tags.*;
+import org.apache.felix.scrplugin.JavaClassDescriptorManager;
+import org.apache.felix.scrplugin.SCRDescriptorException;
+import org.apache.felix.scrplugin.tags.JavaField;
+import org.apache.felix.scrplugin.tags.JavaTag;
 import org.apache.felix.scrplugin.tags.qdox.QDoxJavaClassDescription;
-import org.apache.maven.plugin.MojoExecutionException;
 
 import com.thoughtworks.qdox.model.JavaClass;
 
@@ -62,7 +66,7 @@
      * @see JavaClassDescription#getTagsByName(String, boolean)
      */
     @Override
-    public JavaTag[] getTagsByName(String name, boolean inherited) throws MojoExecutionException {
+    public JavaTag[] getTagsByName(String name, boolean inherited) throws SCRDescriptorException {
 
         List<JavaTag> tags = new ArrayList<JavaTag>();
         for(com.thoughtworks.qdox.model.Annotation annotation : this.javaClass.getAnnotations()) {
@@ -104,7 +108,7 @@
      * @see JavaClassDescription#getFieldByName(String)
      */
     @Override
-    public JavaField getFieldByName(String name) throws MojoExecutionException {
+    public JavaField getFieldByName(String name) throws SCRDescriptorException {
         final com.thoughtworks.qdox.model.JavaField field = this.javaClass.getFieldByName(name);
         if (field != null) {
             return new AnnotationJavaField(field, this);
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/AnnotationTagProviderManager.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/AnnotationTagProviderManager.java
index d9068f0..9b7dbde 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/AnnotationTagProviderManager.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/AnnotationTagProviderManager.java
@@ -21,11 +21,11 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.felix.scrplugin.SCRDescriptorFailureException;
 import org.apache.felix.scrplugin.tags.JavaField;
 import org.apache.felix.scrplugin.tags.JavaTag;
 import org.apache.felix.scrplugin.tags.annotation.defaulttag.DefaultAnnotationTagProvider;
 import org.apache.felix.scrplugin.tags.annotation.sling.SlingAnnotationTagProvider;
-import org.apache.maven.plugin.MojoFailureException;
 
 import com.thoughtworks.qdox.model.Annotation;
 import com.thoughtworks.qdox.model.JavaClass;
@@ -49,7 +49,7 @@
      *            {@link AnnotationTagProvider} interface.
      * @throws MojoFailureException
      */
-    public AnnotationTagProviderManager(String[] annotationTagProviderClasses) throws MojoFailureException {
+    public AnnotationTagProviderManager(String[] annotationTagProviderClasses) throws SCRDescriptorFailureException {
 
         // always add provider supporting built-in SCR default properties
         annotationTagProviders.add(new DefaultAnnotationTagProvider());
@@ -62,17 +62,17 @@
                 try {
                     annotationTagProviders.add((AnnotationTagProvider) clazz.newInstance());
                 } catch (ClassCastException e) {
-                    throw new MojoFailureException("Class '" + clazz.getName() + "' "
+                    throw new SCRDescriptorFailureException("Class '" + clazz.getName() + "' "
                             + "does not implement interface '" + AnnotationTagProvider.class.getName() + "'.");
                 } catch (InstantiationException e) {
-                    throw new MojoFailureException("Unable to instantiate class '" + clazz.getName() + "': "
+                    throw new SCRDescriptorFailureException("Unable to instantiate class '" + clazz.getName() + "': "
                             + e.getMessage());
                 } catch (IllegalAccessException e) {
-                    throw new MojoFailureException("Illegal access to class '" + clazz.getName() + "': "
+                    throw new SCRDescriptorFailureException("Illegal access to class '" + clazz.getName() + "': "
                             + e.getMessage());
                 }
             } catch (ClassNotFoundException ex) {
-                throw new MojoFailureException("Annotation provider class '" + annotationTagProviderClasses[i]
+                throw new SCRDescriptorFailureException("Annotation provider class '" + annotationTagProviderClasses[i]
                         + "' not found.");
             }
         }
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/defaulttag/Util.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/defaulttag/Util.java
index 28f71c7..2a4b050 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/defaulttag/Util.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/defaulttag/Util.java
@@ -20,11 +20,16 @@
 
 import java.util.List;
 
-import org.apache.felix.scrplugin.tags.*;
-import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.felix.scrplugin.SCRDescriptorException;
+import org.apache.felix.scrplugin.tags.ClassUtil;
+import org.apache.felix.scrplugin.tags.JavaClassDescription;
+import org.apache.felix.scrplugin.tags.JavaField;
 
 import com.thoughtworks.qdox.model.Annotation;
-import com.thoughtworks.qdox.model.annotation.*;
+import com.thoughtworks.qdox.model.annotation.AnnotationConstant;
+import com.thoughtworks.qdox.model.annotation.AnnotationFieldRef;
+import com.thoughtworks.qdox.model.annotation.AnnotationValue;
+import com.thoughtworks.qdox.model.annotation.AnnotationValueList;
 
 /**
  * Helper class for getting values from annotations.
@@ -378,7 +383,7 @@
                 }
                 throw new IllegalArgumentException("Something is wrong.");
             }
-            catch (MojoExecutionException mee)
+            catch (SCRDescriptorException mee)
             {
                 throw new IllegalArgumentException(mee);
             }
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingServletPropertyTag.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingServletPropertyTag.java
index 58a9d87..62a2557 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingServletPropertyTag.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingServletPropertyTag.java
@@ -18,12 +18,14 @@
  */
 package org.apache.felix.scrplugin.tags.annotation.sling;
 
-import java.util.*;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
 
 import org.apache.felix.scrplugin.Constants;
+import org.apache.felix.scrplugin.helper.StringUtils;
 import org.apache.felix.scrplugin.tags.JavaClassDescription;
 import org.apache.felix.scrplugin.tags.annotation.defaulttag.AbstractTag;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * Description of a java tag for components.
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/cl/ClassLoaderJavaClassDescription.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/cl/ClassLoaderJavaClassDescription.java
index c7cba6f..cb98c98 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/cl/ClassLoaderJavaClassDescription.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/cl/ClassLoaderJavaClassDescription.java
@@ -18,13 +18,21 @@
  */
 package org.apache.felix.scrplugin.tags.cl;
 
-import java.lang.reflect.*;
-import java.util.*;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 import org.apache.felix.scrplugin.Constants;
+import org.apache.felix.scrplugin.JavaClassDescriptorManager;
+import org.apache.felix.scrplugin.SCRDescriptorException;
 import org.apache.felix.scrplugin.om.Component;
-import org.apache.felix.scrplugin.tags.*;
-import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.felix.scrplugin.tags.JavaClassDescription;
+import org.apache.felix.scrplugin.tags.JavaField;
+import org.apache.felix.scrplugin.tags.JavaMethod;
+import org.apache.felix.scrplugin.tags.JavaTag;
 
 /**
  * <code>ClassLoaderJavaClassDescription.java</code>...
@@ -61,7 +69,7 @@
     /**
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#getFieldByName(java.lang.String)
      */
-    public JavaField getFieldByName(String name) throws MojoExecutionException {
+    public JavaField getFieldByName(String name) throws SCRDescriptorException {
         Field field = null;
         try {
             field = this.clazz.getField(name);
@@ -83,22 +91,22 @@
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#getExternalFieldByName(java.lang.String)
      */
     public JavaField getExternalFieldByName(String name)
-    throws MojoExecutionException {
-        throw new MojoExecutionException("getExternalFieldByName not supported for this class.");
+    throws SCRDescriptorException {
+        throw new SCRDescriptorException("getExternalFieldByName not supported for this class.");
     }
 
     /**
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#getReferencedClass(java.lang.String)
      */
     public JavaClassDescription getReferencedClass(String referencedName)
-    throws MojoExecutionException {
-        throw new MojoExecutionException("getReferencedClass not supported for this class.");
+    throws SCRDescriptorException {
+        throw new SCRDescriptorException("getReferencedClass not supported for this class.");
     }
 
     /**
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#getImplementedInterfaces()
      */
-    public JavaClassDescription[] getImplementedInterfaces() throws MojoExecutionException {
+    public JavaClassDescription[] getImplementedInterfaces() throws SCRDescriptorException {
         Class<?>[] implemented = clazz.getInterfaces();
         if (implemented.length == 0) {
             return JavaClassDescription.EMPTY_RESULT;
@@ -115,7 +123,7 @@
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#getMethodBySignature(java.lang.String, java.lang.String[])
      */
     public JavaMethod getMethodBySignature(String name, String[] parameters)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         Class<?>[] classParameters = null;
         if ( parameters != null ) {
             classParameters = new Class[parameters.length];
@@ -133,7 +141,7 @@
         } catch (NoClassDefFoundError ncdfe) {
             // if this occurs it usually means that a problem with the maven
             // scopes exists.
-            throw new MojoExecutionException("Class loading error. This error usually occurs if you have a " +
+            throw new SCRDescriptorException("Class loading error. This error usually occurs if you have a " +
                     "service inheriting from a class coming from another bundle and that class using a " +
                     "third library and all dependencies are specified with scope 'provided'.", ncdfe);
         } catch (NoSuchMethodException e) {
@@ -166,7 +174,7 @@
     /**
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#getSuperClass()
      */
-    public JavaClassDescription getSuperClass() throws MojoExecutionException {
+    public JavaClassDescription getSuperClass() throws SCRDescriptorException {
         if ( this.clazz.getSuperclass() != null ) {
             return this.manager.getJavaClassDescription(this.clazz.getSuperclass().getName());
         }
@@ -186,7 +194,7 @@
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#getTagsByName(java.lang.String, boolean)
      */
     public JavaTag[] getTagsByName(String name, boolean inherited)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         JavaTag[] javaTags = EMPTY_TAGS;
         if ( this.component != null ) {
             if ( Constants.SERVICE.equals(name) ) {
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/qdox/QDoxJavaClassDescription.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/qdox/QDoxJavaClassDescription.java
index 8a9c221..27023d5 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/qdox/QDoxJavaClassDescription.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/qdox/QDoxJavaClassDescription.java
@@ -18,18 +18,32 @@
  */
 package org.apache.felix.scrplugin.tags.qdox;
 
-import java.io.*;
-import java.util.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
-import org.apache.felix.scrplugin.tags.*;
+import org.apache.felix.scrplugin.JavaClassDescriptorManager;
+import org.apache.felix.scrplugin.SCRDescriptorException;
+import org.apache.felix.scrplugin.tags.JavaClassDescription;
 import org.apache.felix.scrplugin.tags.JavaField;
 import org.apache.felix.scrplugin.tags.JavaMethod;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.objectweb.asm.*;
+import org.apache.felix.scrplugin.tags.JavaTag;
+import org.apache.felix.scrplugin.tags.ModifiableJavaClassDescription;
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.tree.ClassNode;
 
-import com.thoughtworks.qdox.model.*;
+import com.thoughtworks.qdox.model.DocletTag;
+import com.thoughtworks.qdox.model.JavaClass;
 import com.thoughtworks.qdox.model.JavaParameter;
+import com.thoughtworks.qdox.model.JavaSource;
 import com.thoughtworks.qdox.model.Type;
 
 /**
@@ -55,7 +69,7 @@
     /**
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#getSuperClass()
      */
-    public JavaClassDescription getSuperClass() throws MojoExecutionException {
+    public JavaClassDescription getSuperClass() throws SCRDescriptorException {
         final JavaClass parent = this.javaClass.getSuperJavaClass();
         if ( parent != null ) {
             return this.manager.getJavaClassDescription(parent.getFullyQualifiedName());
@@ -85,7 +99,7 @@
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#getTagsByName(java.lang.String, boolean)
      */
     public JavaTag[] getTagsByName(String name, boolean inherited)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         final DocletTag[] tags = this.javaClass.getTagsByName(name, false);
         JavaTag[] javaTags;
         if ( tags == null || tags.length == 0 ) {
@@ -126,7 +140,7 @@
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#getFieldByName(java.lang.String)
      */
     public JavaField getFieldByName(String name)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         final com.thoughtworks.qdox.model.JavaField field = this.javaClass.getFieldByName(name);
         if ( field != null ) {
             return new QDoxJavaField(field, this);
@@ -141,7 +155,7 @@
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#getExternalFieldByName(java.lang.String)
      */
     public JavaField getExternalFieldByName(String name)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         int lastDot = name.lastIndexOf('.');
         // if there is no dot, this should be a static import
         if ( lastDot == -1 ) {
@@ -216,7 +230,7 @@
         }
         try {
             return this.manager.getJavaClassDescription(className);
-        } catch (MojoExecutionException mee) {
+        } catch (SCRDescriptorException mee) {
             return null;
         }
     }
@@ -225,7 +239,7 @@
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#getImplementedInterfaces()
      */
     public JavaClassDescription[] getImplementedInterfaces()
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         final JavaClass[] interfaces = this.javaClass.getImplementedInterfaces();
         if ( interfaces == null || interfaces.length == 0 ) {
             return JavaClassDescription.EMPTY_RESULT;
@@ -241,7 +255,7 @@
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#getMethodBySignature(java.lang.String, java.lang.String[])
      */
     public JavaMethod getMethodBySignature(String name, String[] parameters)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         Type[] types = null;
         if ( parameters == null || parameters.length == 0 ) {
             types = new Type[0];
@@ -279,7 +293,7 @@
     /**
      * @see org.apache.felix.scrplugin.tags.JavaClassDescription#isA(java.lang.String)
      */
-    public boolean isA(String type) throws MojoExecutionException {
+    public boolean isA(String type) throws SCRDescriptorException {
         final Type qType = new Type(type);
         if ( this.javaClass.isA(type) ) {
             return true;
@@ -326,9 +340,9 @@
                            final String className,
                            final boolean createBind,
                            final boolean createUnbind)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         // now do byte code manipulation
-        final String targetDirectory = this.manager.getProject().getBuild().getOutputDirectory();
+        final String targetDirectory = this.manager.getOutputDirectory();
         final String fileName = targetDirectory + File.separatorChar +  this.getName().replace('.', File.separatorChar) + ".class";
         final ClassNode cn = new ClassNode();
         try {
@@ -375,7 +389,7 @@
             fos.write(writer.toByteArray());
             fos.close();
         } catch (Exception e) {
-            throw new MojoExecutionException("Unable to add methods to " + this.getName(), e);
+            throw new SCRDescriptorException("Unable to add methods to " + this.getName(), e);
         }
     }
 
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java
index d997848..482201e 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java
@@ -20,14 +20,23 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.StringTokenizer;
 
 import javax.xml.transform.TransformerException;
 
 import org.apache.felix.scrplugin.Constants;
-import org.apache.felix.scrplugin.om.*;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.xml.sax.*;
+import org.apache.felix.scrplugin.SCRDescriptorException;
+import org.apache.felix.scrplugin.om.Component;
+import org.apache.felix.scrplugin.om.Components;
+import org.apache.felix.scrplugin.om.Implementation;
+import org.apache.felix.scrplugin.om.Interface;
+import org.apache.felix.scrplugin.om.Property;
+import org.apache.felix.scrplugin.om.Reference;
+import org.apache.felix.scrplugin.om.Service;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
 import org.xml.sax.helpers.AttributesImpl;
 import org.xml.sax.helpers.DefaultHandler;
 
@@ -104,16 +113,14 @@
 
     private static final String INTERFACE_QNAME = INTERFACE;
 
-    public static Components read(File file)
-    throws MojoExecutionException {
+    public static Components read(InputStream file)
+    throws SCRDescriptorException {
         try {
             final XmlHandler xmlHandler = new XmlHandler();
             IOUtils.parse(file, xmlHandler);
             return xmlHandler.components;
         } catch (TransformerException e) {
-            throw new MojoExecutionException("Unable to read xml from " + file, e);
-        } catch (IOException e) {
-            throw new MojoExecutionException("Unable to read xml from " + file, e);
+            throw new SCRDescriptorException("Unable to read xml from " + file, e);
         }
     }
 
@@ -121,18 +128,18 @@
      * Write the component descriptors to the file.
      * @param components
      * @param file
-     * @throws MojoExecutionException
+     * @throws SCRDescriptorException
      */
     public static void write(Components components, File file, boolean isScrPrivateFile)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         try {
             generateXML(components, IOUtils.getSerializer(file), isScrPrivateFile);
         } catch (TransformerException e) {
-            throw new MojoExecutionException("Unable to write xml to " + file, e);
+            throw new SCRDescriptorException("Unable to write xml to " + file, e);
         } catch (SAXException e) {
-            throw new MojoExecutionException("Unable to generate xml for " + file, e);
+            throw new SCRDescriptorException("Unable to generate xml for " + file, e);
         } catch (IOException e) {
-            throw new MojoExecutionException("Unable to write xml to " + file, e);
+            throw new SCRDescriptorException("Unable to write xml to " + file, e);
         }
     }
 
@@ -428,25 +435,36 @@
                     impl.setClassname(attributes.getValue("class"));
 
                 } else if (localName.equals(PROPERTY)) {
-                    final Property prop = new Property();
 
-                    prop.setName(attributes.getValue("name"));
-                    prop.setType(attributes.getValue("type"));
+                    // read the property, unless it is the service.pid
+                    // property which must not be inherited
+                    final String propName = attributes.getValue( "name" );
+                    if ( !org.osgi.framework.Constants.SERVICE_PID.equals( propName ) )
+                    {
+                        final Property prop = new Property();
 
-                    if ( attributes.getValue("value") != null) {
-                        prop.setValue(attributes.getValue("value"));
-                        this.currentComponent.addProperty(prop);
-                    } else {
-                        // hold the property pending as we have a multi value
-                        this.pendingProperty = prop;
-                    }
-                    // check for abstract properties
-                    prop.setLabel(attributes.getValue("label"));
-                    prop.setDescription(attributes.getValue("description"));
-                    prop.setCardinality(attributes.getValue("cardinality"));
-                    final String pValue = attributes.getValue("private");
-                    if ( pValue != null ) {
-                        prop.setPrivate(Boolean.valueOf(pValue).booleanValue());
+                        prop.setName( propName );
+                        prop.setType( attributes.getValue( "type" ) );
+
+                        if ( attributes.getValue( "value" ) != null )
+                        {
+                            prop.setValue( attributes.getValue( "value" ) );
+                            this.currentComponent.addProperty( prop );
+                        }
+                        else
+                        {
+                            // hold the property pending as we have a multi value
+                            this.pendingProperty = prop;
+                        }
+                        // check for abstract properties
+                        prop.setLabel( attributes.getValue( "label" ) );
+                        prop.setDescription( attributes.getValue( "description" ) );
+                        prop.setCardinality( attributes.getValue( "cardinality" ) );
+                        final String pValue = attributes.getValue( "private" );
+                        if ( pValue != null )
+                        {
+                            prop.setPrivate( Boolean.valueOf( pValue ).booleanValue() );
+                        }
                     }
 
                 } else if (localName.equals("properties")) {
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/IOUtils.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/IOUtils.java
index 46b819a..8671088 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/IOUtils.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/IOUtils.java
@@ -49,11 +49,10 @@
      * @throws IOException
      * @throws TransformerException
      */
-    public static final void parse(File file, ContentHandler handler)
-    throws IOException, TransformerException {
+    public static final void parse(InputStream file, ContentHandler handler)
+    throws TransformerException {
         final Transformer transformer = FACTORY.newTransformer();
-        transformer.transform(new StreamSource(new FileReader(file)),
-                new SAXResult(handler));
+        transformer.transform( new StreamSource( file ), new SAXResult( handler ) );
     }
 
     public static ContentHandler getSerializer(File file)
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/MetaTypeIO.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/MetaTypeIO.java
index 7bb4f36..15eeaff 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/MetaTypeIO.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/MetaTypeIO.java
@@ -25,8 +25,12 @@
 
 import javax.xml.transform.TransformerException;
 
-import org.apache.felix.scrplugin.om.metatype.*;
-import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.felix.scrplugin.SCRDescriptorException;
+import org.apache.felix.scrplugin.om.metatype.AttributeDefinition;
+import org.apache.felix.scrplugin.om.metatype.Designate;
+import org.apache.felix.scrplugin.om.metatype.MTObject;
+import org.apache.felix.scrplugin.om.metatype.MetaData;
+import org.apache.felix.scrplugin.om.metatype.OCD;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.AttributesImpl;
@@ -65,15 +69,15 @@
     protected static final String OPTION_ELEMENT_QNAME = OPTION_ELEMENT;
 
     public static void write(MetaData metaData, File file)
-    throws MojoExecutionException {
+    throws SCRDescriptorException {
         try {
             generateXML(metaData, IOUtils.getSerializer(file));
         } catch (TransformerException e) {
-            throw new MojoExecutionException("Unable to write xml to " + file, e);
+            throw new SCRDescriptorException("Unable to write xml to " + file, e);
         } catch (SAXException e) {
-            throw new MojoExecutionException("Unable to generate xml for " + file, e);
+            throw new SCRDescriptorException("Unable to generate xml for " + file, e);
         } catch (IOException e) {
-            throw new MojoExecutionException("Unable to write xml to " + file, e);
+            throw new SCRDescriptorException("Unable to write xml to " + file, e);
         }
     }