/* * 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 ASF 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 de.unioninvestment.eai.portal.portlet.crud.domain.model; import groovy.jmx.builder.JmxBuilder; import groovy.util.GroovyMBean; import java.io.IOException; import java.io.Serializable; import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import javax.management.JMException; import javax.management.MBeanServerConnection; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; import javax.naming.Context; import de.unioninvestment.eai.portal.portlet.crud.domain.exception.TechnicalCrudPortletException; /** * JMX Wrapper Objekt die JMX Connections und JMX Operationen * * @author markus.bonsch * */ public class JMXWrapper { private static final String JBOSS_REMOTING_URL = "service:jmx:rmi:///jndi/jmxconnector"; private static final String JOLOKIA_REC = "jolokia"; @SuppressWarnings("rawtypes") private Map connectionArgs; private MBeanServerConnection connection; private boolean hasRemoteScriptingMBean; private ObjectName remoteScriptingMBeanName; private String url; private HashMap<String, String> environment; /** * Konstruktor. * * @param connectionArgs * Parameter der Verbindung */ public JMXWrapper(@SuppressWarnings("rawtypes") Map connectionArgs) { this.connectionArgs = connectionArgs; } /** * Konstruktor. * * @param serverAdress * IP oder Name des Servers * @param serverPort * Portnummer */ public JMXWrapper(String serverAdress, String serverPort) { this(serverAdress + ":" + serverPort); } /** * No-Args constructor uses the globally available <code>MBeanServer</code>. * * @since 1.46 * @author Jan Malcomess (codecentric AG) * @see ManagementFactory#getPlatformMBeanServer() */ public JMXWrapper() { this(ManagementFactory.getPlatformMBeanServer()); } /** * @param connection * bestehende Verbindung zum MBeanServer */ public JMXWrapper(MBeanServerConnection connection) { this.connection = connection; } /** * Konstruktor. * * @param connectionString * siehe {@link #connect(String)} */ public JMXWrapper(String connectionString) { init(connectionString); } /** * @param connectionString * verbindet sich mit dem Server anhand der Angaben im * {@code connectionString}. Dieser kann entweder im Format * <code>"server:port"</code> oder * <code>"service:jmx:rmi:///jndi/rmi://#/jmxconnector"</code> * oder <code>"http://server/jolokia"</code> angegeben werden. */ public void connect(String connectionString) { init(connectionString); } private void init(String connectionString) { if (connectionString != null && connectionString.length() > 0) { url = connectionString; environment = null; if (!connectionString.startsWith("service:jmx") && !connectionString.contains(JOLOKIA_REC)) { url = JBOSS_REMOTING_URL; environment = new HashMap<String, String>(); environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); environment.put(Context.PROVIDER_URL, "rmi://" + connectionString); } } connectionArgs = null; connection = null; } /** * Gibt die Vebindung zum JMXServer zurück. * * @return die Vebindung zum JMXServer * @throws IOException * bei Verbindungsproblemen */ public MBeanServerConnection getServer() throws IOException { if (connection == null) { JMXConnector connector; if (url != null && url.contains(JOLOKIA_REC)) { connector = JolokiaJMXConnectorFactory.connect(url); } else if (connectionArgs != null) { JmxBuilder jmxBuilder = new JmxBuilder(); connector = (JMXConnector) jmxBuilder.invokeMethod("client", getConnectionArgs()); } else if (url != null) { connector = JMXConnectorFactory.connect(new JMXServiceURL(url), environment); } else { connector = JMXConnectorFactory.connect(new JMXServiceURL( JBOSS_REMOTING_URL), environment); } connector.connect(); setConnection(connector.getMBeanServerConnection()); try { remoteScriptingMBeanName = new ObjectName( "crud:service=CrudRemoteScript,name=script"); hasRemoteScriptingMBean = connection .isRegistered(remoteScriptingMBeanName); } catch (MalformedObjectNameException e) { throw new TechnicalCrudPortletException( "Error querying for CrudRemoteScript-MBean", e); } } return connection; } /** * Gibt eine GroovyMBean anhand des Beannames zurück. * * @param beanName * Beanname * @return MBean * @throws IOException * bei Verbindungsproblemen * @throws JMException * bei sonstigen JMX-Fehlern */ public GroovyMBean proxyFor(String beanName) throws JMException, IOException { return new GroovyMBean(getServer(), beanName); } /** * Gibt die Parameter der Verbindung zurück. * * @return Parameter der Verbindung */ @SuppressWarnings("rawtypes") Map getConnectionArgs() { return connectionArgs; } void setConnection(MBeanServerConnection connection) { this.connection = connection; } /** * Liest aus der Ergebnismenge der Query die Attribute aus. * * @param query * Query-String * @param properties * Liste von zu lesenden Attributen * @return Attribute aus der Ergebnismenge * @throws IOException * bei Verbindungsproblemen * @throws JMException * bei sonstigen JMX-Fehlern */ public Map<String, ? extends Map<String, ? extends Object>> query( String query, List<String> properties) throws IOException, JMException { if (connectionNotConfigured() || query == null || query.length() == 0) { return new HashMap<String, Map<String, Object>>(); } MBeanServerConnection con = getServer(); if (hasRemoteScriptingMBean) { return query(query, properties, new LinkedList<String>()); } else { Map<String, Map<String, Object>> result = new HashMap<String, Map<String, Object>>(); Set<ObjectName> queryNames = con.queryNames(new ObjectName(query), null); for (ObjectName objectName : queryNames) { Map<String, Object> attributesMap = new HashMap<String, Object>(); result.put(objectName.getCanonicalName(), attributesMap); for (String propertyName : properties) { attributesMap.put(propertyName, con.getAttribute(objectName, propertyName)); } } return result; } } private boolean connectionNotConfigured() { return connectionArgs == null && url == null && connection == null; } /** * @param query * die Datenbankquery als MBean-Selektor * @param properties * die Namen der abzufragenden Attribute * @param getterScripts * optional:die Liste von Scripten, die zur Ermittlung der * Spaltenwerte auf jedes MBean anzuwenden sind. Die Reihenfolge * und Anzahl muss denen des {@code properties} Parameters * entsprechen. {@code null}-Listeneinträge werden wie gehabt als * Standard-MBean-Attribute abgefragt. * @return eine Map mit den MBean-ObjectName-Strings als Key und einer * Map<String,Serializable> für die Werte * @throws IOException * bei Verbindungsproblemen * @throws JMException * bei sonstigen JMX-Fehlern */ @SuppressWarnings("unchecked") public Map<String, Map<String, Serializable>> query(String query, List<String> properties, List<String> getterScripts) throws IOException, JMException { if (connectionNotConfigured() || query == null || query.length() == 0) { return new HashMap<String, Map<String, Serializable>>(); } return (Map<String, Map<String, Serializable>>) getServer().invoke( remoteScriptingMBeanName, "query", new Object[] { query, new ArrayList<String>(properties), new ArrayList<String>(getterScripts) }, new String[] { "java.lang.String", "java.util.List", "java.util.List" }); } void setRemoteScriptingMBeanName(ObjectName remoteScriptingMBeanName) { this.remoteScriptingMBeanName = remoteScriptingMBeanName; } /** * @param script * Groovy-Script, dass Serverseitig auszuführen ist. * @return serialisierbarer Rückgabewert des Scripts * @throws IOException * bei Verbindungsproblemen * @throws JMException * bei sonstigen JMX-Fehlern */ public Serializable executeScript(String script) throws JMException, IOException { return (Serializable) getServer().invoke(remoteScriptingMBeanName, "executeScript", new Object[] { script }, new String[] { "java.lang.String" }); } }