001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.appender; 018 019import java.util.HashMap; 020import java.util.Map; 021import java.util.concurrent.locks.Lock; 022import java.util.concurrent.locks.ReentrantLock; 023 024import org.apache.logging.log4j.Level; 025import org.apache.logging.log4j.Logger; 026import org.apache.logging.log4j.message.Message; 027import org.apache.logging.log4j.status.StatusLogger; 028 029/** 030 * Abstract base class used to register managers. 031 */ 032public abstract class AbstractManager { 033 034 /** 035 * Allow subclasses access to the status logger without creating another instance. 036 */ 037 protected static final Logger LOGGER = StatusLogger.getLogger(); 038 039 // Need to lock that map instead of using a ConcurrentMap due to stop removing the 040 // manager from the map and closing the stream, requiring the whole stop method to be locked. 041 private static final Map<String, AbstractManager> MAP = new HashMap<>(); 042 043 private static final Lock LOCK = new ReentrantLock(); 044 045 /** 046 * Number of Appenders using this manager. 047 */ 048 protected int count; 049 050 private final String name; 051 052 protected AbstractManager(final String name) { 053 this.name = name; 054 LOGGER.debug("Starting {} {}", this.getClass().getSimpleName(), name); 055 } 056 057 /** 058 * Retrieves a Manager if it has been previously created or creates a new Manager. 059 * @param name The name of the Manager to retrieve. 060 * @param factory The Factory to use to create the Manager. 061 * @param data An Object that should be passed to the factory when creating the Manager. 062 * @param <M> The Type of the Manager to be created. 063 * @param <T> The type of the Factory data. 064 * @return A Manager with the specified name and type. 065 */ 066 public static <M extends AbstractManager, T> M getManager(final String name, final ManagerFactory<M, T> factory, 067 final T data) { 068 LOCK.lock(); 069 try { 070 @SuppressWarnings("unchecked") 071 M manager = (M) MAP.get(name); 072 if (manager == null) { 073 manager = factory.createManager(name, data); 074 if (manager == null) { 075 throw new IllegalStateException("ManagerFactory [" + factory + "] unable to create manager for [" 076 + name + "] with data [" + data + "]"); 077 } 078 MAP.put(name, manager); 079 } else { 080 manager.updateData(data); 081 } 082 manager.count++; 083 return manager; 084 } finally { 085 LOCK.unlock(); 086 } 087 } 088 089 public void updateData(final Object data) { 090 } 091 092 /** 093 * Determines if a Manager with the specified name exists. 094 * @param name The name of the Manager. 095 * @return True if the Manager exists, false otherwise. 096 */ 097 public static boolean hasManager(final String name) { 098 LOCK.lock(); 099 try { 100 return MAP.containsKey(name); 101 } finally { 102 LOCK.unlock(); 103 } 104 } 105 106 /** 107 * May be overridden by Managers to perform processing while the Manager is being released and the 108 * lock is held. 109 */ 110 protected void releaseSub() { 111 } 112 113 protected int getCount() { 114 return count; 115 } 116 117 /** 118 * Called to signify that this Manager is no longer required by an Appender. 119 */ 120 public void release() { 121 LOCK.lock(); 122 try { 123 --count; 124 if (count <= 0) { 125 MAP.remove(name); 126 LOGGER.debug("Shutting down {} {}", this.getClass().getSimpleName(), getName()); 127 releaseSub(); 128 } 129 } finally { 130 LOCK.unlock(); 131 } 132 } 133 134 /** 135 * Returns the name of the Manager. 136 * @return The name of the Manager. 137 */ 138 public String getName() { 139 return name; 140 } 141 142 /** 143 * Provide a description of the content format supported by this Manager. Default implementation returns an empty 144 * (unspecified) Map. 145 * 146 * @return a Map of key/value pairs describing the Manager-specific content format, or an empty Map if no content 147 * format descriptors are specified. 148 */ 149 public Map<String, String> getContentFormat() { 150 return new HashMap<>(); 151 } 152 153 protected void log(final Level level, final String message, final Throwable throwable) { 154 final Message m = LOGGER.getMessageFactory().newMessage("{} {} {}: {}", 155 getClass().getSimpleName(), getName(), message, throwable); 156 LOGGER.log(level, m, throwable); 157 } 158 159 protected void logDebug(final String message, final Throwable throwable) { 160 log(Level.DEBUG, message, throwable); 161 } 162 163 protected void logError(final String message, final Throwable throwable) { 164 log(Level.ERROR, message, throwable); 165 } 166 167 protected void logWarn(final String message, final Throwable throwable) { 168 log(Level.WARN, message, throwable); 169 } 170 171}