1 | // Copyright 2004-2007 Jean-Francois Poilpret |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | package net.sourceforge.hiveutils.service.impl; |
16 | |
17 | import java.lang.reflect.InvocationHandler; |
18 | import java.lang.reflect.InvocationTargetException; |
19 | import java.lang.reflect.Method; |
20 | import java.lang.reflect.Proxy; |
21 | import java.util.List; |
22 | |
23 | import org.apache.commons.logging.Log; |
24 | |
25 | import org.apache.hivemind.InterceptorStack; |
26 | import org.apache.hivemind.ServiceInterceptorFactory; |
27 | import org.apache.hivemind.internal.Module; |
28 | import org.apache.hivemind.methodmatch.MethodMatcher; |
29 | import org.apache.hivemind.service.MethodSignature; |
30 | import org.apache.hivemind.service.impl.LoggingUtils; |
31 | |
32 | /** |
33 | * This service creates service interceptors that allow to log all calls to a |
34 | * service. Logging level is customizable. Any <code>Throwable</code> thrown |
35 | * by the service will be logged, including <code>Error</code>s. |
36 | * |
37 | * @author Jean-Francois Poilpret |
38 | */ |
39 | public class LoggingInterceptorFactory implements ServiceInterceptorFactory |
40 | { |
41 | public LoggingInterceptorFactory() |
42 | { |
43 | _default.setLogEnter(LoggingLevel.Debug); |
44 | _default.setLogLeave(LoggingLevel.Debug); |
45 | _default.setLogThrow(LoggingLevel.Debug); |
46 | } |
47 | |
48 | @SuppressWarnings("unchecked") |
49 | public void createInterceptor( InterceptorStack stack, |
50 | Module invokingMod, |
51 | List parameters) |
52 | { |
53 | Log logger = stack.getServiceLog(); |
54 | stack.push(Proxy.newProxyInstance( |
55 | invokingMod.getClassResolver().getClassLoader(), |
56 | new Class[] {stack.getServiceInterface()}, |
57 | new Interceptor(logger, stack.peek(), parameters))); |
58 | } |
59 | |
60 | private class Interceptor implements InvocationHandler |
61 | { |
62 | public Interceptor(Log logger, Object target, List<LoggingContribution> parameters) |
63 | { |
64 | _logger = logger; |
65 | _target = target; |
66 | for (LoggingContribution contrib: parameters) |
67 | { |
68 | _methodMatcher.put(contrib.getPattern(), contrib); |
69 | } |
70 | } |
71 | |
72 | //CSOFF: IllegalThrowsCheck |
73 | //CSOFF: IllegalCatchCheck |
74 | public Object invoke(Object proxy, Method method, Object[] args) |
75 | throws Throwable |
76 | { |
77 | MethodSignature signature = new MethodSignature(method); |
78 | LoggingContribution info = getLoggingInfo(signature); |
79 | try |
80 | { |
81 | logEnter(info.getLogEnter(), signature, args); |
82 | Object result = method.invoke(_target, args); |
83 | logLeave(info.getLogLeave(), signature, result); |
84 | return result; |
85 | } |
86 | catch (InvocationTargetException e) |
87 | { |
88 | Throwable t = e.getTargetException(); |
89 | logThrow(info.getLogThrow(), signature, t); |
90 | throw t; |
91 | } |
92 | catch (Throwable t) |
93 | { |
94 | logThrow(info.getLogThrow(), signature, t); |
95 | throw t; |
96 | } |
97 | } |
98 | //CSON: IllegalCatchCheck |
99 | //CSON: IllegalThrowsCheck |
100 | |
101 | private LoggingContribution getLoggingInfo(MethodSignature signature) |
102 | { |
103 | LoggingContribution info = (LoggingContribution) _methodMatcher.get(signature); |
104 | return (info != null ? info : _default); |
105 | } |
106 | |
107 | private void logEnter(LoggingLevel level, MethodSignature signature, Object[] args) |
108 | { |
109 | if (mustLog(level)) |
110 | { |
111 | Log logger = new LogWrapper(_logger, level); |
112 | LoggingUtils.entry(logger, signature.getName(), args); |
113 | } |
114 | } |
115 | |
116 | private void logThrow(LoggingLevel level, MethodSignature signature, Throwable t) |
117 | { |
118 | if (mustLog(level)) |
119 | { |
120 | Log logger = new LogWrapper(_logger, level); |
121 | LoggingUtils.exception(logger, signature.getName(), t); |
122 | } |
123 | } |
124 | |
125 | private void logLeave(LoggingLevel level, MethodSignature signature, Object result) |
126 | { |
127 | if (mustLog(level)) |
128 | { |
129 | Log logger = new LogWrapper(_logger, level); |
130 | if (signature.getReturnType() == void.class) |
131 | { |
132 | LoggingUtils.voidExit(logger, signature.getName()); |
133 | } |
134 | else |
135 | { |
136 | LoggingUtils.exit(logger, signature.getName(), result); |
137 | } |
138 | } |
139 | } |
140 | |
141 | private boolean mustLog(LoggingLevel level) |
142 | { |
143 | switch (level) |
144 | { |
145 | case Error: |
146 | return _logger.isErrorEnabled(); |
147 | |
148 | case Warn: |
149 | return _logger.isWarnEnabled(); |
150 | |
151 | case Info: |
152 | return _logger.isInfoEnabled(); |
153 | |
154 | case Debug: |
155 | return _logger.isDebugEnabled(); |
156 | |
157 | case None: |
158 | default: |
159 | return false; |
160 | } |
161 | } |
162 | |
163 | private final Log _logger; |
164 | private final Object _target; |
165 | private final MethodMatcher _methodMatcher = new MethodMatcher(); |
166 | } |
167 | |
168 | private final LoggingContribution _default = new LoggingContribution(); |
169 | } |