1 /* 2 * Copyright the original author or authors. 3 * 4 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.mozilla.org/MPL/MPL-1.1.html 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import org.as2lib.core.BasicClass; 18 import org.as2lib.env.reflect.ReflectUtil; 19 import org.as2lib.env.log.Logger; 20 import org.as2lib.env.log.LoggerRepository; 21 22 /** 23 * {@code LogManager} is the core access point of the As2lib Logging API. 24 * 25 * <p>You use it to set the underlying repository that stores and releases loggers 26 * and to obtain a logger according to a logger's name of the repository. 27 * 28 * <p>The repository must be set before anything else when you are using this 29 * class as access point to obtain loggers. There is no default repository. This 30 * means that all messages sent to loggers obtained from the {@link #getLogger} method, 31 * before the repository has been set will not be logged. 32 * 33 * <p>This class could be used as follows with a non-singleton repository. Note 34 * that you can of course also use any other kind of logger repository. 35 * 36 * <code> 37 * // configuration: when setting everything up 38 * var loggerHierarchy:LoggerHierarchy = new LoggerHierarchy(); 39 * var traceLogger:SimpleHierarchicalLogger = new SimpleHierarchicalLogger("org.mydomain"); 40 * traceLogger.addHandler(new TraceHandler()); 41 * loggerHierarchy.addLogger(traceLogger); 42 * LogManager.setLoggerRepository(loggerHierarchy); 43 * // usage: in the class org.mydomain.MyClass 44 * var myLogger:Logger = LogManager.getLogger("org.mydomain.MyClass"); 45 * if (myLogger.isInfoEnabled()) { 46 * myLogger.info("This is an informative log message."); 47 * } 48 * </code> 49 * 50 * <p>If you have one logger that shall always be returned you can use the 51 * convenience method {@link #setLogger} that does all the work with the repository 52 * for you. 53 * 54 * <code> 55 * // configuration: when setting everything up 56 * var traceLogger:SimpleLogger = new SimpleLogger(); 57 * traceLogger.addHandler(new TraceHandler()); 58 * LogManager.setLogger(traceLogger); 59 * // usage: in the class org.mydomain.MyClass 60 * var myLogger:Logger = LogManager.getLogger("org.mydomain.MyClass"); 61 * if (myLogger.isInfoEnabled()) { 62 * myLogger.info("This is an informative log message."); 63 * } 64 * </code> 65 * 66 * <p>It is common practice to obtain loggers per class. You may thus consider the 67 * following strategy of obtaining loggers: 68 * <code>private static var logger:Logger = LogManager.getLogger("org.as2lib.MyClass");</code> 69 * 70 * <p>Applying this strategy you have a logger per class that can be used within 71 * per class and per instance methods of the logging class. 72 * 73 * @author Simon Wacker 74 */ 75 class org.as2lib.env.log.LogManager extends BasicClass { 76 77 /** Repository that stores already retrieved loggers. */ 78 private static var repository:LoggerRepository; 79 80 /** Proxies of loggers that are replaced by real loggers as soon as repository gets set. */ 81 private static var loggerProxies:Array; 82 83 /** 84 * @overload #getLoggerByName 85 * @overload #getLoggerByObject 86 */ 87 public static function getLogger():Logger { 88 // do not use Overloading API hear because 'LogManager' must be as light-weight as possible 89 if (arguments[0].__proto__ != String.prototype) { 90 return getLoggerByObject(arguments[0]); 91 } 92 return getLoggerByName(arguments[0]); 93 } 94 95 /** 96 * Returns the logger according to the passed-in {@code object}. 97 * 98 * <p>If {@code object} is of type 'function' it is supposed that this is the type 99 * to get the name of otherwise it is supposed to be the instance of the type to get 100 * the name of. 101 * 102 * <p>The name of the type is used as logger name. 103 * 104 * <p>Note that evaluating the name is rather slow. It is thus recommended to 105 * hardcode the name and use the {@link #getLoggerByName} method. 106 * 107 * @param object the object to return the type name of 108 * @return the logger for the given {@code object} 109 * @see #getLoggerByName 110 */ 111 public static function getLoggerByObject(object):Logger { 112 return getLoggerByName(ReflectUtil.getTypeName(object)); 113 } 114 115 /** 116 * Returns the logger according the passed-in {@code loggerName}. 117 * 118 * <p>Uses the set logger repository to receive the logger that is returned. 119 * 120 * <p>{@code null} is only returned if the logger repository is initialized and 121 * returns {@code null} or {@code undefined}. 122 * 123 * <p>If the logger repository has not been initialized yet a proxy gets returned 124 * that is replaced by the actual logger of the repository, as soon as the 125 * repository gets initialized. This means that the following access in classes is 126 * possible: 127 * <code>private static var logger:Logger = LogManager.getLogger("org.as2lib.MyClass");</code> 128 * 129 * <p>But note that you shall not log messages before the actual initialization of 130 * the repository; these messages will never be logged. Proxies are just returne to 131 * enable the convenient logger access above. 132 * 133 * @param loggerName the name of the logger to return 134 * @return the logger according to the passed-in {@code name} 135 */ 136 public static function getLoggerByName(loggerName:String):Logger { 137 if (!repository) { 138 if (loggerProxies[loggerName]) return loggerProxies[loggerName]; 139 if (!loggerProxies) loggerProxies = new Array(); 140 var result:Logger = getBlankLogger(); 141 result["__resolve"] = function() { 142 return false; 143 }; 144 result["name"] = loggerName; 145 loggerProxies.push(result); 146 loggerProxies[loggerName] = result; 147 return result; 148 } 149 var result:Logger = repository.getLogger(loggerName); 150 if (result) return result; 151 return null; 152 } 153 154 /** 155 * Returns a blank logger. 156 * 157 * <p>This is a {@code Logger} instance with no implemented methods. 158 * 159 * @return a blank logger 160 */ 161 private static function getBlankLogger(Void):Logger { 162 var result = new Object(); 163 result.__proto__ = Logger["prototype"]; 164 result.__constructor__ = Logger; 165 return result; 166 } 167 168 /** 169 * Sets the {@code logger} that is returned on calls to the {@link #getLogger} 170 * method. 171 * 172 * <p>This method actually sets a singleton repository via the static 173 * {@link #setLoggerRepository} that always returns the passed-in {@code logger} 174 * and ignores the name. 175 * 176 * <p>You could also set the repository by hand, this is just an easier way of 177 * doing it if you always want the same logger to be returned. 178 * 179 * @param logger the logger to return on calls to the {@code #getLogger} method 180 */ 181 public static function setLogger(logger:Logger):Void { 182 repository = getBlankLoggerRepository(); 183 repository.getLogger = function(loggerName:String):Logger { 184 return logger; 185 }; 186 } 187 188 /** 189 * Returns a blank logger repository. 190 * 191 * <p>This is a {@code LoggerRepository} instance with no implemented methods. 192 * 193 * @return a blank logger repository 194 */ 195 private static function getBlankLoggerRepository(Void):LoggerRepository { 196 var result = new Object(); 197 result.__proto__ = LoggerRepository["prototype"]; 198 result.__constructor__ = LoggerRepository; 199 return result; 200 } 201 202 /** 203 * Reutrns the logger repository set via {@link #setLoggerRepository}. 204 * 205 * <p>There is no default logger repository, so you must set it before anything 206 * else. 207 * 208 * @return the set logger repository 209 */ 210 public static function getLoggerRepository(Void):LoggerRepository { 211 return repository; 212 } 213 214 /** 215 * Sets a new repositroy returned by {@link #getLoggerRepository}. 216 * 217 * <p>The {@link #getLogger} method uses this repository to obtain the logger for 218 * the given logger name. 219 * 220 * @param loggerRepository the new logger repository 221 */ 222 public static function setLoggerRepository(loggerRepository:LoggerRepository):Void { 223 repository = loggerRepository; 224 if (loggerProxies) { 225 for (var i:Number = loggerProxies.length - 1; i >= 0; i--) { 226 var proxy:Logger = loggerProxies[i]; 227 var name:String = proxy["name"]; 228 delete proxy["__constructor__"]; 229 delete proxy["__resolve"]; 230 delete proxy["name"]; 231 loggerProxies.pop(); 232 delete loggerProxies[name]; 233 var logger:Logger = loggerRepository.getLogger(name); 234 proxy["__proto__"] = logger; 235 } 236 } 237 } 238 239 /** 240 * Returns whether a logger repository has been added. 241 * 242 * @return {@code true} if a logger repository has been added else {@code false} 243 */ 244 public static function hasLoggerRepository(Void):Boolean { 245 return (repository != null); 246 } 247 248 /** 249 * Private constructor. 250 */ 251 private function LogManager(Void) { 252 } 253 254 }