You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sirona.apache.org by rm...@apache.org on 2013/11/05 18:25:24 UTC

svn commit: r1539076 [2/17] - in /incubator/sirona/trunk: ./ agent/ agent/performance/ agent/performance/aop/ agent/performance/aop/src/ agent/performance/aop/src/main/ agent/performance/aop/src/main/java/ agent/performance/aop/src/main/java/org/ agent...

Added: incubator/sirona/trunk/agent/performance/cdi/src/main/java/org/apache/sirona/cdi/SironaInterceptor.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/cdi/src/main/java/org/apache/sirona/cdi/SironaInterceptor.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/cdi/src/main/java/org/apache/sirona/cdi/SironaInterceptor.java (added)
+++ incubator/sirona/trunk/agent/performance/cdi/src/main/java/org/apache/sirona/cdi/SironaInterceptor.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,49 @@
+/*
+ * 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.sirona.cdi;
+
+import org.apache.sirona.aop.AbstractPerformanceInterceptor;
+
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.AroundTimeout;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+@Interceptor
+@Monitored
+public class SironaInterceptor extends AbstractPerformanceInterceptor<InvocationContext> {
+    @AroundInvoke
+    @AroundTimeout
+    public Object monitor(final InvocationContext invocationContext) throws Throwable {
+        return doInvoke(invocationContext);
+    }
+
+    @Override
+    protected Object proceed(final InvocationContext invocation) throws Throwable {
+        return invocation.proceed();
+    }
+
+    @Override
+    protected String getCounterName(final InvocationContext invocation) {
+        return getCounterName(invocation.getTarget(), invocation.getMethod());
+    }
+
+    @Override
+    protected Object extractContextKey(final InvocationContext invocation) {
+        return new SerializableMethod(invocation.getMethod());
+    }
+}

Added: incubator/sirona/trunk/agent/performance/cdi/src/main/java/org/apache/sirona/cdi/internal/SironaPerformanceExtension.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/cdi/src/main/java/org/apache/sirona/cdi/internal/SironaPerformanceExtension.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/cdi/src/main/java/org/apache/sirona/cdi/internal/SironaPerformanceExtension.java (added)
+++ incubator/sirona/trunk/agent/performance/cdi/src/main/java/org/apache/sirona/cdi/internal/SironaPerformanceExtension.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,154 @@
+/*
+ * 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.sirona.cdi.internal;
+
+import org.apache.sirona.cdi.Monitored;
+import org.apache.sirona.configuration.Configuration;
+import org.apache.sirona.configuration.predicate.PredicateEvaluator;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.ProcessAnnotatedType;
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+public class SironaPerformanceExtension implements Extension {
+    private final boolean enabled = Configuration.is(Configuration.CONFIG_PROPERTY_PREFIX + "cdi.enabled", true);
+    private final Monitored performanceBinding = newAnnotation(Monitored.class);
+    private final Annotation jtaBinding = tryNewAnnotation("org.apache.sirona.jta.JTAMonitored");
+
+    private PredicateEvaluator performaceEvaluator;
+    private PredicateEvaluator jtaEvaluator;
+
+    void init(final @Observes BeforeBeanDiscovery beforeBeanDiscovery) {
+        if (!enabled) {
+            return;
+        }
+
+        performaceEvaluator = new PredicateEvaluator(Configuration.getProperty(Configuration.CONFIG_PROPERTY_PREFIX + "cdi.performance", null), ",");
+        jtaEvaluator = new PredicateEvaluator(Configuration.getProperty(Configuration.CONFIG_PROPERTY_PREFIX + "cdi.jta", null), ",");
+    }
+
+    <A> void processAnnotatedType(final @Observes ProcessAnnotatedType<A> pat) {
+        if (!enabled) {
+            return;
+        }
+
+        final String beanClassName = pat.getAnnotatedType().getJavaClass().getName();
+        final boolean addPerf = performaceEvaluator.matches(beanClassName);
+        final boolean addJta = jtaEvaluator.matches(beanClassName);
+
+        final WrappedAnnotatedType<A> wrapper;
+        if (addPerf || addJta) {
+            wrapper = new WrappedAnnotatedType<A>(pat.getAnnotatedType());
+            if (addPerf) {
+                wrapper.getAnnotations().add(performanceBinding);
+            }
+            if (addJta) {
+                wrapper.getAnnotations().add(jtaBinding);
+            }
+        } else {
+            wrapper = null;
+        }
+        if (wrapper != null) {
+            pat.setAnnotatedType(wrapper);
+        }
+    }
+
+    private static String findConfiguration(final String name) {
+        String current = name;
+        String property;
+        do {
+            property = Configuration.getProperty(current + ".cdi", null);
+
+            final int endIndex = current.lastIndexOf('.');
+            if (endIndex > 0) {
+                current = current.substring(0, endIndex);
+            } else {
+                current = null;
+            }
+        } while (property == null && current != null);
+        return property;
+    }
+
+    private static Annotation tryNewAnnotation(final String clazz) {
+        try {
+            return newAnnotation(Class.class.cast(Thread.currentThread().getContextClassLoader().loadClass(clazz)));
+        } catch (final ClassNotFoundException e) {
+            return null;
+        } catch (final NoClassDefFoundError e) {
+            return null;
+        }
+    }
+    private static <T extends Annotation> T newAnnotation(final Class<T> clazz) {
+        return clazz.cast(
+                Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
+                new Class<?>[]{ Annotation.class, clazz },
+                new AnnotationHandler(clazz)));
+    }
+
+    // Note: for annotations without any members
+    private static class AnnotationHandler implements InvocationHandler, Annotation, Serializable {
+        private final Class<? extends Annotation> annotationClass;
+
+        private AnnotationHandler(final Class<? extends Annotation> annotationClass) {
+            this.annotationClass = annotationClass;
+        }
+
+        @Override
+        public Object invoke(final Object proxy, final Method method, final Object[] args) throws Exception {
+            if ("hashCode".equals(method.getName())) {
+                return hashCode();
+            } else if ("equals".equals(method.getName())) {
+                if (Proxy.isProxyClass(args[0].getClass()) && AnnotationHandler.class.isInstance(Proxy.getInvocationHandler(args[0]))) {
+                    return equals(Proxy.getInvocationHandler(args[0]));
+                }
+                return equals(args[0]);
+            } else if ("annotationType".equals(method.getName())) {
+                return annotationType();
+            } else if ("toString".equals(method.getName())) {
+                return toString();
+            }
+            return method.getDefaultValue();
+        }
+
+        @Override
+        public Class<? extends Annotation> annotationType() {
+            return annotationClass;
+        }
+
+        @Override
+        public String toString() {
+            return "@" + annotationClass.getName();
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            return this == o
+                || Annotation.class.isInstance(o) && Annotation.class.cast(o).annotationType().equals(annotationClass);
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+    }
+}

Added: incubator/sirona/trunk/agent/performance/cdi/src/main/java/org/apache/sirona/cdi/internal/WrappedAnnotatedType.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/cdi/src/main/java/org/apache/sirona/cdi/internal/WrappedAnnotatedType.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/cdi/src/main/java/org/apache/sirona/cdi/internal/WrappedAnnotatedType.java (added)
+++ incubator/sirona/trunk/agent/performance/cdi/src/main/java/org/apache/sirona/cdi/internal/WrappedAnnotatedType.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,88 @@
+/*
+ * 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.sirona.cdi.internal;
+
+import javax.enterprise.inject.spi.AnnotatedConstructor;
+import javax.enterprise.inject.spi.AnnotatedField;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedType;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.HashSet;
+import java.util.Set;
+
+public class WrappedAnnotatedType<A> implements AnnotatedType<A> {
+    private final AnnotatedType<A> delegate;
+    private final Set<Annotation> annotations;
+
+    public WrappedAnnotatedType(final AnnotatedType<A> at) {
+        this.delegate = at;
+
+        this.annotations = new HashSet<Annotation>(at.getAnnotations().size());
+        this.annotations.addAll(at.getAnnotations());
+    }
+
+    @Override
+    public Set<Annotation> getAnnotations() {
+        return annotations;
+    }
+
+    @Override
+    public <T extends Annotation> T getAnnotation(final Class<T> annotationType) {
+        for (final Annotation ann : annotations) {
+            if (ann.annotationType().equals(annotationType)) {
+                return annotationType.cast(ann);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean isAnnotationPresent(final Class<? extends Annotation> annotationType) {
+        return getAnnotation(annotationType) != null;
+    }
+
+    @Override
+    public Class<A> getJavaClass() {
+        return delegate.getJavaClass();
+    }
+
+    @Override
+    public Set<AnnotatedConstructor<A>> getConstructors() {
+        return delegate.getConstructors();
+    }
+
+    @Override
+    public Set<AnnotatedMethod<? super A>> getMethods() {
+        return delegate.getMethods();
+    }
+
+    @Override
+    public Set<AnnotatedField<? super A>> getFields() {
+        return delegate.getFields();
+    }
+
+    @Override
+    public Type getBaseType() {
+        return delegate.getBaseType();
+    }
+
+    @Override
+    public Set<Type> getTypeClosure() {
+        return delegate.getTypeClosure();
+    }
+}

Added: incubator/sirona/trunk/agent/performance/cdi/src/main/resources/META-INF/beans.xml
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/cdi/src/main/resources/META-INF/beans.xml?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/cdi/src/main/resources/META-INF/beans.xml (added)
+++ incubator/sirona/trunk/agent/performance/cdi/src/main/resources/META-INF/beans.xml Tue Nov  5 17:25:15 2013
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
+                            http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+  <interceptors>
+    <class>org.apache.sirona.cdi.SironaInterceptor</class>
+  </interceptors>
+</beans>

Added: incubator/sirona/trunk/agent/performance/cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension (added)
+++ incubator/sirona/trunk/agent/performance/cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension Tue Nov  5 17:25:15 2013
@@ -0,0 +1 @@
+org.apache.sirona.cdi.internal.SironaPerformanceExtension

Added: incubator/sirona/trunk/agent/performance/cdi/src/test/java/org/apache/sirona/cdi/SironaExtensionTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/cdi/src/test/java/org/apache/sirona/cdi/SironaExtensionTest.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/cdi/src/test/java/org/apache/sirona/cdi/SironaExtensionTest.java (added)
+++ incubator/sirona/trunk/agent/performance/cdi/src/test/java/org/apache/sirona/cdi/SironaExtensionTest.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,37 @@
+/*
+ * 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.sirona.cdi;
+
+import javax.enterprise.context.ApplicationScoped;
+
+public class SironaExtensionTest extends SironaExtensionTestBase {
+    @Override
+    protected Class<? extends TwoSeconds> type() {
+        return AutoMonitoredBean.class;
+    }
+
+    @ApplicationScoped
+    public static class AutoMonitoredBean implements TwoSeconds {
+        public void twoSeconds() {
+            try {
+                Thread.sleep(2000);
+            } catch (final InterruptedException e) {
+                // no-op
+            }
+        }
+    }
+}

Added: incubator/sirona/trunk/agent/performance/cdi/src/test/java/org/apache/sirona/cdi/SironaExtensionTestBase.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/cdi/src/test/java/org/apache/sirona/cdi/SironaExtensionTestBase.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/cdi/src/test/java/org/apache/sirona/cdi/SironaExtensionTestBase.java (added)
+++ incubator/sirona/trunk/agent/performance/cdi/src/test/java/org/apache/sirona/cdi/SironaExtensionTestBase.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,58 @@
+/*
+ * 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.sirona.cdi;
+
+import org.apache.sirona.Role;
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.repositories.Repository;
+import org.apache.webbeans.cditest.CdiTestContainer;
+import org.apache.webbeans.cditest.CdiTestContainerLoader;
+import org.junit.Test;
+
+import javax.enterprise.inject.spi.BeanManager;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public abstract class SironaExtensionTestBase {
+    @Test
+    public void checkMeasures() throws Exception {
+        final CdiTestContainer container = CdiTestContainerLoader.getCdiContainer();
+        container.bootContainer();
+        container.startApplicationScope();
+
+        final BeanManager beanManager = container.getBeanManager();
+        final Class<?> type = type();
+        final TwoSeconds bean = TwoSeconds.class.cast(beanManager.getReference(beanManager.resolve(beanManager.getBeans(type)), type, null));
+
+        bean.twoSeconds();
+
+        container.stopApplicationScope();
+        container.shutdownContainer();
+
+        final Counter perf = Repository.INSTANCE.getCounter(new Counter.Key(Role.PERFORMANCES, type.getName() + ".twoSeconds"));
+        assertNotNull(perf);
+        assertEquals(2000, TimeUnit.NANOSECONDS.toMillis((int) perf.getMax()), 200);
+    }
+
+    protected abstract Class<? extends TwoSeconds> type();
+
+    protected static interface TwoSeconds {
+        void twoSeconds();
+    }
+}

Added: incubator/sirona/trunk/agent/performance/cdi/src/test/java/org/apache/sirona/cdi/SironaInterceptorTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/cdi/src/test/java/org/apache/sirona/cdi/SironaInterceptorTest.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/cdi/src/test/java/org/apache/sirona/cdi/SironaInterceptorTest.java (added)
+++ incubator/sirona/trunk/agent/performance/cdi/src/test/java/org/apache/sirona/cdi/SironaInterceptorTest.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,38 @@
+/*
+ * 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.sirona.cdi;
+
+import javax.enterprise.context.ApplicationScoped;
+
+public class SironaInterceptorTest extends SironaExtensionTestBase {
+    @Override
+    protected Class<? extends TwoSeconds> type() {
+        return MonitoredBean.class;
+    }
+
+    @Monitored
+    @ApplicationScoped
+    public static class MonitoredBean implements TwoSeconds {
+        public void twoSeconds() {
+            try {
+                Thread.sleep(2000);
+            } catch (final InterruptedException e) {
+                // no-op
+            }
+        }
+    }
+}

Added: incubator/sirona/trunk/agent/performance/cdi/src/test/resources/META-INF/beans.xml
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/cdi/src/test/resources/META-INF/beans.xml?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/cdi/src/test/resources/META-INF/beans.xml (added)
+++ incubator/sirona/trunk/agent/performance/cdi/src/test/resources/META-INF/beans.xml Tue Nov  5 17:25:15 2013
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
+                            http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+
+</beans>

Added: incubator/sirona/trunk/agent/performance/cdi/src/test/resources/sirona.properties
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/cdi/src/test/resources/sirona.properties?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/cdi/src/test/resources/sirona.properties (added)
+++ incubator/sirona/trunk/agent/performance/cdi/src/test/resources/sirona.properties Tue Nov  5 17:25:15 2013
@@ -0,0 +1,17 @@
+# 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.
+org.apache.sirona.cdi.performance = prefix:org.apache.sirona.cdi.SironaExtensionTest$AutoMonitoredBean

Added: incubator/sirona/trunk/agent/performance/jdbc/pom.xml
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jdbc/pom.xml?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jdbc/pom.xml (added)
+++ incubator/sirona/trunk/agent/performance/jdbc/pom.xml Tue Nov  5 17:25:15 2013
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <artifactId>sirona-performance</artifactId>
+    <groupId>org.apache.sirona</groupId>
+    <version>0.1-incubating-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>sirona-jdbc</artifactId>
+  <version>0.1-incubating-SNAPSHOT</version>
+  <name>Apache Sirona Incubator :: Agent :: Performance  :: JDBC</name>
+
+  <properties>
+    <!-- Java6 required for JDBC 4 -->
+    <maven.compile.source>1.6</maven.compile.source>
+    <maven.compile.target>1.6</maven.compile.target>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.sirona</groupId>
+      <artifactId>sirona-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.hsqldb</groupId>
+      <artifactId>hsqldb</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file

Added: incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/ConnectionClosedCallBack.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/ConnectionClosedCallBack.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/ConnectionClosedCallBack.java (added)
+++ incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/ConnectionClosedCallBack.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,25 @@
+/*
+ * 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.sirona.jdbc;
+
+/**
+ * CallBack on connection beeing closed
+ */
+public interface ConnectionClosedCallBack {
+    void onConnectionClosed();
+}
\ No newline at end of file

