| /* |
| * 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 org.apache.logging.log4j.jmx.gui; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Objects; |
| import java.util.Set; |
| |
| import javax.management.JMException; |
| import javax.management.JMX; |
| import javax.management.MBeanServerConnection; |
| import javax.management.MalformedObjectNameException; |
| import javax.management.ObjectName; |
| import javax.management.remote.JMXConnector; |
| |
| import org.apache.logging.log4j.core.jmx.LoggerContextAdminMBean; |
| import org.apache.logging.log4j.core.jmx.Server; |
| import org.apache.logging.log4j.core.jmx.StatusLoggerAdminMBean; |
| import org.apache.logging.log4j.core.util.Closer; |
| |
| /** |
| * This class allows client-side code to perform operations on remote |
| * (server-side) MBeans via proxies. |
| */ |
| public class Client { |
| private JMXConnector connector; |
| private final MBeanServerConnection connection; |
| |
| /** |
| * Constructs a new {@code Client} object and creates proxies for all known |
| * remote MBeans. |
| * |
| * @param connector used to create the MBean server connection through which |
| * to communicate with the remote mbeans |
| * @throws MalformedObjectNameException if a problem occurred identifying |
| * one of the remote mbeans |
| * @throws IOException if the connection failed |
| */ |
| public Client(final JMXConnector connector) throws MalformedObjectNameException, IOException { |
| this.connector = Objects.requireNonNull(connector, "JMXConnector"); |
| this.connector.connect(); |
| this.connection = connector.getMBeanServerConnection(); |
| init(); |
| } |
| |
| /** |
| * Constructs a new {@code Client} object and creates proxies for all known |
| * remote MBeans. |
| * |
| * @param mBeanServerConnection the MBean server connection through which to |
| * communicate with the remote mbeans |
| * @throws MalformedObjectNameException if a problem occurred identifying |
| * one of the remote mbeans |
| * @throws IOException if the connection failed |
| */ |
| public Client(final MBeanServerConnection mBeanServerConnection) throws MalformedObjectNameException, IOException { |
| this.connection = mBeanServerConnection; |
| init(); |
| } |
| |
| private void init() throws MalformedObjectNameException, IOException { |
| } |
| |
| private Set<ObjectName> find(final String pattern) throws JMException, IOException { |
| final ObjectName search = new ObjectName(String.format(pattern, "*")); |
| final Set<ObjectName> result = connection.queryNames(search, null); |
| return result; |
| } |
| |
| /** |
| * Returns a list of proxies that allow operations to be performed on the |
| * remote {@code LoggerContextAdminMBean}s. |
| * |
| * @return a list of proxies to the remote {@code LoggerContextAdminMBean}s |
| * @throws IOException If an I/O error occurred |
| * @throws JMException If a management error occurred |
| */ |
| public List<LoggerContextAdminMBean> getLoggerContextAdmins() throws JMException, IOException { |
| final List<LoggerContextAdminMBean> result = new ArrayList<>(); |
| final Set<ObjectName> contextNames = find(LoggerContextAdminMBean.PATTERN); |
| for (final ObjectName contextName : contextNames) { |
| result.add(getLoggerContextAdmin(contextName)); |
| } |
| return result; |
| } |
| |
| public LoggerContextAdminMBean getLoggerContextAdmin(final ObjectName name) { |
| final LoggerContextAdminMBean ctx = JMX.newMBeanProxy(connection, // |
| name, // |
| LoggerContextAdminMBean.class, false); |
| return ctx; |
| } |
| |
| /** |
| * Closes the client connection to its server. Any ongoing or new requests |
| * to the MBeanServerConnection will fail. |
| */ |
| public void close() { |
| Closer.closeSilently(connector); |
| } |
| |
| /** |
| * Returns the MBean server connection through which to communicate with the |
| * remote mbeans. |
| * |
| * @return the MBean server connection |
| */ |
| public MBeanServerConnection getConnection() { |
| return connection; |
| } |
| |
| /** |
| * Returns the {@code StatusLoggerAdminMBean} associated with the specified |
| * context name, or {@code null}. |
| * |
| * @param contextName search key |
| * @return StatusLoggerAdminMBean or null |
| * @throws MalformedObjectNameException If an object name is malformed |
| * @throws IOException If an I/O error occurred |
| */ |
| public StatusLoggerAdminMBean getStatusLoggerAdmin(final String contextName) |
| throws MalformedObjectNameException, IOException { |
| final String pattern = StatusLoggerAdminMBean.PATTERN; |
| final String mbean = String.format(pattern, Server.escape(contextName)); |
| final ObjectName search = new ObjectName(mbean); |
| final Set<ObjectName> result = connection.queryNames(search, null); |
| if (result.size() == 0) { |
| return null; |
| } |
| if (result.size() > 1) { |
| System.err.println("WARN: multiple status loggers found for " + contextName + ": " + result); |
| } |
| final StatusLoggerAdminMBean proxy = JMX.newMBeanProxy(connection, // |
| result.iterator().next(), // |
| StatusLoggerAdminMBean.class, true); // notificationBroadcaster |
| return proxy; |
| } |
| |
| /** |
| * Returns {@code true} if the specified {@code ObjectName} is for a |
| * {@code LoggerContextAdminMBean}, {@code false} otherwise. |
| * |
| * @param mbeanName the {@code ObjectName} to check. |
| * @return {@code true} if the specified {@code ObjectName} is for a |
| * {@code LoggerContextAdminMBean}, {@code false} otherwise |
| */ |
| public boolean isLoggerContext(final ObjectName mbeanName) { |
| return Server.DOMAIN.equals(mbeanName.getDomain()) // |
| && mbeanName.getKeyPropertyList().containsKey("type") // |
| && mbeanName.getKeyPropertyList().size() == 1; |
| } |
| |
| /** |
| * Returns the {@code ObjectName} of the {@code StatusLoggerAdminMBean} |
| * associated with the specified {@code LoggerContextAdminMBean}. |
| * |
| * @param loggerContextObjName the {@code ObjectName} of a |
| * {@code LoggerContextAdminMBean} |
| * @return {@code ObjectName} of the {@code StatusLoggerAdminMBean} |
| */ |
| public ObjectName getStatusLoggerObjectName(final ObjectName loggerContextObjName) { |
| if (!isLoggerContext(loggerContextObjName)) { |
| throw new IllegalArgumentException("Not a LoggerContext: " + loggerContextObjName); |
| } |
| final String cxtName = loggerContextObjName.getKeyProperty("type"); |
| final String name = String.format(StatusLoggerAdminMBean.PATTERN, cxtName); |
| try { |
| return new ObjectName(name); |
| } catch (final MalformedObjectNameException ex) { |
| throw new IllegalStateException(name, ex); |
| } |
| } |
| } |