GestoreRisorseJMX.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */


  20. package org.openspcoop2.utils.jmx;

  21. import java.lang.reflect.Constructor;
  22. import java.lang.reflect.Method;
  23. import java.util.ArrayList;
  24. import java.util.HashMap;
  25. import java.util.List;
  26. import java.util.Properties;

  27. import javax.management.MBeanServer;
  28. import javax.management.ObjectName;
  29. import javax.naming.Context;

  30. import org.openspcoop2.utils.LoggerWrapperFactory;
  31. import org.openspcoop2.utils.resources.ClassLoaderUtilities;
  32. import org.openspcoop2.utils.resources.GestoreJNDI;
  33. import org.slf4j.Logger;


  34. /**
  35.  * Gestore risorse JMX utilizzate da OpenSPCoop
  36.  *  
  37.  * @author Poli Andrea (apoli@link.it)
  38.  * @author $Author$
  39.  * @version $Rev$, $Date$
  40.  */
  41. public class GestoreRisorseJMX {

  42.     /** MBeanServer */
  43.     private MBeanServer mbeanServer  = null;
  44.     /** MBeanServerConnection */
  45.     private Object mbeanServerConnection = null;
  46.     /** Logger */
  47.     protected Logger log = null;
  48.     protected void logInfo(String msg) {
  49.         if(this.log!=null && this.logActive) {
  50.             this.log.info(msg);
  51.         }
  52.     }
  53.     protected void logDebug(String msg, Throwable e) {
  54.         if(this.log!=null && this.logActive) {
  55.             this.log.debug(msg, e);
  56.         }
  57.     }
  58.     protected void logError(String msg, Throwable e) {
  59.         if(this.log!=null && this.logActive) {
  60.             this.log.error(msg, e);
  61.         }
  62.     }
  63.     private boolean logActive = true;  
  64.     public boolean isLogActive() {
  65.         return this.logActive;
  66.     }
  67.     public void setLogActive(boolean logActive) {
  68.         this.logActive = logActive;
  69.     }
  70.    
  71.     private static final String MBEAN_SERVER_CONNECTION = "javax.management.MBeanServerConnection";
  72.    
  73.     /** JMX Name */
  74.     private List<ObjectName> jmxNames = new ArrayList<>();
  75.    
  76.    
  77.     /**
  78.      * Inizializzazione del Gestore delle risorse JMX
  79.      */
  80.     public GestoreRisorseJMX() throws RisorseJMXException{
  81.         this(null,null,null);
  82.     }
  83.     public GestoreRisorseJMX(Logger logger) throws RisorseJMXException{
  84.         this(null,null,logger);
  85.     }
  86.     /**
  87.      * Inizializzazione del Gestore delle risorse JMX
  88.      *
  89.      * @param jndiNameMBeanServer Nome JNDI del MBean Server
  90.      * @param jndiContext Contesto jndi per localizzare il MBean Server
  91.      */
  92.     public GestoreRisorseJMX(String jndiNameMBeanServer,java.util.Properties jndiContext) throws RisorseJMXException{
  93.         this(jndiNameMBeanServer,jndiContext,null,null);
  94.     }
  95.     public GestoreRisorseJMX(String jndiNameMBeanServer,java.util.Properties jndiContext,Logger logger) throws RisorseJMXException{
  96.         this(jndiNameMBeanServer,jndiContext,logger,null);
  97.     }
  98.     public GestoreRisorseJMX(String jndiNameMBeanServer,java.util.Properties jndiContext,Logger logger,Logger loggerConsole) throws RisorseJMXException{
  99.         this(jndiNameMBeanServer,jndiContext,
  100.                 null,null,null,null,null,
  101.                 logger,loggerConsole);
  102.     }
  103.    
  104.     public GestoreRisorseJMX(String tipoApplicationServer, String factory, String serverUrl, String username,  String password) throws RisorseJMXException{
  105.         this(null,null,
  106.                 tipoApplicationServer,factory,serverUrl,username,password,
  107.                 null,null);
  108.     }
  109.     public GestoreRisorseJMX(String tipoApplicationServer, String factory, String serverUrl, String username,  String password,
  110.             Logger logger) throws RisorseJMXException{
  111.         this(null,null,
  112.                 tipoApplicationServer,factory,serverUrl,username,password,
  113.                 logger,null);
  114.     }
  115.     public GestoreRisorseJMX(String tipoApplicationServer, String factory, String serverUrl, String username,  String password,
  116.             Logger logger,Logger loggerConsole) throws RisorseJMXException{
  117.         this(null,null,
  118.                 tipoApplicationServer,factory,serverUrl,username,password,
  119.                 logger,loggerConsole);
  120.     }
  121.    
  122.     private GestoreRisorseJMX(String modalita1JndiNameMBeanServer,java.util.Properties modalita1JndiContext,
  123.             String modalita2TipoApplicationServer, String modalita2Factory, String modalita2ServerUrl, String modalita2Username,  String modalita2Password,
  124.             Logger logger,Logger loggerConsole) throws RisorseJMXException{
  125.    
  126.         // log
  127.         if(logger==null){
  128.             this.log = LoggerWrapperFactory.getLogger(GestoreRisorseJMX.class);
  129.         }
  130.         else{
  131.             this.log = logger;
  132.         }
  133.        
  134.         // logConsole
  135.         if(loggerConsole==null){
  136.             loggerConsole = LoggerWrapperFactory.getLogger("govway.startup");
  137.         }
  138.        
  139.         try{
  140.             //  Ci sono tre modi per avere l'MBean SERVER
  141.            
  142.             // 1: da JNDI
  143.             if(modalita1JndiNameMBeanServer!=null){
  144.                 GestoreJNDI jndi = new GestoreJNDI(modalita1JndiContext);
  145.                 this.mbeanServer = (javax.management.MBeanServer) jndi.lookup(modalita1JndiNameMBeanServer);
  146.                 if(this.mbeanServer==null)
  147.                     throw new RisorseJMXException("MBeanServer ["+modalita1JndiNameMBeanServer+"] non trovato");
  148.                 else{
  149.                     String msg = "Attivata gestione jmx attraverso MBeanServer ["+modalita1JndiNameMBeanServer+"]: "+this.mbeanServer.toString();
  150.                     if(logger==null) {
  151.                         loggerConsole.info(msg);
  152.                     }
  153.                     this.logInfo(msg);
  154.                 }
  155.             }

  156.             // 2: via url
  157.             else if(modalita2TipoApplicationServer!=null && !"".equals(modalita2TipoApplicationServer)){
  158.                 if(modalita2Factory==null || "".equals(modalita2Factory)){
  159.                         throw new RisorseJMXException("Parametro 'factory' non fornito");
  160.                 }
  161.                 if(modalita2ServerUrl==null || "".equals(modalita2ServerUrl)){
  162.                         throw new RisorseJMXException("Parametro 'serverUrl' non fornito");
  163.                 }
  164.                 if(modalita2TipoApplicationServer.equals("jboss7") ||
  165.                         (modalita2TipoApplicationServer!=null && modalita2TipoApplicationServer.startsWith("wildfly")) ||
  166.                         modalita2TipoApplicationServer.startsWith("tomcat")){
  167.                    
  168.                     Class<?>jmxServiceURLClass = Class.forName("javax.management.remote.JMXServiceURL");
  169.                     Constructor<?> constructorJmxServiceURLClass = jmxServiceURLClass.getConstructor(String.class);
  170.                     Object serviceURL = constructorJmxServiceURLClass.newInstance(modalita2ServerUrl);

  171.                     java.util.Map<String, Object> env = null;
  172.                     if(modalita2Username!=null && modalita2Password!=null){
  173.                         String[] creds = {modalita2Username, modalita2Password};
  174.                         env = new HashMap<>();
  175.                         env.put("jmx.remote.credentials", creds);
  176.                     }
  177.                    
  178.                     Class<?>jmxConnectorFactoryClass = Class.forName("javax.management.remote.JMXConnectorFactory");
  179.                     Method connect = jmxConnectorFactoryClass.getMethod("connect", jmxServiceURLClass, java.util.Map.class);
  180.                     Object jmxConnector = connect.invoke(null, serviceURL, env);
  181.                    
  182.                     Class<?>jmxConnectorClass = Class.forName("javax.management.remote.JMXConnector");
  183.                     Method getMBeanServerConnection = jmxConnectorClass.getMethod("getMBeanServerConnection");
  184.                     this.mbeanServerConnection = getMBeanServerConnection.invoke(jmxConnector);
  185.                 }
  186.                 else{
  187.                     Properties properties = new Properties();
  188.                     properties.put(Context.INITIAL_CONTEXT_FACTORY, modalita2Factory);
  189.                     properties.put(Context.PROVIDER_URL, modalita2ServerUrl);
  190.                     GestoreJNDI jndi = new GestoreJNDI(properties);
  191.                     this.mbeanServerConnection = jndi.lookup("jmx/invoker/RMIAdaptor");
  192.                    
  193.                     if(modalita2Username!=null && modalita2Password!=null){
  194.                        
  195.                         Class<?>simplePrincipalClass = Class.forName("org.jboss.security.SimplePrincipal");
  196.                         Constructor<?> constructorPrincipalClass = simplePrincipalClass.getConstructor(String.class);
  197.                         Object simplePrincipal = constructorPrincipalClass.newInstance(modalita2Username);
  198.                        
  199.                         Class<?>securityAssociationClass = Class.forName("org.jboss.security.SecurityAssociation");
  200.                         Method setPrincipal = securityAssociationClass.getMethod("setPrincipal", simplePrincipalClass);
  201.                         setPrincipal.invoke(null, simplePrincipal);
  202.                         Method setCredential = securityAssociationClass.getMethod("setCredential", String.class);
  203.                         setCredential.invoke(null, modalita2Password);
  204.                     }
  205.                    
  206.                 }
  207.             }
  208.            
  209.            
  210.             // 3: Prendendolo dall'application server, cercandone uno di default
  211.             else{
  212.                 java.util.ArrayList<?> lServer = javax.management.MBeanServerFactory.findMBeanServer(null);
  213.                 if(lServer==null){
  214.                     throw new RisorseJMXException("Lista di MBean Server di default non trovata (MBeanServerFactory.findMBeanServer)");
  215.                 }else{
  216.                     if(lServer.isEmpty()){
  217.                         throw new RisorseJMXException("Lista di MBean Server di default vuota");
  218.                     }else{
  219.                         java.util.Iterator<?> it =  lServer.iterator();
  220.                         if(it.hasNext()){
  221.                             this.mbeanServer = (javax.management.MBeanServer) it.next();
  222.                             if(this.mbeanServer==null)
  223.                                 throw new RisorseJMXException("MBeanServer di default non trovato");
  224.                             else{
  225.                                 String msg = "Attivata gestione jmx attraverso MBeanServer: "+this.mbeanServer.toString();
  226.                                 if(logger==null)
  227.                                     loggerConsole.info(msg);
  228.                                 this.logInfo(msg);
  229.                             }
  230.                         }else{
  231.                             throw new RisorseJMXException("Lista di MBean Server di default vuota ?");
  232.                         }
  233.                     }
  234.                 }
  235.             }
  236.            
  237.         }catch(Exception e){
  238.             this.logError("Riscontrato errore durante l'inizializzazione del gestore delle RisorseJMX: "+e.getMessage(),e);
  239.             throw new RisorseJMXException("Riscontrato errore durante l'inizializzazione del gestore delle RisorseJMX: "+e.getMessage(),e);
  240.         }
  241.     }
  242.    
  243.    
  244.    
  245.        
  246.    
  247.     /**
  248.      * Registrazione del MBean generico
  249.      *
  250.      * @throws RisorseJMXException
  251.      */
  252.     public void registerMBean(Class<?> c,String nome)throws RisorseJMXException{
  253.         this.registerMBean(c, CostantiJMX.JMX_DOMINIO,CostantiJMX.JMX_TYPE, nome, true);        
  254.     }
  255.     public void registerMBean(Class<?> c,String dominio,String type,String nome)throws RisorseJMXException{
  256.         this.registerMBean(c, dominio, type, nome, true);      
  257.     }
  258.     public void registerMBean(Class<?> c,String dominio,String type,String nome, boolean throwExceptionAlreadyExists)throws RisorseJMXException{
  259.         try{
  260.             javax.management.ObjectName jmxName =
  261.                 new javax.management.ObjectName(dominio,type,nome);
  262.             if(this.mbeanServer==null){
  263.                 throw new RisorseJMXException("Operazione di registrazione permessa solo se il gestore viene inizializzato con il costruttore di default o indicando l'MBeanServer");
  264.             }
  265.             this.mbeanServer.registerMBean(ClassLoaderUtilities.newInstance(c), jmxName);
  266.             this.jmxNames.add(jmxName);
  267.         }catch(Exception e){
  268.             if((e instanceof javax.management.InstanceAlreadyExistsException) && !throwExceptionAlreadyExists){
  269.                 this.logDebug("Risorsa JMX ["+nome+"] giĆ  esistente: "+e.getMessage(),e);
  270.             }
  271.             else{
  272.                 this.logError("Riscontrato errore durante l'inizializzazione della risorsa JMX ["+nome+"]: "+e.getMessage(),e);
  273.                 throw new RisorseJMXException("Riscontrato errore durante l'inizializzazione della risorsa JMX ["+nome+"]: "+e.getMessage(),e);
  274.             }
  275.         }  
  276.        
  277.     }
  278.    
  279.    
  280.     /**
  281.      * Eliminazione dei MBean registrati
  282.      */
  283.     public void unregisterMBeans(){
  284.         for(int i=0; i<this.jmxNames.size(); i++){
  285.             javax.management.ObjectName jmxName = this.jmxNames.get(i);
  286.             try{
  287.                 if(this.mbeanServer==null){
  288.                     throw new RisorseJMXException("Operazione di cancellazione permessa solo se il gestore viene inizializzato con il costruttore di default o indicando l'MBeanServer");
  289.                 }
  290.                 this.mbeanServer.unregisterMBean(jmxName);
  291.                 this.logInfo("Unbound della risorsa JMX ["+jmxName.toString()+"]");
  292.             }catch(Exception e){
  293.                 this.logError("Riscontrato errore durante l'unbound della risorsa JMX ["+jmxName.toString()+"]: "+e.getMessage(),e);
  294.             }  
  295.         }
  296.     }
  297.    
  298.        
  299.     public Object getAttribute(String nomeRisorsa,String nomeAttributo)throws RisorseJMXException{
  300.         return this.getAttribute(CostantiJMX.JMX_DOMINIO,CostantiJMX.JMX_TYPE,nomeRisorsa,nomeAttributo);
  301.     }
  302.     public Object getAttribute(String dominio,String tipo,String nomeRisorsa,String nomeAttributo)throws RisorseJMXException{
  303.         try{
  304.             ObjectName name = new ObjectName(dominio,tipo,nomeRisorsa);
  305.             if(this.mbeanServerConnection!=null){
  306.                 Class<?> c = Class.forName(MBEAN_SERVER_CONNECTION);
  307.                 Method m = c.getMethod("getAttribute", ObjectName.class, String.class);
  308.                 return m.invoke(this.mbeanServerConnection, name, nomeAttributo);
  309.             }
  310.             else{
  311.                 return this.mbeanServer.getAttribute(name, nomeAttributo);
  312.             }
  313.         }catch(Exception e){
  314.             String msg = "Riscontrato errore durante la lettura dell'attributo ["+nomeAttributo+"] nella risorsa ["+nomeRisorsa+"]: "+e.getMessage();
  315.             this.logError(msg,e);
  316.             throw new RisorseJMXException(msg,e);
  317.         }  
  318.     }
  319.    
  320.     public void setAttribute(String nomeRisorsa,String nomeAttributo, Object value)throws RisorseJMXException{
  321.         this.setAttribute(CostantiJMX.JMX_DOMINIO,CostantiJMX.JMX_TYPE,nomeRisorsa,nomeAttributo,value);
  322.     }
  323.     public void setAttribute(String dominio,String tipo,String nomeRisorsa,String nomeAttributo, Object value)throws RisorseJMXException{
  324.         try{
  325.             ObjectName name = new ObjectName(dominio,tipo,nomeRisorsa);
  326.             javax.management.Attribute attribute = new javax.management.Attribute(nomeAttributo, value);
  327.             if(this.mbeanServerConnection!=null){
  328.                 Class<?> c = Class.forName(MBEAN_SERVER_CONNECTION);
  329.                 Method m = c.getMethod("setAttribute", ObjectName.class, javax.management.Attribute.class);
  330.                 m.invoke(this.mbeanServerConnection, name, nomeAttributo);
  331.             }
  332.             else{
  333.                 this.mbeanServer.setAttribute(name, attribute);
  334.             }
  335.         }catch(Exception e){
  336.             String msg = "Riscontrato errore durante l'aggiornamento dell'attributo ["+nomeAttributo+"] della risorsa ["+nomeRisorsa+"]: "+e.getMessage();
  337.             this.logError(msg,e);
  338.             throw new RisorseJMXException(msg,e);
  339.         }  
  340.     }
  341.    
  342.    
  343.     public Object invoke(String nomeRisorsa,String nomeMetodo,Object[]params,String[]signature)throws RisorseJMXException{
  344.         return this.invoke(CostantiJMX.JMX_DOMINIO,CostantiJMX.JMX_TYPE,nomeRisorsa,nomeMetodo,params,signature);
  345.     }
  346.     public Object invoke(String dominio,String tipo,String nomeRisorsa,String nomeMetodo,Object[]params,String[]signature)throws RisorseJMXException{
  347.         try{
  348.             ObjectName name = new ObjectName(dominio,tipo,nomeRisorsa);
  349.             if(this.mbeanServerConnection!=null){
  350.                 Class<?> c = Class.forName(MBEAN_SERVER_CONNECTION);
  351.                 Method m = c.getMethod("invoke", ObjectName.class, String.class, Object[].class, String[].class);
  352.                 return m.invoke(this.mbeanServerConnection, name, nomeMetodo, params, signature);
  353.             }
  354.             else{
  355.                 return this.mbeanServer.invoke(name, nomeMetodo, params, signature);
  356.             }
  357.         }catch(Exception e){
  358.             String msg = "Riscontrato errore durante l'invocazione del metodo ["+nomeMetodo+"] della risorsa ["+nomeRisorsa+"]: "+e.getMessage();
  359.             this.logError(msg,e);
  360.             throw new RisorseJMXException(msg,e);
  361.         }  
  362.     }
  363.    
  364. }