FELIX-2303 : Add annotation for a Sling servlet filter

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@938334 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr-annotations/src/main/java/org/apache/felix/scr/annotations/sling/SlingFilter.java b/scr-annotations/src/main/java/org/apache/felix/scr/annotations/sling/SlingFilter.java
new file mode 100644
index 0000000..5cb4fc5
--- /dev/null
+++ b/scr-annotations/src/main/java/org/apache/felix/scr/annotations/sling/SlingFilter.java
@@ -0,0 +1,95 @@
+/*
+ * 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.scr.annotations.sling;
+
+import java.lang.annotation.*;
+
+/**
+ * Marks servlet classes as SCR component, and allows to add a
+ * filter to Sling's processing.
+ * This annotation generates to private properties for the
+ * order and the scope.
+ * By default it also generates a component and a service tag,
+ * but this generation can be overriden.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.SOURCE)
+@Documented
+public @interface SlingFilter {
+
+    /**
+     * The order of the filter.
+     * This value is used to sort the filters. Filters with a lower order
+     * are executed before a filter with a higher order. If two filters
+     * have the same order, they are executed in an undefined order.
+     */
+    int order();
+
+    /**
+     * The scope of a filter.
+     * If the filter has request scope, it is run once for a request.
+     * If the filter has component scope, it is run once for every included
+     * component (rendering).
+     */
+    SlingFilterScope scope() default SlingFilterScope.REQUEST;
+
+    /**
+     * Whether to generate a default SCR component tag with. If
+     * set to false, a {@link org.apache.felix.scr.annotations.Component}
+     * annotation can be added manually with defined whatever configuration
+     * needed.
+     */
+    boolean generateComponent() default true;
+
+    /**
+     * Whether to generate a default SCR service tag with
+     * "interface=javax.servlet.Filter". If set to false, a
+     * {@link org.apache.felix.scr.annotations.Service} annotation can be added
+     * manually with defined whatever configuration needed.
+     */
+    boolean generateService() default true;
+
+    /**
+     * Defines the Component name also used as the PID for the Configuration
+     * Admin Service. Default value: Fully qualified name of the Java class.
+     */
+    String name() default "";
+
+    /**
+     * Whether Metatype Service data is generated or not. If this parameter is
+     * set to true Metatype Service data is generated in the
+     * <code>metatype.xml</code> file for this component. Otherwise no Metatype
+     * Service data is generated for this component.
+     */
+    boolean metatype() default false;
+
+    /**
+     * This is generally used as a title for the object described by the meta
+     * type. This name may be localized by prepending a % sign to the name.
+     * Default value: %&lt;name&gt;.name
+     */
+    String label() default "";
+
+    /**
+     * This is generally used as a description for the object described by the
+     * meta type. This name may be localized by prepending a % sign to the name.
+     * Default value: %&lt;name&gt;.description
+     */
+    String description() default "";
+}
diff --git a/scr-annotations/src/main/java/org/apache/felix/scr/annotations/sling/SlingFilterScope.java b/scr-annotations/src/main/java/org/apache/felix/scr/annotations/sling/SlingFilterScope.java
new file mode 100644
index 0000000..72bed73
--- /dev/null
+++ b/scr-annotations/src/main/java/org/apache/felix/scr/annotations/sling/SlingFilterScope.java
@@ -0,0 +1,42 @@
+/*
+ * 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.scr.annotations.sling;
+
+/**
+ * The possible scopes for the {@link SlingFilter#scope()} annotation.
+ */
+public enum SlingFilterScope {
+
+    REQUEST("request"),
+
+    COMPONENT("component");
+
+    private final String scope;
+
+    private SlingFilterScope(final String scope) {
+        this.scope = scope;
+    }
+
+    /**
+     * @return String representation of the scope
+     */
+    public String getScope() {
+        return this.scope;
+    }
+}
diff --git a/scr-annotations/src/main/java/org/apache/felix/scr/annotations/sling/SlingServlet.java b/scr-annotations/src/main/java/org/apache/felix/scr/annotations/sling/SlingServlet.java
index 67f7de0..091b0cf 100644
--- a/scr-annotations/src/main/java/org/apache/felix/scr/annotations/sling/SlingServlet.java
+++ b/scr-annotations/src/main/java/org/apache/felix/scr/annotations/sling/SlingServlet.java
@@ -18,15 +18,11 @@
  */
 package org.apache.felix.scr.annotations.sling;
 
