/* * Copyright 2009-2010 Rickard Öberg AB * Copyright 2012 Paul Merlin * * 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.qi4j.library.circuitbreaker.jmx; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.HashMap; import java.util.Map; import javax.management.JMException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.qi4j.api.activation.ActivatorAdapter; import org.qi4j.api.activation.Activators; import org.qi4j.api.injection.scope.Service; import org.qi4j.api.injection.scope.Structure; import org.qi4j.api.mixin.Mixins; import org.qi4j.api.service.ServiceComposite; import org.qi4j.api.service.ServiceReference; import org.qi4j.api.structure.Application; import org.qi4j.library.circuitbreaker.CircuitBreaker; import org.qi4j.library.circuitbreaker.service.ServiceCircuitBreaker; import org.qi4j.library.jmx.Qi4jMBeans; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * JMX service that exposes ServiceCircuitBreakers as MBeans. * Logs exposed CircuitBreakers state changes. */ @Mixins( CircuitBreakerManagement.Mixin.class ) @Activators( CircuitBreakerManagement.Activator.class ) public interface CircuitBreakerManagement extends ServiceComposite { /** * Expose all visible CircuitBreakers in JMX. */ void registerCircuitBreakers() throws JMException; /** * Unregister all exposed CircuitBreakers. */ void unregisterCircuitBreakers() throws JMException; class Activator extends ActivatorAdapter<ServiceReference<CircuitBreakerManagement>> { @Override public void afterActivation( ServiceReference<CircuitBreakerManagement> activated ) throws Exception { activated.get().registerCircuitBreakers(); } @Override public void beforePassivation( ServiceReference<CircuitBreakerManagement> passivating ) throws Exception { passivating.get().unregisterCircuitBreakers(); } } abstract class Mixin implements CircuitBreakerManagement { private static final Logger LOGGER = LoggerFactory.getLogger( CircuitBreakerManagement.class ); private final Map<CircuitBreaker, ObjectName> registeredCircuitBreakers = new HashMap<CircuitBreaker, ObjectName>(); @Structure private Application application; @Service private MBeanServer server; @Service Iterable<ServiceReference<ServiceCircuitBreaker>> circuitBreakers; @Override public void registerCircuitBreakers() throws JMException { for ( ServiceReference<ServiceCircuitBreaker> circuitBreaker : circuitBreakers ) { registerCircuitBreaker( circuitBreaker.get().circuitBreaker(), circuitBreaker.identity() ); } } @Override public void unregisterCircuitBreakers() throws JMException { for ( ObjectName objectName : registeredCircuitBreakers.values() ) { server.unregisterMBean( objectName ); } registeredCircuitBreakers.clear(); } private void registerCircuitBreaker( final CircuitBreaker circuitBreaker, final String name ) throws JMException { ObjectName mbeanObjectName = null; ObjectName serviceName = Qi4jMBeans.findServiceName( server, application.name(), name ); if ( serviceName != null ) { mbeanObjectName = new ObjectName( serviceName.toString() + ",name=Circuit breaker" ); } else { try { mbeanObjectName = new ObjectName( "CircuitBreaker:name=" + name ); } catch ( MalformedObjectNameException e ) { throw new IllegalArgumentException( "Illegal name:" + name ); } } CircuitBreakerJMX bean = new CircuitBreakerJMX( circuitBreaker, mbeanObjectName ); server.registerMBean( bean, mbeanObjectName ); registeredCircuitBreakers.put( circuitBreaker, mbeanObjectName ); // Add logger circuitBreaker.addPropertyChangeListener( new PropertyChangeListener() { @Override public void propertyChange( PropertyChangeEvent evt ) { if ( "status".equals( evt.getPropertyName() ) ) { if ( CircuitBreaker.Status.on.equals( evt.getNewValue() ) ) { LOGGER.info( "Circuit breaker " + name + " is now on" ); } else { LOGGER.error( "Circuit breaker " + name + " is now off" ); } } } } ); } } }