FELIX-2642 Implement Ant Task for DS and Metatype service
descriptor generation
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1025755 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scrplugin/pom.xml b/scrplugin/pom.xml
index 8b383a9..0ea3fdf 100644
--- a/scrplugin/pom.xml
+++ b/scrplugin/pom.xml
@@ -49,18 +49,26 @@
<artifactId>maven-plugin-api</artifactId>
<version>2.0.7</version>
</dependency>
-
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-archiver</artifactId>
<version>2.2</version>
</dependency>
+
+ <!-- Ant Task Implementation -->
+ <dependency>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant</artifactId>
+ <version>1.7.0</version>
+ <scope>provided</scope>
+ </dependency>
<!-- JavaDoc Tags -->
<dependency>
<groupId>com.thoughtworks.qdox</groupId>
<artifactId>qdox</artifactId>
<version>1.12</version>
+ <scope>provided</scope>
</dependency>
<!-- SCR Annotations -->
@@ -68,42 +76,55 @@
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.3.1-SNAPSHOT</version>
+ <scope>provided</scope>
</dependency>
- <!-- Sling Servlet SCR Annotation -->
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.4</version>
- <scope>compile</scope>
- </dependency>
-
<!-- bind/unbind method generation -->
<dependency>
<groupId>asm</groupId>
<artifactId>asm-all</artifactId>
<version>3.1</version>
+ <scope>provided</scope>
</dependency>
- <!-- OSGi APIs -->
+ <!-- OSGi APIs (some constant references used only) -->
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>4.0.0</version>
- <scope>compile</scope>
+ <scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
<version>4.0.0</version>
- <scope>compile</scope>
+ <scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
+ <!-- unpack qdox, asm and annotations into bundle package -->
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <configuration>
+ <includeArtifactIds>
+ qdox,asm-all,org.apache.felix.scr.annotations
+ </includeArtifactIds>
+ <outputDirectory>
+ ${project.build.outputDirectory}
+ </outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
- <!-- JDK 1.5 needed for annotation support -->
+ <!-- JDK 1.5 needed for annotation support -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
@@ -112,8 +133,6 @@
<target>1.5</target>
</configuration>
</plugin>
-
</plugins>
</build>
-
</project>
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/JavaClassDescriptorManager.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/JavaClassDescriptorManager.java
index f6e737a..8320269 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/JavaClassDescriptorManager.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/JavaClassDescriptorManager.java
@@ -1,26 +1,27 @@
/*
- * 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.
+ * 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.io.FilterInputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.util.*;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
import org.apache.felix.scrplugin.om.Component;
import org.apache.felix.scrplugin.om.Components;
@@ -30,7 +31,7 @@
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.JavaDocBuilder;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaSource;
@@ -55,7 +56,8 @@
private final Map<String, JavaClassDescription> javaClassDescriptions = new HashMap<String, JavaClassDescription>();
/**
- * Supports mapping of built-in and custom java anntoations to {@link JavaTag} implementations.
+ * Supports mapping of built-in and custom java anntoations to
+ * {@link JavaTag} implementations.
*/
private final AnnotationTagProviderManager annotationTagProviderManager;
@@ -65,13 +67,16 @@
/** Process Annotations? */
private final boolean processAnnotations;
+ /** The Java sources gathered by {@link #getSourceDescriptions()} */
+ private JavaSource[] sources;
+
+ /** The component definitions from other bundles hashed by classname. */
+ private Map<String, Component> componentDescriptions;
+
/**
* Construct a new manager.
- * @param log
- * @param annotationTagProviders List of annotation tag providers
- * @param parseJavadocs Should the javadocs be parsed?
- * @param processAnnotations Should the annotations be processed?
+ *
* @throws SCRDescriptorFailureException
*/
public JavaClassDescriptorManager( final Log log, final ClassLoader classLoader,
@@ -83,29 +88,200 @@
this.log = log;
this.annotationTagProviderManager = new AnnotationTagProviderManager( annotationTagProviders );
this.classloader = classLoader;
+
ClassUtil.classLoader = this.classloader;
}
/**
- * Returns the QDox JavaSource instances representing the source files
- * for which the Declarative Services and Metatype descriptors have to be
+ * Returns the QDox JavaSource instances representing the source files for
+ * which the Declarative Services and Metatype descriptors have to be
* generated.
*
- * @throws SCRDescriptorException May be thrown if an error occurrs gathering
- * the java sources.
+ * @throws SCRDescriptorException May be thrown if an error occurrs
+ * gathering the java sources.
*/
- protected abstract JavaSource[] getSources() throws SCRDescriptorException;
+ protected JavaSource[] getSources() throws SCRDescriptorException
+ {
+ if ( this.sources == null )
+ {
+ this.log.debug( "Setting up QDox" );
+
+ JavaDocBuilder builder = new JavaDocBuilder();
+ builder.getClassLibrary().addClassLoader( this.getClassLoader() );
+
+ final Iterator<File> i = getSourceFiles();
+ while ( i.hasNext() )
+ {
+ File file = i.next();
+ this.log.debug( "Adding source file " + file );
+ try
+ {
+ builder.addSource( file );
+ }
+ catch ( IOException e )
+ {
+ // also FileNotFoundException
+ throw new SCRDescriptorException( "Unable to add source file", file.toString(), 0, e );
+ }
+ }
+ this.sources = builder.getSources();
+ }
+
+ return this.sources;
+ }
+
+
+ /**
+ * Returns an iterator of paths to directories providing Java source files
+ * to be parsed.
+ * <p>
+ * This method is called by the default {@link #getSources()} implementation
+ * to return the root directories for the Java files to be parsed. This
+ * default implementation returns an empty iterator. Implementations of this
+ * class not overwriting the {@link #getSources()} method should overwrite
+ * this method by providing the concrete source locations.
+ *
+ * @return An iterator of Java source locations.
+ */
+ protected Iterator<File> getSourceFiles()
+ {
+ return Collections.<File> emptyList().iterator();
+ }
/**
* Returns a map of component descriptors which may be extended by the java
* sources returned by the {@link #getSources()} method.
+ * <p>
+ * This method calls the {@link #getDependencies()} method and checks for
+ * any Service-Component descriptors in the returned files.
+ * <p>
+ * This method may be overwritten by extensions of this class.
*
- * @throws SCRDescriptorException May be thrown if an error occurrs gethering
- * the component descriptors.
+ * @throws SCRDescriptorException May be thrown if an error occurrs
+ * gethering the component descriptors.
*/
- protected abstract Map<String, Component> getComponentDescriptors() throws SCRDescriptorException;
+ protected Map<String, Component> getComponentDescriptors() throws SCRDescriptorException
+ {
+ if ( this.componentDescriptions == null )
+ {
+ final List<Component> components = new ArrayList<Component>();
+ final List<File> dependencies = getDependencies();
+ for ( File artifact : dependencies )
+ {
+ 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.toString(), 0,
+ 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.toString(), 0,
+ ioe );
+ }
+ finally
+ {
+ if ( scrInfoFile != null )
+ {
+ try
+ {
+ scrInfoFile.close();
+ }
+ catch ( IOException ignore )
+ {
+ }
+ }
+ }
+
+ // now create map with component descriptions
+ this.componentDescriptions = new HashMap<String, Component>();
+ for ( final Component component : components )
+ {
+ this.componentDescriptions.put( component.getImplementation().getClassame(), component );
+ }
+ }
+ }
+
+ return this.componentDescriptions;
+ }
+
+
+ /**
+ * Returns a list of files denoting dependencies of the module for which
+ * descriptors are to be generated. The returned dependencies are expected
+ * to be bundles which may (or may not) contain Service Component
+ * descriptors (or internal descriptors in the case of abstract components
+ * not listed in the "official" descriptors).
+ * <p>
+ * This method is called by the {@link #getComponentDescriptors()} method in
+ * this class to get the list of bundles from where base component
+ * descriptors are to be extracted.
+ * <p>
+ * Extensions of this class not overwriting the
+ * {@link #getComponentDescriptors()} method should overwrite this method if
+ * they wish to provide such base component descriptors.
+ *
+ * @return
+ */
+ protected List<File> getDependencies()
+ {
+ return Collections.<File> emptyList();
+ }
/**
@@ -167,12 +343,12 @@
/**
- * Parses the descriptors read from the given input stream. This method
- * may be called by the {@link #getComponentDescriptors()} method to parse
- * the descriptors gathered in an implementation dependent way.
+ * Parses the descriptors read from the given input stream. This method may
+ * be called by the {@link #getComponentDescriptors()} method to parse the
+ * descriptors gathered in an implementation dependent way.
*
- * @throws SCRDescriptorException If an error occurrs reading the descriptors
- * from the stream.
+ * @throws SCRDescriptorException If an error occurrs reading the
+ * descriptors from the stream.
*/
protected Components parseServiceComponentDescriptor( InputStream file ) throws SCRDescriptorException
{
@@ -182,6 +358,7 @@
/**
* Return all source descriptions of this project.
+ *
* @return All contained java class descriptions.
*/
public JavaClassDescription[] getSourceDescriptions() throws SCRDescriptorException
@@ -198,6 +375,7 @@
/**
* Get a java class description for the class.
+ *
* @param className
* @return The java class description.
* @throws SCRDescriptorException
@@ -217,7 +395,8 @@
{
try
{
- // check for java annotation descriptions - fallback to QDox if none found
+ // check for java annotation descriptions - fallback to
+ // QDox if none found
Class<?> clazz = this.classloader.loadClass( className );
if ( this.processAnnotations
&& getAnnotationTagProviderManager().hasScrPluginAnnotation( javaClass ) )
@@ -251,7 +430,7 @@
}
catch ( ClassNotFoundException e )
{
- throw new SCRDescriptorException( "Unable to load class", className, 0);
+ throw new SCRDescriptorException( "Unable to load class", className, 0 );
}
}
this.javaClassDescriptions.put( className, result );
@@ -261,7 +440,9 @@
/**
- * Get a list of all {@link JavaClass} definitions four all source files (including nested/inner classes)
+ * 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
@@ -270,7 +451,7 @@
final List<JavaClass> classes = new ArrayList<JavaClass>();
for ( int i = 0; i < sources.length; i++ )
{
- if (sources[i].getClasses() == null || sources[i].getClasses().length == 0)
+ if ( sources[i].getClasses() == null || sources[i].getClasses().length == 0 )
{
continue;
}
@@ -288,4 +469,148 @@
return classes.toArray( new JavaClass[classes.size()] );
}
+
+ /**
+ * Read the service component description.
+ *
+ * @param artifact
+ * @param entry
+ * @throws IOException
+ * @throws SCRDescriptorException
+ */
+ private Components readServiceComponentDescriptor( File jarFile, String entry )
+ {
+ this.log.debug( "Reading " + entry + " from " + jarFile );
+ InputStream xml = null;
+ try
+ {
+ xml = this.getFile( jarFile, entry );
+ if ( xml == null )
+ {
+ throw new SCRDescriptorException( "Entry " + entry + " not contained in JAR File ", jarFile.toString(),
+ 0 );
+ }
+ return this.parseServiceComponentDescriptor( xml );
+ }
+ catch ( IOException mee )
+ {
+ this.log.warn( "Unable to read SCR descriptor file from JAR File " + jarFile + " 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 JAR File " + jarFile + " at " + entry );
+ this.log.debug( "Exception occurred during reading: " + mee.getMessage(), mee );
+ }
+ finally
+ {
+ if ( xml != null )
+ {
+ try
+ {
+ xml.close();
+ }
+ catch ( IOException ignore )
+ {
+ }
+ }
+ }
+ return null;
+ }
+
+
+ private Manifest getManifest( File artifact ) throws IOException
+ {
+ JarFile file = null;
+ try
+ {
+ file = new JarFile( artifact );
+ return file.getManifest();
+ }
+ finally
+ {
+ if ( file != null )
+ {
+ try
+ {
+ file.close();
+ }
+ catch ( IOException ignore )
+ {
+ }
+ }
+ }
+ }
+
+
+ private InputStream getFile( File jarFile, String path ) throws IOException
+ {
+ JarFile file = null;
+ try
+ {
+ file = new JarFile( jarFile );
+ 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/ant/AntJavaClassDescriptorManager.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/ant/AntJavaClassDescriptorManager.java
new file mode 100644
index 0000000..f79059e
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/ant/AntJavaClassDescriptorManager.java
@@ -0,0 +1,125 @@
+/*
+ * 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.ant;
+
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.apache.felix.scrplugin.JavaClassDescriptorManager;
+import org.apache.felix.scrplugin.Log;
+import org.apache.felix.scrplugin.SCRDescriptorFailureException;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.resources.FileResource;
+
+
+public class AntJavaClassDescriptorManager extends JavaClassDescriptorManager
+{
+
+ private final FileSet sourceFiles;
+
+ private final String classesDirectory;
+
+ private final Path classPath;
+
+
+ public AntJavaClassDescriptorManager( Log log, ClassLoader classLoader, FileSet sourceFiles, File classesDirectory,
+ Path classPath, String[] annotationTagProviders, boolean parseJavadocs, boolean processAnnotations )
+ throws SCRDescriptorFailureException
+ {
+ super( log, classLoader, annotationTagProviders, parseJavadocs, processAnnotations );
+ this.sourceFiles = sourceFiles;
+ this.classesDirectory = classesDirectory.getAbsolutePath();
+ this.classPath = classPath;
+ }
+
+
+ @Override
+ protected Iterator<File> getSourceFiles()
+ {
+ @SuppressWarnings("unchecked")
+ final Iterator<Resource> resources = sourceFiles.iterator();
+ return new Iterator<File>()
+ {
+ File next = seek();
+
+
+ public boolean hasNext()
+ {
+ return next != null;
+ }
+
+
+ public File next()
+ {
+ if ( !hasNext() )
+ {
+ throw new NoSuchElementException();
+ }
+ File result = next;
+ next = seek();
+ return result;
+ }
+
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException( "remove" );
+ }
+
+
+ private File seek()
+ {
+ while ( resources.hasNext() )
+ {
+ Resource r = resources.next();
+ if ( r instanceof FileResource )
+ {
+ return ( ( FileResource ) r ).getFile();
+ }
+ }
+ return null;
+ }
+ };
+ }
+
+
+ @Override
+ protected List<File> getDependencies()
+ {
+ ArrayList<File> files = new ArrayList<File>();
+ for ( String entry : classPath.list() )
+ {
+ File file = new File( entry );
+ if ( file.isFile() )
+ {
+ files.add( file );
+ }
+ }
+ return files;
+ }
+
+
+ @Override
+ public String getOutputDirectory()
+ {
+ return classesDirectory;
+ }
+
+}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/ant/AntLog.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/ant/AntLog.java
new file mode 100644
index 0000000..605e75a
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/ant/AntLog.java
@@ -0,0 +1,150 @@
+/*
+ * 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.ant;
+
+
+import org.apache.felix.scrplugin.Log;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+
+public class AntLog implements Log
+{
+
+ private final Task task;
+
+
+ AntLog( final Task task )
+ {
+ this.task = task;
+ }
+
+
+ public boolean isDebugEnabled()
+ {
+ // cannot tell, assume yes
+ return true;
+ }
+
+
+ public void debug( String content )
+ {
+ task.log( content, Project.MSG_DEBUG );
+ }
+
+
+ public void debug( String content, Throwable error )
+ {
+ task.log( content, error, Project.MSG_DEBUG );
+ }
+
+
+ public void debug( Throwable error )
+ {
+ task.log( error, Project.MSG_DEBUG );
+ }
+
+
+ public boolean isInfoEnabled()
+ {
+ // cannot tell, assume yes
+ return true;
+ }
+
+
+ public void info( String content )
+ {
+ task.log( content, Project.MSG_INFO );
+ }
+
+
+ public void info( String content, Throwable error )
+ {
+ task.log( content, error, Project.MSG_INFO );
+ }
+
+
+ public void info( Throwable error )
+ {
+ task.log( error, Project.MSG_INFO );
+ }
+
+
+ public boolean isWarnEnabled()
+ {
+ // cannot tell, assume yes
+ return true;
+ }
+
+
+ public void warn( String content )
+ {
+ task.log( content, Project.MSG_WARN );
+ }
+
+
+ public void warn( String content, String location, int lineNumber )
+ {
+ warn( String.format( "%s [%s,%d]", content, location, lineNumber ) );
+ }
+
+
+ public void warn( String content, Throwable error )
+ {
+ task.log( content, error, Project.MSG_WARN );
+ }
+
+
+ public void warn( Throwable error )
+ {
+ task.log( error, Project.MSG_WARN );
+ }
+
+
+ public boolean isErrorEnabled()
+ {
+ // cannot tell, assume yes
+ return true;
+ }
+
+
+ public void error( String content )
+ {
+ task.log( content, Project.MSG_ERR );
+ }
+
+
+ public void error( String content, String location, int lineNumber )
+ {
+ error( String.format( "%s [%s,%d]", content, location, lineNumber ) );
+ }
+
+
+ public void error( String content, Throwable error )
+ {
+ task.log( content, error, Project.MSG_ERR );
+ }
+
+
+ public void error( Throwable error )
+ {
+ task.log( error, Project.MSG_ERR );
+ }
+
+}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/ant/SCRDescriptorTask.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/ant/SCRDescriptorTask.java
new file mode 100644
index 0000000..82f8c46
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/ant/SCRDescriptorTask.java
@@ -0,0 +1,252 @@
+/*
+ * 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.ant;
+
+
+import java.io.File;
+import java.util.*;
+
+import org.apache.felix.scrplugin.*;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Location;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+
+/**
+ * The <code>SCRDescriptorTask</code> generates a service descriptor file based
+ * on annotations found in the sources.
+ */
+public class SCRDescriptorTask extends MatchingTask
+{
+
+ private File destdir;
+
+ private Path classpath;
+
+ /**
+ * Name of the generated descriptor.
+ */
+ private String finalName = "serviceComponents.xml";
+
+ /**
+ * Name of the generated meta type file.
+ */
+ private String metaTypeName = "metatype.xml";
+
+ /**
+ * This flag controls the generation of the bind/unbind methods.
+ */
+ private boolean generateAccessors = true;
+
+ /**
+ * This flag controls whether the javadoc source code will be scanned for
+ * tags.
+ */
+ protected boolean parseJavadoc = true;
+
+ /**
+ * This flag controls whether the annotations in the sources will be
+ * processed.
+ */
+ protected boolean processAnnotations = true;
+
+ /**
+ * In strict mode the plugin even fails on warnings.
+ */
+ protected boolean strictMode = false;
+
+ /**
+ * 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;
+
+
+ @Override
+ public void execute() throws BuildException
+ {
+
+ // ensure we know the source
+ if (getImplicitFileSet().getDir() == null) {
+ throw new BuildException( "srcdir attribute must be set!", getLocation());
+ }
+
+ // while debugging
+ final org.apache.felix.scrplugin.Log scrLog = new AntLog( this );
+
+ scrLog.debug( "SCRDescriptorTask Configuration" );
+ scrLog.debug( " implicitFileset: " + getImplicitFileSet() );
+ scrLog.debug( " outputDirectory: " + destdir );
+ scrLog.debug( " classpath: " + classpath );
+ scrLog.debug( " finalName: " + finalName );
+ scrLog.debug( " metaTypeName: " + metaTypeName );
+ scrLog.debug( " generateAccessors: " + generateAccessors );
+ scrLog.debug( " parseJavadoc: " + parseJavadoc );
+ scrLog.debug( " processAnnotations: " + processAnnotations );
+ scrLog.debug( " strictMode: " + strictMode );
+ scrLog.debug( " specVersion: " + specVersion );
+
+ try
+ {
+ final ClassLoader classLoader = getClassLoader( this.getClass().getClassLoader() );
+ final JavaClassDescriptorManager jManager = new AntJavaClassDescriptorManager( scrLog, classLoader,
+ getImplicitFileSet(), destdir, createClasspath(), this.annotationTagProviders, this.parseJavadoc, this.processAnnotations );
+
+ final SCRDescriptorGenerator generator = new SCRDescriptorGenerator( scrLog );
+
+ // setup from plugin configuration
+ generator.setOutputDirectory( destdir );
+ generator.setDescriptorManager( jManager );
+ generator.setFinalName( finalName );
+ generator.setMetaTypeName( metaTypeName );
+ generator.setGenerateAccessors( generateAccessors );
+ generator.setStrictMode( strictMode );
+ generator.setProperties( new HashMap<String, String>() );
+ generator.setSpecVersion( specVersion );
+
+ generator.execute();
+ }
+ catch ( SCRDescriptorException sde )
+ {
+ if ( sde.getSourceLocation() != null )
+ {
+ Location loc = new Location( sde.getSourceLocation(), sde.getLineNumber(), 0 );
+ throw new BuildException( sde.getMessage(), sde.getCause(), loc );
+ }
+ throw new BuildException( sde.getMessage(), sde.getCause() );
+ }
+ catch ( SCRDescriptorFailureException sdfe )
+ {
+ throw new BuildException( sdfe.getMessage(), sdfe.getCause() );
+ }
+ }
+
+
+ private ClassLoader getClassLoader( final ClassLoader parent ) throws BuildException
+ {
+ Path classPath = createClasspath();
+ log( "Using classes from: " + classPath, Project.MSG_DEBUG );
+ return getProject().createClassLoader( parent, classpath );
+ }
+
+
+ // ---------- setters for configuration fields
+
+ public Path createClasspath()
+ {
+ if ( this.classpath == null )
+ {
+ this.classpath = new Path( getProject() );
+ }
+ return this.classpath;
+ }
+
+
+ public void setClasspath( Path classPath )
+ {
+ createClasspath().add( classPath );
+ }
+
+
+ public void setClasspathRef( Reference classpathRef )
+ {
+ if ( classpathRef != null && classpathRef.getReferencedObject() instanceof Path )
+ {
+ createClasspath().add( ( Path ) classpathRef.getReferencedObject() );
+ }
+ }
+
+
+ public void setSrcdir( File srcdir )
+ {
+ getImplicitFileSet().setDir( srcdir );
+ }
+
+
+ public void setDestdir( File outputDirectory )
+ {
+ this.destdir = outputDirectory;
+ if ( destdir != null )
+ {
+ Path dst = new Path( getProject() );
+ dst.setLocation( destdir );
+ createClasspath().add( dst );
+ }
+ }
+
+
+ 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 setParseJavadoc( boolean parseJavadoc )
+ {
+ this.parseJavadoc = parseJavadoc;
+ }
+
+
+ public void setProcessAnnotations( boolean processAnnotations )
+ {
+ this.processAnnotations = processAnnotations;
+ }
+
+
+ public void setStrictMode( boolean strictMode )
+ {
+ this.strictMode = strictMode;
+ }
+
+
+ public void setAnnotationTagProviders( String[] annotationTagProviders )
+ {
+ this.annotationTagProviders = annotationTagProviders;
+ }
+
+
+ public void setSpecVersion( String specVersion )
+ {
+ this.specVersion = specVersion;
+ }
+
+}
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
index c7df967..63fd4c0 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/mojo/MavenJavaClassDescriptorManager.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/mojo/MavenJavaClassDescriptorManager.java
@@ -21,20 +21,15 @@
import java.io.*;
import java.util.*;
-import java.util.jar.*;
import org.apache.felix.scrplugin.*;
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
{
@@ -43,8 +38,6 @@
private final String excludeString;
- private JavaSource[] sources;
-
/** The component definitions from other bundles hashed by classname. */
private Map<String, Component> componentDescriptions;
@@ -66,210 +59,96 @@
}
- protected JavaSource[] getSources() throws SCRDescriptorException
+ @Override
+ protected Iterator<File> getSourceFiles()
{
- if ( this.sources == null )
+ ArrayList<File> files = new ArrayList<File>();
+
+ @SuppressWarnings("unchecked")
+ final Iterator<String> i = project.getCompileSourceRoots().iterator();
+
+ // FELIX-509: check for excludes
+ final String[] includes = new String[] { "**/*.java" };
+ final String[] excludes;
+ if ( excludeString != 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.", files[m], 0, e );
- }
- catch ( IOException e )
- {
- throw new SCRDescriptorException( "Unable to scan directory.", files[m], 0, 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();
+ excludes = StringUtils.split( excludeString, "," );
+ }
+ else
+ {
+ excludes = null;
}
- return this.sources;
+ 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();
+
+ for ( String fileName : scanner.getIncludedFiles() )
+ {
+ files.add( new File( directory, fileName ) );
+
+ }
+ }
+
+ return files.iterator();
}
- protected Map<String, Component> getComponentDescriptors() throws SCRDescriptorException
+ @Override
+ protected List<File> getDependencies()
{
- if ( this.componentDescriptions == null )
- {
- this.componentDescriptions = new HashMap<String, Component>();
+ ArrayList<File> dependencies = new ArrayList<File>();
- // and now scan artifacts
- final List<Component> components = new ArrayList<Component>();
- @SuppressWarnings("unchecked")
- final Map<String, Artifact> resolved = project.getArtifactMap();
- final Iterator<Artifact> it = resolved.values().iterator();
- while ( it.hasNext() )
+ @SuppressWarnings("unchecked")
+ final Map<String, Artifact> resolved = project.getArtifactMap();
+ final Iterator<Artifact> it = resolved.values().iterator();
+ while ( it.hasNext() )
+ {
+ final Artifact declared = it.next();
+ this.log.debug( "Checking artifact " + declared );
+ if ( this.isJavaArtifact( declared ) )
{
- 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() ) )
{
- 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( "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
- .toString(), 0, 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
- .toString(), 0, ioe );
- }
- finally
- {
- if ( scrInfoFile != null )
- {
- try
- {
- scrInfoFile.close();
- }
- catch ( IOException ignore )
- {
- }
- }
- }
- }
- else
- {
- this.log.debug( "Unable to resolve artifact " + declared );
- }
+ dependencies.add( artifact.getFile() );
}
else
{
- this.log.debug( "Artifact " + declared + " has not scope compile or runtime, but "
- + declared.getScope() );
+ this.log.debug( "Unable to resolve artifact " + declared );
}
}
else
{
- this.log.debug( "Artifact " + declared + " is not a java artifact, type is " + declared.getType() );
+ this.log.debug( "Artifact " + declared + " has not scope compile or runtime, but "
+ + declared.getScope() );
}
}
- // now create map with component descriptions
- for ( final Component component : components )
+ else
{
- this.componentDescriptions.put( component.getImplementation().getClassame(), component );
+ this.log.debug( "Artifact " + declared + " is not a java artifact, type is " + declared.getType() );
}
}
- return this.componentDescriptions;
+ return dependencies;
}
@@ -289,119 +168,4 @@
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( "Entry " + entry + " not contained in artifact", artifact.toString(),
- 0 );
- }
- 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/tags/annotation/sling/SlingFilterServiceTag.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingFilterServiceTag.java
index a1f963b..efe63e0 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingFilterServiceTag.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingFilterServiceTag.java
@@ -21,7 +21,6 @@
import java.util.Collections;
import java.util.Map;
-import javax.servlet.Filter;
import org.apache.felix.scrplugin.Constants;
import org.apache.felix.scrplugin.tags.JavaClassDescription;
@@ -35,7 +34,7 @@
public class SlingFilterServiceTag extends AbstractTag {
private static final Map<String, String> INTERFACE_MAP =
- Collections.singletonMap(Constants.SERVICE_INTERFACE, Filter.class.getName());
+ Collections.singletonMap(Constants.SERVICE_INTERFACE, "javax.servlet.Filter");
/**
* @param desc Description
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingServletServiceTag.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingServletServiceTag.java
index 34e871c..3ad2181 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingServletServiceTag.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingServletServiceTag.java
@@ -21,8 +21,6 @@
import java.util.Collections;
import java.util.Map;
-import javax.servlet.Servlet;
-
import org.apache.felix.scrplugin.Constants;
import org.apache.felix.scrplugin.tags.JavaClassDescription;
import org.apache.felix.scrplugin.tags.annotation.defaulttag.AbstractTag;
@@ -35,7 +33,7 @@
public class SlingServletServiceTag extends AbstractTag {
private static final Map<String, String> INTERFACE_MAP =
- Collections.singletonMap(Constants.SERVICE_INTERFACE, Servlet.class.getName());
+ Collections.singletonMap(Constants.SERVICE_INTERFACE, "javax.servlet.Servlet");
/**
* @param desc Description
diff --git a/scrplugin/src/main/resources/scrtask.properties b/scrplugin/src/main/resources/scrtask.properties
new file mode 100644
index 0000000..d2b975f
--- /dev/null
+++ b/scrplugin/src/main/resources/scrtask.properties
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+# Define the ANT Tasks provided in this library
+scr=org.apache.felix.scrplugin.ant.SCRDescriptorTask
\ No newline at end of file