-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;
+import java.lang.annotation.*;
 
 /**
- * Marks servlet classes as felix SCR component, and allows to configure sling
- * resource resolving mapping.
+ * Marks servlet classes as SCR component, and allows to configure
+ * Sling's resource resolver mapping.
  */
 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.SOURCE)
@@ -42,7 +38,7 @@
     boolean generateComponent() default true;
 
     /**
-     * Whether to generate a default SCR service tag with with
+     * Whether to generate a default SCR service tag with
      * "interface=javax.servlet.Servlet". If set to false, a
      * {@link org.apache.felix.scr.annotations.Service} annotation can be added
      * manually with defined whatever configuration needed.
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingAnnotationTagProvider.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingAnnotationTagProvider.java
index b83a691..7a102d2 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingAnnotationTagProvider.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingAnnotationTagProvider.java
@@ -21,7 +21,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.felix.scr.annotations.sling.SlingServlet;
+import org.apache.felix.scr.annotations.sling.*;
 import org.apache.felix.scrplugin.tags.JavaField;
 import org.apache.felix.scrplugin.tags.JavaTag;
 import org.apache.felix.scrplugin.tags.annotation.AnnotationJavaClassDescription;
@@ -33,56 +33,109 @@
  */
 public class SlingAnnotationTagProvider implements AnnotationTagProvider {
 
-    public List<JavaTag> getTags(com.thoughtworks.qdox.model.Annotation annotation,
-            AnnotationJavaClassDescription description, JavaField field) {
-        List<JavaTag> tags = new ArrayList<JavaTag>();
+    /**
+     * @see org.apache.felix.scrplugin.tags.annotation.AnnotationTagProvider#getTags(com.thoughtworks.qdox.model.Annotation, org.apache.felix.scrplugin.tags.annotation.AnnotationJavaClassDescription, org.apache.felix.scrplugin.tags.JavaField)
+     */
+    public List<JavaTag> getTags(final com.thoughtworks.qdox.model.Annotation annotation,
+            final AnnotationJavaClassDescription description,
+            final JavaField field)
+   {
+        final String annotationName = annotation.getType().getJavaClass().getFullyQualifiedName();
+        final List<JavaTag> tags = new ArrayList<JavaTag>();
 
-        if (annotation.getType().getJavaClass().getFullyQualifiedName().equals(SlingServlet.class.getName())) {
+        // SlingServlet annotation
+        if (annotationName.equals(SlingServlet.class.getName()))
+        {
 
             // generate @Component tag if required
             boolean generateComponent = Util.getBooleanValue(annotation, "generateComponent", SlingServlet.class);
-            if (generateComponent) {
+            if (generateComponent)
+            {
                 tags.add(new SlingServletComponentTag(annotation, description));
             }
 
             // generate @Service tag if required
             boolean generateService = Util.getBooleanValue(annotation, "generateService", SlingServlet.class);
-            if (generateService) {
+            if (generateService)
+            {
                 tags.add(new SlingServletServiceTag(annotation, description));
             }
 
             // generate @Property tags
             // {@see org.apache.sling.servlets.resolver.internal.ServletResolverConstants.SLING_SERVLET_PATHS}
             String[] paths = Util.getStringValues(annotation, description, "paths");
-            if (paths != null && paths.length != 0) {
+            if (paths != null && paths.length != 0)
+            {
                 tags.add(new SlingServletPropertyTag(annotation, "sling.servlet.paths", paths, description));
             }
 
             // {@see org.apache.sling.servlets.resolver.internal.ServletResolverConstants.SLING_SERVLET_RESOURCE_TYPES}
             String[] resourceTypes = Util.getStringValues(annotation, description, "resourceTypes");
-            if (resourceTypes != null && resourceTypes.length != 0) {
+            if (resourceTypes != null && resourceTypes.length != 0)
+            {
                 tags.add(new SlingServletPropertyTag(annotation, "sling.servlet.resourceTypes", resourceTypes, description));
             }
 
             // {@see org.apache.sling.servlets.resolver.internal.ServletResolverConstants.SLING_SERVLET_SELECTORS}
             String[] selectors = Util.getStringValues(annotation, description, "selectors");
-            if (selectors != null && selectors.length != 0) {
+            if (selectors != null && selectors.length != 0)
+            {
                 tags.add(new SlingServletPropertyTag(annotation, "sling.servlet.selectors", selectors, description));
             }
 
             // {@see org.apache.sling.servlets.resolver.internal.ServletResolverConstants.SLING_SERVLET_EXTENSIONS}
             String[] extensions = Util.getStringValues(annotation, description, "extensions");
-            if (extensions != null && extensions.length != 0) {
+            if (extensions != null && extensions.length != 0)
+            {
                 tags.add(new SlingServletPropertyTag(annotation, "sling.servlet.extensions", extensions, description));
             }
 
             // {@see org.apache.sling.servlets.resolver.internal.ServletResolverConstants.SLING_SERVLET_METHODS}
             String[] methods = Util.getStringValues(annotation, description, "methods");
-            if (methods != null && methods.length != 0) {
+            if (methods != null && methods.length != 0)
+            {
                 tags.add(new SlingServletPropertyTag(annotation, "sling.servlet.methods", methods, description));
             }
 
         }
+        // Filter annotation
+        else if ( annotationName.equals(SlingFilter.class.getName()) )
+        {
+            // generate @Component tag if required
+            boolean generateComponent = Util.getBooleanValue(annotation, "generateComponent", SlingFilter.class);
+            if (generateComponent)
+            {
+                String name = Util.getStringValue(annotation, description, "name", SlingFilter.class);
+                if ( name != null && name.trim().length() == 0 ) {
+                    name = null;
+                }
+                String label = Util.getStringValue(annotation, description, "label", SlingFilter.class);
+                if ( label != null && label.trim().length() == 0 ) {
+                    label = null;
+                }
+                String desc = Util.getStringValue(annotation, description, "description", SlingFilter.class);
+                if ( desc != null && desc.trim().length() == 0 ) {
+                    desc = null;
+                }
+                final boolean createMetatype = Util.getBooleanValue(annotation, "metatype", SlingFilter.class);
+                tags.add(new SlingFilterComponentTag(annotation, description, createMetatype, name, label, desc));
+            }
+
+            // generate @Service tag if required
+            boolean generateService = Util.getBooleanValue(annotation, "generateService", SlingFilter.class);
+            if (generateService)
+            {
+                tags.add(new SlingFilterServiceTag(annotation, description));
+            }
+
+            // property order
+            final int order = Util.getIntValue(annotation, "order", SlingFilter.class);
+            tags.add(new SlingServletPropertyTag(annotation, "filter.order",String.valueOf(order), description, "Integer", true));
+
+            // property scope
+            final SlingFilterScope scope = Util.getEnumValue(annotation, "scope", SlingFilterScope.class, SlingFilter.class);
+            tags.add(new SlingServletPropertyTag(annotation, "filter.scope",scope.getScope(), description, null, true));
+        }
 
         return tags;
     }
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingFilterComponentTag.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingFilterComponentTag.java
new file mode 100644
index 0000000..e60abd4
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingFilterComponentTag.java
@@ -0,0 +1,77 @@
+/*
+ * 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.annotation.sling;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.scrplugin.Constants;
+import org.apache.felix.scrplugin.tags.JavaClassDescription;
+import org.apache.felix.scrplugin.tags.annotation.defaulttag.AbstractTag;
+
+import com.thoughtworks.qdox.model.Annotation;
+
+/**
+ * Description of a java tag for components.
+ */
+public class SlingFilterComponentTag extends AbstractTag {
+
+    private final boolean createMetatype;
+    private final String name;
+    private final String label;
+    private final String description;
+
+    /**
+     * @param desc Description
+     */
+    public SlingFilterComponentTag(final Annotation annotation,
+            final JavaClassDescription desc,
+            final boolean createMetatype,
+            final String name,
+            final String label,
+            final String description) {
+        super(annotation, desc, null);
+        this.createMetatype = createMetatype;
+        this.name = name;
+        this.label = label;
+        this.description = description;
+    }
+
+    @Override
+    public String getName() {
+        return Constants.COMPONENT;
+    }
+
+    @Override
+    public Map<String, String> createNamedParameterMap() {
+        final Map<String, String> params = new HashMap<String, String>();
+        if ( this.name != null ) {
+            params.put(Constants.COMPONENT_NAME, this.name);
+        }
+        if ( this.label != null ) {
+            params.put(Constants.COMPONENT_LABEL, this.label);
+        }
+        if ( this.description != null ) {
+            params.put(Constants.COMPONENT_DESCRIPTION, this.description);
+        }
+        params.put(Constants.COMPONENT_METATYPE, String.valueOf(this.createMetatype));
+        return params;
+    }
+
+}
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
new file mode 100644
index 0000000..a1f963b
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingFilterServiceTag.java
@@ -0,0 +1,57 @@
+/*
+ * 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.annotation.sling;
+
+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;
+import org.apache.felix.scrplugin.tags.annotation.defaulttag.AbstractTag;
+
+import com.thoughtworks.qdox.model.Annotation;
+
+/**
+ * Description of a java tag for components.
+ */
+public class SlingFilterServiceTag extends AbstractTag {
+
+    private static final Map<String, String> INTERFACE_MAP =
+        Collections.singletonMap(Constants.SERVICE_INTERFACE, Filter.class.getName());
+
+    /**
+     * @param desc Description
+     */
+    public SlingFilterServiceTag(Annotation annotation, JavaClassDescription desc) {
+        super(annotation, desc, null);
+    }
+
+    @Override
+    public String getName() {
+        return Constants.SERVICE;
+    }
+
+    @Override
+    public Map<String, String> createNamedParameterMap() {
+        return INTERFACE_MAP;
+    }
+
+}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingServletComponentTag.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingServletComponentTag.java
index 105186a..42cbe8e 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingServletComponentTag.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/annotation/sling/SlingServletComponentTag.java
@@ -18,7 +18,7 @@
  */
 package org.apache.felix.scrplugin.tags.annotation.sling;
 
-import java.util.HashMap;
+import java.util.Collections;
 import java.util.Map;
 
 import org.apache.felix.scrplugin.Constants;
@@ -32,6 +32,9 @@
  */
 public class SlingServletComponentTag extends AbstractTag {
 
+    private static final Map<String, String> IMMEDIATE_MAP =
+            Collections.singletonMap(Constants.COMPONENT_IMMEDIATE, String.valueOf(true));
+
     /**
      * @param desc Description
      */
@@ -46,11 +49,7 @@
 
     @Override
     public Map<String, String> createNamedParameterMap() {
-        final Map<String, String> map = new HashMap<String, String>();
-
-        map.put(Constants.COMPONENT_IMMEDIATE, String.valueOf(true));
-
-        return map;
+        return IMMEDIATE_MAP;
     }
 
 }
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 e88b5b6..984ae00 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,9 +18,7 @@
  */
 package org.apache.felix.scrplugin.tags.annotation.sling;
 
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
+import java.util.*;
 
 import org.apache.felix.scrplugin.Constants;
 import org.apache.felix.scrplugin.helper.StringUtils;
@@ -30,12 +28,14 @@
 import com.thoughtworks.qdox.model.Annotation;
 
 /**
- * Description of a java tag for components.
+ * A property tag.
  */
 public class SlingServletPropertyTag extends AbstractTag {
 
     protected final String name;
     protected final String[] values;
+    protected final String type;
+    protected final Boolean isPrivate;
 
     /**
      * @param name Property name
@@ -46,6 +46,26 @@
         super(annotation, desc, null);
         this.name = name;
         this.values = values;
+        this.type = null;
+        this.isPrivate = null;
+    }
+
+    /**
+     * @param name Property name
+     * @param value Property value
+     * @param desc Description
+     */
+    public SlingServletPropertyTag(final Annotation annotation,
+            final String name,
+            final String value,
+            final JavaClassDescription desc,
+            final String type,
+            final boolean isPrivate) {
+        super(annotation, desc, null);
+        this.name = name;
+        this.values = new String[] {value};
+        this.type = type;
+        this.isPrivate = isPrivate;
     }
 
     @Override
@@ -71,6 +91,13 @@
             }
         }
 
+        if ( this.type != null ) {
+            map.put(Constants.PROPERTY_TYPE, type);
+        }
+        if ( this.isPrivate != null ) {
+            map.put(Constants.PROPERTY_PRIVATE, String.valueOf(this.isPrivate));
+        }
+
         return map;
     }
 
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 8ca4d99..34e871c 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
@@ -18,7 +18,7 @@
  */
 package org.apache.felix.scrplugin.tags.annotation.sling;
 
-import java.util.HashMap;
+import java.util.Collections;
 import java.util.Map;
 
 import javax.servlet.Servlet;
@@ -34,6 +34,9 @@
  */
 public class SlingServletServiceTag extends AbstractTag {
 
+    private static final Map<String, String> INTERFACE_MAP =
+        Collections.singletonMap(Constants.SERVICE_INTERFACE, Servlet.class.getName());
+
     /**
      * @param desc Description
      */
@@ -48,11 +51,7 @@
 
     @Override
     public Map<String, String> createNamedParameterMap() {
-        final Map<String, String> map = new HashMap<String, String>();
-
-        map.put(Constants.SERVICE_INTERFACE, Servlet.class.getName());
-
-        return map;
+        return INTERFACE_MAP;
     }
 
 }