You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2014/01/10 15:02:02 UTC

svn commit: r1557124 - in /sling/trunk/bundles/extensions/healthcheck/core/src: main/java/org/apache/sling/hc/jmx/ main/java/org/apache/sling/hc/jmx/impl/ test/java/org/apache/sling/hc/jmx/ test/java/org/apache/sling/hc/jmx/impl/

Author: cziegeler
Date: Fri Jan 10 14:02:01 2014
New Revision: 1557124

URL: http://svn.apache.org/r1557124
Log:
SLING-3312 : Move JMX bean registration into core module

Added:
    sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/
    sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/
    sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBean.java   (with props)
    sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanCreator.java   (with props)
    sling/trunk/bundles/extensions/healthcheck/core/src/test/java/org/apache/sling/hc/jmx/
    sling/trunk/bundles/extensions/healthcheck/core/src/test/java/org/apache/sling/hc/jmx/impl/
    sling/trunk/bundles/extensions/healthcheck/core/src/test/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanTest.java   (with props)

Added: sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBean.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBean.java?rev=1557124&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBean.java (added)
+++ sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBean.java Fri Jan 10 14:02:01 2014
@@ -0,0 +1,261 @@
+/*
+ * 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 SF 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.sling.hc.jmx.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.InvalidAttributeValueException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.ReflectionException;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
+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;
+
+import org.apache.sling.hc.api.HealthCheck;
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.api.ResultLog;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/** A {@link DynamicMBean} used to execute a {@link HealthCheck} service */
+public class HealthCheckMBean implements DynamicMBean {
+
+    /** A HC result is cached for this time (ms) */
+    private static final long RESULT_TTL = 1500;
+
+    public static final String HC_OK_ATTRIBUTE_NAME = "ok";
+    public static final String HC_STATUS_ATTRIBUTE_NAME = "status";
+    public static final String HC_LOG_ATTRIBUTE_NAME = "log";
+
+    private static CompositeType LOG_ROW_TYPE;
+    private static TabularType LOG_TABLE_TYPE;
+
+    public static final String INDEX_COLUMN = "index";
+    public static final String LEVEL_COLUMN = "level";
+    public static final String MESSAGE_COLUMN = "message";
+
+    public static final String JMX_TYPE_NAME = "HealthCheck";
+    public static final String JMX_DOMAIN = "org.apache.sling.healthcheck";
+
+    /** The health check service to call. */
+    private final HealthCheck healthCheck;
+
+    /** The mbean info. */
+    private final MBeanInfo mbeanInfo;
+
+    /** The default attributes. */
+    private final Map<String, Object> defaultAttributes;
+
+    private long healthCheckInvocationTime;
+
+    private Result healthCheckResult;
+
+    static {
+        try {
+            // Define the log row and table types
+            LOG_ROW_TYPE = new CompositeType(
+                    "LogLine",
+                    "A line in the result log",
+                    new String [] { INDEX_COLUMN, LEVEL_COLUMN, MESSAGE_COLUMN },
+                    new String [] { "log line index", "log level", "log message"},
+                    new OpenType[] { SimpleType.INTEGER, SimpleType.STRING, SimpleType.STRING }
+                    );
+            final String [] indexes = { INDEX_COLUMN };
+            LOG_TABLE_TYPE = new TabularType("LogTable", "Result log messages", LOG_ROW_TYPE, indexes);
+        } catch(Exception ignore) {
+            // row or table type will be null if this happens
+        }
+    }
+
+    public HealthCheckMBean(final ServiceReference ref, final HealthCheck hc) {
+        this.healthCheck = hc;
+        this.mbeanInfo = this.createMBeanInfo(ref);
+        this.defaultAttributes = this.createDefaultAttributes(ref);
+    }
+
+    @Override
+    public Object getAttribute(final String attribute)
+    throws AttributeNotFoundException, MBeanException, ReflectionException {
+        // we should call getAttributes - and not vice versa to have the result
+        // of a single check call - and not do a check call for each attribute
+        final AttributeList result = this.getAttributes(new String[] {attribute});
+        if ( result.size() == 0 ) {
+            throw new AttributeNotFoundException(attribute);
+        }
+        final Attribute attr = (Attribute) result.get(0);
+        return attr.getValue();
+    }
+
+    private TabularData logData(final Result er) throws OpenDataException {
+        final TabularDataSupport result = new TabularDataSupport(LOG_TABLE_TYPE);
+        int i = 1;
+        for(final ResultLog.Entry e : er) {
+            final Map<String, Object> data = new HashMap<String, Object>();
+            data.put(INDEX_COLUMN, i++);
+            data.put(LEVEL_COLUMN, e.getStatus().toString());
+            data.put(MESSAGE_COLUMN, e.getMessage());
+
+            result.put(new CompositeDataSupport(LOG_ROW_TYPE, data));
+        }
+        return result;
+    }
+
+    @Override
+    public AttributeList getAttributes(final String[] attributes) {
+        final AttributeList result = new AttributeList();
+        if ( attributes != null ) {
+            Result hcResult = null;
+            for(final String key : attributes) {
+                final Object defaultValue = this.defaultAttributes.get(key);
+                if ( defaultValue != null ) {
+                    result.add(new Attribute(key, defaultValue));
+                } else {
+                    // we assume that a valid attribute name is used
+                    // which is requesting a hc result
+                    if ( hcResult == null ) {
+                        hcResult = this.getHealthCheckResult();
+                    }
+
+                    if ( HC_OK_ATTRIBUTE_NAME.equals(key) ) {
+                        result.add(new Attribute(key, hcResult.isOk()));
+                    } else if ( HC_LOG_ATTRIBUTE_NAME.equals(key) ) {
+                        try {
+                            result.add(new Attribute(key, logData(hcResult)));
+                        } catch ( final OpenDataException ignore ) {
+                            // we ignore this and simply don't add the attribute
+                        }
+                    } else if ( HC_STATUS_ATTRIBUTE_NAME.equals(key) ) {
+                        result.add(new Attribute(key, hcResult.getStatus().toString()));
+                    }
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Create the mbean info
+     */
+    private MBeanInfo createMBeanInfo(final ServiceReference serviceReference) {
+        final List<MBeanAttributeInfo> attrs = new ArrayList<MBeanAttributeInfo>();
+
+        // add relevant service properties
+        if ( serviceReference.getProperty(HealthCheck.NAME) != null ) {
+            attrs.add(new MBeanAttributeInfo(HealthCheck.NAME, String.class.getName(), "The name of the health check service.", true, false, false));
+        }
+        if ( serviceReference.getProperty(HealthCheck.TAGS) != null ) {
+            attrs.add(new MBeanAttributeInfo(HealthCheck.TAGS, String.class.getName(), "The tags of the health check service.", true, false, false));
+        }
+        if ( serviceReference.getProperty(Constants.SERVICE_PID) != null ) {
+            attrs.add(new MBeanAttributeInfo(Constants.SERVICE_PID, String.class.getName(), "The persistence identifier of the service.", true, false, false));
+        }
+
+        // add standard attributes
+        attrs.add(new MBeanAttributeInfo(HC_OK_ATTRIBUTE_NAME, Boolean.class.getName(), "The health check result", true, false, false));
+        attrs.add(new MBeanAttributeInfo(HC_STATUS_ATTRIBUTE_NAME, String.class.getName(), "The health check status", true, false, false));
+
+        attrs.add(new OpenMBeanAttributeInfoSupport(HC_LOG_ATTRIBUTE_NAME, "The health check result log", LOG_TABLE_TYPE, true, false, false));
+
+        final String description;
+        if ( serviceReference.getProperty(Constants.SERVICE_DESCRIPTION) != null ) {
+            description = serviceReference.getProperty(Constants.SERVICE_DESCRIPTION).toString();
+        } else {
+            description = "Health check";
+        }
+        return new MBeanInfo(this.getClass().getName(),
+                   description,
+                   attrs.toArray(new MBeanAttributeInfo[attrs.size()]), null, null, null);
+    }
+
+    /**
+     * Create the default attributes.
+     */
+    private Map<String, Object> createDefaultAttributes(final ServiceReference serviceReference) {
+        final Map<String, Object> list = new HashMap<String, Object>();
+        if ( serviceReference.getProperty(HealthCheck.NAME) != null ) {
+            list.put(HealthCheck.NAME, serviceReference.getProperty(HealthCheck.NAME).toString());
+        }
+        if ( serviceReference.getProperty(HealthCheck.TAGS) != null ) {
+            final Object value = serviceReference.getProperty(HealthCheck.TAGS);
+            if ( value instanceof String[] ) {
+                list.put(HealthCheck.TAGS, Arrays.toString((String[])value));
+            } else {
+                list.put(HealthCheck.TAGS, value.toString());
+            }
+        }
+        if ( serviceReference.getProperty(Constants.SERVICE_PID) != null ) {
+            list.put(Constants.SERVICE_PID, serviceReference.getProperty(Constants.SERVICE_PID).toString());
+        }
+        return list;
+    }
+
+    @Override
+    public MBeanInfo getMBeanInfo() {
+        return this.mbeanInfo;
+    }
+
+    @Override
+    public Object invoke(final String actionName, final Object[] params, final String[] signature)
+            throws MBeanException, ReflectionException {
+        throw new MBeanException(new UnsupportedOperationException(getClass().getSimpleName() + " does not support operations."));
+    }
+
+    @Override
+    public void setAttribute(final Attribute attribute)
+    throws AttributeNotFoundException, InvalidAttributeValueException,
+            MBeanException, ReflectionException {
+        throw new MBeanException(new UnsupportedOperationException(getClass().getSimpleName() + " does not support setting attributes."));
+    }
+
+    @Override
+    public AttributeList setAttributes(final AttributeList attributes) {
+        return new AttributeList();
+    }
+
+    @Override
+    public String toString() {
+        return "HealthCheckMBean [healthCheck=" + healthCheck + "]";
+    }
+
+    private Result getHealthCheckResult() {
+        synchronized ( this ) {
+            if ( this.healthCheckResult == null || this.healthCheckInvocationTime < System.currentTimeMillis() ) {
+                this.healthCheckResult = this.healthCheck.execute();
+                this.healthCheckInvocationTime = System.currentTimeMillis() + RESULT_TTL;
+            }
+            return this.healthCheckResult;
+        }
+    }
+}
\ No newline at end of file

Propchange: sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBean.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBean.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBean.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanCreator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanCreator.java?rev=1557124&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanCreator.java (added)
+++ sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanCreator.java Fri Jan 10 14:02:01 2014
@@ -0,0 +1,192 @@
+/*
+ * 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 SF 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.sling.hc.jmx.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.DynamicMBean;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.sling.hc.api.HealthCheck;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Creates an {@link HealthCheckMbean} for every {@link HealthCheckMBean} service
+ *
+ */
+@Component
+public class HealthCheckMBeanCreator {
+
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+
+    private final Map<ServiceReference, Registration> registeredServices = new HashMap<ServiceReference, Registration>();
+
+    private final Map<String, List<ServiceReference>> sortedRegistrations = new HashMap<String, List<ServiceReference>>();
+
+    private ServiceTracker hcTracker;
+
+    @Activate
+    protected void activate(final BundleContext btx) {
+        this.hcTracker = new ServiceTracker(btx, HealthCheck.class.getName(), null) {
+
+            @Override
+            public Object addingService(final ServiceReference reference) {
+                return registerHCMBean(btx, reference);
+            }
+
+            @Override
+            public void modifiedService(final ServiceReference reference,
+                    final Object service) {
+                unregisterHCMBean(btx, reference);
+                registerHCMBean(btx, reference);
+            }
+
+            @Override
+            public void removedService(final ServiceReference reference,
+                    final Object service) {
+                unregisterHCMBean(btx, reference);
+            }
+
+        };
+        this.hcTracker.open();
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        if ( this.hcTracker != null ) {
+            this.hcTracker.close();
+            this.hcTracker = null;
+        }
+    }
+
+    /**
+     * Register an mbean for a health check service.
+     * The mbean is only registered if
+     * - the service has an mbean registration property
+     * - if there is no other service with the same name but a higher service ranking
+     *
+     * @param bundleContext The bundle context
+     * @param reference     The service reference to the health check service
+     * @return The registered mbean or <code>null</code>
+     */
+    private synchronized Object registerHCMBean(final BundleContext bundleContext, final ServiceReference reference) {
+        final Registration reg = Registration.getRegistration(bundleContext, reference);
+        if ( reg != null ) {
+            this.registeredServices.put(reference, reg);
+
+            List<ServiceReference> registered = this.sortedRegistrations.get(reg.name);
+            if ( registered == null ) {
+                registered = new ArrayList<ServiceReference>();
+                this.sortedRegistrations.put(reg.name, registered);
+            }
+            registered.add(reference);
+            // sort orders the references with lowest ranking first
+            // we want the highest!
+            Collections.sort(registered);
+            final int lastIndex = registered.size() - 1;
+            if ( registered.get(lastIndex).equals(reference) ) {
+                if ( registered.size() > 1 ) {
+                    final ServiceReference prevRef = registered.get(lastIndex - 1);
+                    final Registration prevReg = this.registeredServices.get(prevRef);
+                    prevReg.unregister(this.logger);
+                }
+                reg.register(this.logger, bundleContext);
+            }
+        }
+        return reg;
+    }
+
+    private synchronized void unregisterHCMBean(final BundleContext bundleContext, final ServiceReference ref) {
+        final Registration reg = registeredServices.remove(ref);
+        if ( reg != null ) {
+            final boolean registerFirst = reg.unregister(this.logger);
+            final List<ServiceReference> registered = this.sortedRegistrations.get(reg.name);
+            registered.remove(ref);
+            if ( registered.size() == 0 ) {
+                this.sortedRegistrations.remove(reg.name);
+            } else if ( registerFirst ) {
+                final ServiceReference newRef = registered.get(0);
+                final Registration newReg = this.registeredServices.get(newRef);
+                newReg.register(this.logger, bundleContext);
+            }
+            bundleContext.ungetService(ref);
+        }
+    }
+
+    private static final class Registration {
+        public final String name;
+        public final HealthCheckMBean mbean;
+        private ServiceRegistration registration;
+
+        public Registration(final String name, final HealthCheckMBean mbean) {
+            this.name = name;
+            this.mbean = mbean;
+        }
+
+        public static Registration getRegistration(final BundleContext bundleContext, final ServiceReference ref) {
+            final Object nameObj = ref.getProperty(HealthCheck.MBEAN_NAME);
+            if ( nameObj != null ) {
+                final HealthCheck service = (HealthCheck) bundleContext.getService(ref);
+                if ( service != null ) {
+                    final HealthCheckMBean mbean = new HealthCheckMBean(ref, service);
+
+                    return new Registration(nameObj.toString().replace(',', '.'), mbean);
+                }
+            }
+            return null;
+        }
+
+        public void register(final Logger logger, final BundleContext btx) {
+            final StringBuilder sb = new StringBuilder(HealthCheckMBean.JMX_DOMAIN);
+            sb.append(":type=");
+            sb.append(HealthCheckMBean.JMX_TYPE_NAME);
+            sb.append(",name=");
+            sb.append(this.name);
+            final String objectName = sb.toString();
+
+            final Dictionary<String, String> mbeanProps = new Hashtable<String, String>();
+            mbeanProps.put("jmx.objectname", objectName);
+            this.registration = btx.registerService(DynamicMBean.class.getName(), this.mbean, mbeanProps);
+
+            logger.debug("Registered health check mbean {} as {}", this.mbean, objectName);
+        }
+
+        public boolean unregister(final Logger logger) {
+            if ( this.registration != null ) {
+                this.registration.unregister();
+                this.registration = null;
+                logger.debug("Unregistered health check mbean {}", this.mbean);
+                return true;
+            }
+            return false;
+        }
+    }
+}

Propchange: sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanCreator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanCreator.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/bundles/extensions/healthcheck/core/src/main/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanCreator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/extensions/healthcheck/core/src/test/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/healthcheck/core/src/test/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanTest.java?rev=1557124&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/healthcheck/core/src/test/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanTest.java (added)
+++ sling/trunk/bundles/extensions/healthcheck/core/src/test/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanTest.java Fri Jan 10 14:02:01 2014
@@ -0,0 +1,118 @@
+/*
+ * 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 SF 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.sling.hc.jmx.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.sling.hc.api.HealthCheck;
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.api.ResultLog;
+import org.apache.sling.hc.util.SimpleConstraintChecker;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+public class HealthCheckMBeanTest {
+    private final MBeanServer jmxServer = ManagementFactory.getPlatformMBeanServer();
+    private boolean resultOk;
+    public static final String OBJECT_NAME = "org.apache.sling.testing:type=HealthCheckMBeanTest";
+
+    private HealthCheck testHealthCheck = new HealthCheck() {
+
+        @Override
+        public Result execute() {
+            if(resultOk) {
+                return new Result(Result.Status.OK, "Nothing to report, result ok");
+            } else {
+                return new Result(Result.Status.WARN, "Result is not ok!");
+            }
+        }
+    };
+
+    private void assertJmxValue(String mbeanName, String attributeName, String constraint, boolean expected) throws Exception {
+        final MBeanServer jmxServer = ManagementFactory.getPlatformMBeanServer();
+        final ObjectName objectName = new ObjectName(mbeanName);
+        if(jmxServer.queryNames(objectName, null).size() == 0) {
+            fail("MBean not found: " + objectName);
+        }
+        final Object value = jmxServer.getAttribute(objectName, attributeName);
+        final ResultLog resultLog = new ResultLog();
+        new SimpleConstraintChecker().check(value, constraint, resultLog);
+        assertEquals("Expecting result " + expected + "(" + resultLog + ")", expected, resultLog.getAggregateStatus().equals(Result.Status.OK));
+
+    }
+
+    @Test
+    public void testBean() throws Exception {
+        final ServiceReference ref = new ServiceReference() {
+
+            @Override
+            public boolean isAssignableTo(Bundle bundle, String className) {
+                return false;
+            }
+
+            @Override
+            public Bundle[] getUsingBundles() {
+                return null;
+            }
+
+            @Override
+            public String[] getPropertyKeys() {
+                return null;
+            }
+
+            @Override
+            public Object getProperty(String key) {
+                return null;
+            }
+
+            @Override
+            public Bundle getBundle() {
+                return null;
+            }
+
+            @Override
+            public int compareTo(Object reference) {
+                return 0;
+            }
+        };
+        final HealthCheckMBean mbean = new HealthCheckMBean(ref, testHealthCheck);
+        final ObjectName name = new ObjectName(OBJECT_NAME);
+        jmxServer.registerMBean(mbean, name);
+        try {
+            resultOk = true;
+            assertJmxValue(OBJECT_NAME, "ok", "true", true);
+
+            Thread.sleep(1500);
+            resultOk = false;
+            assertJmxValue(OBJECT_NAME, "ok", "true", false);
+
+            Thread.sleep(1500);
+            assertJmxValue(OBJECT_NAME, "log", "contains message=Result is not ok!", true);
+        } finally {
+            jmxServer.unregisterMBean(name);
+        }
+    }
+
+}
\ No newline at end of file

Propchange: sling/trunk/bundles/extensions/healthcheck/core/src/test/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/extensions/healthcheck/core/src/test/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/bundles/extensions/healthcheck/core/src/test/java/org/apache/sling/hc/jmx/impl/HealthCheckMBeanTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain