View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements. See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache license, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License. You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the license for the specific language governing permissions and
    15   * limitations under the license.
    16   */
    17  package org.apache.logging.log4j.jmx.gui;
    18
    19  import java.io.IOException;
    20  import java.util.ArrayList;
    21  import java.util.List;
    22  import java.util.Set;
    23
    24  import javax.management.JMException;
    25  import javax.management.JMX;
    26  import javax.management.MBeanServerConnection;
    27  import javax.management.MalformedObjectNameException;
    28  import javax.management.ObjectName;
    29  import javax.management.remote.JMXConnector;
    30
    31  import org.apache.logging.log4j.core.jmx.LoggerContextAdminMBean;
    32  import org.apache.logging.log4j.core.jmx.Server;
    33  import org.apache.logging.log4j.core.jmx.StatusLoggerAdminMBean;
    34  import org.apache.logging.log4j.core.util.Assert;
    35  import org.apache.logging.log4j.core.util.Closer;
    36
    37  /**
    38   * This class allows client-side code to perform operations on remote
    39   * (server-side) MBeans via proxies.
    40   */
    41  public class Client {
    42      private JMXConnector connector;
    43      private final MBeanServerConnection connection;
    44
    45      /**
    46       * Constructs a new {@code Client} object and creates proxies for all known
    47       * remote MBeans.
    48       *
    49       * @param connector used to create the MBean server connection through which
    50       *            to communicate with the remote mbeans
    51       * @throws MalformedObjectNameException if a problem occurred identifying
    52       *             one of the remote mbeans
    53       * @throws IOException if the connection failed
    54       */
    55      public Client(final JMXConnector connector) throws MalformedObjectNameException, IOException {
    56          this.connector = Assert.requireNonNull(connector, "JMXConnector");
    57          this.connector.connect();
    58          this.connection = connector.getMBeanServerConnection();
    59          init();
    60      }
    61
    62      /**
    63       * Constructs a new {@code Client} object and creates proxies for all known
    64       * remote MBeans.
    65       *
    66       * @param mBeanServerConnection the MBean server connection through which to
    67       *            communicate with the remote mbeans
    68       * @throws MalformedObjectNameException if a problem occurred identifying
    69       *             one of the remote mbeans
    70       * @throws IOException if the connection failed
    71       */
    72      public Client(final MBeanServerConnection mBeanServerConnection) throws MalformedObjectNameException, IOException {
    73          this.connection = mBeanServerConnection;
    74          init();
    75      }
    76
    77      private void init() throws MalformedObjectNameException, IOException {
    78      }
    79
    80      private Set<ObjectName> find(final String pattern) throws JMException, IOException {
    81          final ObjectName search = new ObjectName(String.format(pattern, "*"));
    82          final Set<ObjectName> result = connection.queryNames(search, null);
    83          return result;
    84      }
    85
    86      /**
    87       * Returns a list of proxies that allow operations to be performed on the
    88       * remote {@code LoggerContextAdminMBean}s.
    89       *
    90       * @return a list of proxies to the remote {@code LoggerContextAdminMBean}s
    91       * @throws IOException If an I/O error occurred
    92       * @throws JMException If a management error occurred
    93       */
    94      public List<LoggerContextAdminMBean> getLoggerContextAdmins() throws JMException, IOException {
    95          final List<LoggerContextAdminMBean> result = new ArrayList<LoggerContextAdminMBean>();
    96          final Set<ObjectName> contextNames = find(LoggerContextAdminMBean.PATTERN);
    97          for (final ObjectName contextName : contextNames) {
    98              result.add(getLoggerContextAdmin(contextName));
    99          }
    100         return result;
    101     }
    102
    103     public LoggerContextAdminMBean getLoggerContextAdmin(final ObjectName name) {
    104         final LoggerContextAdminMBean ctx = JMX.newMBeanProxy(connection, //
    105                 name, //
    106                 LoggerContextAdminMBean.class, false);
    107         return ctx;
    108     }
    109
    110     /**
    111      * Closes the client connection to its server. Any ongoing or new requests
    112      * to the MBeanServerConnection will fail.
    113      */
    114     public void close() {
    115         Closer.closeSilently(connector);
    116     }
    117
    118     /**
    119      * Returns the MBean server connection through which to communicate with the
    120      * remote mbeans.
    121      *
    122      * @return the MBean server connection
    123      */
    124     public MBeanServerConnection getConnection() {
    125         return connection;
    126     }
    127
    128     /**
    129      * Returns the {@code StatusLoggerAdminMBean} associated with the specified
    130      * context name, or {@code null}.
    131      *
    132      * @param contextName search key
    133      * @return StatusLoggerAdminMBean or null
    134      * @throws MalformedObjectNameException If an object name is malformed
    135      * @throws IOException If an I/O error occurred
    136      */
    137     public StatusLoggerAdminMBean getStatusLoggerAdmin(final String contextName)
    138             throws MalformedObjectNameException, IOException {
    139         final String pattern = StatusLoggerAdminMBean.PATTERN;
    140         final String mbean = String.format(pattern, Server.escape(contextName));
    141         final ObjectName search = new ObjectName(mbean);
    142         final Set<ObjectName> result = connection.queryNames(search, null);
    143         if (result.size() == 0) {
    144             return null;
    145         }
    146         if (result.size() > 1) {
    147             System.err.println("WARN: multiple status loggers found for " + contextName + ": " + result);
    148         }
    149         final StatusLoggerAdminMBean proxy = JMX.newMBeanProxy(connection, //
    150                 result.iterator().next(), //
    151                 StatusLoggerAdminMBean.class, true); // notificationBroadcaster
    152         return proxy;
    153     }
    154
    155     /**
    156      * Returns {@code true} if the specified {@code ObjectName} is for a
    157      * {@code LoggerContextAdminMBean}, {@code false} otherwise.
    158      *
    159      * @param mbeanName the {@code ObjectName} to check.
    160      * @return {@code true} if the specified {@code ObjectName} is for a
    161      *         {@code LoggerContextAdminMBean}, {@code false} otherwise
    162      */
    163     public boolean isLoggerContext(final ObjectName mbeanName) {
    164         return Server.DOMAIN.equals(mbeanName.getDomain()) //
    165                 && mbeanName.getKeyPropertyList().containsKey("type") //
    166                 && mbeanName.getKeyPropertyList().size() == 1;
    167     }
    168
    169     /**
    170      * Returns the {@code ObjectName} of the {@code StatusLoggerAdminMBean}
    171      * associated with the specified {@code LoggerContextAdminMBean}.
    172      *
    173      * @param loggerContextObjName the {@code ObjectName} of a
    174      *            {@code LoggerContextAdminMBean}
    175      * @return {@code ObjectName} of the {@code StatusLoggerAdminMBean}
    176      */
    177     public ObjectName getStatusLoggerObjectName(final ObjectName loggerContextObjName) {
    178         if (!isLoggerContext(loggerContextObjName)) {
    179             throw new IllegalArgumentException("Not a LoggerContext: " + loggerContextObjName);
    180         }
    181         final String cxtName = loggerContextObjName.getKeyProperty("type");
    182         final String name = String.format(StatusLoggerAdminMBean.PATTERN, cxtName);
    183         try {
    184             return new ObjectName(name);
    185         } catch (final MalformedObjectNameException ex) {
    186             throw new IllegalStateException(name, ex);
    187         }
    188     }
    189 }