1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package net.sourceforge.servletspy.handler.base;
23
24 import java.beans.BeanInfo;
25 import java.beans.Introspector;
26 import java.beans.PropertyDescriptor;
27 import java.lang.reflect.Method;
28 import java.lang.reflect.Modifier;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.StringTokenizer;
32
33 import net.sourceforge.servletspy.IContext;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38 /***
39 * @author arno schumacher
40 */
41 public abstract class AbstractInterfaceTransformer extends AbstractHandler {
42
43 /*** The logger. */
44 private static final Log LOGGER = LogFactory
45 .getLog(AbstractInterfaceTransformer.class);
46
47 /***
48 * Returns an array of <code>java.lang.Class</code> objects using
49 * the provided space separated string of class names as input.
50 *
51 * @param clazzes The class names, space separated.
52 * @return An array of <code>java.lang.Class</code> objects.
53 */
54 protected static Class[] fromString(final String clazzes) {
55 final List interfaceList = new ArrayList();
56 final StringTokenizer st = new StringTokenizer(clazzes);
57 while (st.hasMoreTokens()) {
58 Class clazz = loadInterface(st.nextToken().trim());
59 if (clazz != null) {
60 interfaceList.add(clazz);
61 }
62 }
63 return (Class[]) interfaceList.toArray(new Class[0]);
64 }
65
66 /***
67 * Loads a <code>java.lang.Class</code>.
68 *
69 * @param s The name of the class.
70 * @return The class object or <code>null</code> in case of an error.
71 */
72 private static Class loadInterface(final String s) {
73 Class clazz = null;
74 try {
75 clazz =
76 Thread.currentThread().getContextClassLoader().loadClass(s);
77 if (!clazz.isInterface()) {
78 clazz = null;
79 }
80 } catch (Exception e) {
81 LOGGER.warn("Could not load class '" + s + "'");
82 }
83 return clazz;
84 }
85
86 private Class[] classes = new Class[0];
87
88 /***
89 * Constructor.
90 */
91 protected AbstractInterfaceTransformer() {
92 }
93
94 /***
95 * Constructor.
96 *
97 * @param clazz an array of class specifying the interfaces for which
98 * the transformer is applicable.
99 */
100 protected AbstractInterfaceTransformer(final Class[] clazz) {
101 if (clazz != null) {
102 this.classes = clazz;
103 }
104 }
105
106 /***
107 * Constructor.
108 *
109 * @param s space separated string of class names specifying the
110 * interfaces for which the transformer is applicable.
111 */
112 protected AbstractInterfaceTransformer(final String s) {
113 this(fromString(s));
114 }
115
116
117
118
119 public final void handle(final IContext context) throws Exception {
120 final Object subject = context.getSubject();
121 for (int i = 0; i < classes.length; i++) {
122 if (classes[i] == null) {
123 continue;
124 }
125 if (classes[i].isAssignableFrom(subject.getClass())) {
126 handleClass(context, classes[i]);
127 return;
128 }
129 }
130 context.proceed();
131 }
132
133 private void handleClass(final IContext context, final Class clazz) throws Exception {
134 final BeanInfo beanInfo = Introspector.getBeanInfo(clazz, clazz
135 .isInterface() ? null : Object.class);
136 final PropertyDescriptor[] apd = beanInfo.getPropertyDescriptors();
137 for (int i = 0; i < apd.length; i++) {
138 final PropertyDescriptor pd = apd[i];
139 final Method m = pd.getReadMethod();
140 final Class clazzType = pd.getPropertyType();
141 if (m == null) {
142 continue;
143 }
144
145 if (m.getParameterTypes().length > 0) {
146 continue;
147 }
148
149
150 if (clazzType == null) {
151 continue;
152 }
153 if (!Modifier.isPublic(m.getModifiers())
154 || Modifier.isStatic(m.getModifiers())) {
155 continue;
156 }
157
158 final String mName = m.getName();
159 String key = null;
160 if (mName.startsWith("get") && mName.length() > 3) {
161 key = Introspector.decapitalize(mName.substring(3));
162 }
163 if (mName.startsWith("is") && mName.length() > 2) {
164 key = Introspector.decapitalize(mName.substring(2));
165 }
166 final Object prop = m.invoke(context.getSubject(), new Object[0]);
167 context.add(key, prop);
168 }
169 }
170 }