You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ju...@apache.org on 2013/06/17 07:53:35 UTC

svn commit: r1493647 - in /jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak: ./ plugins/observation/ spi/whiteboard/

Author: jukka
Date: Mon Jun 17 05:53:34 2013
New Revision: 1493647

URL: http://svn.apache.org/r1493647
Log:
OAK-804: MBean to track observation listeners

Add listener MBeans based on the work in JCR-3608

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeProcessor.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ObservationManagerImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/WhiteboardUtils.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java?rev=1493647&r1=1493646&r2=1493647&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java Mon Jun 17 05:53:34 2013
@@ -29,6 +29,9 @@ import java.util.concurrent.TimeUnit;
 
 import javax.annotation.Nonnull;
 import javax.jcr.NoSuchWorkspaceException;
+import javax.management.JMException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
 import javax.security.auth.login.LoginException;
 
 import com.google.common.base.Function;
@@ -100,6 +103,8 @@ public class Oak {
 
     private ScheduledExecutorService executor = newScheduledThreadPool(0);
 
+    private MBeanServer mbeanServer;
+
     private String defaultWorkspaceName = DEFAULT_WORKSPACE_NAME;
 
     @SuppressWarnings("unchecked")
@@ -128,7 +133,6 @@ public class Oak {
                 Long period =
                         getValue(properties, "scheduler.period", Long.class);
                 if (period != null) {
-
                     Boolean concurrent = getValue(
                             properties, "scheduler.concurrent",
                             Boolean.class, Boolean.FALSE);
@@ -142,13 +146,36 @@ public class Oak {
                 }
             }
 
+            ObjectName objectName = null;
+            Object name = properties.get("jmx.objectname");
+            if (mbeanServer != null && name != null) {
+                try {
+                    if (name instanceof ObjectName) {
+                        objectName = (ObjectName) name;
+                    } else {
+                        objectName = new ObjectName(String.valueOf(name));
+                    }
+                    mbeanServer.registerMBean(service, objectName);
+                } catch (JMException e) {
+                    // ignore
+                }
+            }
+
             final Future<?> f = future;
+            final ObjectName on = objectName;
             return new Registration() {
                 @Override
                 public void unregister() {
                     if (f != null) {
                         f.cancel(false);
                     }
+                    if (on != null) {
+                        try {
+                            mbeanServer.unregisterMBean(on);
+                        } catch (JMException e) {
+                            // ignore
+                        }
+                    }
                 }
             };
         }
@@ -308,6 +335,12 @@ public class Oak {
     }
 
     @Nonnull
+    public Oak with(@Nonnull MBeanServer mbeanServer) {
+        this.mbeanServer = mbeanServer;
+        return this;
+    }
+
+    @Nonnull
     public Oak with(@Nonnull Whiteboard whiteboard) {
         this.whiteboard = whiteboard;
         return this;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeProcessor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeProcessor.java?rev=1493647&r1=1493646&r2=1493647&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeProcessor.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ChangeProcessor.java Mon Jun 17 05:53:34 2013
@@ -33,7 +33,9 @@ import com.google.common.base.Function;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Iterators;
 import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.jmx.EventListenerMBean;
 import org.apache.jackrabbit.commons.iterator.EventIteratorAdapter;
+import org.apache.jackrabbit.commons.observation.ListenerTracker;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
@@ -49,39 +51,37 @@ import org.apache.jackrabbit.oak.spi.whi
 import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.slf4j.Marker;
-import org.slf4j.MarkerFactory;
 
 class ChangeProcessor implements Runnable {
-    private static final Logger log = LoggerFactory.getLogger(ChangeProcessor.class);
-    private static final Marker DEPRECATED = MarkerFactory.getMarker("deprecated");
+
+    private static final Logger log =
+            LoggerFactory.getLogger(ChangeProcessor.class);
 
     private final ObservationManagerImpl observationManager;
     private final NamePathMapper namePathMapper;
-    private final EventListener listener;
     private final AtomicReference<EventFilter> filterRef;
     private final AtomicReference<String> userDataRef = new AtomicReference<String>(null);
 
-    private final Exception initStacktrace;
+    private final ListenerTracker tracker;
+    private final EventListener listener;
 
     private volatile Thread running = null;
     private volatile boolean stopping = false;
     private Runnable deferredUnregister;
 
-    private Registration registration;
+    private Registration runnable;
+    private Registration mbean;
     private Listener changeListener;
 
-    private boolean userInfoAccessedWithoutExternalsCheck;
-    private boolean userInfoAccessedFromExternalEvent;
-    private boolean dateAccessedWithoutExternalsCheck;
-    private boolean dateAccessedFromExternalEvent;
-
-    public ChangeProcessor(ObservationManagerImpl observationManager, EventListener listener, EventFilter filter) {
+    public ChangeProcessor(
+            ObservationManagerImpl observationManager,
+            ListenerTracker tracker,
+            EventFilter filter) {
         this.observationManager = observationManager;
         this.namePathMapper = observationManager.getNamePathMapper();
-        this.listener = listener;
+        this.tracker = tracker;
+        this.listener = tracker.getTrackedListener();
         filterRef = new AtomicReference<EventFilter>(filter);
-        initStacktrace = log.isWarnEnabled(DEPRECATED) ? new Exception("Initialized here") : null;
     }
 
     public void setFilter(EventFilter filter) {
@@ -98,12 +98,14 @@ class ChangeProcessor implements Runnabl
      * @throws IllegalStateException if started already
      */
     public synchronized void start(Whiteboard whiteboard) {
-        checkState(registration == null, "Change processor started already");
+        checkState(runnable == null, "Change processor started already");
 
         stopping = false;
         changeListener = observationManager.newChangeListener();
-        registration =
-                WhiteboardUtils.scheduleWithFixedDelay(whiteboard, this, 1);
+        runnable = WhiteboardUtils.scheduleWithFixedDelay(whiteboard, this, 1);
+        mbean = WhiteboardUtils.registerMBean(
+                whiteboard, EventListenerMBean.class, tracker.getListenerMBean(),
+                "ObservationListener", tracker.toString());
     }
 
     /**
@@ -140,9 +142,10 @@ class ChangeProcessor implements Runnabl
     }
 
     private void unregister() {
-        checkState(registration != null, "Change processor not started");
+        checkState(runnable != null, "Change processor not started");
+        mbean.unregister();
+        runnable.unregister();
         changeListener.dispose();
-        registration.unregister();
     }
 
     @Override
@@ -177,48 +180,6 @@ class ChangeProcessor implements Runnabl
         }
     }
 
-    synchronized void userInfoAccessedWithoutExternalCheck(Event event) {
-        if (!userInfoAccessedWithoutExternalsCheck) {
-            log.warn(DEPRECATED,
-                    "Event listener " + listener + " is trying to access"
-                    + " event user information on event " + event
-                    + " without checking whether the event is external."
-                    + " The event listener was registered here: ",  initStacktrace);
-            userInfoAccessedWithoutExternalsCheck = true;
-        }
-    }
-
-    synchronized void userInfoAccessedFromExternalEvent(Event event) {
-        if (!userInfoAccessedFromExternalEvent) {
-            log.warn(DEPRECATED,
-                    "Event listener " + listener + " is trying to access"
-                    + " event user information for external event " + event + '.'
-                    + " The event listener was registered here: ", initStacktrace);
-            userInfoAccessedFromExternalEvent = true;
-        }
-    }
-
-    synchronized void dateAccessedWithoutExternalCheck(Event event) {
-        if (!dateAccessedWithoutExternalsCheck) {
-            log.warn(DEPRECATED,
-                    "Event listener " + listener + " is trying to access"
-                    + " event date information on event " + event
-                    + " without checking whether the event is external."
-                    + " The event listener was registered here: ", initStacktrace);
-            dateAccessedWithoutExternalsCheck = true;
-        }
-    }
-
-    synchronized void dateAccessedFromExternalEvent(Event event) {
-        if (!dateAccessedFromExternalEvent) {
-            log.warn(DEPRECATED,
-                    "Event listener " + listener + " is trying to access"
-                    + " event date information for external event " + event + '.'
-                    + " The event listener was registered here: ", initStacktrace);
-            dateAccessedFromExternalEvent = true;
-        }
-    }
-
     //------------------------------------------------------------< private >---
 
     private class EventGeneratingNodeStateDiff extends RecursingNodeStateDiff {
@@ -339,8 +300,10 @@ class ChangeProcessor implements Runnabl
 
         private EventImpl createEvent(int eventType, String jcrPath, String id) {
             // TODO support info
-            return new EventImpl(ChangeProcessor.this, eventType, jcrPath, changes.getUserId(),
-                    id, null, changes.getDate(), userDataRef.get(), changes.isExternal());
+            return new EventImpl(
+                    eventType, jcrPath, changes.getUserId(),
+                    id, null, changes.getDate(), userDataRef.get(),
+                    changes.isExternal());
         }
 
         private String getRootId() {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventImpl.java?rev=1493647&r1=1493646&r2=1493647&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventImpl.java Mon Jun 17 05:53:34 2013
@@ -30,8 +30,6 @@ import org.apache.jackrabbit.api.observa
  * TODO document
  */
 public class EventImpl implements JackrabbitEvent {
-    private final ChangeProcessor collector;
-    private boolean externalAccessed;
 
     private final int type;
     private final String path;
@@ -43,10 +41,8 @@ public class EventImpl implements Jackra
     private final boolean external;
 
     public EventImpl(
-            ChangeProcessor processor,
             int type, String path, String userID, String identifier,
             Map<?, ?> info, long date, String userData, boolean external) {
-        this.collector = processor;
         this.type = type;
         this.path = path;
         this.userID = userID;
@@ -68,51 +64,32 @@ public class EventImpl implements Jackra
     }
 
     @Override
-    public synchronized String getUserID() {
-        if (!externalAccessed) {
-            collector.userInfoAccessedWithoutExternalCheck(this);
-        }
-        if (external) {
-            collector.userInfoAccessedFromExternalEvent(this);
-        }
+    public String getUserID() {
         return userID;
     }
 
     @Override
-    public String getIdentifier() throws RepositoryException {
+    public String getIdentifier() {
         return identifier;
     }
 
     @Override
-    public Map<?, ?> getInfo() throws RepositoryException {
+    public Map<?, ?> getInfo() {
         return info;
     }
 
     @Override
-    public String getUserData() throws RepositoryException {
-        if (!externalAccessed) {
-            collector.userInfoAccessedWithoutExternalCheck(this);
-        }
-        if (external) {
-            collector.userInfoAccessedFromExternalEvent(this);
-        }
+    public String getUserData() {
         return userData;
     }
 
     @Override
-    public long getDate() throws RepositoryException {
-        if (!externalAccessed) {
-            collector.dateAccessedWithoutExternalCheck(this);
-        }
-        if (external) {
-            collector.dateAccessedFromExternalEvent(this);
-        }
+    public long getDate() {
         return date;
     }
 
     @Override
     public synchronized boolean isExternal() {
-        externalAccessed = true;
         return external;
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ObservationManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ObservationManagerImpl.java?rev=1493647&r1=1493646&r2=1493647&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ObservationManagerImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/ObservationManagerImpl.java Mon Jun 17 05:53:34 2013
@@ -35,6 +35,7 @@ import javax.jcr.observation.Observation
 import com.google.common.base.Preconditions;
 
 import org.apache.jackrabbit.commons.iterator.EventListenerIteratorAdapter;
+import org.apache.jackrabbit.commons.observation.ListenerTracker;
 import org.apache.jackrabbit.oak.api.ContentSession;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
@@ -47,7 +48,12 @@ import org.slf4j.MarkerFactory;
 
 public class ObservationManagerImpl implements ObservationManager {
     private static final Logger log = LoggerFactory.getLogger(ObservationManagerImpl.class);
-    public static final Marker OBSERVATION = MarkerFactory.getMarker("observation");
+
+    public static final Marker OBSERVATION =
+            MarkerFactory.getMarker("observation");
+
+    private static final Marker DEPRECATED =
+            MarkerFactory.getMarker("deprecated");
 
     private final Map<EventListener, ChangeProcessor> processors = new HashMap<EventListener, ChangeProcessor>();
     private final AtomicBoolean hasEvents = new AtomicBoolean(false);
@@ -96,8 +102,16 @@ public class ObservationManagerImpl impl
                 absPath, isDeep, uuid, nodeTypeName, noLocal);
         ChangeProcessor processor = processors.get(listener);
         if (processor == null) {
-            log.error(OBSERVATION, "Registering event listener {} with filter {}", listener, filter);
-            processor = new ChangeProcessor(this, listener, filter);
+            log.info(OBSERVATION, "Registering event listener {} with filter {}", listener, filter);
+            ListenerTracker tracker = new ListenerTracker(
+                    listener, eventTypes, absPath, isDeep,
+                    uuid, nodeTypeName, noLocal) {
+                        @Override
+                        protected void warn(String message) {
+                            log.warn(DEPRECATED, message, initStackTrace);
+                        }
+            };
+            processor = new ChangeProcessor(this, tracker, filter);
             processors.put(listener, processor);
             processor.start(whiteboard);
         } else {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/WhiteboardUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/WhiteboardUtils.java?rev=1493647&r1=1493646&r2=1493647&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/WhiteboardUtils.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/WhiteboardUtils.java Mon Jun 17 05:53:34 2013
@@ -16,10 +16,18 @@
  */
 package org.apache.jackrabbit.oak.spi.whiteboard;
 
+import java.util.Hashtable;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
 import com.google.common.collect.ImmutableMap;
 
 public class WhiteboardUtils {
 
+    private static final AtomicLong COUNTER = new AtomicLong();
+
     public static Registration scheduleWithFixedDelay(
             Whiteboard whiteboard, Runnable runnable, long delay) {
         return whiteboard.register(
@@ -29,4 +37,20 @@ public class WhiteboardUtils {
                     .build());
     }
 
+    public static <T> Registration registerMBean(
+            Whiteboard whiteboard,
+            Class<T> iface, T bean, String type, String name) {
+        try {
+            Hashtable<String, String> table = new Hashtable<String, String>();
+            table.put("type", type);
+            table.put("name", name);
+            table.put("id", String.valueOf(COUNTER.incrementAndGet()));
+            return whiteboard.register(iface, bean, ImmutableMap.of(
+                    "jmx.objectname",
+                    new ObjectName("org.apache.jackrabbit.oak", table)));
+        } catch (MalformedObjectNameException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
 }