1 | // Copyright (c) 2002 SPY internetworking <dustin@spy.net> |
2 | |
3 | package net.spy.memcached.compat.log; |
4 | |
5 | import java.lang.reflect.Constructor; |
6 | import java.lang.reflect.InvocationTargetException; |
7 | import java.util.concurrent.ConcurrentHashMap; |
8 | import java.util.concurrent.ConcurrentMap; |
9 | |
10 | /** |
11 | * Factory to get logger instances. |
12 | * |
13 | * The system property <code>net.spy.compat.log.LoggerImpl</code> |
14 | * should point to an implementation of net.spy.compat.log.Logger to |
15 | * use. |
16 | * |
17 | * <p> |
18 | * Depending on how and where this was compiled, a sun logger (jdk 1.4) |
19 | * and/or <a href="http://jakarta.apache.org/log4j/docs/">log4j</a> logger |
20 | * implementation may be included. Both are included with the official |
21 | * distribution. |
22 | * </p> |
23 | * |
24 | * @see AbstractLogger |
25 | */ |
26 | public final class LoggerFactory extends Object { |
27 | |
28 | private static LoggerFactory instance=null; |
29 | |
30 | private final ConcurrentMap<String, Logger> instances; |
31 | private Constructor<? extends Logger> instanceConstructor; |
32 | |
33 | /** |
34 | * Get an instance of LoggerFactory. |
35 | */ |
36 | private LoggerFactory() { |
37 | super(); |
38 | |
39 | instances=new ConcurrentHashMap<String, Logger>(); |
40 | } |
41 | |
42 | private static void init() { |
43 | if(instance == null) { |
44 | instance=new LoggerFactory(); |
45 | } |
46 | } |
47 | |
48 | /** |
49 | * Get a logger by class. |
50 | * |
51 | * @param clazz the class for which we want the logger. |
52 | * @return a Logger instance |
53 | */ |
54 | public static Logger getLogger(Class<?> clazz) { |
55 | return(getLogger(clazz.getName())); |
56 | } |
57 | |
58 | /** |
59 | * Get a logger by name. |
60 | * |
61 | * @param name the name for which we want the logger |
62 | * @return a Logger instance |
63 | */ |
64 | public static Logger getLogger(String name) { |
65 | if(name == null) { |
66 | throw new NullPointerException("Logger name may not be null."); |
67 | } |
68 | init(); |
69 | return(instance.internalGetLogger(name)); |
70 | } |
71 | |
72 | // Get an instance of Logger from internal mechanisms. |
73 | private Logger internalGetLogger(String name) { |
74 | assert name != null : "Name was null"; |
75 | Logger rv=instances.get(name); |
76 | |
77 | if (rv==null) { |
78 | Logger newLogger=null; |
79 | try { |
80 | newLogger=getNewInstance(name); |
81 | } catch(Exception e) { |
82 | throw new RuntimeException("Problem getting logger", e); |
83 | } |
84 | Logger tmp=instances.putIfAbsent(name, newLogger); |
85 | // Return either the new logger we've just made, or one that was |
86 | // created while we were waiting |
87 | rv = tmp == null ? newLogger : tmp; |
88 | } |
89 | |
90 | return(rv); |
91 | |
92 | } |
93 | |
94 | private Logger getNewInstance(String name) |
95 | throws InstantiationException, IllegalAccessException, |
96 | IllegalArgumentException, InvocationTargetException { |
97 | |
98 | if(instanceConstructor==null) { |
99 | getConstructor(); |
100 | } |
101 | Object[] args={name}; |
102 | Logger rv=instanceConstructor.newInstance(args); |
103 | |
104 | return (rv); |
105 | } |
106 | |
107 | // Find the appropriate constructor |
108 | @SuppressWarnings("unchecked") |
109 | private void getConstructor() { |
110 | Class<? extends Logger> c=DefaultLogger.class; |
111 | String className=System.getProperty("net.spy.log.LoggerImpl"); |
112 | |
113 | if(className!=null) { |
114 | try { |
115 | c=(Class<? extends Logger>) Class.forName(className); |
116 | } catch(NoClassDefFoundError e) { |
117 | System.err.println("Warning: " + className |
118 | + " not found while initializing" |
119 | + " net.spy.compat.log.LoggerFactory"); |
120 | e.printStackTrace(); |
121 | c=DefaultLogger.class; |
122 | } catch(ClassNotFoundException e) { |
123 | System.err.println("Warning: " + className |
124 | + " not found while initializing" |
125 | + " net.spy.compat.log.LoggerFactory"); |
126 | e.printStackTrace(); |
127 | c=DefaultLogger.class; |
128 | } |
129 | } |
130 | |
131 | // Find the best constructor |
132 | try { |
133 | // Try to find a constructor that takes a single string |
134 | Class[] args={String.class}; |
135 | instanceConstructor=c.getConstructor(args); |
136 | } catch(NoSuchMethodException e) { |
137 | try { |
138 | // Try to find an empty constructor |
139 | Class[] args={}; |
140 | instanceConstructor=c.getConstructor(args); |
141 | } catch(NoSuchMethodException e2) { |
142 | System.err.println("Warning: " + className |
143 | + " has no appropriate constructor, using defaults."); |
144 | |
145 | // Try to find a constructor that takes a single string |
146 | try { |
147 | Class[] args={String.class}; |
148 | instanceConstructor= |
149 | DefaultLogger.class.getConstructor(args); |
150 | } catch(NoSuchMethodException e3) { |
151 | // This shouldn't happen. |
152 | throw new NoSuchMethodError( |
153 | "There used to be a constructor that takes a single " |
154 | + "String on " |
155 | + DefaultLogger.class + ", but I can't " |
156 | + "find one now."); |
157 | } // SOL |
158 | } // No empty constructor |
159 | } // No constructor that takes a string |
160 | } // getConstructor |
161 | |
162 | } |