You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ju...@apache.org on 2011/12/02 03:51:47 UTC

svn commit: r1209336 - in /sling/trunk: ./ maven/adapter-annotations/ maven/adapter-annotations/src/ maven/adapter-annotations/src/main/ maven/adapter-annotations/src/main/java/ maven/adapter-annotations/src/main/java/org/ maven/adapter-annotations/src...

Author: justin
Date: Fri Dec  2 02:51:45 2011
New Revision: 1209336

URL: http://svn.apache.org/viewvc?rev=1209336&view=rev
Log:
SLING-2313 - creating a new adapter annotations module and enhancing the sling plugin to generate the adapter JSON file

Added:
    sling/trunk/maven/adapter-annotations/
    sling/trunk/maven/adapter-annotations/src/
    sling/trunk/maven/adapter-annotations/src/main/
    sling/trunk/maven/adapter-annotations/src/main/java/
    sling/trunk/maven/adapter-annotations/src/main/java/org/
    sling/trunk/maven/adapter-annotations/src/main/java/org/apache/
    sling/trunk/maven/adapter-annotations/src/main/java/org/apache/sling/
    sling/trunk/maven/adapter-annotations/src/main/java/org/apache/sling/adapter/
    sling/trunk/maven/adapter-annotations/src/main/java/org/apache/sling/adapter/annotations/
    sling/trunk/maven/adapter-annotations/src/main/java/org/apache/sling/adapter/annotations/Adaptable.java
    sling/trunk/maven/adapter-annotations/src/main/java/org/apache/sling/adapter/annotations/Adapter.java
    sling/trunk/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/GenerateAdapterMetadataMojo.java
Modified:
    sling/trunk/maven/maven-sling-plugin/pom.xml
    sling/trunk/pom.xml

Added: sling/trunk/maven/adapter-annotations/src/main/java/org/apache/sling/adapter/annotations/Adaptable.java
URL: http://svn.apache.org/viewvc/sling/trunk/maven/adapter-annotations/src/main/java/org/apache/sling/adapter/annotations/Adaptable.java?rev=1209336&view=auto
==============================================================================
--- sling/trunk/maven/adapter-annotations/src/main/java/org/apache/sling/adapter/annotations/Adaptable.java (added)
+++ sling/trunk/maven/adapter-annotations/src/main/java/org/apache/sling/adapter/annotations/Adaptable.java Fri Dec  2 02:51:45 2011
@@ -0,0 +1,47 @@
+/*
+ * 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.sling.adapter.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The <code>AdaptableInfo</code> annotation defines metadata about an implementation
+ * of <code>org.apache.sling.api.adapter.Adaptable</code>.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@Documented
+public @interface Adaptable {
+    
+    /**
+     * The class which can be adapted.
+     */
+    Class<?> adaptableClass();
+    
+    /**
+     * The possible adapters for this adaptable.
+     */
+    Adapter[] adapters();
+    
+
+}
\ No newline at end of file

Added: sling/trunk/maven/adapter-annotations/src/main/java/org/apache/sling/adapter/annotations/Adapter.java
URL: http://svn.apache.org/viewvc/sling/trunk/maven/adapter-annotations/src/main/java/org/apache/sling/adapter/annotations/Adapter.java?rev=1209336&view=auto
==============================================================================
--- sling/trunk/maven/adapter-annotations/src/main/java/org/apache/sling/adapter/annotations/Adapter.java (added)
+++ sling/trunk/maven/adapter-annotations/src/main/java/org/apache/sling/adapter/annotations/Adapter.java Fri Dec  2 02:51:45 2011
@@ -0,0 +1,43 @@
+/*
+ * 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.sling.adapter.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The <code>Adapter</code> annotation the target of the adaptation of an
+ * <code>Adaptable</code> and, optionally, the condition under which the
+ * adaptation will produce a non-null result.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@Documented
+public @interface Adapter {
+    /**
+     * The list of classes to which the adaptable can be adapted.
+     * */
+    Class<?>[] value();
+
+    /**
+     * The condition under which an adaptation will be successful.
+     */
+    String condition() default "";
+}

