You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by st...@apache.org on 2018/02/09 21:25:04 UTC

[1/5] deltaspike git commit: DELTASPIKE-1316 add InterDynExtension

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 <st...@apache.org>
Authored: Fri Feb 9 18:31:33 2018 +0100
Committer: Mark Struberg <st...@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;
+    }
+}


[4/5] deltaspike git commit: DELTASPIKE-1316 activate InterDynExtension

Posted by st...@apache.org.
DELTASPIKE-1316 activate InterDynExtension


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

Branch: refs/heads/master
Commit: 0a914ba3cd05f9a74ce19c7843f56445fa2a932c
Parents: 9423d74
Author: Mark Struberg <st...@apache.org>
Authored: Fri Feb 9 20:52:22 2018 +0100
Committer: Mark Struberg <st...@apache.org>
Committed: Fri Feb 9 20:52:22 2018 +0100

----------------------------------------------------------------------
 .../core/impl/interceptor/interdyn/InterDynExtension.java        | 4 +++-
 .../META-INF/services/javax.enterprise.inject.spi.Extension      | 3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltaspike/blob/0a914ba3/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
index d948722..bcbb4ff 100644
--- 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
@@ -44,7 +44,9 @@ 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>
+ * applying annotations (e.g. CDI interceptors) to a class.</p>
+ *
+ * The main usage is to apply Interceptors per regExp, thus the name.
  *
  */
 public class InterDynExtension implements Deactivatable, Extension

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/0a914ba3/deltaspike/core/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/deltaspike/core/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
index fbcb10a..b81b882 100644
--- a/deltaspike/core/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
+++ b/deltaspike/core/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -23,4 +23,5 @@ org.apache.deltaspike.core.impl.exception.control.extension.ExceptionControlExte
 org.apache.deltaspike.core.impl.config.ConfigurationExtension
 org.apache.deltaspike.core.impl.jmx.MBeanExtension
 org.apache.deltaspike.core.impl.scope.DeltaSpikeContextExtension
-org.apache.deltaspike.core.impl.interceptor.GlobalInterceptorExtension
\ No newline at end of file
+org.apache.deltaspike.core.impl.interceptor.GlobalInterceptorExtension
+org.apache.deltaspike.core.impl.interceptor.interdyn.InterDynExtension
\ No newline at end of file


[2/5] deltaspike git commit: DELTASPIKE-1316 skip interdyn with empty match or class config

Posted by st...@apache.org.
DELTASPIKE-1316 skip interdyn with empty match or class config


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

Branch: refs/heads/master
Commit: 8cc2a7f6853c32e49d7aa93176b667502ce74f7c
Parents: 2c185bd
Author: Mark Struberg <st...@apache.org>
Authored: Fri Feb 9 18:49:54 2018 +0100
Committer: Mark Struberg <st...@apache.org>
Committed: Fri Feb 9 18:49:54 2018 +0100

----------------------------------------------------------------------
 .../apache/deltaspike/core/api/config/base/CoreBaseConfig.java    | 2 +-
 .../core/impl/interceptor/interdyn/InterDynExtension.java         | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltaspike/blob/8cc2a7f6/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 02312f4..e988f57 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
@@ -122,7 +122,7 @@ public interface CoreBaseConfig extends DeltaSpikeBaseConfig
          * 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
+         * deltaspike.interdyn.rule.1.annotation=org.apache.deltaspike.core.api.monitoring.InvocationMonitored
          * </pre>
          */
         String INTERDYN_RULE_PREFIX = "deltaspike.interdyn.rule.";

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/8cc2a7f6/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
index 61a60e7..d948722 100644
--- 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
@@ -94,7 +94,8 @@ public class InterDynExtension implements Deactivatable, Extension
             String match = ConfigResolver.getPropertyValue(ruleConfigKey + ".match");
             String annotationClassName = ConfigResolver.getPropertyValue(ruleConfigKey + ".annotation");
 
