/* * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * 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.drools.core.management; import org.drools.core.common.InternalWorkingMemory; import org.drools.core.impl.InternalKnowledgeBase; import org.kie.api.builder.model.KieSessionModel; import org.kie.api.event.KieRuntimeEventManager; import org.kie.api.management.KieManagementAgentMBean; import org.kie.internal.runtime.StatelessKnowledgeSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.StandardMBean; import java.lang.management.ManagementFactory; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * The main management agent for Drools. The purpose of this * agent is to serve as a singleton for knowledge base and session * monitoring mbeans registration and management. */ public class DroolsManagementAgent implements KieManagementAgentMBean { private static final String CONTAINER_NAME_PREFIX = "org.kie"; private static DroolsManagementAgent INSTANCE; private static MBeanServer mbs; protected static final transient Logger logger = LoggerFactory.getLogger(DroolsManagementAgent.class); private long kbases; private long ksessions; private Map<Object, List<ObjectName>> mbeans; private Map<Object, Object> mbeansRefs = new HashMap<Object, Object>(); private DroolsManagementAgent() { kbases = 0; ksessions = 0; mbeans = new HashMap<Object, List<ObjectName>>(); } public static synchronized DroolsManagementAgent getInstance() { if ( INSTANCE == null ) { INSTANCE = new DroolsManagementAgent(); } return INSTANCE; } public static ObjectName createObjectNameFor(InternalKnowledgeBase kbase) { return DroolsManagementAgent.createObjectName( DroolsManagementAgent.createObjectNameBy(kbase.getContainerId()) + ",kbaseId=" + ObjectName.quote(kbase.getId()) ); } public static ObjectName createObjectNameFor(InternalWorkingMemory ksession) { return DroolsManagementAgent.createObjectName( DroolsManagementAgent.createObjectNameFor(ksession.getKnowledgeBase()) + ",group=Sessions,ksessionId=Session-"+ksession.getIdentifier()); } public static ObjectName createObjectNameBy(String containerId) { return DroolsManagementAgent.createObjectName(CONTAINER_NAME_PREFIX + ":kcontainerId="+ObjectName.quote(containerId)); } public static ObjectName createObjectNameBy(String containerId, String kbaseId, KieSessionModel.KieSessionType ksessionType, String ksessionName) { return DroolsManagementAgent.createObjectName(CONTAINER_NAME_PREFIX + ":kcontainerId="+ObjectName.quote(containerId) + ",kbaseId=" + ObjectName.quote(kbaseId) + ",ksessionType=" + ksessionType(ksessionType) + ",ksessionName=" + ObjectName.quote(ksessionName) ); } private static String ksessionType(KieSessionModel.KieSessionType ksessionType) { switch(ksessionType) { case STATELESS: return "Stateless"; case STATEFUL: default: return "Stateful"; } } public synchronized long getKieBaseCount() { return kbases; } public synchronized long getSessionCount() { return ksessions; } public synchronized long getNextKnowledgeBaseId() { return ++kbases; } public synchronized long getNextKnowledgeSessionId() { return ++ksessions; } public void registerKnowledgeBase(InternalKnowledgeBase kbase) { KnowledgeBaseMonitoring mbean = new KnowledgeBaseMonitoring( kbase ); registerMBean( kbase, mbean, mbean.getName() ); } public void unregisterKnowledgeBase(InternalKnowledgeBase kbase) { unregisterMBeansFromOwner(kbase); } public void registerKnowledgeSessionUnderName(CBSKey cbsKey, KieRuntimeEventManager ksession) { GenericKieSessionMonitoringImpl bean = getKnowledgeSessionBean(cbsKey, ksession); if (bean != null) { bean.attach(ksession); } } public void unregisterKnowledgeSessionUnderName(CBSKey cbsKey, KieRuntimeEventManager ksession) { GenericKieSessionMonitoringImpl bean = getKnowledgeSessionBean(cbsKey, ksession); if (bean != null) { bean.detach(ksession); } } public void unregisterKnowledgeSessionBean(CBSKey cbsKey) { unregisterMBeansFromOwner(cbsKey); } /** * Get currently registered session monitor, eventually creating it if necessary. * @return the currently registered or newly created session monitor, or null if unable to create and register it on the JMX server. */ private GenericKieSessionMonitoringImpl getKnowledgeSessionBean(CBSKey cbsKey, KieRuntimeEventManager ksession) { if (mbeansRefs.get(cbsKey) != null) { return (GenericKieSessionMonitoringImpl) mbeansRefs.get(cbsKey); } else { if (ksession instanceof StatelessKnowledgeSession) { synchronized (mbeansRefs) { if (mbeansRefs.get(cbsKey) != null) { return (GenericKieSessionMonitoringImpl) mbeansRefs.get(cbsKey); } else { try { StatelessKieSessionMonitoringImpl mbean = new StatelessKieSessionMonitoringImpl( cbsKey.kcontainerId, cbsKey.kbaseId, cbsKey.ksessionName ); registerMBean( cbsKey, mbean, mbean.getName() ); mbeansRefs.put(cbsKey, mbean); return mbean; } catch ( Exception e ) { logger.error("Unable to instantiate and register StatelessKieSessionMonitoringMBean"); } return null; } } } else { synchronized (mbeansRefs) { if (mbeansRefs.get(cbsKey) != null) { return (GenericKieSessionMonitoringImpl) mbeansRefs.get(cbsKey); } else { try { KieSessionMonitoringImpl mbean = new KieSessionMonitoringImpl( cbsKey.kcontainerId, cbsKey.kbaseId, cbsKey.ksessionName ); registerMBean( cbsKey, mbean, mbean.getName() ); mbeansRefs.put(cbsKey, mbean); return mbean; } catch ( Exception e ) { logger.error("Unable to instantiate and register (stateful) KieSessionMonitoringMBean"); } return null; } } } } } public void registerMBean(Object owner, Object mbean, ObjectName name) { try { MBeanServer mbs = getMBeanServer(); if ( !mbs.isRegistered( name ) ) { mbs.registerMBean( mbean, name ); List<ObjectName> mbl = mbeans.get( owner ); if ( mbl == null ) { mbl = new LinkedList<ObjectName>(); mbeans.put( owner, mbl ); if (mbean instanceof StandardMBean) { mbeansRefs.put(owner, ((StandardMBean) mbean).getImplementation()); } else { mbeansRefs.put(owner, mbean); } } mbl.add( name ); logger.debug( "Registered {} into the platform MBean Server", name ); } } catch ( Exception e ) { logger.error( "Unable to register mbean " + name + " into the platform MBean Server", e ); } } public void unregisterMBeansFromOwner(Object owner) { List<ObjectName> mbl = mbeans.remove( owner ); mbeansRefs.remove(owner); if ( mbl != null ) { MBeanServer mbs = getMBeanServer(); for ( ObjectName name : mbl ) { unregisterMBeanFromServer( mbs, name ); } } } private void unregisterMBeanFromServer(MBeanServer mbs, ObjectName name) { try { mbs.unregisterMBean( name ); logger.debug( "Unregistered from MBean Server: {}", name); } catch ( Exception e ) { logger.error( "Exception unregistering mbean: " + name, e); } } public void unregisterMBean( Object owner, ObjectName mbean ) { List<ObjectName> mbl = mbeans.get( owner ); if( mbl != null ) { mbl.remove( mbean ); } MBeanServer mbs = getMBeanServer(); unregisterMBeanFromServer( mbs, mbean ); } public void unregisterDependentsMBeansFromOwner(Object owner) { List<ObjectName> mbl = mbeans.get( owner ); if ( mbl != null ) { MBeanServer mbs = getMBeanServer(); for ( ObjectName name : mbl.subList( 1, mbl.size() ) ) { unregisterMBeanFromServer( mbs, name ); } mbl.subList( 1, mbl.size() ).clear(); } } public static ObjectName createObjectName(String name) { try { return new ObjectName( name ); } catch ( Exception e ) { logger.error( "This is a bug. Error creating ObjectName for MBean: " + name + "\nPlease contact the development team and provide the following stack trace: " + e.getMessage(), e); return null; } } private static MBeanServer getMBeanServer() { if ( mbs == null ) { mbs = ManagementFactory.getPlatformMBeanServer(); } return mbs; } public static class CBSKey { private final String kcontainerId; private final String kbaseId; private final String ksessionName; public CBSKey(String kcontainerId, String kbaseId, String ksessionName) { super(); this.kcontainerId = kcontainerId; this.kbaseId = kbaseId; this.ksessionName = ksessionName; } public String getKcontainerId() { return kcontainerId; } public String getKbaseId() { return kbaseId; } public String getKsessionName() { return ksessionName; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((kbaseId == null) ? 0 : kbaseId.hashCode()); result = prime * result + ((kcontainerId == null) ? 0 : kcontainerId.hashCode()); result = prime * result + ((ksessionName == null) ? 0 : ksessionName.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof CBSKey)) return false; CBSKey other = (CBSKey) obj; if (kbaseId == null) { if (other.kbaseId != null) return false; } else if (!kbaseId.equals(other.kbaseId)) return false; if (kcontainerId == null) { if (other.kcontainerId != null) return false; } else if (!kcontainerId.equals(other.kcontainerId)) return false; if (ksessionName == null) { if (other.ksessionName != null) return false; } else if (!ksessionName.equals(other.ksessionName)) return false; return true; } @Override public String toString() { return "CBSKey [kcontainerId=" + kcontainerId + ", kbaseId=" + kbaseId + ", ksessionName=" + ksessionName + "]"; } } }