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