Added: incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredConnection.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredConnection.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredConnection.java (added)
+++ incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredConnection.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,102 @@
+/*
+ * 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.sirona.jdbc;
+
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.stopwatches.CounterStopWatch;
+import org.apache.sirona.stopwatches.StopWatch;
+import org.apache.sirona.util.ClassLoaders;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.Statement;
+
+/**
+ * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
+ */
+public class MonitoredConnection implements InvocationHandler {
+    private Connection connection;
+    private StopWatch stopWatch;
+
+    /**
+     * @param connection target connection
+     */
+    public MonitoredConnection(final Connection connection, final StopWatch stopWatch) {
+        this.connection = connection;
+        this.stopWatch = stopWatch;
+    }
+
+    @Override
+    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+        final String name = method.getName();
+        if ("close".equals(name)) {
+            connection.close();
+            stopWatch.stop();
+            return null;
+        }
+
+        if (name.startsWith("prepare") || name.startsWith("create")) {
+            final Class<?> returnType = method.getReturnType();
+            if (CallableStatement.class.equals(returnType)) {
+                return monitor(CallableStatement.class.cast(doInvoke(method, args)), (String) args[0]);
+            } else if (PreparedStatement.class.equals(returnType)) {
+                return monitor(PreparedStatement.class.cast(doInvoke(method, args)), (String) args[0]);
+            } else if (Statement.class.equals(returnType)) {
+                return monitor(Statement.class.cast(doInvoke(method, args)));
+            }
+        }
+
+        return doInvoke(method, args);
+    }
+
+    private Object doInvoke(final Method method, final Object[] args) throws IllegalAccessException, InvocationTargetException {
+        return method.invoke(connection, args);
+    }
+
+    private Statement monitor(final Statement statement) {
+        return Statement.class.cast(Proxy.newProxyInstance(ClassLoaders.current(), new Class<?>[]{Statement.class}, new MonitoredStatement(statement)));
+    }
+
+    /**
+     * @param statement traget PreparedStatement
+     * @param sql       SQL Query
+     * @return monitored PreparedStatement
+     */
+    private PreparedStatement monitor(final PreparedStatement statement, final String sql) {
+        return PreparedStatement.class.cast(Proxy.newProxyInstance(ClassLoaders.current(), new Class<?>[]{PreparedStatement.class}, new MonitoredPreparedStatement(statement, sql)));
+    }
+
+    /**
+     * @param statement target PreparedStatement
+     * @param sql       SQL Query
+     * @return Monitored CallableStatement
+     */
+    private CallableStatement monitor(final CallableStatement statement, final String sql) {
+        return CallableStatement.class.cast(Proxy.newProxyInstance(ClassLoaders.current(), new Class<?>[]{CallableStatement.class}, new MonitoredPreparedStatement(statement, sql)));
+    }
+
+    public static Connection monitor(final Connection connection, final Counter counter) {
+        final StopWatch stopWatch = new CounterStopWatch(counter);
+        return Connection.class.cast(Proxy.newProxyInstance(ClassLoaders.current(), new Class<?>[]{Connection.class}, new MonitoredConnection(connection, stopWatch)));
+    }
+}

