Author: seb
Date: Tue Dec  5 16:31:33 2006
New Revision: 1063

Added:
   logback/trunk/logback-examples/src/main/java/chapter7/
   logback/trunk/logback-examples/src/main/java/chapter7/NumberCruncher.java
   
logback/trunk/logback-examples/src/main/java/chapter7/NumberCruncherClient.java
   
logback/trunk/logback-examples/src/main/java/chapter7/NumberCruncherServer.java
   logback/trunk/logback-examples/src/main/java/chapter7/SimpleMDC.java
   logback/trunk/logback-examples/src/main/java/chapter7/mdc1.xml
   logback/trunk/logback-site/src/site/xdocTemplates/manual/mdc.xml
Modified:
   logback/trunk/logback-site/src/site/xdocTemplates/manual/filters.xml

Log:
On going work on chapter 7

Added: logback/trunk/logback-examples/src/main/java/chapter7/NumberCruncher.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-examples/src/main/java/chapter7/NumberCruncher.java   
Tue Dec  5 16:31:33 2006
@@ -0,0 +1,26 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it 
under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package chapter7;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+
+/**
+ * NumberCruncher factors positive integers.
+ */
+public interface NumberCruncher extends Remote {
+  /**
+   * Factor a positive integer <code>number</code> and return its
+   * <em>distinct</em> factor's as an integer array.
+   * */
+  int[] factor(int number) throws RemoteException;
+}

Added: 
logback/trunk/logback-examples/src/main/java/chapter7/NumberCruncherClient.java
==============================================================================
--- (empty file)
+++ 
logback/trunk/logback-examples/src/main/java/chapter7/NumberCruncherClient.java 
    Tue Dec  5 16:31:33 2006
