Repository: deltaspike
Updated Branches:
  refs/heads/master 028ec5bf3 -> 3734100fe


DELTASPIKE-1316 add InterDynExtension

this allows to configurably add annotations to classes
identified via a regexp.


Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/2c185bd5
Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/2c185bd5
Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/2c185bd5

Branch: refs/heads/master
Commit: 2c185bd5f02ea842b9d2f4628a7204c0453eec0d
Parents: 028ec5b
Author: Mark Struberg <strub...@apache.org>
Authored: Fri Feb 9 18:31:33 2018 +0100
Committer: Mark Struberg <strub...@apache.org>
Committed: Fri Feb 9 18:31:33 2018 +0100

----------------------------------------------------------------------
 .../core/api/config/base/CoreBaseConfig.java    |  31 ++++
 .../interceptor/interdyn/AnnotationRule.java    |  55 +++++++
 .../interceptor/interdyn/InterDynExtension.java | 161 +++++++++++++++++++
 3 files changed, 247 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2c185bd5/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/base/CoreBaseConfig.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/base/CoreBaseConfig.java
 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/base/CoreBaseConfig.java
index befd31e..02312f4 100644
--- 
a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/base/CoreBaseConfig.java
+++ 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/base/CoreBaseConfig.java
@@ -110,4 +110,35 @@ public interface CoreBaseConfig extends 
DeltaSpikeBaseConfig
                         .withDefault(Boolean.FALSE)
                         .getValue();
     }
