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.core.appender;
    18
    19  import java.util.HashMap;
    20  import java.util.Map;
    21  import java.util.concurrent.locks.Lock;
    22  import java.util.concurrent.locks.ReentrantLock;
    23
    24  import org.apache.logging.log4j.Logger;
    25  import org.apache.logging.log4j.status.StatusLogger;
    26
    27  /**
    28   * Abstract base class used to register managers.
    29   */
    30  public abstract class AbstractManager {
    31
    32      /**
    33       * Allow subclasses access to the status logger without creating another instance.
    34       */
    35      protected static final Logger LOGGER = StatusLogger.getLogger();
    36
    37      // Need to lock that map instead of using a ConcurrentMap due to stop removing the
    38      // manager from the map and closing the stream, requiring the whole stop method to be locked.
    39      private static final Map<String, AbstractManager> MAP = new HashMap<String, AbstractManager>();
    40
    41      private static final Lock LOCK = new ReentrantLock();
    42
    43      /**
    44       * Number of Appenders using this manager.
    45       */
    46      protected int count;
    47
    48      private final String name;
    49
    50      protected AbstractManager(final String name) {
    51          this.name = name;
    52          LOGGER.debug("Starting {} {}", this.getClass().getSimpleName(), name);
    53      }
    54
    55      /**
    56       * Retrieves a Manager if it has been previously created or creates a new Manager.
    57       * @param name The name of the Manager to retrieve.
    58       * @param factory The Factory to use to create the Manager.
    59       * @param data An Object that should be passed to the factory when creating the Manager.
    60       * @param <M> The Type of the Manager to be created.
    61       * @param <T> The type of the Factory data.
    62       * @return A Manager with the specified name and type.
    63       */
    64      public static <M extends AbstractManager, T> M getManager(final String name, final ManagerFactory<M, T> factory,
    65                                                                final T data) {
    66          LOCK.lock();
    67          try {
    68              @SuppressWarnings("unchecked")
    69              M manager = (M) MAP.get(name);
    70              if (manager == null) {
    71                  manager = factory.createManager(name, data);
    72                  if (manager == null) {
    73                      throw new IllegalStateException("Unable to create a manager");
    74                  }
    75                  MAP.put(name, manager);
    76              }
    77              manager.count++;
    78              return manager;
    79          } finally {
    80              LOCK.unlock();
    81          }
    82      }
    83
    84      /**
    85       * Determines if a Manager with the specified name exists.
    86       * @param name The name of the Manager.
    87       * @return True if the Manager exists, false otherwise.
    88       */
    89      public static boolean hasManager(final String name) {
    90          LOCK.lock();
    91          try {
    92              return MAP.containsKey(name);
    93          } finally {
    94              LOCK.unlock();
    95          }
    96      }
    97
    98      /**
    99       * May be overridden by Managers to perform processing while the Manager is being released and the
    100      * lock is held.
    101      */
    102     protected void releaseSub() {
    103     }
    104
    105     protected int getCount() {
    106         return count;
    107     }
    108
    109     /**
    110      * Called to signify that this Manager is no longer required by an Appender.
    111      */
    112     public void release() {
    113         LOCK.lock();
    114         try {
    115             --count;
    116             if (count <= 0) {
    117                 MAP.remove(name);
    118                 LOGGER.debug("Shutting down {} {}", this.getClass().getSimpleName(), getName());
    119                 releaseSub();
    120             }
    121         } finally {
    122             LOCK.unlock();
    123         }
    124     }
    125
    126     /**
    127      * Returns the name of the Manager.
    128      * @return The name of the Manager.
    129      */
    130     public String getName() {
    131         return name;
    132     }
    133
    134     /**
    135      * Provide a description of the content format supported by this Manager.  Default implementation returns an empty
    136      * (unspecified) Map.
    137      *
    138      * @return a Map of key/value pairs describing the Manager-specific content format, or an empty Map if no content
    139      * format descriptors are specified.
    140      */
    141     public Map<String, String> getContentFormat() {
    142         return new HashMap<String, String>();
    143     }
    144 }