You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2011/04/05 16:37:23 UTC

svn commit: r1089061 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/ main/java/org/apache/jackrabbit/core/jmx/ main/java/org/apache/jackrabbit/core/jmx/query/ main/java/org/apache/jackrabbit/core/query/ test/java/org/a...

Author: jukka
Date: Tue Apr  5 14:37:22 2011
New Revision: 1089061

URL: http://svn.apache.org/viewvc?rev=1089061&view=rev
Log:
JCR-2936: JMX Bindings for Jackrabbit

Patch by Alex Parvulescu

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JackrabbitBaseMBean.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistry.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistryUtils.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStat.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManager.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerBase.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerImplMBean.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/jmx/
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/jmx/QueryStatManagerTest.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java?rev=1089061&r1=1089060&r2=1089061&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java Tue Apr  5 14:37:22 2011
@@ -81,6 +81,8 @@ import org.apache.jackrabbit.core.fs.Fil
 import org.apache.jackrabbit.core.fs.FileSystemResource;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.id.NodeIdFactory;
+import org.apache.jackrabbit.core.jmx.JmxRegistry;
+import org.apache.jackrabbit.core.jmx.JmxRegistryImpl;
 import org.apache.jackrabbit.core.lock.LockManager;
 import org.apache.jackrabbit.core.lock.LockManagerImpl;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
@@ -231,6 +233,8 @@ public class RepositoryImpl extends Abst
      */
     private final CacheManager cacheMgr = new CacheManager();
 
+    private final JmxRegistry jmxRegistry = new JmxRegistryImpl();
+
     /**
      * Chanel for posting create workspace messages.
      */
@@ -355,6 +359,9 @@ public class RepositoryImpl extends Abst
             // initialize system search manager
             getSystemSearchManager(repConfig.getDefaultWorkspaceName());
 
+            //this has to be live before initSecurityManager(), to be able to track all the queries
+            initJmxRegistry();
+
             // Initialise the security manager;
             initSecurityManager();
 
@@ -461,6 +468,10 @@ public class RepositoryImpl extends Abst
         return cacheMgr;
     }
 