-            if (match != null && annotationClassName != null)
+            if (match != null && annotationClassName != null &&
+                match.length() > 0 && annotationClassName.length() > 0)
             {
                 Annotation anno = getAnnotationImplementation(annotationClassName);
                 interceptorRules.add(new AnnotationRule(match, anno));


[3/5] deltaspike git commit: DELTASPIKE-1316 add @InvocationMonitored

Posted by st...@apache.org.
DELTASPIKE-1316 add @InvocationMonitored

wip, still misses tests


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

Branch: refs/heads/master
Commit: 9423d7466d9507bc243ca3e7bea5a97986bd3bb6
Parents: 8cc2a7f
Author: Mark Struberg <st...@apache.org>
Authored: Fri Feb 9 20:43:19 2018 +0100
Committer: Mark Struberg <st...@apache.org>
Committed: Fri Feb 9 20:43:19 2018 +0100

----------------------------------------------------------------------
 .../api/monitoring/InvocationMonitored.java     |  43 +++++
 .../core/api/monitoring/MonitorResultEvent.java |  81 ++++++++++
 .../InvocationMonitorInterceptor.java           |  47 ++++++
 .../impl/monitoring/InvocationResultLogger.java | 160 +++++++++++++++++++
 .../monitoring/RequestInvocationCounter.java    | 105 ++++++++++++
 5 files changed, 436 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltaspike/blob/9423d746/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/monitoring/InvocationMonitored.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/monitoring/InvocationMonitored.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/monitoring/InvocationMonitored.java
new file mode 100644
index 0000000..48170c8
--- /dev/null
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/monitoring/InvocationMonitored.java
@@ -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.deltaspike.core.api.monitoring;
+
+import javax.interceptor.InterceptorBinding;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Use this annotation to mark a bean as being monitored.
+ * This will activate a CDI Interceptor which will track
+ * all method invocations on that class and measure how
+ * often they got invoked and how much time they consume.
+ *
+ * At the end of a request the final times will get sent out
+ * as {@link MonitorResultEvent}.
+ */
+@Inherited
+@InterceptorBinding
+@Target( { ElementType.TYPE, ElementType.METHOD } )
+@Retention(RetentionPolicy.RUNTIME)
+public @interface InvocationMonitored
+{
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/9423d746/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/monitoring/MonitorResultEvent.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/monitoring/MonitorResultEvent.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/monitoring/MonitorResultEvent.java
new file mode 100644
index 0000000..7c4db7b
--- /dev/null
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/monitoring/MonitorResultEvent.java
@@ -0,0 +1,81 @@
+/*
+ * 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.api.monitoring;
+
+import javax.enterprise.inject.Typed;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * This class will be used as event to transport final monitor values
+ *
+ * @see InvocationMonitored
+ */
+@Typed()
+public class MonitorResultEvent
+{
+    private Map<String, AtomicInteger> methodInvocations = new HashMap<String, AtomicInteger>();
+
+    private Map<String, AtomicInteger> classInvocations  = new HashMap<String, AtomicInteger>();
+
+    private Map<String, AtomicLong> methodDurations = new HashMap<String, AtomicLong>();
+
+    public MonitorResultEvent(Map<String, AtomicInteger> methodInvocations,
+                              Map<String, AtomicInteger> classInvocations,
+                              Map<String, AtomicLong> methodDurations)
+    {
+        this.methodInvocations = methodInvocations;
+        this.classInvocations = classInvocations;
+        this.methodDurations = methodDurations;
+    }
+
+
+    /**
+     * @return Map with Counters for all method invocations
+     * key = fully qualified method name (includes class)
+     * value = AtomicInteger with invocation count value
+     */
+    public Map<String, AtomicInteger> getMethodInvocations()
+    {
+        return methodInvocations;
+    }
+
+    /**
+     * @return Map with Counter for all class invocations
+     * key = fully qualified class name
+     * value = AtomicInteger with invocation count value
+     */
+    public Map<String, AtomicInteger> getClassInvocations()
+    {
+        return classInvocations;
+    }
+
+
+    /**
+     * @return Map with duration for all method invocations
+     * key = fully qualified method name (includes class)
+     * value = AtomicLong with duration nanos
+     */
+    public Map<String, AtomicLong> getMethodDurations()
+    {
+        return methodDurations;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/9423d746/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/monitoring/InvocationMonitorInterceptor.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/monitoring/InvocationMonitorInterceptor.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/monitoring/InvocationMonitorInterceptor.java
new file mode 100644
index 0000000..54b3b7d
--- /dev/null
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/monitoring/InvocationMonitorInterceptor.java
@@ -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.deltaspike.core.impl.monitoring;
+
+import org.apache.deltaspike.core.api.monitoring.InvocationMonitored;
+
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+import java.io.Serializable;
+
+@Interceptor
+@InvocationMonitored
+public class InvocationMonitorInterceptor implements Serializable
+{
+    @Inject
+    private RequestInvocationCounter requestInvocationCounter;
+
+    @AroundInvoke
+    public Object track(InvocationContext ic) throws Exception
+    {
+        long start = System.nanoTime();
+        Object retVal = ic.proceed();
+        long end = System.nanoTime();
+        requestInvocationCounter.count(ic.getTarget().getClass().getName(), ic.getMethod().getName(), end - start);
+
+        return retVal;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/9423d746/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/monitoring/InvocationResultLogger.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/monitoring/InvocationResultLogger.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/monitoring/InvocationResultLogger.java
new file mode 100644
index 0000000..52639e2
--- /dev/null
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/monitoring/InvocationResultLogger.java
@@ -0,0 +1,160 @@
+/*
+ * 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.monitoring;
+
+import org.apache.deltaspike.core.api.monitoring.MonitorResultEvent;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.logging.Logger;
+
+/**
+ * This class will observe all {@link MonitorResultEvent}s
+ * and log them accordingly
+ */
+@ApplicationScoped
+public class InvocationResultLogger
+{
+    private static final Logger logger = Logger.getLogger(InvocationResultLogger.class.getName());
+
+    private static final int DEFAULT_MAX_LOG_LINES = 8;
+    private static final String PROPERTY_MAX_LOG_LINES = "MAX_LOG_LINES";
+
+    private int maxLogLines = DEFAULT_MAX_LOG_LINES + 1;
+
+    @PostConstruct
+    private void init()
+    {
+        String maxLogLinesProp = System.getProperty(PROPERTY_MAX_LOG_LINES);
+        if (maxLogLinesProp != null)
+        {
+            maxLogLines = Integer.parseInt(maxLogLinesProp) + 1;
+        }
+
+        logger.info("Using MAX_LOG_LINE=" + maxLogLines);
+    }
+
+    public void logMonitorResultEvents(@Observes MonitorResultEvent mre)
+    {
+        // we copy them because we don't like to make the event data dirty.
+        // there might be other observers interested in the result...
+        List<ResultEntry> methodInvocations
+            = createMethodResultEntries(mre.getMethodInvocations(), mre.getMethodDurations());
+        List<ResultEntry> classInvocations
+            = createClassResultEntries(mre.getClassInvocations());
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("Top Class Invocations:\n");
+        for (int i = 1; i < maxLogLines && i <= classInvocations.size(); i++)
+        {
+            ResultEntry re = classInvocations.get(classInvocations.size() - i);
+            sb.append("  count: ").append(re.getCount()).append("\t").append(re.getToken()).append("\n");
+        }
+        logger.info(sb.toString());
+
+        sb = new StringBuilder();
+        sb.append("Top Method Invocations:\n");
+        for (int i = 1; i < maxLogLines && i <= methodInvocations.size(); i++)
+        {
+            ResultEntry re = methodInvocations.get(methodInvocations.size() - i);
+            sb.append("  dur[ms]: ").append(re.getDuration() / 1e6f).append("\tcount: ").
+                    append(re.getCount()).append("\t").append(re.getToken()).append("\n");
+        }
+        logger.info(sb.toString());
+    }
+
+
+    private List<ResultEntry> createMethodResultEntries(Map<String, AtomicInteger> invocations,
+                                                        Map<String, AtomicLong> durations)
+    {
+        List<ResultEntry> resultEntries = new ArrayList<ResultEntry>(invocations.size());
+
+
+
+        for (Map.Entry<String, AtomicInteger> entry : invocations.entrySet())
+        {
+            long dur = durations.get(entry.getKey()).longValue();
+            resultEntries.add(new ResultEntry(entry.getValue().intValue(), entry.getKey(), dur));
+        }
+
+        Collections.sort(resultEntries);
+
+        return resultEntries;
+    }
+
+    private List<ResultEntry> createClassResultEntries(Map<String, AtomicInteger> invocations)
+    {
+        List<ResultEntry> resultEntries = new ArrayList<ResultEntry>(invocations.size());
+
+        for (Map.Entry<String, AtomicInteger> entry : invocations.entrySet())
+        {
+            resultEntries.add(new ResultEntry(entry.getValue().intValue(), entry.getKey(), 0L));
+        }
+
+        Collections.sort(resultEntries);
+
+        return resultEntries;
+    }
+
+    private static class ResultEntry implements Comparable<ResultEntry>
+    {
+        private Integer count;
+        private String token;
+        private long    duration;
+
+        private ResultEntry(Integer count, String token, long duration)
+        {
+            this.count = count;
+            this.token = token;
+            this.duration = duration;
+        }
+
+        public Integer getCount()
+        {
+            return count;
+        }
+
+        public String getToken()
+        {
+            return token;
+        }
+
+        public long getDuration()
+        {
+            return duration;
+        }
+
+        public int compareTo(ResultEntry o)
+        {
+            if (duration == 0 && o.duration == 0)
+            {
+                return count.compareTo(o.count);
+            }
+
+            return duration < o.duration ? -1 : (duration == o.duration ? 0 : 1);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/9423d746/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/monitoring/RequestInvocationCounter.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/monitoring/RequestInvocationCounter.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/monitoring/RequestInvocationCounter.java
new file mode 100644
index 0000000..8f46c37
--- /dev/null
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/monitoring/RequestInvocationCounter.java
@@ -0,0 +1,105 @@
+/*
+ * 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.monitoring;
+
+import org.apache.deltaspike.core.api.monitoring.MonitorResultEvent;
+
+import javax.annotation.PreDestroy;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.event.Event;
+import javax.inject.Inject;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * This bean will get used to count invocations for a single request
+ */
+@RequestScoped
+public class RequestInvocationCounter
+{
+    @Inject
+    private Event<MonitorResultEvent> mre;
+
+
+    /**
+     * Counter for all method invocations
+     * key = fully qualified method name (includes class)
+     * value = Integer with value
+     */
+    private Map<String, AtomicInteger> methodInvocations = new HashMap<String, AtomicInteger>();
+
+    /**
+     * Duration of all method invocations
+     * key = fully qualified method name (includes class)
+     * value = Integer with value
+     */
+    private Map<String, AtomicLong> methodDurations = new HashMap<String, AtomicLong>();
+
+    /**
+     * Counter for all class invocations
+     * key = fully qualified class name
+     * value = Integer with value
+     */
+    private Map<String, AtomicInteger> classInvocations  = new HashMap<String, AtomicInteger>();
+
+
+    @PreDestroy
+    public void postUsage()
+    {
+        mre.fire(new MonitorResultEvent(methodInvocations, classInvocations, methodDurations));
+    }
+
+    /**
+     * increment the respective counters
+     * @param className the getName() of the class
+     * @param methodName the invoked methods name
+     * @param duration duration of the method invocation in nano time
+     */
+    public void count(String className, String methodName, long duration)
+    {
+        AtomicInteger classCount = classInvocations.get(className);
+        if (classCount == null)
+        {
+            classCount = new AtomicInteger(0);
+            classInvocations.put(className, classCount);
+        }
+        classCount.incrementAndGet();
+
+
+        String methodKey = className + "#" + methodName;
+
+        AtomicInteger methCount = methodInvocations.get(methodKey);
+        if (methCount == null)
+        {
+            methCount = new AtomicInteger(0);
+            methodInvocations.put(methodKey, methCount);
+        }
+        methCount.incrementAndGet();
+
+        AtomicLong methDur = methodDurations.get(methodKey);
+        if (methDur == null)
+        {
+            methDur = new AtomicLong(0);
+            methodDurations.put(methodKey, methDur);
+        }
+        methDur.addAndGet(duration);
+    }
+}


[5/5] deltaspike git commit: DELTASPIKE-1316 add unit test and enable interceptor

Posted by st...@apache.org.
DELTASPIKE-1316 add unit test and enable interceptor


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

Branch: refs/heads/master
Commit: 3734100febf7895923028a5ef836027eed2015c0
Parents: 0a914ba
Author: Mark Struberg <st...@apache.org>
Authored: Fri Feb 9 22:22:30 2018 +0100
Committer: Mark Struberg <st...@apache.org>
Committed: Fri Feb 9 22:23:05 2018 +0100

----------------------------------------------------------------------
 .../impl/src/main/resources/META-INF/beans.xml  |  1 +
 .../test/core/impl/interdyn/InterDynTest.java   | 61 +++++++++++++++++++
 .../core/impl/interdyn/SomeTestService.java     | 63 ++++++++++++++++++++
 .../META-INF/apache-deltaspike.properties       |  5 ++
 4 files changed, 130 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltaspike/blob/3734100f/deltaspike/core/impl/src/main/resources/META-INF/beans.xml
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/resources/META-INF/beans.xml b/deltaspike/core/impl/src/main/resources/META-INF/beans.xml
index 5d96bf1..e3319aa 100644
--- a/deltaspike/core/impl/src/main/resources/META-INF/beans.xml
+++ b/deltaspike/core/impl/src/main/resources/META-INF/beans.xml
@@ -24,5 +24,6 @@
     <class>org.apache.deltaspike.core.impl.throttling.ThrottledInterceptor</class>
     <class>org.apache.deltaspike.core.impl.lock.LockedInterceptor</class>
     <class>org.apache.deltaspike.core.impl.future.FutureableInterceptor</class>
+    <class>org.apache.deltaspike.core.impl.monitoring.InvocationMonitorInterceptor</class>
   </interceptors>
 </beans>

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/3734100f/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/interdyn/InterDynTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/interdyn/InterDynTest.java b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/interdyn/InterDynTest.java
new file mode 100644
index 0000000..8264a9e
--- /dev/null
+++ b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/interdyn/InterDynTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.test.core.impl.interdyn;
+
+import org.apache.deltaspike.test.util.ArchiveUtils;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.inject.Inject;
+
+@RunWith(Arquillian.class)
+public class InterDynTest {
+
+    @Deployment
+    public static WebArchive deploy()
+    {
+        JavaArchive testJar = ShrinkWrap.create(JavaArchive.class, "InterDynTest.jar")
+                .addPackage(SomeTestService.class.getPackage().getName())
+                .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
+
+        return ShrinkWrap.create(WebArchive.class, "InterDynTest.war")
+                .addAsLibraries(ArchiveUtils.getDeltaSpikeCoreArchive())
+                .addAsLibraries(testJar)
+                .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
+    }
+
+    @Inject
+    private SomeTestService service;
+
+    @Test
+    public void invokeServiceMethods()
+    {
+        service.enableChecking();
+
+        service.pingA();
+        service.pingB();
+        service.pingA();
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/3734100f/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/interdyn/SomeTestService.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/interdyn/SomeTestService.java b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/interdyn/SomeTestService.java
new file mode 100644
index 0000000..fa1adfb
--- /dev/null
+++ b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/interdyn/SomeTestService.java
@@ -0,0 +1,63 @@
+/*
+ * 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.test.core.impl.interdyn;
+
+import org.apache.deltaspike.core.api.monitoring.MonitorResultEvent;
+import org.junit.Assert;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+
+@ApplicationScoped
+public class SomeTestService
+{
+
+    private boolean check = false;
+
+    public String pingA()
+    {
+        return "a";
+    }
+
+    public String pingB()
+    {
+        try
+        {
+            Thread.sleep(30L);
+        }
+        catch (InterruptedException e) {
+            // all fine
+        }
+        return "b";
+    }
+
+    public void enableChecking()
+    {
+        this.check = true;
+    }
+
+    public void observer(@Observes MonitorResultEvent mre)
+    {
+        if (check)
+        {
+            Assert.assertTrue(mre.getClassInvocations().keySet().contains(SomeTestService.class.getName()));
+            check = false;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/3734100f/deltaspike/core/impl/src/test/resources/META-INF/apache-deltaspike.properties
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/test/resources/META-INF/apache-deltaspike.properties b/deltaspike/core/impl/src/test/resources/META-INF/apache-deltaspike.properties
index 2bb3fc0..d979b4c 100644
--- a/deltaspike/core/impl/src/test/resources/META-INF/apache-deltaspike.properties
+++ b/deltaspike/core/impl/src/test/resources/META-INF/apache-deltaspike.properties
@@ -55,3 +55,8 @@ deactivate.org.apache.deltaspike.test.core.impl.activation.DeactivatedClass=true
 urlListFromProperties = http://127.0.0.2
 
 prefix.suffix = done
+
+# InterDynTest
+deltaspike.interdyn.enabled=true
+deltaspike.interdyn.rule.1.match=org\\.apache\\.deltaspike\\.test\\.core\\.impl\\.interdyn\\.Some.*Service
+deltaspike.interdyn.rule.1.annotation=org.apache.deltaspike.core.api.monitoring.InvocationMonitored