@@ -0,0 +1,83 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it 
under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package chapter7;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.rmi.Naming;
+import java.rmi.RemoteException;
+
+
+/**
+ * NumberCruncherClient is a simple client for factoring integers. A
+ * remote NumberCruncher is contacted and asked to factor an
+ * integer. The factors returned by the [EMAIL PROTECTED] NumberCruncherServer}
+ * are displayed on the screen.
+ * */
+public class NumberCruncherClient {
+  public static void main(String[] args) {
+    if (args.length == 1) {
+      try {
+        String url = "rmi://" + args[0] + "/Factor";
+        NumberCruncher nc = (NumberCruncher) Naming.lookup(url);
+        loop(nc);
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    } else {
+      usage("Wrong number of arguments.");
+    }
+  }
+
+  static void usage(String msg) {
+    System.err.println(msg);
+    System.err.println("Usage: java chapter7.NumberCruncherClient HOST\n" +
+      "   where HOST is the machine where the NumberCruncherServer is 
running.");
+    System.exit(1);
+  }
+
+  static void loop(NumberCruncher nc) {
+    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+    int i = 0;
+
+    while (true) {
+      System.out.print("Enter a number to factor, '-1' to quit: ");
+
+      try {
+        i = Integer.parseInt(in.readLine());
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+
+      if (i == -1) {
+        System.out.print("Exiting loop.");
+
+        return;
+      } else {
+        try {
+          System.out.println("Will attempt to factor " + i);
+
+          int[] factors = nc.factor(i);
+          System.out.print("The factors of " + i + " are");
+
+          for (int k = 0; k < factors.length; k++) {
+            System.out.print(" " + factors[k]);
+          }
+
+          System.out.println(".");
+        } catch (RemoteException e) {
+          System.err.println("Could not factor " + i);
+          e.printStackTrace();
+        }
+      }
+    }
+  }
+}

Added: 
logback/trunk/logback-examples/src/main/java/chapter7/NumberCruncherServer.java
==============================================================================
--- (empty file)
+++ 
logback/trunk/logback-examples/src/main/java/chapter7/NumberCruncherServer.java 
    Tue Dec  5 16:31:33 2006
@@ -0,0 +1,159 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it 
under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package chapter7;
+
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Vector;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.MDC;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.core.joran.spi.JoranException;
+
+
+/**
+ * A simple NumberCruncher implementation that logs its progress when
+ * factoring numbers. The purpose of the whole exercise is to show the
+ * use of mapped diagnostic contexts in order to distinguish the log
+ * output from different client requests.
+ * */
+public class NumberCruncherServer extends UnicastRemoteObject
+  implements NumberCruncher {
+
+  private static final long serialVersionUID = 1L;
+
+  static Logger logger = LoggerFactory.getLogger(NumberCruncherServer.class);
+
+  public NumberCruncherServer() throws RemoteException {
+  }
+
+  public int[] factor(int number) throws RemoteException {
+    // The client's host is an important source of information.
+    try {
+      MDC.put("client", NumberCruncherServer.getClientHost());
+    } catch (java.rmi.server.ServerNotActiveException e) {
+      logger.warn("Caught unexpected ServerNotActiveException.", e);
+    }
+
+    // The information contained within the request is another source
+    // of distinctive information. It might reveal the users name,
+    // date of request, request ID etc. In servlet type environments,
+    // useful information is contained in the HttpRequest or in the  
+    // HttpSession.
+    MDC.put("number", String.valueOf(number));
+
+    logger.info("Beginning to factor.");
+
+    if (number <= 0) {
+      throw new IllegalArgumentException(number +
+        " is not a positive integer.");
+    } else if (number == 1) {
+      return new int[] { 1 };
+    }
+
+    Vector<Integer> factors = new Vector<Integer>();
+    int n = number;
+
+    for (int i = 2; (i <= n) && ((i * i) <= number); i++) {
+      // It is bad practice to place log requests within tight loops.
+      // It is done here to show interleaved log output from
+      // different requests. 
+      logger.debug("Trying " + i + " as a factor.");
+
+      if ((n % i) == 0) {
+        logger.info("Found factor " + i);
+        factors.addElement(new Integer(i));
+
+        do {
+          n /= i;
+        } while ((n % i) == 0);
+      }
+
+      // Placing artificial delays in tight-loops will also lead to
+      // sub-optimal resuts. :-)
+      delay(100);
+    }
+
+    if (n != 1) {
+      logger.info("Found factor " + n);
+      factors.addElement(new Integer(n));
+    }
+
+    int len = factors.size();
+
+    int[] result = new int[len];
+
+    for (int i = 0; i < len; i++) {
+      result[i] = ((Integer) factors.elementAt(i)).intValue();
+    }
+
+    // clean up
+    MDC.remove("client");
+    MDC.remove("number");
+
+    return result;
+  }
+
+  static void usage(String msg) {
+    System.err.println(msg);
+    System.err.println("Usage: java chapter7.NumberCruncherServer 
configFile\n" +
+      "   where configFile is a logback configuration file.");
+    System.exit(1);
+  }
+
+  public static void delay(int millis) {
+    try {
+      Thread.sleep(millis);
+    } catch (InterruptedException e) {
+    }
+  }
+
+  public static void main(String[] args) {
+    if (args.length != 1) {
+      usage("Wrong number of arguments.");
+    }
+
+    String configFile = args[0];
+
+    if (configFile.endsWith(".xml")) {
+      try {
+        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+        JoranConfigurator configurator = new JoranConfigurator();
+        configurator.setContext(lc);
+        lc.shutdownAndReset();
+        configurator.doConfigure(args[0]);
+      } catch (JoranException je) {
+        je.printStackTrace();
+      }
+    }
+
+    NumberCruncherServer ncs;
+
+    try {
+      ncs = new NumberCruncherServer();
+      logger.info("Creating registry.");
+
+      Registry registry = 
LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
+      registry.rebind("Factor", ncs);
+      logger.info("NumberCruncherServer bound and ready.");
+    } catch (Exception e) {
+      logger.error("Could not bind NumberCruncherServer.", e);
+
+      return;
+    }
+  }
+}

Added: logback/trunk/logback-examples/src/main/java/chapter7/SimpleMDC.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-examples/src/main/java/chapter7/SimpleMDC.java        
Tue Dec  5 16:31:33 2006
@@ -0,0 +1,52 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it 
under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package chapter7;
+
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.MDC;
+import ch.qos.logback.classic.PatternLayout;
+import ch.qos.logback.core.ConsoleAppender;
+
+public class SimpleMDC {
+  static public void main(String[] args) throws Exception {
+    // You can put values in the MDC at any time. We first put the
+    // first name
+    MDC.put("first", "Dorothy");
+
+    // Configure logback
+    PatternLayout layout = new PatternLayout();
+    layout.setPattern("%X{first} %X{last} - %m%n");
+    layout.start();
+    ConsoleAppender appender = new ConsoleAppender();
+    appender.setLayout(layout);
+    appender.start();
+    Logger root = (Logger)LoggerFactory.getLogger("root");
+    root.addAppender(appender);
+    
+    // get a logger
+    Logger logger = (Logger)LoggerFactory.getLogger(SimpleMDC.class);
+
+    // We now put the last name
+    MDC.put("last", "Parker");
+
+    // The most beautiful two words in the English language according
+    // to Dorothy Parker:
+    logger.info("Check enclosed.");
+    logger.debug("The most beautiful two words in English.");
+
+    MDC.put("first", "Richard");
+    MDC.put("last", "Nixon");
+    logger.info("I am not a crook.");
+    logger.info("Attributed to the former US president. 17 Nov 1973.");
+  }
+}

Added: logback/trunk/logback-examples/src/main/java/chapter7/mdc1.xml
==============================================================================
--- (empty file)
+++ logback/trunk/logback-examples/src/main/java/chapter7/mdc1.xml      Tue Dec 
 5 16:31:33 2006
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<configuration>
+
+  <appender name="CONSOLE"
+            class="ch.qos.logback.core.ConsoleAppender">
+    <layout class="ch.qos.logback.classic.PatternLayout">
+      <Pattern>%-4r [%thread] %-5level C:%X{client} N:%X{number} - 
%msg%n</Pattern>
+    </layout>      
+  </appender>
+  
+  <root>
+    <level value ="debug"/>
+    <appender-ref ref="CONSOLE"/>
+  </root>  
+</configuration>

Modified: logback/trunk/logback-site/src/site/xdocTemplates/manual/filters.xml
==============================================================================
--- logback/trunk/logback-site/src/site/xdocTemplates/manual/filters.xml        
(original)
+++ logback/trunk/logback-site/src/site/xdocTemplates/manual/filters.xml        
Tue Dec  5 16:31:33 2006
@@ -157,11 +157,11 @@
                </p>
                
                <table>
-                       <th>
-                               <td>Name</td>
-                               <td>Type</td>
-                               <td>Description</td>
-                       </th>
+                       <tr>
+                               <th>Name</th>
+                               <th>Type</th>
+                               <th>Description</th>
+                       </tr>
                        <tr>
                                <td>event
                                </td>
@@ -285,21 +285,21 @@
 <em>Example 6.1: Basic event evaluator usage 
(logback-examples/src/main/java/chapter6/turboFilters.xml)</em>
 <div class="source"><pre>&lt;configuration>
 
-       &lt;turboFilter class="ch.qos.logback.classic.turbo.MDCFilter">
-               &lt;MDCKey>username&lt;/MDCKey>
-               &lt;Value>sebastien&lt;/Value>
-               &lt;OnMatch>ACCEPT&lt;/OnMatch>
-       &lt;/turboFilter>
+  &lt;turboFilter class="ch.qos.logback.classic.turbo.MDCFilter">
+    &lt;MDCKey>username&lt;/MDCKey>
+    &lt;Value>sebastien&lt;/Value>
+    &lt;OnMatch>ACCEPT&lt;/OnMatch>
+  &lt;/turboFilter>
        
-       &lt;turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
-               &lt;Marker>billing&lt;/Marker>
-               &lt;OnMatch>DENY&lt;/OnMatch>
-       &lt;/turboFilter>
+  &lt;turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
+    &lt;Marker>billing&lt;/Marker>
+    &lt;OnMatch>DENY&lt;/OnMatch>
+  &lt;/turboFilter>
 
   &lt;appender name="console" class="ch.qos.logback.core.ConsoleAppender">
     &lt;layout class="ch.qos.logback.classic.PatternLayout">
       &lt;Pattern>%date [%thread] %-5level %logger - %msg%n&lt;/Pattern>
-    &lt;/layout>
+  &lt;/layout>
   &lt;/appender>
 
   &lt;root>
@@ -358,7 +358,7 @@
                </p>
     
     
-    <h3>Logback Access</h3>
+    <h2>Logback Access</h2>
     
     <p>
        Logback access benefits from most of the possibilities available
@@ -368,7 +368,7 @@
        <code>TurboFilter</code> objects are not available to the access module.
     </p>
     
-    <h2>Filters</h2>
+    <h3>Filters</h3>
     
     <p>
        <code>EvaluatorFilter</code> objects, with their expressions, are 
available to

Added: logback/trunk/logback-site/src/site/xdocTemplates/manual/mdc.xml
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/xdocTemplates/manual/mdc.xml    Tue Dec 
 5 16:31:33 2006
@@ -0,0 +1,478 @@
+<document>
+<!-- 
+               
+               Warning: do not use any auto-format function on this file.
+               Since "source" divs use pre as white-space, it affects the
+               look of the code parts in this document.
+               
+       -->
+
+       <body>
+               <h2>Chapter 7: Mapped Diagnostic Context</h2>
+               <div class="author">
+                       Authors: Ceki G&#252;lc&#252;, S&#233;bastien Pennec
+               </div>
+
+               <table>
+                       <tr>
+                               <td valign="top" align="top">
+                                               <a rel="license"
+                                                       
href="http://creativecommons.org/licenses/by-nc-sa/2.5/";>
+                                                       <img alt="Creative 
Commons License"
+                                                               
style="border-width: 0"
+                                                               
src="http://creativecommons.org/images/public/somerights20.png"; />
+                                               </a>
+                               </td>
+                               <td>
+                                       <p>Copyright &#169; 2000-2006, 
QOS.ch</p>
+
+                                       <p>
+                                               <!--Creative Commons License-->
+                                               This work is licensed under a
+                                               <a rel="license"
+                                                       
href="http://creativecommons.org/licenses/by-nc-sa/2.5/";>
+                                                       Creative Commons
+                                                       
Attribution-NonCommercial-ShareAlike 2.5
+                                                       License
+                                               </a>.
+                                               <!--/Creative Commons License-->
+                                       </p>
+                               </td>
+                       </tr>
+               </table>
+               
+               <p>
+                               One of the design goals of logback is to audit 
and debug complex distributed applications. 
+                               Most real-world distributed systems need to 
deal with multiple clients simultaneously. 
+                               In a typical multithreaded implementation of 
such a system, different threads will handle 
+                               different clients. A possible but discouraged 
approach to differentiate the logging output of 
+                               one client from another consists of 
instantiating a new and separate logger for each client. 
+                               This technique promotes the proliferation of 
loggers and considerably increases 
+                               their management overhead.
+               </p>
+               <p> 
+                               A lighter technique consists of uniquely 
stamping each 
+                               log request servicing a given client. Neil 
Harrison described this method in the book 
+                               <em>"Patterns for Logging Diagnostic 
Messages,"</em> in 
+                               Pattern Languages of Program Design 3, edited 
by R. Martin, D. Riehle, 
+                               and F. Buschmann (Addison-Wesley, 1997). 
Logback offers a variant of this technique: 
+                               Mapped Diagnostic Contexts (MDC).
+               </p>
+               
+               <p>
+                       To uniquely stamp each request, the user puts 
contextual information into the 
+                       <code><a 
href="../xref/ch/qos/logback/classic/MDC.html">MDC</a></code>, 
+                       the abbreviation of Mapped Diagnostic Context. 
+                       The public interface of the MDC class is shown below. 
+               </p>
+
+<div class="source"><pre>package ch.qos.logback.classic;
+
+public class MDC {
+  //Put a context value as identified by <em>key</em>
+  //into the current thread's context map.
+  <b>public static void put(String key, String val);</b>
+
+  //Get the context identified by the <code>key</code> parameter.
+  <b>public static String get(String key);</b>
+
+  //Remove the the context identified by the <code>key</code> parameter.
+  <b>public static void remove(String key);</b>
+
+  //Clear all entries in the MDC.
+  <b>public static void clear();</b>
+
+  //Returns the keys in the MDC as a Set. The returned value can be null.
+  <b>public static Set&lt;String> getKeys();</b>
+}</pre></div>
+
+               <p>
+                       The <code>MDC</code> class contains only static 
methods. 
+                       It lets the developer place information in a 
“diagnostic context” that can be 
+                       subsequently retrieved by certain logback components. 
The 
+                       <code>MDC</code> manages contextual information on a 
per thread basis.  
+                       Typically, while starting to service a new client 
request, the developer will 
+                       insert pertinent contextual information, such as the 
client id, client's IP 
+                       address, request parameters etc. into the 
<code>MDC</code>. Logback components, 
+                       if appropriately configured, will automatically include 
this information 
+                       in each log entry.
+               </p>
+
+               <p>
+                       The next application named 
+                       <code><a 
href="../xref/chapter7/SimpleMDC.html">SimpleMDC</a></code> 
+                       demonstrates this basic principle.
+               </p>
+<em>Example 7.1: Basic MDC usage (<a href="../xref/chapter7/SimpleMDC.html">
+logback-examples/src/main/java/chapter7/SimpleMDC.java)</a></em>
+<div class="source"><pre>package chapter7;
+
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.MDC;
+import ch.qos.logback.classic.PatternLayout;
+import ch.qos.logback.core.ConsoleAppender;
+
+public class SimpleMDC {
+  static public void main(String[] args) throws Exception {
+    // You can put values in the MDC at any time. We first put the
+    // first name
+    <b>MDC.put("first", "Dorothy");</b>
+
+    // Configure logback
+    PatternLayout layout = new PatternLayout();
+    layout.setPattern("%X{first} %X{last} - %m%n");
+    layout.start();
+    ConsoleAppender appender = new ConsoleAppender();
+    appender.setLayout(layout);
+    appender.start();
+    Logger root = (Logger)LoggerFactory.getLogger("root");
+    root.addAppender(appender);
+    
+    // get a logger
+    Logger logger = (Logger)LoggerFactory.getLogger(SimpleMDC.class);
+
+    // We now put the last name
+    <b>MDC.put("last", "Parker");</b>
+
+    // The most beautiful two words in the English language according
+    // to Dorothy Parker:
+    logger.info("Check enclosed.");
+    logger.debug("The most beautiful two words in English.");
+
+    MDC.put("first", "Richard");
+    MDC.put("last", "Nixon");
+    logger.info("I am not a crook.");
+    logger.info("Attributed to the former US president. 17 Nov 1973.");
+  }
+}</pre></div>
+
+               <p>
+                       The main method starts by associating the value 
<em>Dorothy</em> with 
+                       the key <em>first</em> in the <code>MDC</code>. You can 
place as many 
+                       value/key associations in the <code>MDC</code> as you 
wish. 
+                       Multiple insertions with the same key will overwrite 
older values. 
+                       The code then proceeds to configure logback. 
+                       Note the usage of the <em>%X</em> specifier within the 
+                       <code>PatternLayout</code> conversion pattern. The 
<em>%X</em> 
+                       conversion specifier is employed twice, once for the 
key <em>first</em> 
+                       and once for the key <em>last</em>. After configuring 
the root logger, 
+                       the code associates the value <em>Parker</em> with the 
key <em>last</em>. 
+                       It then invokes the logger twice with different 
messages. 
+                       The code finishes by setting the <code>MDC</code> to 
different values 
+                       and issuing several logging requests. Running SimpleMDC 
yields:
+               </p>
+
+<div class="source"><pre>Dorothy Parker - Check enclosed.
+Dorothy Parker - The most beautiful two words in English.
+Richard Nixon - I am not a crook.
+Richard Nixon - Attributed to the former US president. 17 Nov 1973.</pre></div>
+
+
+               <p>
+                       The <code>SimpleMDC</code> application illustrates how 
logback layouts, 
+                       if configured appropriately, automatically output 
<code>MDC</code> information. 
+                       Moreover, the information placed into the 
<code>MDC</code> can be used by 
+                       multiple logger invocations.
+               </p>
+               
+               <p>
+                       Mapped Diagnostic Contexts shine brightest within 
client server architectures. 
+                       Typically, multiple clients will be served by multiple 
threads on the server. 
+                       Although the methods in the <code>MDC</code> class are 
static, 
+                       the diagnostic context is managed on a per thread 
basis, allowing each server 
+                       thread to bear a distinct <code>MDC</code> stamp. 
<code>MDC</code> operations 
+                       such as <code>put()</code> and <code>get()</code> 
affect the <code>MDC</code> 
+                       of the <em>current</em> thread only. The 
<code>MDC</code> in other threads remain 
+                       unaffected. Given that <code>MDC</code> information is 
managed on a 
+                       per thread basis, each thread will have its own copy of 
the <code>MDC</code>. 
+                       Thus, there is no need for the developer to worry about 
thread-safety or 
+                       synchronization when programming with the 
<code>MDC</code> because 
+                       it safely and transparently handles these issues.
+               </p>
+
+               <p>
+                       The next example is somewhat more advanced. 
+                       It shows how the        <code>MDC</code> can be used in 
a client-server setting. 
+                       The server-side implements the 
<code>NumberCruncher</code> interface shown in 
+                       Example 7.2 below. <code>The NumberCruncher</code> 
interface contains a single 
+                       method named <code>factor()</code>. Using RMI 
technology, client invokes the 
+                       <code>factor()</code> method of the server application 
to retrieve the distinct 
+                       factors of an integer.
+               </p>
+
+<em>Example 7.2: The service interface (<a 
href="../xref/chapter7/NumberCruncher.html">
+logback-examples/src/main/java/chapter7/NumberCruncher.java)</a></em>
+<div class="source"><pre>package chapter7;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * NumberCruncher factors positive integers.
+ */
+public interface NumberCruncher extends Remote {
+  /**
+   * Factor a positive integer <code>number</code> and return its
+   * <em>distinct</em> factor's as an integer array.
+   * */
+  int[] factor(int number) throws RemoteException;
+}</pre></div>
+
+               <p>
+                       The <code>NumberCruncherServer</code> application, 
listed in Example 7.3 below, 
+                       implements the <code>NumberCruncher</code> interface. 
Its main method exports 
+                       an RMI Registry on the local host that accepts requests 
on a well-known port.  
+               </p>
+
+<em>Example 7.2: The server side (<a 
href="../xref/chapter7/NumberCruncherServer.html">
+logback-examples/src/main/java/chapter7/NumberCruncherServer.java)</a></em>
+<div class="source"><pre>package chapter7;
+
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Vector;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.MDC;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.core.joran.spi.JoranException;
+
+
+/**
+ * A simple NumberCruncher implementation that logs its progress when
+ * factoring numbers. The purpose of the whole exercise is to show the
+ * use of mapped diagnostic contexts in order to distinguish the log
+ * output from different client requests.
+ * */
+public class NumberCruncherServer extends UnicastRemoteObject
+  implements NumberCruncher {
+
+  private static final long serialVersionUID = 1L;
+
+  static Logger logger = LoggerFactory.getLogger(NumberCruncherServer.class);
+
+  public NumberCruncherServer() throws RemoteException {
+  }
+
+  public int[] factor(int number) throws RemoteException {
+    // The client's host is an important source of information.
+    try {
+      <b>MDC.put("client", NumberCruncherServer.getClientHost());</b>
+    } catch (java.rmi.server.ServerNotActiveException e) {
+      logger.warn("Caught unexpected ServerNotActiveException.", e);
+    }
+
+    // The information contained within the request is another source
+    // of distinctive information. It might reveal the users name,
+    // date of request, request ID etc. In servlet type environments,
+    // useful information is contained in the HttpRequest or in the  
+    // HttpSession.
+    <b>MDC.put("number", String.valueOf(number));</b>
+
+    logger.info("Beginning to factor.");
+
+    if (number &lt;= 0) {
+      throw new IllegalArgumentException(number +
+        " is not a positive integer.");
+    } else if (number == 1) {
+      return new int[] { 1 };
+    }
+
+    Vector&lt;Integer> factors = new Vector&lt;Integer>();
+    int n = number;
+
+    for (int i = 2; (i &lt;= n) &amp;&amp; ((i * i) &lt;= number); i++) {
+      // It is bad practice to place log requests within tight loops.
+      // It is done here to show interleaved log output from
+      // different requests. 
+      logger.debug("Trying " + i + " as a factor.");
+
+      if ((n % i) == 0) {
+        logger.info("Found factor " + i);
+        factors.addElement(new Integer(i));
+
+        do {
+          n /= i;
+        } while ((n % i) == 0);
+      }
+
+      // Placing artificial delays in tight-loops will also lead to
+      // sub-optimal resuts. :-)
+      delay(100);
+    }
+
+    if (n != 1) {
+      logger.info("Found factor " + n);
+      factors.addElement(new Integer(n));
+    }
+
+    int len = factors.size();
+
+    int[] result = new int[len];
+
+    for (int i = 0; i &lt; len; i++) {
+      result[i] = ((Integer) factors.elementAt(i)).intValue();
+    }
+
+    <b>// clean up
+    MDC.remove("client");
+    MDC.remove("number");</b>
+
+    return result;
+  }
+
+  static void usage(String msg) {
+    System.err.println(msg);
+    System.err.println("Usage: java chapter7.NumberCruncherServer 
configFile\n" +
+      "   where configFile is a logback configuration file.");
+    System.exit(1);
+  }
+
+  public static void delay(int millis) {
+    try {
+      Thread.sleep(millis);
+    } catch (InterruptedException e) {
+    }
+  }
+
+  public static void main(String[] args) {
+    if (args.length != 1) {
+      usage("Wrong number of arguments.");
+    }
+
+    String configFile = args[0];
+
+    if (configFile.endsWith(".xml")) {
+      try {
+        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+        JoranConfigurator configurator = new JoranConfigurator();
+        configurator.setContext(lc);
+        lc.shutdownAndReset();
+        configurator.doConfigure(args[0]);
+      } catch (JoranException je) {
+        je.printStackTrace();
+      }
+    }
+
+    NumberCruncherServer ncs;
+
+    try {
+      ncs = new NumberCruncherServer();
+      logger.info("Creating registry.");
+
+      Registry registry = 
LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
+      registry.rebind("Factor", ncs);
+      logger.info("NumberCruncherServer bound and ready.");
+    } catch (Exception e) {
+      logger.error("Could not bind NumberCruncherServer.", e);
+
+      return;
+    }
+  }
+}</pre></div>
+
+               <p>
+                               The implementation of the <code>factor(int 
number)</code> method is 
+                               of particular relevance. It starts by putting 
the client's hostname into the 
+                               <code>MDC</code> under the key <em>client</em>. 
The number to factor, 
+                               as requested by the client, is put into the 
<code>MDC</code> under the key 
+                               <em>number</em>. After computing the distinct 
factors of the integer 
+                               parameter, the result is returned to the 
client. Before returning the 
+                               result however, the values for the 
<em>client</em> and <em>number</em> are 
+                               cleared by calling the 
<code>MDC.remove(9</code> method. Normally, 
+                               a <code>put()</code> operation should be 
balanced by the corresponding 
+                               <code>remove()</code> operation. Otherwise, the 
<code>MDC</code> will 
+                               contain stale values for certain keys. We would 
recommend that whenever 
+                               possible <code>remove()</code> operations be 
performed within finally blocks, 
+                               ensuring their invocation regardless of the 
execution path of the code.
+               </p>    
+               
+               <p>
+                       After these theoretical explanations, we are ready to 
run the number 
+                       cruncher example. Start the server with the following 
command:
+               </p>
+               
+<div class="source"><pre>java chapter7.NumberCruncherServer 
src/main/java/chapter7/mdc1.xml</pre></div>
+               
+               <p>
+                       The <em>mdc1.xml</em> configuration file is listed 
below:
+               </p>
+
+<div class="source"><pre>&lt;configuration>
+
+  &lt;appender name="CONSOLE"
+    class="ch.qos.logback.core.ConsoleAppender">
+    &lt;layout class="ch.qos.logback.classic.PatternLayout">
+      &lt;Pattern>%-4r [%thread] %-5level <b>C:%X{client} N:%X{number}</b> - 
%msg%n&lt;/Pattern>
+    &lt;/layout>           
+  &lt;/appender>
+  
+  &lt;root>
+    &lt;level value ="debug"/>
+    &lt;appender-ref ref="CONSOLE"/>
+  &lt;/root>  
+&lt;/configuration></pre></div>
+
+               <p>
+                       Note the use of the <em>%X</em> conversion specifier 
within the 
+                       <span class="option">Pattern</span> option.
+               </p>
+       
+               <p>
+                       The following command starts an instance of 
<code>NumberCruncherClient</code> 
+                       application:    
+               </p>
+               
+<div class="source"><pre>java chapter7.NumberCruncherClient 
<em>hostname</em></pre></div>
+
+               <p>
+                       where <em>hostname</em> is the host where the 
+                       <code>NumberCruncherServer</code> is running
+               </p>
+               
+               <p>
+                       Executing multiple instances of the client and 
requesting the server to factor 
+                       the numbers 129 from the first client and shortly 
thereafter 
+                       the number 71 from the second client, the server 
outputs the following (edited to fit):
+               </p>
+               
+<div class="source"><pre>
+70984 [RMI TCP Connection(4)-192.168.1.6] INFO  C:192.168.1.6 N:129 - 
Beginning to factor.
+70984 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:192.168.1.6 N:129 - Trying 2 
as a factor.
+71093 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:192.168.1.6 N:129 - Trying 3 
as a factor.
+71093 [RMI TCP Connection(4)-192.168.1.6] INFO  C:192.168.1.6 N:129 - Found 
factor 3
+71187 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:192.168.1.6 N:129 - Trying 4 
as a factor.
+71297 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:192.168.1.6 N:129 - Trying 5 
as a factor.
+71390 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:192.168.1.6 N:129 - Trying 6 
as a factor.
+71453 [RMI TCP Connection(5)-192.168.1.6] INFO  C:192.168.1.6 N:71 - Beginning 
to factor.
+71453 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:192.168.1.6 N:71 - Trying 2 
as a factor.
+71484 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:192.168.1.6 N:129 - Trying 7 
as a factor.
+71547 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:192.168.1.6 N:71 - Trying 3 
as a factor.
+71593 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:192.168.1.6 N:129 - Trying 8 
as a factor.
+71656 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:192.168.1.6 N:71 - Trying 4 
as a factor.
+71687 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:192.168.1.6 N:129 - Trying 9 
as a factor.
+71750 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:192.168.1.6 N:71 - Trying 5 
as a factor.
+71797 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:192.168.1.6 N:129 - Trying 
10 as a factor.
+71859 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:192.168.1.6 N:71 - Trying 6 
as a factor.
+71890 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:192.168.1.6 N:129 - Trying 
11 as a factor.
+71953 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:192.168.1.6 N:71 - Trying 7 
as a factor.
+72000 [RMI TCP Connection(4)-192.168.1.6] INFO  C:192.168.1.6 N:129 - Found 
factor 43
+72062 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:192.168.1.6 N:71 - Trying 8 
as a factor.
+72156 [RMI TCP Connection(5)-192.168.1.6] INFO  C:192.168.1.6 N:71 - Found 
factor 71</pre></div>
+               
+               
+               
+
+
+
+
+
+  </body>
+</document>
\ No newline at end of file
_______________________________________________
logback-dev mailing list
[email protected]
http://qos.ch/mailman/listinfo/logback-dev

Reply via email to