+    public JmxRegistry getJmxRegistry(){
+        return jmxRegistry;
+    }
+
     /**
      * Creates the {@link org.apache.jackrabbit.core.security.JackrabbitSecurityManager SecurityManager}
      * of this <code>Repository</code> and adds it to the repository context.
@@ -1192,6 +1203,8 @@ public class RepositoryImpl extends Abst
 
         context.getTimer().cancel();
 
+        jmxRegistry.stop();
+
         log.info("Repository has been shutdown");
     }
 
@@ -1452,6 +1465,9 @@ public class RepositoryImpl extends Abst
         return new GarbageCollector(context.getDataStore(), ipmList, sessions);
     }
 
+    protected void initJmxRegistry(){
+        this.jmxRegistry.start();
+    }
 
     //-----------------------------------------------------------< Repository >
     /**

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JackrabbitBaseMBean.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JackrabbitBaseMBean.java?rev=1089061&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JackrabbitBaseMBean.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JackrabbitBaseMBean.java Tue Apr  5 14:37:22 2011
@@ -0,0 +1,34 @@
+/*
+ * 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.jackrabbit.core.jmx;
+
+/**
+ * http://www.oracle.com/technetwork/java/javase/tech/best-practices-jsp-136021.
+ * html
+ * 
+ * This should be the base for any MBean Services built for Jackrabbit
+ * 
+ */
+public interface JackrabbitBaseMBean {
+
+    String BASE_NAME = "org.apache.jackrabbit";
+
+    boolean isEnabled();
+
+    void setEnabled(boolean enabled);
+
+}

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistry.java?rev=1089061&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistry.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistry.java Tue Apr  5 14:37:22 2011
@@ -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.jackrabbit.core.jmx;
+
+import javax.management.ObjectName;
+
+import org.apache.jackrabbit.core.jmx.query.QueryStatManager;
+
+/**
+ * JMX Mbean registration service
+ * 
+ */
+public interface JmxRegistry {
+
+    /**
+     * starts the service
+     */
+    void start();
+
+    /**
+     * stops the service
+     */
+    void stop();
+
+    /**
+     * Registers a new MBEan under the given name
+     * 
+     * @param bean
+     *            to be registered
+     * @param name
+     * @throws Exception
+     */
+    void register(JackrabbitBaseMBean bean, ObjectName name) throws Exception;
+
+    /**
+     * Unregisters a bean
+     * 
+     * @param name
+     * @throws Exception
+     */
+    void unregister(ObjectName name) throws Exception;
+
+    QueryStatManager getQueryStatManager();
+}

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistryImpl.java?rev=1089061&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistryImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistryImpl.java Tue Apr  5 14:37:22 2011
@@ -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.jackrabbit.core.jmx;
+
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.jackrabbit.core.jmx.query.QueryStatManager;
+import org.apache.jackrabbit.core.jmx.query.QueryStatManagerImpl;
+import org.apache.jackrabbit.core.jmx.query.QueryStatManagerImplMBean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * JmxRegistry default implementation
+ * 
+ */
+public class JmxRegistryImpl implements JmxRegistry {
+
+    private static Logger log = LoggerFactory.getLogger(JmxRegistryImpl.class);
+
+    private MBeanServer server;
+
+    private List<ObjectName> registry = new ArrayList<ObjectName>();
+
+    private QueryStatManagerImpl queryStatManager;
+
+    public JmxRegistryImpl() {
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.jmx.JmxRegistry#start()
+     */
+    public void start() {
+        server = ManagementFactory.getPlatformMBeanServer();
+        try {
+            queryStatManager = new QueryStatManagerImpl();
+            register(queryStatManager, new ObjectName(
+                    QueryStatManagerImplMBean.NAME));
+            log.info("Started JMX Registry");
+        } catch (Exception e) {
+            queryStatManager = null;
+            log.error("Unable to start JMX Registry", e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.jmx.JmxRegistry#stop()
+     */
+    public void stop() {
+        if (server == null) {
+            return;
+        }
+
+        for (ObjectName o : registry) {
+            try {
+                server.unregisterMBean(o);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        registry.clear();
+        server = null;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * org.apache.jackrabbit.core.jmx.JmxRegistry#register(org.apache.jackrabbit
+     * .core.jmx.JackrabbitMBean, javax.management.ObjectName)
+     */
+    public void register(JackrabbitBaseMBean bean, ObjectName name)
+            throws Exception {
+        this.server.registerMBean(bean, name);
+        this.registry.add(name);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * org.apache.jackrabbit.core.jmx.JmxRegistry#unregister(javax.management
+     * .ObjectName)
+     */
+    public void unregister(ObjectName name) throws Exception {
+        if (server == null || !server.isRegistered(name)) {
+            return;
+        }
+        registry.remove(name);
+        server.unregisterMBean(name);
+    }
+
+    public QueryStatManager getQueryStatManager() {
+        return queryStatManager;
+    }
+}

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistryUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistryUtils.java?rev=1089061&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistryUtils.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/JmxRegistryUtils.java Tue Apr  5 14:37:22 2011
@@ -0,0 +1,48 @@
+/*
+ * 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.jackrabbit.core.jmx;
+
+import org.apache.jackrabbit.core.jmx.query.QueryStat;
+import org.apache.jackrabbit.core.query.QueryImpl;
+
+/**
+ * Utilities related to JMX
+ * 
+ */
+public class JmxRegistryUtils {
+
+    /**
+     * private constructor
+     */
+    private JmxRegistryUtils() {
+        //
+    }
+
+    /**
+     * Transforms a Query into a QueryStat
+     * 
+     * @param q
+     *            the query
+     * @param duration
+     *            duration of the query
+     * @return the stat object
+     */
+    public static QueryStat buildQueryStat(QueryImpl q, long duration) {
+        return new QueryStat(q.getLanguage(), q.getStatement(), duration);
+    }
+
+}

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStat.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStat.java?rev=1089061&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStat.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStat.java Tue Apr  5 14:37:22 2011
@@ -0,0 +1,97 @@
+/*
+ * 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.jackrabbit.core.jmx.query;
+
+import java.io.Serializable;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * Object that holds statistical info about a query.
+ * 
+ */
+public class QueryStat implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * lazy, computed at call time
+     */
+    private long position;
+
+    /**
+     * the time that the query was created
+     */
+    private final Date creationTime;
+
+    /**
+     * run duration
+     */
+    private final long duration;
+
+    /**
+     * query language
+     */
+    private final String language;
+
+    /**
+     * query statement
+     */
+    private final String statement;
+
+    public QueryStat(final String language, final String statement,
+            long duration) {
+        this.duration = duration;
+        this.language = language;
+        this.statement = statement;
+
+        Calendar c = Calendar.getInstance();
+        c.setTimeInMillis(System.currentTimeMillis() - duration);
+        this.creationTime = c.getTime();
+    }
+
+    public long getDuration() {
+        return duration;
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getStatement() {
+        return statement;
+    }
+
+    public String getCreationTime() {
+        return creationTime.toString();
+    }
+
+    public long getPosition() {
+        return position;
+    }
+
+    public void setPosition(long position) {
+        this.position = position;
+    }
+
+    @Override
+    public String toString() {
+        return "QueryStat [creationTime=" + creationTime + ", duration="
+                + duration + ", language=" + language + ", statement="
+                + statement + "]";
+    }
+}

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManager.java?rev=1089061&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManager.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManager.java Tue Apr  5 14:37:22 2011
@@ -0,0 +1,35 @@
+/*
+ * 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.jackrabbit.core.jmx.query;
+
+/**
+ * 
+ * Extends QueryStatManagerBase with write access to the query log. <br>
+ * 
+ */
+public interface QueryStatManager extends QueryStatManagerBase {
+
+    /**
+     * log a {@link QueryStat} to the service if it is enabled
+     * 
+     * @param query
+     */
+    void logQuery(QueryStat query);
+
+    QueryStat[] getTopQueries();
+
+}

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerBase.java?rev=1089061&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerBase.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerBase.java Tue Apr  5 14:37:22 2011
@@ -0,0 +1,60 @@
+/*
+ * 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.jackrabbit.core.jmx.query;
+
+/**
+ * 
+ * Service that tracks statistics for queries. <br>
+ * 
+ * It acts as a <b>Top X</b> longest running queries.
+ * 
+ */
+public interface QueryStatManagerBase {
+
+    /**
+     * @return how big the <b>Top X</b> queue is
+     */
+    int getQueueSize();
+
+    /**
+     * Change the <b>Top X</b> queue size
+     * 
+     * @param size
+     *            the new size
+     */
+    void setQueueSize(int size);
+
+    /**
+     * clears the queue
+     */
+    void clearQueue();
+
+    /**
+     * If this service is currently registering stats
+     * 
+     * @return <code>true</code> if the service is enabled
+     */
+    boolean isEnabled();
+
+    /**
+     * Enables/Disables the service
+     * 
+     * @param enabled
+     */
+    void setEnabled(boolean enabled);
+
+}

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerImpl.java?rev=1089061&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerImpl.java Tue Apr  5 14:37:22 2011
@@ -0,0 +1,164 @@
+/*
+ * 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.jackrabbit.core.jmx.query;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.PriorityQueue;
+
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.TabularType;
+
+/**
+ * Default {@link QueryStatManager} implementation
+ * 
+ */
+public class QueryStatManagerImpl implements QueryStatManagerImplMBean,
+        QueryStatManager {
+
+    private final static Comparator<QueryStat> comparator = new QueryStatComp();
+
+    private final static Comparator<QueryStat> comparatorRev = Collections
+            .reverseOrder(comparator);
+
+    private int queueSize = 15;
+
+    private PriorityQueue<QueryStat> queries = new PriorityQueue<QueryStat>(
+            queueSize + 1, new QueryStatComp());
+
+    private boolean enabled;
+
+    /**
+     * Default constructor. This will disable the monitoring service
+     */
+    public QueryStatManagerImpl() {
+        this(false);
+    }
+
+    /**
+     * Constructor allowing the enabling/disabling of the service
+     * 
+     * @param isEnabled
+     */
+    public QueryStatManagerImpl(boolean isEnabled) {
+        this.enabled = isEnabled;
+    }
+
+    public int getQueueSize() {
+        return queueSize;
+    }
+
+    public synchronized void setQueueSize(int size) {
+        this.queueSize = size;
+        this.queries = new PriorityQueue<QueryStat>(this.queueSize + 1,
+                comparator);
+    }
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+        this.queries = new PriorityQueue<QueryStat>(this.queueSize + 1,
+                comparator);
+    }
+
+    public QueryStat[] getTopQueries() {
+        // TODO cache this call
+        QueryStat[] top = queries.toArray(new QueryStat[queries.size()]);
+        Arrays.sort(top, comparatorRev);
+        for (int i = 0; i < top.length; i++) {
+            top[i].setPosition(i + 1);
+        }
+        return top;
+    }
+
+    public TabularData getQueries() {
+        TabularDataSupport tds = null;
+        try {
+            CompositeType ct = QueryStatCompositeTypeFactory.getCompositeType();
+
+            TabularType tt = new TabularType(QueryStat.class.getName(),
+                    "Query History", ct, QueryStatCompositeTypeFactory.index);
+            tds = new TabularDataSupport(tt);
+
+            for (QueryStat q : getTopQueries()) {
+                tds.put(new CompositeDataSupport(ct,
+                        QueryStatCompositeTypeFactory.names,
+                        QueryStatCompositeTypeFactory.getValues(q)));
+            }
+            return tds;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public synchronized void logQuery(QueryStat stat) {
+        if (!enabled) {
+            return;
+        }
+        queries.add(stat);
+        if (queries.size() > queueSize) {
+            queries.remove();
+        }
+    }
+
+    private static class QueryStatComp implements Comparator<QueryStat> {
+
+        public int compare(QueryStat o1, QueryStat o2) {
+            return new Long(o1.getDuration()).compareTo(o2.getDuration());
+        }
+    }
+
+    private static class QueryStatCompositeTypeFactory {
+
+        private final static String[] index = { "position" };
+
+        private final static String[] names = { "position", "duration",
+                "language", "statement", "creationTime" };
+
+        private final static String[] descriptions = { "position", "duration",
+                "language", "statement", "creationTime" };
+
+        private final static OpenType[] types = { SimpleType.LONG,
+                SimpleType.LONG, SimpleType.STRING, SimpleType.STRING,
+                SimpleType.STRING };
+
+        public static CompositeType getCompositeType() throws OpenDataException {
+            return new CompositeType(QueryStat.class.getName(),
+                    QueryStat.class.getName(), names, descriptions, types);
+        }
+
+        public static Object[] getValues(QueryStat q) {
+            return new Object[] { q.getPosition(), q.getDuration(),
+                    q.getLanguage(), q.getStatement(), q.getCreationTime() };
+        }
+    }
+
+    public void clearQueue() {
+        this.queries.clear();
+    }
+}

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerImplMBean.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerImplMBean.java?rev=1089061&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerImplMBean.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/query/QueryStatManagerImplMBean.java Tue Apr  5 14:37:22 2011
@@ -0,0 +1,33 @@
+/*
+ * 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.jackrabbit.core.jmx.query;
+
+import javax.management.openmbean.TabularData;
+
+import org.apache.jackrabbit.core.jmx.JackrabbitBaseMBean;
+
+/**
+ * JMX Binding for the {@link QueryStatManagerImpl}. <br>
+ * 
+ */
+public interface QueryStatManagerImplMBean extends JackrabbitBaseMBean,
+        QueryStatManagerBase {
+
+    String NAME = BASE_NAME + ":type=QueryStats";
+
+    TabularData getQueries();
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java?rev=1089061&r1=1089060&r2=1089061&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java Tue Apr  5 14:37:22 2011
@@ -35,6 +35,8 @@ import javax.jcr.query.InvalidQueryExcep
 import javax.jcr.query.QueryResult;
 import javax.jcr.version.VersionException;
 
+import org.apache.jackrabbit.core.jmx.JmxRegistryUtils;
+import org.apache.jackrabbit.core.jmx.query.QueryStatManager;
 import org.apache.jackrabbit.core.session.SessionContext;
 import org.apache.jackrabbit.core.session.SessionOperation;
 import org.apache.jackrabbit.spi.Path;
@@ -134,8 +136,13 @@ public class QueryImpl extends AbstractQ
                         return "query.execute(" + statement + ")";
                     }
                 });
+        time = System.currentTimeMillis() - time;
+        QueryStatManager qsm = sessionContext.getRepository().getJmxRegistry()
+                .getQueryStatManager();
+        if (qsm != null) {
+            qsm.logQuery(JmxRegistryUtils.buildQueryStat(this, time));
+        }
         if (log.isDebugEnabled()) {
-            time = System.currentTimeMillis() - time;
             NumberFormat format = NumberFormat.getNumberInstance();
             format.setMinimumFractionDigits(2);
             format.setMaximumFractionDigits(2);

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java?rev=1089061&r1=1089060&r2=1089061&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java Tue Apr  5 14:37:22 2011
@@ -32,6 +32,8 @@ import javax.jcr.query.qom.QueryObjectMo
 import javax.jcr.query.qom.Source;
 
 import org.apache.jackrabbit.commons.query.QueryObjectModelBuilderRegistry;
+import org.apache.jackrabbit.core.jmx.JmxRegistryUtils;
+import org.apache.jackrabbit.core.jmx.query.QueryStatManager;
 import org.apache.jackrabbit.core.query.lucene.LuceneQueryFactory;
 import org.apache.jackrabbit.core.query.lucene.SearchIndex;
 import org.apache.jackrabbit.core.query.lucene.join.QueryEngine;
@@ -123,6 +125,12 @@ public class QueryObjectModelImpl extend
         QueryResult qr = engine.execute(getColumns(), getSource(),
                 getConstraint(), getOrderings(), offset, limit);
         time = System.currentTimeMillis() - time;
+
+        QueryStatManager qsm = sessionContext.getRepository().getJmxRegistry()
+        .getQueryStatManager();
+        if (qsm != null) {
+            qsm.logQuery(JmxRegistryUtils.buildQueryStat(this, time));
+        }
         if (log.isDebugEnabled()) {
             NumberFormat format = NumberFormat.getNumberInstance();
             format.setMinimumFractionDigits(2);

Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/jmx/QueryStatManagerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/jmx/QueryStatManagerTest.java?rev=1089061&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/jmx/QueryStatManagerTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/jmx/QueryStatManagerTest.java Tue Apr  5 14:37:22 2011
@@ -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.jackrabbit.core.jmx;
+
+import javax.jcr.query.Query;
+
+import org.apache.jackrabbit.core.RepositoryImpl;
+import org.apache.jackrabbit.core.jmx.query.QueryStat;
+import org.apache.jackrabbit.core.jmx.query.QueryStatManager;
+import org.apache.jackrabbit.core.query.AbstractQueryTest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Performs various JMX test cases.
+ */
+public class QueryStatManagerTest extends AbstractQueryTest {
+
+    private static Logger log = LoggerFactory
+            .getLogger(QueryStatManagerTest.class);
+
+    public void testLogDuration() throws Exception {
+
+        int queueSize = 15;
+        int runTimes = 50;
+
+        RepositoryImpl r = (RepositoryImpl) superuser.getRepository();
+        QueryStatManager qsm = r.getJmxRegistry().getQueryStatManager();
+        qsm.setQueueSize(queueSize);
+        qsm.setEnabled(false);
+
+        // just to warm up the cache
+        double initial = doStatTest(runTimes);
+
+        qsm.setEnabled(false);
+        double off = doStatTest(runTimes);
+
+        qsm.setEnabled(true);
+        double on = doStatTest(runTimes);
+
+        log.info("Logging times: initial=" + initial
+                + ", without QueryStatManager = " + off
+                + ", with QueryStatManager = " + on);
+
+        QueryStat[] top = qsm.getTopQueries();
+        assertNotNull("Query Top should not be null", top);
+        assertEquals("Query Top should contain entries ",
+                Math.min(queueSize, runTimes), top.length);
+    }
+
+    private double doStatTest(int times) throws Exception {
+
+        long total = 0;
+        for (int i = 0; i < times; i++) {
+            long start = System.currentTimeMillis();
+            Query q = qm.createQuery("SELECT * FROM [nt:base]", Query.JCR_SQL2);
+            q.execute();
+            long dur = System.currentTimeMillis() - start;
+            total += dur;
+        }
+        return (double) total / times;
+    }
+}