001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package chapters.mdc; 015 016import java.rmi.RemoteException; 017import java.rmi.registry.LocateRegistry; 018import java.rmi.registry.Registry; 019import java.rmi.server.UnicastRemoteObject; 020import java.util.Vector; 021 022import org.slf4j.Logger; 023import org.slf4j.LoggerFactory; 024import org.slf4j.MDC; 025 026import ch.qos.logback.classic.LoggerContext; 027import ch.qos.logback.classic.joran.JoranConfigurator; 028import ch.qos.logback.core.joran.spi.JoranException; 029 030/** 031 * A simple NumberCruncher implementation that logs its progress when 032 * factoring numbers. The purpose of the whole exercise is to show the 033 * use of mapped diagnostic contexts in order to distinguish the log 034 * output from different client requests. 035 * */ 036public class NumberCruncherServer extends UnicastRemoteObject implements NumberCruncher { 037 038 private static final long serialVersionUID = 1L; 039 040 static Logger logger = LoggerFactory.getLogger(NumberCruncherServer.class); 041 042 public NumberCruncherServer() throws RemoteException { 043 } 044 045 public int[] factor(int number) throws RemoteException { 046 // The client's host is an important source of information. 047 try { 048 MDC.put("client", NumberCruncherServer.getClientHost()); 049 } catch (java.rmi.server.ServerNotActiveException e) { 050 logger.warn("Caught unexpected ServerNotActiveException.", e); 051 } 052 053 // The information contained within the request is another source 054 // of distinctive information. It might reveal the users name, 055 // date of request, request ID etc. In servlet type environments, 056 // useful information is contained in the HttpRequest or in the 057 // HttpSession. 058 MDC.put("number", String.valueOf(number)); 059 060 logger.info("Beginning to factor."); 061 062 if (number <= 0) { 063 throw new IllegalArgumentException(number + " is not a positive integer."); 064 } else if (number == 1) { 065 return new int[] { 1 }; 066 } 067 068 Vector<Integer> factors = new Vector<Integer>(); 069 int n = number; 070 071 for (int i = 2; (i <= n) && ((i * i) <= number); i++) { 072 // It is bad practice to place log requests within tight loops. 073 // It is done here to show interleaved log output from 074 // different requests. 075 logger.debug("Trying " + i + " as a factor."); 076 077 if ((n % i) == 0) { 078 logger.info("Found factor " + i); 079 factors.addElement(i); 080 081 do { 082 n /= i; 083 } while ((n % i) == 0); 084 } 085 086 // Placing artificial delays in tight loops will also lead to 087 // sub-optimal results. :-) 088 delay(100); 089 } 090 091 if (n != 1) { 092 logger.info("Found factor " + n); 093 factors.addElement(n); 094 } 095 096 int len = factors.size(); 097 098 int[] result = new int[len]; 099 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}