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