Modified: sling/trunk/maven/maven-sling-plugin/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/maven/maven-sling-plugin/pom.xml?rev=1209336&r1=1209335&r2=1209336&view=diff
==============================================================================
--- sling/trunk/maven/maven-sling-plugin/pom.xml (original)
+++ sling/trunk/maven/maven-sling-plugin/pom.xml Fri Dec  2 02:51:45 2011
@@ -108,5 +108,20 @@
             <artifactId>maven-archiver</artifactId>
             <version>2.0</version>
         </dependency>
+        <dependency>
+            <groupId>net.sf.scannotation</groupId>
+            <artifactId>scannotation</artifactId>
+            <version>1.0.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>adapter-annotations</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>asm</groupId>
+            <artifactId>asm-all</artifactId>
+            <version>3.3.1</version>
+        </dependency>
     </dependencies>
 </project>

Added: sling/trunk/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/GenerateAdapterMetadataMojo.java
URL: http://svn.apache.org/viewvc/sling/trunk/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/GenerateAdapterMetadataMojo.java?rev=1209336&view=auto
==============================================================================
--- sling/trunk/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/GenerateAdapterMetadataMojo.java (added)
+++ sling/trunk/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/GenerateAdapterMetadataMojo.java Fri Dec  2 02:51:45 2011
@@ -0,0 +1,243 @@
+/*
+ * 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.sling.maven.bundlesupport;
+
+import static org.objectweb.asm.ClassReader.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+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.apache.sling.adapter.annotations.Adaptable;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.StringUtils;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.AnnotationNode;
+import org.objectweb.asm.tree.ClassNode;
+import org.scannotation.AnnotationDB;
+
+/**
+ * @goal generate-adapter-metadata
+ * @phase process-classes
+ * @threadSafe
+ * @description Build Adapter Metadata from Annotated Classes
+ * @requiresDependencyResolution compile
+ */
+public class GenerateAdapterMetadataMojo extends AbstractMojo {
+
+    private static final int JSON_INDENTATION = 4;
+
+    private static final String ADAPTABLE_DESC = "L" + Adaptable.class.getName().replace('.', '/') + ";";
+
+    private static final String DEFAULT_CONDITION = "If the adaptable is a %s.";
+
+    private static String getSimpleName(final ClassNode clazz) {
+        final String internalName = clazz.name;
+        final int idx = internalName.lastIndexOf('/');
+        if (idx == -1) {
+            return internalName;
+        } else {
+            return internalName.substring(idx + 1);
+        }
+    }
+
+    /**
+     * @parameter expression="${project.build.outputDirectory}"
+     * @required
+     * @readonly
+     */
+    private File buildOutputDirectory;
+
+    /**
+     * Name of the generated descriptor file.
+     * 
+     * @parameter expression="${adapter.descriptor.name}"
+     *            default-value="SLING-INF/adapters.json"
+     */
+    private String fileName;
+
+    /**
+     * @parameter 
+     *            expression="${project.build.directory}/adapter-plugin-generated"
+     * @required
+     * @readonly
+     */
+    private File outputDirectory;
+
+    /**
+     * The Maven project.
+     * 
+     * @parameter expression="${project}"
+     * @required
+     * @readonly
+     */
+    private MavenProject project;
+
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        try {
+            final JSONObject descriptor = new JSONObject();
+
+            final AnnotationDB annotationDb = new AnnotationDB();
+            annotationDb.scanArchives(buildOutputDirectory.toURI().toURL());
+
+            final Set<String> annotatedClassNames = annotationDb.getAnnotationIndex().get(Adaptable.class.getName());
+            if (annotatedClassNames.isEmpty()) {
+                getLog().debug("No classes found with adaptable annotations.");
+            }
+
+            for (final String annotatedClassName : annotatedClassNames) {
+                getLog().info(String.format("found adaptable annotation on %s", annotatedClassName));
+                final String pathToClassFile = annotatedClassName.replace('.', '/') + ".class";
+                final File classFile = new File(buildOutputDirectory, pathToClassFile);
+                final FileInputStream input = new FileInputStream(classFile);
+                final ClassReader classReader;
+                try {
+                    classReader = new ClassReader(input);
+                } finally {
+                    input.close();
+                }
+                final ClassNode classNode = new ClassNode();
+                classReader.accept(classNode, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES);
+
+                @SuppressWarnings("unchecked")
+                final List<AnnotationNode> annotations = classNode.invisibleAnnotations;
+                for (final AnnotationNode annotation : annotations) {
+                    if (ADAPTABLE_DESC.equals(annotation.desc)) {
+                        parseAdaptableAnnotation(annotation, classNode, descriptor);
+                    }
+                }
+
+            }
+
+            final File outputFile = new File(outputDirectory, fileName);
+            outputFile.getParentFile().mkdirs();
+            final FileWriter writer = new FileWriter(outputFile);
+            try {
+                IOUtil.copy(descriptor.toString(JSON_INDENTATION), writer);
+            } finally {
+                IOUtil.close(writer);
+            }
+            addResource();
+
+        } catch (IOException e) {
+            throw new MojoExecutionException("Unable to generate metadata", e);
+        } catch (JSONException e) {
+            throw new MojoExecutionException("Unable to generate metadata", e);
+        }
+
+    }
+
+    private void addResource() {
+        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);
+        }
+
+    }
+
+    @SuppressWarnings("unchecked")
+    private void parseAdaptableAnnotation(final AnnotationNode annotation, final ClassNode annotatedClass,
+            final JSONObject descriptor) throws JSONException {
+        String adaptableClassName = null;
+        List<AnnotationNode> adapters = null;
+
+        final List<?> values = annotation.values;
+
+        final Iterator<?> it = values.iterator();
+        while (it.hasNext()) {
+            Object name = it.next();
+            Object value = it.next();
+
+            if ("adaptableClass".equals(name)) {
+                adaptableClassName = ((Type) value).getClassName();
+            } else if ("adapters".equals(name)) {
+                adapters = (List<AnnotationNode>) value;
+            }
+        }
+
+        if (adaptableClassName == null || adapters == null) {
+            throw new IllegalArgumentException(
+                    "Adaptable annotation is malformed. Expecting a classname and a list of adapter annotation.");
+        }
+
+        JSONObject adaptableDescription;
+        if (descriptor.has(adaptableClassName)) {
+            adaptableDescription = descriptor.getJSONObject(adaptableClassName);
+        } else {
+            adaptableDescription = new JSONObject();
+            descriptor.put(adaptableClassName, adaptableDescription);
+        }
+
+        for (final AnnotationNode adapter : adapters) {
+            parseAdapterAnnotation(adapter, annotatedClass, adaptableDescription);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private void parseAdapterAnnotation(final AnnotationNode annotation, final ClassNode annotatedClass,
+            final JSONObject adaptableDescription) throws JSONException {
+        String condition = null;
+        List<Type> adapterClasses = null;
+
+        final List<?> values = annotation.values;
+
+        final Iterator<?> it = values.iterator();
+        while (it.hasNext()) {
+            final Object name = it.next();
+            final Object value = it.next();
+
+            if (StringUtils.isEmpty(condition)) {
+                condition = String.format(DEFAULT_CONDITION, getSimpleName(annotatedClass));
+            }
+
+            if ("condition".equals(name)) {
+                condition = (String) value;
+            } else if ("value".equals(name)) {
+                adapterClasses = (List<Type>) value;
+            }
+        }
+
+        if (adapterClasses == null) {
+            throw new IllegalArgumentException("Adapter annotation is malformed. Expecting a list of adapter classes");
+        }
+        
+        for (final Type adapterClass : adapterClasses) {
+            adaptableDescription.accumulate(condition, adapterClass.getClassName());
+        }
+    }
+}

Modified: sling/trunk/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/pom.xml?rev=1209336&r1=1209335&r2=1209336&view=diff
==============================================================================
--- sling/trunk/pom.xml (original)
+++ sling/trunk/pom.xml Fri Dec  2 02:51:45 2011
@@ -87,6 +87,7 @@
         <module>parent</module>
 
         <!-- The Maven Plugins and Archeyptes-->
+        <module>maven/adapter-annotations</module>
         <module>maven/maven-jcrocm-plugin</module>
         <module>maven/maven-jspc-plugin</module>
         <module>maven/maven-sling-plugin</module>