View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package chapter7;
15  
16  import java.rmi.RemoteException;
17  import java.rmi.registry.LocateRegistry;
18  import java.rmi.registry.Registry;
19  import java.rmi.server.UnicastRemoteObject;
20  import java.util.Vector;
21  
22  import org.slf4j.Logger;
23  import org.slf4j.LoggerFactory;
24  import org.slf4j.MDC;
25  
26  import ch.qos.logback.classic.LoggerContext;
27  import ch.qos.logback.classic.joran.JoranConfigurator;
28  import ch.qos.logback.core.joran.spi.JoranException;
29  
30  
31  /**
32   * A simple NumberCruncher implementation that logs its progress when
33   * factoring numbers. The purpose of the whole exercise is to show the
34   * use of mapped diagnostic contexts in order to distinguish the log
35   * output from different client requests.
36   * */
37  public class NumberCruncherServer extends UnicastRemoteObject
38    implements NumberCruncher {
39  
40    private static final long serialVersionUID = 1L;
41  
42    static Logger logger = LoggerFactory.getLogger(NumberCruncherServer.class);
43  
44    public NumberCruncherServer() throws RemoteException {
45    }
46  
47    public int[] factor(int number) throws RemoteException {
48      // The client's host is an important source of information.
49      try {
50        MDC.put("client", NumberCruncherServer.getClientHost());
51      } catch (java.rmi.server.ServerNotActiveException e) {
52        logger.warn("Caught unexpected ServerNotActiveException.", e);
53      }
54  
55      // The information contained within the request is another source
56      // of distinctive information. It might reveal the users name,
57      // date of request, request ID etc. In servlet type environments,
58      // useful information is contained in the HttpRequest or in the  
59      // HttpSession.
60      MDC.put("number", String.valueOf(number));
61  
62      logger.info("Beginning to factor.");
63  
64      if (number <= 0) {
65        throw new IllegalArgumentException(number +
66          " is not a positive integer.");
67      } else if (number == 1) {
68        return new int[] { 1 };
69      }
70  
71      Vector<Integer> factors = new Vector<Integer>();
72      int n = number;
73  
74      for (int i = 2; (i <= n) && ((i * i) <= number); i++) {
75        // It is bad practice to place log requests within tight loops.
76        // It is done here to show interleaved log output from
77        // different requests. 
78        logger.debug("Trying " + i + " as a factor.");
79  
80        if ((n % i) == 0) {
81          logger.info("Found factor " + i);
82          factors.addElement(new Integer(i));
83  
84          do {
85            n /= i;
86          } while ((n % i) == 0);
87        }
88  
89        // Placing artificial delays in tight loops will also lead to
90        // sub-optimal resuts. :-)
91        delay(100);
92      }
93  
94      if (n != 1) {
95        logger.info("Found factor " + n);
96        factors.addElement(new Integer(n));
97      }
98  
99      int len = factors.size();
100 
101     int[] result = new int[len];
102 
103     for (int i = 0; i < len; i++) {
104       result[i] = ((Integer) factors.elementAt(i)).intValue();
105     }
106 
107     // clean up
108     MDC.remove("client");
109     MDC.remove("number");
110 
111     return result;
112   }
113 
114   static void usage(String msg) {
115     System.err.println(msg);
116     System.err.println("Usage: java chapter7.NumberCruncherServer configFile\n" +
117       "   where configFile is a logback configuration file.");
118     System.exit(1);
119   }
120 
121   public static void delay(int millis) {
122     try {
123       Thread.sleep(millis);
124     } catch (InterruptedException e) {
125     }
126   }
127 
128   public static void main(String[] args) {
129     if (args.length != 1) {
130       usage("Wrong number of arguments.");
131     }
132 
133     String configFile = args[0];
134 
135     if (configFile.endsWith(".xml")) {
136       try {
137         LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
138         JoranConfigurator configurator = new JoranConfigurator();
139         configurator.setContext(lc);
140         lc.reset();
141         configurator.doConfigure(args[0]);
142       } catch (JoranException je) {
143         je.printStackTrace();
144       }
145     }
146 
147     NumberCruncherServer ncs;
148 
149     try {
150       ncs = new NumberCruncherServer();
151       logger.info("Creating registry.");
152 
153       Registry registry = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
154       registry.rebind("Factor", ncs);
155       logger.info("NumberCruncherServer bound and ready.");
156     } catch (Exception e) {
157       logger.error("Could not bind NumberCruncherServer.", e);
158 
159       return;
160     }
161   }
162 }