Added: incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredDataSource.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredDataSource.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredDataSource.java (added)
+++ incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredDataSource.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,147 @@
+/*
+ * 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.sirona.jdbc;
+
+
+import org.apache.sirona.Role;
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.repositories.Repository;
+
+import javax.sql.DataSource;
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.logging.Logger;
+
+
+/**
+ * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
+ */
+public class MonitoredDataSource implements DataSource {
+    /**
+     * delegate DataSource
+     */
+    private DataSource dataSource;
+
+    /**
+     * dataSource name
+     */
+    private String dataSourceName = DataSource.class.getName();
+    private Counter counter;
+
+    /**
+     * Constructor
+     *
+     * @param dataSource the datasource to counter
+     */
+    public MonitoredDataSource(final DataSource dataSource) {
+        this.dataSource = dataSource;
+        this.counter = Repository.INSTANCE.getCounter(new Counter.Key(Role.JDBC, dataSourceName));
+    }
+
+    public MonitoredDataSource() {
+        super();
+    }
+
+    public void setDataSource(final DataSource dataSource) {
+        this.dataSource = dataSource;
+    }
+
+    /**
+     * @param dataSourceName the dataSourceName to set
+     */
+    public void setDataSourceName(final String dataSourceName) {
+        this.dataSourceName = dataSourceName;
+    }
+
+    /**
+     * @param counter the counter to set
+     */
+    public void setCounter(final Counter counter) {
+        this.counter = counter;
+    }
+
+    protected Connection monitor(final Connection connection) {
+        return MonitoredConnection.monitor(connection, counter);
+    }
+
+    /**
+     * @return the dataSource
+     */
+    protected DataSource getDataSource() {
+        return dataSource;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see javax.sql.DataSource#getConnection()
+     */
+    public Connection getConnection()
+        throws SQLException {
+        return monitor(getDataSource().getConnection());
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see javax.sql.DataSource#getConnection(java.lang.String, java.lang.String)
+     */
+    public Connection getConnection(String username, String password)
+        throws SQLException {
+        return monitor(getDataSource().getConnection(username, password));
+    }
+
+    public int getLoginTimeout()
+        throws SQLException {
+        return getDataSource().getLoginTimeout();
+    }
+
+    public PrintWriter getLogWriter()
+        throws SQLException {
+        return getDataSource().getLogWriter();
+    }
+
+    public void setLoginTimeout(int seconds)
+        throws SQLException {
+        getDataSource().setLoginTimeout(seconds);
+    }
+
+    public void setLogWriter(PrintWriter out)
+        throws SQLException {
+        getDataSource().setLogWriter(out);
+    }
+
+    // --- jdbc4 ----
+
+    public boolean isWrapperFor(Class<?> iface)
+        throws SQLException {
+        return getDataSource().isWrapperFor(iface);
+    }
+
+    public <T> T unwrap(Class<T> iface)
+        throws SQLException {
+        return getDataSource().unwrap(iface);
+    }
+
+    public Logger getParentLogger()
+        throws SQLFeatureNotSupportedException {
+        return Logger.getLogger("commons-monitoring.datasource");
+    }
+}

Added: incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredPreparedStatement.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredPreparedStatement.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredPreparedStatement.java (added)
+++ incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredPreparedStatement.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sirona.jdbc;
+
+import org.apache.sirona.Role;
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.repositories.Repository;
+import org.apache.sirona.stopwatches.StopWatch;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.PreparedStatement;
+
+/**
+ * @author ndeloof
+ */
+public class MonitoredPreparedStatement extends MonitoredStatement {
+    private final PreparedStatement statement;
+    private final String sql;
+
+    public MonitoredPreparedStatement(final PreparedStatement statement, final String sql) {
+        super(statement);
+        this.statement = statement;
+        this.sql = sql;
+    }
+
+    @Override
+    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+        final String name = method.getName();
+        if ((args == null || args.length == 0) && name.startsWith("execute")) {
+            final StopWatch stopWatch = Repository.INSTANCE.start(Repository.INSTANCE.getCounter(new Counter.Key(Role.JDBC, sql)));
+            try {
+                return method.invoke(statement, args);
+            } catch (final InvocationTargetException e) {
+                throw extractSQLException(e);
+            } finally {
+                stopWatch.stop();
+            }
+        }
+        return super.invoke(proxy, method, args);
+    }
+
+}

Added: incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredStatement.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredStatement.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredStatement.java (added)
+++ incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoredStatement.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sirona.jdbc;
+
+import org.apache.sirona.Role;
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.repositories.Repository;
+import org.apache.sirona.stopwatches.StopWatch;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+public class MonitoredStatement implements InvocationHandler {
+    private final Statement statement;
+
+    public MonitoredStatement(final Statement statement) {
+        this.statement = statement;
+    }
+
+    protected SQLException monitor(final SQLException sqle) {
+        final String name = "SQLException:" + sqle.getSQLState() + ":" + sqle.getErrorCode();
+        Repository.INSTANCE.getCounter(new Counter.Key(Role.FAILURES, name)).add(1);
+        return sqle;
+    }
+
+    @Override
+    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+        final String name = method.getName();
+        if (name.startsWith("execute")) {
+            final StopWatch stopWatch;
+            if (name.endsWith("Batch") && (args == null || args.length == 0)) {
+                stopWatch = Repository.INSTANCE.start(Repository.INSTANCE.getCounter(new Counter.Key(Role.JDBC, "batch")));
+            } else {
+                stopWatch = Repository.INSTANCE.start(Repository.INSTANCE.getCounter(new Counter.Key(Role.JDBC, (String) args[0])));
+            }
+
+            try {
+                return doInvoke(method, args);
+            } catch (final InvocationTargetException e) {
+                throw extractSQLException(e);
+            } finally {
+                stopWatch.stop();
+            }
+        }
+        return doInvoke(method, args);
+    }
+
+    private Object doInvoke(final Method method, final Object[] args) throws IllegalAccessException, InvocationTargetException {
+        return method.invoke(statement, args);
+    }
+
+    protected Throwable extractSQLException(final InvocationTargetException e) throws Throwable {
+        final Throwable th = e.getCause();
+        if (SQLException.class.isInstance(th)) {
+            return monitor(SQLException.class.cast(th));
+        }
+        return th;
+    }
+}

