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.env.event.distributor.EventDistributorControl;
    18  import org.as2lib.env.event.distributor.SimpleEventDistributorControl;
    19  import org.as2lib.env.log.LogHandler;
    20  import org.as2lib.env.log.ConfigurableLogger;
    21  import org.as2lib.env.log.LogLevel;
    22  import org.as2lib.env.log.LogMessage;
    23  import org.as2lib.env.log.logger.AbstractLogger;
    24  
    25  /**
    26   * {@code SimpleLogger} is a simple implementation of the {@code ConfigurableLogger}
    27   * interface.
    28   * 
    29   * <p>The basic methods to write the log messages are {@link #log}, {@link #debug},
    30   * {@link #info}, {@link #warning} and {@link #fatal}.
    31   *
    32   * <p>The first thing to note is that you can log messages at different levels.
    33   * These levels are {@code DEBUG}, {@code INFO}, {@code WARNING}, {@code ERROR}
    34   * and {@code FATAL}. Depending on what level has been set only messages at a
    35   * given level are logged. The levels are organized in a hierarchical manner. That
    36   * means if you set the log level to {@code ALL} every messages is logged. If you
    37   * set it to {@code ERROR} only messages at {@code ERROR} and {@code FATAL} level
    38   * are logged and so on. It is also possible to define your own set of levels. You
    39   * can therefor use the {@link #isEnabled} and {@link #log} methods.
    40   *
    41   * <p>To do not waste unnecessary performance in constructing log messages that are
    42   * not logged you can use the methods {@link #isEnabled}, {@link #isDebugEnabled},
    43   * {@link #isInfoEnabled}, {@link #isWarningEnabled}, {@link #isErrorEnabled}
    44   * and {@link #isFatalEnabled}.
    45   * 
    46   * <p>Note that the message does in neither case have to be a string. That means
    47   * you can pass-in messages and let the actual log handler decide how to produce a
    48   * string representation of the message. This is in most cases done by using the
    49   * {@code toString} method of the specific message. You can use this method to do
    50   * not lose performance in cases where the message is not logged.
    51   *
    52   * <p>The actaul log output is made by log handlers. To configure and
    53   * access the handlers of this logger you can use the methods {@link #addHandler},
    54   * {@link #removeHandler}, {@link #removeAllHandlers} and {@link #getAllHandlers}.
    55   * There are a few pre-defined handlers for different output devices.
    56   * Take a look at the {@code org.as2lib.env.log.handler} package for these.
    57   *
    58   * <p>Example:
    59   * <code>
    60   *   var logger:SimpleLogger = new SimpleLogger("mySimpleLogger");
    61   *   // adds a trace handler that is responsible for making the output
    62   *   logger.addHandler(new TraceHandler());
    63   *   // checks if the output gets actually made
    64   *   if (logger.isInfoEnabled()) {
    65   *	     // log the message at the info level
    66   *       logger.info("This is an informative log message.");
    67   *   }
    68   * </code>
    69   *
    70   * <p>This logger cannot be used with the {@code LoggerHierarchy} because it does
    71   * not offer hierarchy support. If you want to use your logger in a hierarchy use
    72   * the {@link SimpleHierarchicalLogger} instead.
    73   * 
    74   * @author Simon Wacker
    75   * @see org.as2lib.env.log.repository.LoggerHierarchy
    76   */
    77  class org.as2lib.env.log.logger.SimpleLogger extends AbstractLogger implements ConfigurableLogger {
    78  	
    79  	/** Makes the static variables of the super-class accessible through this class. */
    80  	private static var __proto__:Function = AbstractLogger;
    81  	
    82  	/** The set level. */
    83  	private var level:LogLevel;
    84  	
    85  	/** The set level as number. */
    86  	private var levelAsNumber:Number;
    87  	
    88  	/** Distributor control that controls the distributor. */
    89  	private var distributorControl:EventDistributorControl;
    90  	
    91  	/** Typed distributor that distributes messages to all log handlers. */
    92  	private var distributor:LogHandler;
    93  	
    94  	/** The name of this logger. */
    95  	private var name:String;
    96  	
    97  	/**
    98  	 * Constructs a new {@code SimpleLogger} instance.
    99  	 *
   100  	 * <p>The default log level is {@code ALL}. This means all messages regardless of
   101  	 * their level are logged.
   102  	 * 
   103  	 * <p>The logger {@code name} is by default shown in the log message to identify
   104  	 * where the message came from.
   105  	 * 
   106  	 * @param name (optional) the name of this logger
   107  	 */
   108  	public function SimpleLogger(name:String) {
   109  		this.name = name;
   110  		distributorControl = new SimpleEventDistributorControl(LogHandler, false);
   111  		distributor = this.distributorControl.getDistributor();
   112  		level = ALL;
   113  		levelAsNumber = level.toNumber();
   114  	}
   115  	
   116  	/**
   117  	 * Returns the name of this logger.
   118  	 *
   119  	 * <p>This method returns {@code null} if no name has been set via the
   120  	 * {@link #setName} method nor on construction.
   121  	 *
   122  	 * @return the name of this logger
   123  	 */
   124  	public function getName(Void):String {
   125  		return name;
   126  	}
   127  	
   128  	/**
   129  	 * Sets the name of this logger.
   130  	 *
   131  	 * <p>The name is by default shown in the log message.
   132  	 *
   133  	 * @param name the new name of this logger
   134  	 */
   135  	public function setName(name:String):Void {
   136  		this.name = name;
   137  	}
   138  	
   139  	/**
   140  	 * Sets the log level.
   141  	 *
   142  	 * <p>The log level determines which messages are logged and which are not.
   143  	 *
   144  	 * <p>A level of value {@code null} or {@code undefined} is interpreted as level
   145  	 * {@code ALL} which is also the default level.
   146  	 *
   147  	 * @param level the new log level
   148  	 */
   149  	public function setLevel(level:LogLevel):Void {
   150  		if (level) {
   151  			this.level = level;
   152  			levelAsNumber = level.toNumber();
   153  		} else {
   154  			this.level = ALL;
   155  			levelAsNumber = level.toNumber();
   156  		}
   157  	}
   158  	
   159  	/**
   160  	 * Returns the set level.
   161  	 *
   162  	 * @return the set level
   163  	 */
   164  	public function getLevel(Void):LogLevel {
   165  		return level;
   166  	}
   167  	
   168  	/**
   169  	 * Adds a new log handler.
   170  	 *
   171  	 * <p>Log handlers are used to actually log the messages. They determine what
   172  	 * information to log and to which output device.
   173  	 *
   174  	 * <p>This method simply does nothing if the passed-in handler is {@code null} or
   175  	 * {@code undefined}.
   176  	 *
   177  	 * @param handler the new log handler to log messages
   178  	 */
   179  	public function addHandler(handler:LogHandler):Void {
   180  		if (handler) {
   181  			distributorControl.addListener(handler);
   182  		}
   183  	}
   184  	
   185  	/**
   186  	 * Removes all occerrences of the passed-in log {@code handler}.
   187  	 *
   188  	 * <p>If the passed-in {@code handler} is {@code null} or {@code undefined} the
   189  	 * method invocation is simply ignored.
   190  	 *
   191  	 * @param handler the log handler to remove
   192  	 */
   193  	public function removeHandler(handler:LogHandler):Void {
   194  		if (handler) {
   195  			distributorControl.removeListener(handler);
   196  		}
   197  	}
   198  	
   199  	/**
   200  	 * Removes all added log handlers.
   201  	 */
   202  	public function removeAllHandlers(Void):Void {
   203  		distributorControl.removeAllListeners();
   204  	}
   205  	
   206  	/**
   207  	 * Returns all handlers that were added to this logger.
   208  	 *
   209  	 * <p>If there are no added handlers an empty array is returned.
   210  	 *
   211  	 * @return all added log handlers
   212  	 */
   213  	public function getAllHandlers(Void):Array {
   214  		return distributorControl.getAllListeners();
   215  	}
   216  	
   217  	/**
   218  	 * Checks whether this logger is enabled for the passed-in {@code level}.
   219  	 *
   220  	 * <p>{@code false} will be returned if:
   221  	 * <ul>
   222  	 *   <li>This logger is not enabled for the passed-in {@code level}.</li>
   223  	 *   <li>The passed-in {@code level} is {@code null} or {@code undefined}.</li>
   224  	 * </ul>
   225  	 *
   226  	 * <p>Using this method as shown in the class documentation may improve performance
   227  	 * depending on how long the log message construction takes.
   228  	 *
   229  	 * @param level the level to make the check upon
   230  	 * @return {@code true} if this logger is enabled for the given {@code level} else
   231  	 * {@code false}
   232  	 * @see #log
   233  	 */
   234  	public function isEnabled(level:LogLevel):Boolean {
   235  		if (!level) return false;
   236  		return (levelAsNumber >= level.toNumber());
   237  	}
   238  	
   239  	/**
   240  	 * Checks if this logger is enabled for debug level log messages.
   241  	 *
   242  	 * <p>Using this method as shown in the class documentation may improve performance
   243  	 * depending on how long the log message construction takes.
   244  	 *
   245  	 * @return {@code true} if debug messages are logged
   246  	 * @see org.as2lib.env.log.level.AbstractLogLevel#DEBUG
   247  	 * @see #debug
   248  	 */
   249  	public function isDebugEnabled(Void):Boolean {
   250  		return (levelAsNumber >= debugLevelAsNumber);
   251  	}
   252  	
   253  	/**
   254  	 * Checks if this logger is enabled for info level log messages.
   255  	 *
   256  	 * <p>Using this method as shown in the class documentation may improve performance
   257  	 * depending on how long the log message construction takes.
   258  	 *
   259  	 * @return {@code true} if info messages are logged
   260  	 * @see org.as2lib.env.log.level.AbstractLogLevel#INFO
   261  	 * @see #info
   262  	 */
   263  	public function isInfoEnabled(Void):Boolean {
   264  		return (levelAsNumber >= infoLevelAsNumber);
   265  	}
   266  	
   267  	/**
   268  	 * Checks if this logger is enabled for warning level log messages.
   269  	 *
   270  	 * <p>Using this method as shown in the class documentation may improve performance
   271  	 * depending on how long the log message construction takes.
   272  	 *
   273  	 * @return {@code true} if warning messages are logged
   274  	 * @see org.as2lib.env.log.level.AbstractLogLevel#WARNING
   275  	 * @see #warning
   276  	 */
   277  	public function isWarningEnabled(Void):Boolean {
   278  		return (levelAsNumber >= warningLevelAsNumber);
   279  	}
   280  	
   281  	/**
   282  	 * Checks if this logger is enabled for error level log messages.
   283  	 *
   284  	 * <p>Using this method as shown in the class documentation may improve performance
   285  	 * depending on how long the log message construction takes.
   286  	 *
   287  	 * @return {@code true} if error messages are logged
   288  	 * @see org.as2lib.env.log.level.AbstractLogLevel#ERROR
   289  	 * @see #error
   290  	 */
   291  	public function isErrorEnabled(Void):Boolean {
   292  		return (levelAsNumber >= errorLevelAsNumber);
   293  	}
   294  	
   295  	/**
   296  	 * Checks if this logger is enabled for fatal level log messages.
   297  	 *
   298  	 * <p>Using this method as shown in the class documentation may improve performance
   299  	 * depending on how long the log message construction takes.
   300  	 *
   301  	 * @return {@code true} if fatal messages are logged
   302  	 * @see org.as2lib.env.log.level.AbstractLogLevel#FATAL
   303  	 * @see #fatal
   304  	 */
   305  	public function isFatalEnabled(Void):Boolean {
   306  		return (levelAsNumber >= fatalLevelAsNumber);
   307  	}
   308  	
   309  	/**
   310  	 * Logs the {@code message} at the given {@code level}.
   311  	 *
   312  	 * <p>The {@code message} is only logged when this logger is enabled for the
   313  	 * passed-in {@code level}.
   314  	 *
   315  	 * @param message the message object to log
   316  	 * @param level the specific level at which the {@code message} shall be logged
   317  	 * @see #isEnabled
   318  	 */
   319  	public function log(message, level:LogLevel):Void {
   320  		if (isEnabled(level)) {
   321  			distributor.write(new LogMessage(message, level, name));
   322  		}
   323  	}
   324  	
   325  	/**
   326  	 * Logs the {@code message} object at debug level.
   327  	 *
   328  	 * <p>The {@code message} is only logged when the level is set to {@code DEBUG} or
   329  	 * a level above.
   330  	 *
   331  	 * @param message the message object to log
   332  	 * @see #isDebugEnabled
   333  	 */
   334  	public function debug(message):Void {
   335  		if (isDebugEnabled()) {
   336  			distributor.write(new LogMessage(message, debugLevel, name));
   337  		}
   338  	}
   339  	
   340  	/**
   341  	 * Logs the {@code message} object at info level.
   342  	 *
   343  	 * <p>The {@code message} gets only logged when the level is set to {@code INFO}
   344  	 * or a level above.
   345  	 *
   346  	 * @param message the message object to log
   347  	 * @see #isInfoEnabled
   348  	 */
   349  	public function info(message):Void {
   350  		if (isInfoEnabled()) {
   351  			distributor.write(new LogMessage(message, infoLevel, name));
   352  		}
   353  	}
   354  	
   355  	/**
   356  	 * Logs the {@code message} object at warning level.
   357  	 *
   358  	 * <p>The {@code message} gets only logged when the level is set to {@code WARNING}
   359  	 * or a level above.
   360  	 *
   361  	 * @param message the message object to log
   362  	 * @see #isWarningEnabled
   363  	 */
   364  	public function warning(message):Void {
   365  		if (isWarningEnabled()) {
   366  			distributor.write(new LogMessage(message, warningLevel, name));
   367  		}
   368  	}
   369  	
   370  	/**
   371  	 * Logs the {@code message} object at error level.
   372  	 *
   373  	 * <p>The {@code message} gets only logged when the level is set to {@code ERROR}
   374  	 * or a level above.
   375  	 *
   376  	 * @param message the message object to log
   377  	 * @see #isErrorEnabled
   378  	 */
   379  	public function error(message):Void {
   380  		if (isErrorEnabled()) {
   381  			distributor.write(new LogMessage(message, errorLevel, name));
   382  		}
   383  	}
   384  	
   385  	/**
   386  	 * Logs the {@code message} object at fatal level.
   387  	 *
   388  	 * <p>The {@code message} gets only logged when the level is set to {@code FATAL}
   389  	 * or a level above.
   390  	 *
   391  	 * @param message the message object to log
   392  	 * @see #isFatalEnabled
   393  	 */
   394  	public function fatal(message):Void {
   395  		if (isFatalEnabled()) {
   396  			distributor.write(new LogMessage(message, fatalLevel, name));
   397  		}
   398  	}
   399  	
   400  }