org.onehippo.cms7
hippo-repository-testutils
${hippo.repository.version}
Index: api/src/main/java/org/hippoecm/frontend/model/TraceMonitor.java
===================================================================
--- api/src/main/java/org/hippoecm/frontend/model/TraceMonitor.java (revision 45500)
+++ api/src/main/java/org/hippoecm/frontend/model/TraceMonitor.java (working copy)
@@ -15,35 +15,79 @@
*/
package org.hippoecm.frontend.model;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.jcr.Item;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.jcr.Item;
+
+import org.apache.commons.collections.map.LRUMap;
+import org.apache.commons.lang.BooleanUtils;
+import org.apache.commons.lang.math.NumberUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+/**
+ * javax.jcr.Item
usage tracing/monitoring utility.
+ *
+ *
+ * Note: This is turned off by default. Set '-DTraceMonitor.enabled=true' system property to turn it on.
+ * Also, the default trace item size is 2000. You can increase it by setting '-DTraceMonitor.max=3000' for instance.
+ * Setting it to zero means unlimited size, which could be dangerous at runtime. So use it only in debugging mode!
+ *
+ *
+ */
+@SuppressWarnings("unchecked")
public class TraceMonitor {
- static final Logger log = LoggerFactory.getLogger(TraceMonitor.class);
+ static Logger log = LoggerFactory.getLogger(TraceMonitor.class);
- private static final Map initializedAndNotDetached = new HashMap();
+ static final String ENABLED_PROP = TraceMonitor.class.getSimpleName() + ".enabled";
+ static final String MAX_PROP = TraceMonitor.class.getSimpleName() + ".max";
+ static final int DEFAULT_MAX_SIZE = 2000;
+ private static final boolean enabled;
+ private static final int maxSize;
+ private static final Map initializedAndNotDetached;
+
+ static {
+ enabled = BooleanUtils.toBoolean(System.getProperty(ENABLED_PROP));
+
+ int max = NumberUtils.toInt(System.getProperty(MAX_PROP), -1);
+ if (max < 0) {
+ maxSize = DEFAULT_MAX_SIZE;
+ } else {
+ maxSize = max;
+ }
+
+ if (enabled) {
+ if (maxSize > 0) {
+ log.info("{}: Max monitoring items set to {}", TraceMonitor.class.getSimpleName(), maxSize);
+ initializedAndNotDetached = Collections.synchronizedMap(new LRUMap(maxSize));
+ } else {
+ log.warn("{}: No limit to monitoring items.", TraceMonitor.class.getSimpleName());
+ initializedAndNotDetached = new ConcurrentHashMap();
+ }
+ } else {
+ initializedAndNotDetached = null;
+ }
+ }
protected static final void track(Item item) {
- if (log.isDebugEnabled()) {
+ if (initializedAndNotDetached != null && log.isDebugEnabled()) {
initializedAndNotDetached.put(item.toString(), getCallee());
}
}
protected static final void release(Item item) {
- if (log.isDebugEnabled()) {
+ if (initializedAndNotDetached != null && log.isDebugEnabled()) {
initializedAndNotDetached.remove(item.toString());
}
}
protected static final void trace(Item item) {
- if (log.isDebugEnabled() && initializedAndNotDetached.containsKey(item.toString())) {
+ if (initializedAndNotDetached != null && log.isDebugEnabled() && initializedAndNotDetached.containsKey(item.toString())) {
String stackTrace = initializedAndNotDetached.get(item.toString());
log.debug(stackTrace);
}
@@ -60,4 +104,11 @@
return os.toString();
}
+ protected static final int getSize() {
+ if (initializedAndNotDetached != null) {
+ return initializedAndNotDetached.size();
+ } else {
+ return 0;
+ }
+ }
}
Index: api/src/test/java/org/hippoecm/frontend/model/TraceMonitorTest.java
===================================================================
--- api/src/test/java/org/hippoecm/frontend/model/TraceMonitorTest.java (revision 0)
+++ api/src/test/java/org/hippoecm/frontend/model/TraceMonitorTest.java (revision 0)
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2014-2014 Hippo B.V. (http://www.onehippo.com)
+ *
+ * Licensed 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.hippoecm.frontend.model;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.commons.lang.BooleanUtils;
+import org.apache.commons.lang.math.NumberUtils;
+import org.easymock.classextension.EasyMock;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onehippo.repository.mock.MockNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TraceMonitor test
+ *
+ * If you run this in a command line, you can run these for instance:
+ *
+ *
+ * - $ mvn test -Dtest=TraceMonitorTest
+ * - $ mvn test -Dtest=TraceMonitorTest -DTraceMonitor.enabled=true
+ * - $ mvn test -Dtest=TraceMonitorTest -DTraceMonitor.enabled=true -DTraceMonitor.max=3000
+ *
+ */
+public class TraceMonitorTest {
+
+ private static Logger log = LoggerFactory.getLogger(TraceMonitorTest.class);
+
+ private static Logger originalLogger;
+ private static Logger testLogger;
+
+ @Before
+ public void before() throws Exception {
+ originalLogger = TraceMonitor.log;
+ testLogger = EasyMock.createNiceMock(Logger.class);
+ EasyMock.expect(testLogger.isDebugEnabled()).andReturn(true).anyTimes();
+ EasyMock.replay(testLogger);
+ TraceMonitor.log = testLogger;
+ }
+
+ @After
+ public void after() throws Exception {
+ TraceMonitor.log = originalLogger;
+ }
+
+ @Test
+ public void testDefault() throws Exception {
+ boolean enabled = BooleanUtils.toBoolean(System.getProperty(TraceMonitor.ENABLED_PROP));
+ int maxSize = NumberUtils.toInt(System.getProperty(TraceMonitor.MAX_PROP), -1);
+
+ if (maxSize < 0) {
+ maxSize = TraceMonitor.DEFAULT_MAX_SIZE;
+ }
+
+ if (!enabled) {
+ log.info("Testing the default setting without any system properties...");
+
+ for (int i = 1; i <= maxSize; i++) {
+ TraceMonitor.track(MockNode.root().addNode("node-" + i, "nt:unstructured"));
+ assertEquals(0, TraceMonitor.getSize());
+ }
+ } else {
+ if (maxSize == 0) {
+ log.info("Testing the setting with `-DTraceMonitor.enabled=true -DTraceMonitor.max=0' ...");
+
+ for (int i = 1; i <= maxSize; i++) {
+ TraceMonitor.track(MockNode.root().addNode("node-" + i, "nt:unstructured"));
+ assertEquals(i, TraceMonitor.getSize());
+ }
+
+ int doubledMaxSize = 2 * maxSize;
+
+ for (int i = maxSize; i <= doubledMaxSize; i++) {
+ TraceMonitor.track(MockNode.root().addNode("node-" + i, "nt:unstructured"));
+ assertEquals(i, TraceMonitor.getSize());
+ }
+ } else {
+ log.info("Testing the setting with `-DTraceMonitor.enabled=true -DTraceMonitor.max=N' (N is 2000 by default) ...");
+
+ for (int i = 1; i <= maxSize; i++) {
+ TraceMonitor.track(MockNode.root().addNode("node-" + i, "nt:unstructured"));
+ assertEquals(i, TraceMonitor.getSize());
+ }
+
+ // one more cycle to track, but the size shouldn't increase over the maximum.
+ for (int i = 1; i <= maxSize; i++) {
+ TraceMonitor.track(MockNode.root().addNode("node-" + i, "nt:unstructured"));
+ assertEquals(maxSize, TraceMonitor.getSize());
+ }
+ }
+ }
+ }
+
+}
Index: api/src/test/resources/log4j.xml
===================================================================
--- api/src/test/resources/log4j.xml (revision 0)
+++ api/src/test/resources/log4j.xml (revision 0)
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+