+
+    interface InterDynCustomization
+    {
+        /**
+         * All interdyn rules start with this prefix and contains a 'match' 
and a 'annotation' part.
+         * The 'match' is a regular expression which depicts the classes which 
should get annotated.
+         * The 'annotation' is the annotation name which should get applied to 
all the classes which
+         * match the 'match' regexp.
+         *
+         * A sample config might look like:
+         * <pre>
+         * deltaspike.interdyn.rule.1.match=com\.mycorp\..*Service.*
+         * 
deltaspike.interdyn.rule.1.annotation=org.apache.deltaspike.core.api.monitor.InvocationMonitored
+         * </pre>
+         */
+        String INTERDYN_RULE_PREFIX = "deltaspike.interdyn.rule.";
+
+        /**
+         * Whether the InterDyn feature is enabled or not.
+         *
+         * If the feature is enabled at startup then we will apply the 
interceptors dynamically
+         * to all the matching classes.
+         * Otherwise we will skip the instrumentation.
+         */
+        ConfigResolver.TypedResolver<Boolean> INTERDYN_ENABLED =
+                ConfigResolver.resolve("deltaspike.interdyn.enabled")
+                        .as(Boolean.class)
+                        .withCurrentProjectStage(true)
+                        .withDefault(Boolean.FALSE);
+
+    }
 }

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2c185bd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/interceptor/interdyn/AnnotationRule.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/interceptor/interdyn/AnnotationRule.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/interceptor/interdyn/AnnotationRule.java
new file mode 100644
index 0000000..a93177b
--- /dev/null
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/interceptor/interdyn/AnnotationRule.java
@@ -0,0 +1,55 @@
+/*
+ * 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.deltaspike.core.impl.interceptor.interdyn;
+
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Contains a mapping between a dynamic interceptor rule and the name of the 
additional annotation to be added
+ */
+
+public class AnnotationRule
+{
+    /**
+     * A RegExp to identify the classes which should get modified
+     */
+    private String rule;
+
+    /**
+     * The Annotation to be added
+     */
+    private Annotation additionalAnnotation;
+
+    public AnnotationRule(String rule, Annotation interceptorBinding)
+    {
+        this.rule = rule;
+        this.additionalAnnotation = interceptorBinding;
+    }
+
+    public String getRule()
+    {
+        return rule;
+    }
+
+    public Annotation getAdditionalAnnotation()
+    {
+        return additionalAnnotation;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2c185bd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/interceptor/interdyn/InterDynExtension.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/interceptor/interdyn/InterDynExtension.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/interceptor/interdyn/InterDynExtension.java
new file mode 100644
index 0000000..61a60e7
--- /dev/null
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/interceptor/interdyn/InterDynExtension.java
@@ -0,0 +1,161 @@
+/*
+ * 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.deltaspike.core.impl.interceptor.interdyn;
+
+
+import org.apache.deltaspike.core.api.config.ConfigResolver;
+import org.apache.deltaspike.core.api.config.base.CoreBaseConfig;
+import org.apache.deltaspike.core.spi.activation.Deactivatable;
+import org.apache.deltaspike.core.util.ClassDeactivationUtils;
+import org.apache.deltaspike.core.util.ClassUtils;
+import org.apache.deltaspike.core.util.metadata.AnnotationInstanceProvider;
+import org.apache.deltaspike.core.util.metadata.builder.AnnotatedTypeBuilder;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.ProcessAnnotatedType;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+/**
+ * <p>InterDyn is a CDI (JSR-299) Extension for dynamically
+ * attaching annotations (e.g. CDI interceptors) to a class.</p>
+ *
+ */
+public class InterDynExtension implements Deactivatable, Extension
+{
+    private List<AnnotationRule> interceptorRules = new 
ArrayList<AnnotationRule>();
+
+
+    private Logger logger = 
Logger.getLogger(InterDynExtension.class.getName());
+
+    private Map<String, Annotation> usedInterceptorBindings = new 
HashMap<String, Annotation>();
+
+    private boolean enabled = false;
+
+    @SuppressWarnings("UnusedDeclaration")
+    protected void init(@Observes BeforeBeanDiscovery beforeBeanDiscovery, 
BeanManager beanManager)
+    {
+        if (!ClassDeactivationUtils.isActivated(getClass()))
+        {
+            return;
+        }
+
+        enabled = 
CoreBaseConfig.InterDynCustomization.INTERDYN_ENABLED.getValue();
+
+        if (enabled)
+        {
+            logger.info("Starting with deltaspike.interdyn instrumentation");
+            init();
+        }
+    }
+
+    public void init()
+    {
+        Set<String> ruleConfigKeys = new HashSet<String>();
+
+        // first we collect all the rule property names
+        for (String propertyName : ConfigResolver.getAllProperties().keySet())
+        {
+            if 
(propertyName.startsWith(CoreBaseConfig.InterDynCustomization.INTERDYN_RULE_PREFIX)
 &&
+                propertyName.contains(".match"))
+            {
+                ruleConfigKeys.add(propertyName.substring(0, 
propertyName.indexOf(".match")));
+            }
+        }
+
+        for (String ruleConfigKey : ruleConfigKeys)
+        {
+            String match = ConfigResolver.getPropertyValue(ruleConfigKey + 
".match");
+            String annotationClassName = 
ConfigResolver.getPropertyValue(ruleConfigKey + ".annotation");
+
+            if (match != null && annotationClassName != null)
+            {
+                Annotation anno = 
getAnnotationImplementation(annotationClassName);
+                interceptorRules.add(new AnnotationRule(match, anno));
+            }
+        }
+
+
+        if (interceptorRules.isEmpty())
+        {
+            enabled = false;
+        }
+    }
+
+    public void processAnnotatedType(@Observes ProcessAnnotatedType pat)
+    {
+        if (enabled)
+        {
+            String beanClassName = 
pat.getAnnotatedType().getJavaClass().getName();
+            AnnotatedType at = pat.getAnnotatedType();
+            AnnotatedTypeBuilder atb = null;
+            for (AnnotationRule rule : interceptorRules)
+            {
+                if (beanClassName.matches(rule.getRule()))
+                {
+                    if (atb == null)
+                    {
+                        atb = new AnnotatedTypeBuilder();
+                        atb.readFromType(at);
+                    }
+                    atb.addToClass(rule.getAdditionalAnnotation());
+                    logger.info("Adding Dynamic Interceptor " + 
rule.getAdditionalAnnotation()
+                            + " to class " + beanClassName );
+                }
+            }
+            if (atb != null)
+            {
+                pat.setAnnotatedType(atb.create());
+            }
+        }
+    }
+
+    private Annotation getAnnotationImplementation(String 
interceptorBindingClassName)
+    {
+        Annotation ann = 
usedInterceptorBindings.get(interceptorBindingClassName);
+
+        if (ann == null)
+        {
+            Class<? extends Annotation> annClass;
+            try
+            {
+                annClass = (Class<? extends Annotation>)
+                        
ClassUtils.getClassLoader(null).loadClass(interceptorBindingClassName);
+            }
+            catch (ClassNotFoundException e)
+            {
+                throw new RuntimeException("Error while picking up dynamic 
InterceptorBindingType for class" +
+                                           interceptorBindingClassName, e);
+            }
+            ann = AnnotationInstanceProvider.of(annClass);
+            usedInterceptorBindings.put(interceptorBindingClassName, ann);
+        }
+        return ann;
+    }
+}

Reply via email to