Added: incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoringDriver.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoringDriver.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoringDriver.java (added)
+++ incubator/sirona/trunk/agent/performance/jdbc/src/main/java/org/apache/sirona/jdbc/MonitoringDriver.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,98 @@
+/*
+ * 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.sirona.jdbc;
+
+import org.apache.sirona.Role;
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.repositories.Repository;
+
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.DriverPropertyInfo;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+public class MonitoringDriver implements Driver {
+    static {
+        try {
+            DriverManager.registerDriver(new MonitoringDriver());
+        } catch (final SQLException e) {
+            // no-op
+        }
+    }
+
+    private static final String PREFIX = "jdbc:monitoring:";
+    private static final String DRIVER_SUFFIX = "delegateDriver=";
+
+    public static void load() {
+    } // sexier than Class.forName("org.apache.sirona.jdbc.MonitoringDriver"); in full java
+
+    @Override
+    public Connection connect(final String url, final Properties info) throws SQLException {
+        if (!acceptsURL(url)) {
+            throw new SQLException("Driver " + MonitoringDriver.class.getName() + " doesn't accept " + url + ". Pattern is jdbc:monitoring:<xxx>:<yyy>?delegateDriver=<zzz>");
+        }
+
+        final int driverIndex = url.indexOf(DRIVER_SUFFIX);
+
+        String realUrl = "jdbc:" + url.substring(PREFIX.length(), driverIndex);
+        if (realUrl.endsWith("?") || realUrl.endsWith("&")) {
+            realUrl = realUrl.substring(0, realUrl.length() - 1);
+        }
+
+        final String realDriver = url.substring(driverIndex + DRIVER_SUFFIX.length());
+        try {
+            final Driver delegate = Driver.class.cast(Class.forName(realDriver).newInstance());
+            return MonitoredConnection.monitor(delegate.connect(realUrl, info), Repository.INSTANCE.getCounter(new Counter.Key(Role.JDBC, url)));
+        } catch (final Exception e) {
+            throw new SQLException(e);
+        }
+    }
+
+    @Override
+    public boolean acceptsURL(final String url) throws SQLException {
+        return url != null && url.startsWith(PREFIX) && url.contains(DRIVER_SUFFIX);
+    }
+
+    @Override
+    public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) throws SQLException {
+        return new DriverPropertyInfo[0];
+    }
+
+    @Override
+    public int getMajorVersion() {
+        return 1;
+    }
+
+    @Override
+    public int getMinorVersion() {
+        return 0;
+    }
+
+    @Override
+    public boolean jdbcCompliant() {
+        return true;
+    }
+
+    // @Override // java 7
+    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+        return Logger.getLogger("commons-monitoring.jdbc-driver");
+    }
+}

Added: incubator/sirona/trunk/agent/performance/jdbc/src/test/java/org/apache/sirona/jdbc/HsqlDBTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jdbc/src/test/java/org/apache/sirona/jdbc/HsqlDBTest.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jdbc/src/test/java/org/apache/sirona/jdbc/HsqlDBTest.java (added)
+++ incubator/sirona/trunk/agent/performance/jdbc/src/test/java/org/apache/sirona/jdbc/HsqlDBTest.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,66 @@
+/*
+ * 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.sirona.jdbc;
+
+import org.apache.sirona.Role;
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.repositories.Repository;
+import org.hsqldb.jdbcDriver;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.Statement;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public class HsqlDBTest {
+    @BeforeClass
+    public static void init() {
+        MonitoringDriver.load();
+    }
+
+    @Test
+    public void driverMonitoring() throws Exception {
+        final Connection connection = DriverManager.getConnection("jdbc:monitoring:hsqldb:mem:monitoring?delegateDriver=" + jdbcDriver.class.getName(), "SA", "");
+        assertNotNull(connection);
+        assertTrue(Proxy.isProxyClass(connection.getClass()));
+        final InvocationHandler handler = Proxy.getInvocationHandler(connection);
+        assertThat(handler, instanceOf(MonitoredConnection.class));
+
+        final String create = "CREATE TABLE Address (Nr INTEGER, Name VARCHAR(128));";
+        final Statement statement = connection.createStatement();
+        statement.execute(create);
+        assertEquals(1, Repository.INSTANCE.getCounter(new Counter.Key(Role.JDBC, create)).getMaxConcurrency(), 0.);
+
+        final String insert = "INSERT INTO Address (Nr, Name) VALUES(1, 'foo')";
+        final PreparedStatement preparedStatement = connection.prepareStatement(insert);
+        preparedStatement.execute();
+        assertEquals(1, Repository.INSTANCE.getCounter(new Counter.Key(Role.JDBC, insert)).getMaxConcurrency(), 0.);
+        preparedStatement.execute();
+        assertEquals(1, Repository.INSTANCE.getCounter(new Counter.Key(Role.JDBC, insert)).getMaxConcurrency(), 0.);
+        assertEquals(2, Repository.INSTANCE.getCounter(new Counter.Key(Role.JDBC, insert)).getHits(), 0.);
+    }
+}

Added: incubator/sirona/trunk/agent/performance/jpa/pom.xml
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jpa/pom.xml?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jpa/pom.xml (added)
+++ incubator/sirona/trunk/agent/performance/jpa/pom.xml Tue Nov  5 17:25:15 2013
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>sirona-performance</artifactId>
+    <groupId>org.apache.sirona</groupId>
+    <version>0.1-incubating-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>sirona-jpa</artifactId>
+  <version>0.1-incubating-SNAPSHOT</version>
+  <name>Apache Sirona Incubator :: Agent :: Performance  :: JPA</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-jpa_2.0_spec</artifactId>
+      <version>1.1</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sirona</groupId>
+      <artifactId>sirona-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sirona</groupId>
+      <artifactId>sirona-aop</artifactId>
+      <exclusions>
+        <exclusion>
+          <groupId>org.apache.commons</groupId>
+          <artifactId>commons-proxy</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.hsqldb</groupId>
+      <artifactId>hsqldb</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.openjpa</groupId>
+      <artifactId>openjpa</artifactId>
+      <version>2.2.2</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file

Added: incubator/sirona/trunk/agent/performance/jpa/src/main/java/org/apache/sirona/jpa/JPAProxyFactory.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jpa/src/main/java/org/apache/sirona/jpa/JPAProxyFactory.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jpa/src/main/java/org/apache/sirona/jpa/JPAProxyFactory.java (added)
+++ incubator/sirona/trunk/agent/performance/jpa/src/main/java/org/apache/sirona/jpa/JPAProxyFactory.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,103 @@
+/*
+ * 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.sirona.jpa;
+
+import org.apache.sirona.Role;
+import org.apache.sirona.aop.AbstractPerformanceInterceptor;
+import org.apache.sirona.util.ClassLoaders;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+public final class JPAProxyFactory {
+    // more designed as internal than user friendly, that's why it is not in aop module
+    public static Object monitor(final Class<?>[] classes, final Object instance, final Role role, final boolean cascade) {
+        return classes[0].cast(
+            Proxy.newProxyInstance(ClassLoaders.current(), classes, new JSEMonitoringHandler(instance, role, cascade)));
+    }
+
+    private JPAProxyFactory() {
+        // no-op
+    }
+
+    private static class JSEMonitoringHandler extends AbstractPerformanceInterceptor<Invocation> implements InvocationHandler {
+        private final Object instance;
+        private final Role role;
+        private final boolean cascade;
+
+        public JSEMonitoringHandler(final Object instance, final Role role, final boolean cascade) {
+            this.instance = instance;
+            this.role = role;
+            this.cascade = cascade;
+        }
+
+        @Override
+        public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+            if ("toString".equals(method.getName())) {
+                return "MonitoringProxy[" + instance + "]";
+            }
+
+            final Object o = doInvoke(new Invocation(instance, method, args));
+            final Class<?> returnType = method.getReturnType();
+            if (cascade && returnType.isInterface()) { // not java.*
+                return monitor(classes(returnType, o), o, role, cascade);
+            }
+            return o;
+        }
+
+        @Override
+        protected Object proceed(final Invocation invocation) throws Throwable {
+            try {
+                return invocation.method.invoke(invocation.target, invocation.args);
+            } catch (final InvocationTargetException ite) {
+                throw ite.getCause();
+            }
+        }
+
+        @Override
+        protected String getCounterName(final Invocation invocation) {
+            return getCounterName(invocation.target, invocation.method);
+        }
+
+        @Override
+        protected Role getRole() {
+            return role;
+        }
+
+        protected Class<?>[] classes(final Class<?> returnType, final Object o) {
+            if (Serializable.class.isInstance(o)) {
+                return new Class<?>[] { returnType, Serializable.class };
+            }
+            return new Class<?>[] { returnType };
+        }
+    }
+
+    private static class Invocation {
+        private final Object target;
+        private final Method method;
+        private final Object[] args;
+
+        private Invocation(final Object target, final Method method, final Object[] args) {
+            this.target = target;
+            this.method = method;
+            this.args = args;
+        }
+    }
+}

Added: incubator/sirona/trunk/agent/performance/jpa/src/main/java/org/apache/sirona/jpa/MonitoringPersistence.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jpa/src/main/java/org/apache/sirona/jpa/MonitoringPersistence.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jpa/src/main/java/org/apache/sirona/jpa/MonitoringPersistence.java (added)
+++ incubator/sirona/trunk/agent/performance/jpa/src/main/java/org/apache/sirona/jpa/MonitoringPersistence.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,174 @@
+/*
+ * 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.sirona.jpa;
+
+import org.apache.sirona.Role;
+import org.apache.sirona.configuration.Configuration;
+import org.apache.sirona.counters.Unit;
+
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.spi.PersistenceProvider;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.persistence.spi.ProviderUtil;
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Map;
+
+import static org.apache.sirona.jpa.JPAProxyFactory.monitor;
+
+public class MonitoringPersistence implements PersistenceProvider {
+    public static final Role ROLE = new Role("jpa", Unit.Time.NANOSECOND);
+
+    private static final String DELEGATE_PROVIDER_KEY = Configuration.CONFIG_PROPERTY_PREFIX + "jpa.provider";
+    private static final String DEFAULT_PROVIDER = System.getProperty(DELEGATE_PROVIDER_KEY);
+    private static final Class<?>[] PROXY_API = new Class<?>[] { EntityManagerFactory.class, Serializable.class};
+
+    private static final String[] PROVIDERS = {
+        "org.apache.openjpa.persistence.PersistenceProviderImpl",
+        "org.hibernate.jpa.HibernatePeristenceProvider",
+        "org.hibernate.ejb.HibernatePeristence",
+        "org.eclipse.persistence.jpa.PersistenceProvider",
+        "oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider",
+        "oracle.toplink.essentials.PersistenceProvider",
+        "me.prettyprint.hom.CassandraPersistenceProvider",
+        "org.datanucleus.jpa.PersistenceProviderImpl",
+        "com.orientechnologies.orient.core.db.object.jpa.OJPAPersistenceProvider",
+        "com.orientechnologies.orient.object.jpa.OJPAPersistenceProvider",
+        "com.spaceprogram.simplejpa.PersistenceProviderImpl"
+    };
+
+    private volatile PersistenceProvider delegate;
+
+    @Override
+    public EntityManagerFactory createEntityManagerFactory(final String unit, final Map map) {
+        final PersistenceProvider persistenceProvider = findDelegate(map);
+        final ClassLoader tccl = tccl();
+
+        final ClassLoader hack = new OverridePersistenceXmlClassLoader(tccl, persistenceProvider.getClass().getName());
+        Thread.currentThread().setContextClassLoader(hack);
+        try {
+            final EntityManagerFactory entityManagerFactory = persistenceProvider.createEntityManagerFactory(unit, map);
+            if (entityManagerFactory == null) {
+                return null;
+            }
+            return EntityManagerFactory.class.cast(
+                monitor(PROXY_API, entityManagerFactory, ROLE, true));
+        } finally {
+            Thread.currentThread().setContextClassLoader(tccl);
+        }
+    }
+
+    @Override
+    public EntityManagerFactory createContainerEntityManagerFactory(final PersistenceUnitInfo info, final Map map) {
+        final PersistenceProvider persistenceProvider = findDelegate(map);
+        final EntityManagerFactory containerEntityManagerFactory = persistenceProvider.createContainerEntityManagerFactory(
+            PersistenceUnitInfo.class.cast(Proxy.newProxyInstance(tccl(), new Class<?>[]{PersistenceUnitInfo.class}, new ProviderAwareHandler(persistenceProvider.getClass().getName(), info))),
+            map);
+        if (containerEntityManagerFactory == null) {
+            return null;
+        }
+        return EntityManagerFactory.class.cast(
+            monitor(PROXY_API, containerEntityManagerFactory, ROLE, true));
+    }
+
+    @Override
+    public ProviderUtil getProviderUtil() { // we suppose it is loaded later than createXXXEMF so we'll get the delegate
+        return loadOrGuessDelegate(null).getProviderUtil();
+    }
+
+    private PersistenceProvider findDelegate(final Map map) {
+        if (map == null) {
+            return loadOrGuessDelegate(null);
+        }
+        return loadOrGuessDelegate(String.class.cast(map.get(DELEGATE_PROVIDER_KEY)));
+    }
+
+    private PersistenceProvider loadOrGuessDelegate(final String name) {
+        if (delegate == null) {
+            synchronized (this) {
+                if (delegate == null) {
+                    if (name == null) {
+                        if (DEFAULT_PROVIDER != null) {
+                            try {
+                                delegate = newPersistence(DEFAULT_PROVIDER);
+                            } catch (final Exception e) {
+                                throw new IllegalStateException(new ClassNotFoundException("Can't instantiate '" + DEFAULT_PROVIDER + "'"));
+                            }
+                        } else {
+                            for (final String provider : PROVIDERS) {
+                                try {
+                                    delegate = newPersistence(provider);
+                                    if (delegate != null) {
+                                        break;
+                                    }
+                                } catch (final Throwable th2) {
+                                    // no-op
+                                }
+                            }
+                        }
+
+                        if (delegate == null) {
+                            throw new IllegalStateException(new ClassNotFoundException("Can't find a delegate"));
+                        }
+                    } else {
+                        try {
+                            delegate = newPersistence(name);
+                        } catch (final Exception e) {
+                            throw new IllegalStateException(new ClassNotFoundException("Can't instantiate '" + name + "'"));
+                        }
+                    }
+                }
+            }
+        }
+        if (name != null && !delegate.getClass().getName().equals(name)) {
+            try {
+                return newPersistence(name);
+            } catch (final Exception e) {
+                throw new IllegalStateException(new ClassNotFoundException("Can't instantiate '" + name + "'"));
+            }
+        }
+        return delegate;
+    }
+
+    private static ClassLoader tccl() {
+        return Thread.currentThread().getContextClassLoader();
+    }
+
+    private static PersistenceProvider newPersistence(final String name) throws Exception {
+        return PersistenceProvider.class.cast(tccl().loadClass(name).newInstance());
+    }
+
+    private static class ProviderAwareHandler implements InvocationHandler {
+        private final String provider;
+        private final PersistenceUnitInfo info;
+
+        public ProviderAwareHandler(final String provider, final PersistenceUnitInfo info) {
+            this.provider = provider;
+            this.info = info;
+        }
+
+        @Override
+        public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+            if ("getPersistenceProviderClassName".equals(method.getName())) {
+                return provider;
+            }
+            return method.invoke(info, args);
+        }
+    }
+}

Added: incubator/sirona/trunk/agent/performance/jpa/src/main/java/org/apache/sirona/jpa/OverridePersistenceXmlClassLoader.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jpa/src/main/java/org/apache/sirona/jpa/OverridePersistenceXmlClassLoader.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jpa/src/main/java/org/apache/sirona/jpa/OverridePersistenceXmlClassLoader.java (added)
+++ incubator/sirona/trunk/agent/performance/jpa/src/main/java/org/apache/sirona/jpa/OverridePersistenceXmlClassLoader.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,142 @@
+/*
+ * 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.sirona.jpa;
+
+import org.apache.sirona.MonitoringException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedList;
+
+public class OverridePersistenceXmlClassLoader extends ClassLoader {
+    private static final String PERSISTENCE_XML = "META-INF/persistence.xml";
+    private static final String PERSISTENCE_PROVIDER = MonitoringPersistence.class.getName();
+    public static final String NO_PROVIDER = "<provider></provider>";
+
+    private final String replacement;
+
+    public OverridePersistenceXmlClassLoader(final ClassLoader parent, final String replacement) {
+        super(parent);
+        this.replacement = replacement;
+    }
+
+    @Override // don't load anything from here
+    protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
+        return super.loadClass(name, resolve);
+    }
+
+    @Override
+    public URL getResource(final String name) {
+        final URL url = super.getResource(name);
+        if (PERSISTENCE_XML.equals(name) && url != null) {
+            return newUrl(url, slurp(url));
+        }
+        return  url;
+    }
+
+    @Override
+    public Enumeration<URL> getResources(final String name) throws IOException {
+        final Enumeration<URL> urls = super.getResources(name);
+        if (PERSISTENCE_XML.equals(name)) {
+            final Collection<URL> overrided = new LinkedList<URL>();
+            while (urls.hasMoreElements()) {
+                final URL url = urls.nextElement();
+                overrided.add(newUrl(url, slurp(url)));
+            }
+            return Collections.enumeration(overrided);
+        }
+        return  urls;
+    }
+
+    private URL newUrl(final URL url, final String slurp) {
+        if (slurp.contains(PERSISTENCE_PROVIDER)) {
+            final String afterReplace = slurp.replace(PERSISTENCE_PROVIDER, replacement).replace(NO_PROVIDER, "");
+            try {
+                return new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile(), new ConstantURLStreamHandler(afterReplace));
+            } catch (final MalformedURLException e) {
+                // no-op
+            }
+        }
+        return url;
+    }
+
+    private static String slurp(final URL url) {
+        InputStream is = null;
+        try {
+            is = url.openStream();
+            final ByteArrayOutputStream out = new ByteArrayOutputStream();
+            final byte[] buffer = new byte[1024];
+            int length;
+            while ((length = is.read(buffer)) != -1) {
+                out.write(buffer, 0, length);
+            }
+            return new String(out.toByteArray());
+        } catch (final IOException e) {
+            throw new MonitoringException(e);
+        } finally {
+            // no need to close out
+            try {
+                if (is != null) {
+                    is.close();
+                }
+            } catch (IOException e) {
+                // no-op
+            }
+        }
+    }
+
+    private static class ConstantURLStreamHandler extends URLStreamHandler {
+        private final String value;
+
+        private ConstantURLStreamHandler(final String value) {
+            this.value = value;
+        }
+
+        @Override
+        protected URLConnection openConnection(final URL u) throws IOException {
+            return new ConstantURLConnection(u, value);
+        }
+    }
+
+    private static class ConstantURLConnection extends URLConnection {
+        private final String value;
+
+        private ConstantURLConnection(final URL url, final String value) {
+            super(url);
+            this.value = value;
+        }
+
+        @Override
+        public void connect() throws IOException {
+            // no-op
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return new ByteArrayInputStream(value.getBytes());
+        }
+    }
+}

Added: incubator/sirona/trunk/agent/performance/jpa/src/main/resources/META-INF/services/javax.persistence.spi.PersistenceProvider
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jpa/src/main/resources/META-INF/services/javax.persistence.spi.PersistenceProvider?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jpa/src/main/resources/META-INF/services/javax.persistence.spi.PersistenceProvider (added)
+++ incubator/sirona/trunk/agent/performance/jpa/src/main/resources/META-INF/services/javax.persistence.spi.PersistenceProvider Tue Nov  5 17:25:15 2013
@@ -0,0 +1 @@
+org.apache.sirona.jpa.MonitoringPersistence

Added: incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/EMFTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/EMFTest.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/EMFTest.java (added)
+++ incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/EMFTest.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sirona.jpa;
+
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.repositories.Repository;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+import javax.persistence.spi.PersistenceUnitInfo;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Collection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class EMFTest {
+    @Before
+    @After
+    public void reset() {
+        Repository.INSTANCE.clear();
+    }
+
+    @Test
+    public void newEmfJSe() {
+        final EntityManagerFactory emf = Persistence.createEntityManagerFactory("test-jse");
+        assertNotNull(emf);
+        emf.close();
+
+        assertCreateCalled();
+    }
+
+    @Test
+    public void newEmfJavaEE() {
+        final EntityManagerFactory emf = new MonitoringPersistence().createContainerEntityManagerFactory(
+            PersistenceUnitInfo.class.cast(Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[]{PersistenceUnitInfo.class}, new InvocationHandler() {
+                @Override
+                public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+                    if (boolean.class.equals(method.getReturnType())) {
+                        return false;
+                    }
+                    return null;
+                }
+            })), null);
+        assertNotNull(emf);
+        emf.close();
+
+        assertCreateCalled();
+    }
+
+    private static void assertCreateCalled() {
+        final Collection<Counter> counters = Repository.INSTANCE.counters();
+        assertEquals(1, counters.size());
+
+        final Counter counter = counters.iterator().next();
+        assertEquals(1, counter.getHits());
+    }
+}

Added: incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/QueryTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/QueryTest.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/QueryTest.java (added)
+++ incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/QueryTest.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,119 @@
+/*
+ * 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.sirona.jpa;
+
+import org.apache.sirona.counters.Counter;
+import org.apache.sirona.jpa.entity.Person;
+import org.apache.sirona.repositories.Repository;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.Persistence;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public class QueryTest {
+    @Before
+    @After
+    public void reset() {
+        Repository.INSTANCE.clear();
+    }
+
+    @Test
+    public void simpleFind() {
+        final EntityManagerFactory emf = Persistence.createEntityManagerFactory("test-jse");
+        assertNotNull(emf);
+        reset(); // get rid of init counter
+
+        try {
+            final EntityManager em = emf.createEntityManager();
+            assertNotNull(em);
+
+            assertCounter("createEntityManager");
+
+            reset(); // get rid of createEntityManager counter
+            try {
+                em.find(Person.class, 0L);
+                assertCounter("find");
+                reset(); // get rid of em.find() counter
+            } finally {
+                em.close();
+                assertCounter("EntityManagerImpl.close");
+            }
+
+            reset(); // get rid of em.close() counter
+        } finally {
+            emf.close();
+        }
+        assertCounter("EntityManagerFactoryImpl.close");
+    }
+
+    @Test
+    public void createNamedQuery() {
+        final EntityManagerFactory emf = Persistence.createEntityManagerFactory("test-jse");
+
+        try {
+            { // init
+                final EntityManager em = emf.createEntityManager();
+                try {
+                    final EntityTransaction transaction = em.getTransaction();
+                    transaction.begin();
+                    try {
+                        final Person p = new Person();
+                        p.setName("sirona");
+
+                        em.persist(p);
+                        transaction.commit();
+                    } catch (final Exception e) {
+                        transaction.rollback();
+                    }
+                } finally {
+                    em.close();
+                }
+            }
+
+            { // checks
+                final EntityManager em = emf.createEntityManager();
+                try {
+                    reset();
+                    em.createNamedQuery("Person.findByName", Person.class).setParameter("name", "sirona").getSingleResult();
+                    assertCounter("createNamedQuery");
+                } finally {
+                    em.close();
+                }
+            }
+        } finally {
+            emf.close();
+        }
+    }
+
+    private static void assertCounter(final String method) {
+        assertTrue(Repository.INSTANCE.counters().iterator().hasNext());
+
+        final Counter counter = Repository.INSTANCE.counters().iterator().next();
+        assertEquals(1, counter.getHits());
+        assertThat(counter.getKey().getName(), containsString(method));
+    }
+}

Added: incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/entity/Address.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/entity/Address.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/entity/Address.java (added)
+++ incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/entity/Address.java Tue Nov  5 17:25:15 2013
@@ -0,0 +1,53 @@
+/*
+ * 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.sirona.jpa.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+
+@Entity
+public class Address {
+    @Id
+    @GeneratedValue
+    private long id;
+    private String street;
+
+    @ManyToOne
+    private Person person;
+
+    public long getId() {
+        return id;
+    }
+
+    public String getStreet() {
+        return street;
+    }
+
+    public void setStreet(final String street) {
+        this.street = street;
+    }
+
+    public Person getPerson() {
+        return person;
+    }
+
+    public void setPerson(final Person person) {
+        this.person = person;
+    }
+}

Added: incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/entity/Person.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/entity/Person.java?rev=1539076&view=auto
==============================================================================
--- incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/entity/Person.java (added)
+++ incubator/sirona/trunk/agent/performance/jpa/src/test/java/org/apache/sirona/jpa/entity/Person.java Tue Nov  5 17:25:15 2013
@@ -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.sirona.jpa.entity;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import java.util.LinkedList;
+import java.util.List;
+
+@Entity
+@NamedQuery(name = "Person.findByName", query = "select p from Person p where p.name = :name")
+public class Person {
+    @Id
+    @GeneratedValue
+    private long id;
+
+    private String name;
+
+    @OneToMany(cascade = { CascadeType.ALL }, mappedBy = "person")
+    private List<Address> addresses = new LinkedList<Address>();
+
+    public long getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public List<Address> getAddresses() {
+        return addresses;
+    }
+}