1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.river.reggie.proxy;
19
20 import java.lang.reflect.Field;
21 import java.lang.reflect.Modifier;
22 import java.util.Arrays;
23 import java.util.Comparator;
24 import java.util.WeakHashMap;
25 import java.lang.ref.SoftReference;
26 import java.rmi.MarshalException;
27
28
29
30
31
32
33
34
35 class ClassMapper {
36
37
38 private static final WeakHashMap serviceMap = new WeakHashMap(23);
39
40 private static final WeakHashMap entryMap = new WeakHashMap(17);
41
42 private static final WeakHashMap fieldMap = new WeakHashMap(17);
43
44 private static final FieldComparator comparator = new FieldComparator();
45 private static final ServiceType[] empty = {};
46 private static final Class[] noArg = new Class[0];
47
48 private ClassMapper() {}
49
50
51 public static ServiceTypeBase toServiceTypeBase(Class cls)
52 throws MarshalException
53 {
54 synchronized (serviceMap) {
55 return toServiceTypeBase(cls, true);
56 }
57 }
58
59
60
61
62
63 private static ServiceTypeBase toServiceTypeBase(Class cls,
64 boolean needCodebase)
65 throws MarshalException
66 {
67 if (cls == null)
68 return null;
69 SoftReference cref = (SoftReference)serviceMap.get(cls);
70 ServiceTypeBase stype = null;
71 if (cref != null)
72 stype = (ServiceTypeBase)cref.get();
73 if (stype == null) {
74 stype = new ServiceTypeBase(
75 new ServiceType(cls,
76 toServiceType(cls.getSuperclass()),
77 toServiceType(cls.getInterfaces())),
78 null);
79 serviceMap.put(cls, new SoftReference(stype));
80 }
81 if (needCodebase && stype.codebase == null)
82 stype.setCodebase(cls);
83 return stype;
84 }
85
86
87 private static ServiceType toServiceType(Class cls)
88 throws MarshalException
89 {
90 if (cls != null)
91 return toServiceTypeBase(cls, false).type;
92 return null;
93 }
94
95
96 public static ServiceType[] toServiceType(Class[] classes)
97 throws MarshalException
98 {
99 if (classes == null)
100 return null;
101 if (classes.length == 0)
102 return empty;
103 ServiceType[] stypes = new ServiceType[classes.length];
104 synchronized (serviceMap) {
105 for (int i = classes.length; --i >= 0; ) {
106 stypes[i] = toServiceType(classes[i]);
107 }
108 }
109 return stypes;
110 }
111
112
113 public static EntryClassBase toEntryClassBase(Class cls)
114 throws MarshalException
115 {
116 synchronized (entryMap) {
117 return toEntryClassBase(cls, true);
118 }
119 }
120
121
122
123
124
125
126 private static EntryClassBase toEntryClassBase(Class cls, boolean base)
127 throws MarshalException
128 {
129 if (cls == null)
130 return null;
131 SoftReference cref = (SoftReference)entryMap.get(cls);
132 EntryClassBase eclass = null;
133 if (cref != null)
134 eclass = (EntryClassBase)cref.get();
135 if (eclass == null) {
136 if (base) {
137 if (!Modifier.isPublic(cls.getModifiers()))
138 throw new IllegalArgumentException("entry class " +
139 cls.getName() +
140 " is not public");
141 try {
142 cls.getConstructor(noArg);
143 } catch (NoSuchMethodException e) {
144 throw new IllegalArgumentException("entry class " +
145 cls.getName() +
146 " does not have a public no-arg constructor");
147 }
148 }
149 eclass = new EntryClassBase(
150 new EntryClass(cls,
151 toEntryClass(cls.getSuperclass())),
152 null);
153 entryMap.put(cls, new SoftReference(eclass));
154 }
155 if (base && eclass.codebase == null)
156 eclass.setCodebase(cls);
157 return eclass;
158 }
159
160
161 private static EntryClass toEntryClass(Class cls) throws MarshalException {
162 if (cls != null)
163 return toEntryClassBase(cls, false).eclass;
164 return null;
165 }
166
167
168 static class EntryField {
169
170 public final Field field;
171
172
173
174
175
176
177 public final boolean marshal;
178
179
180
181
182 public EntryField(Field field) {
183 this.field = field;
184 Class c = field.getType();
185 marshal = !(c == String.class ||
186 c == Integer.class ||
187 c == Boolean.class ||
188 c == Character.class ||
189 c == Long.class ||
190 c == Float.class ||
191 c == Double.class ||
192 c == Byte.class ||
193 c == Short.class);
194 }
195 }
196
197
198
199
200
201 public static EntryField[] getFields(Class cls) {
202 synchronized (fieldMap) {
203 SoftReference cref = (SoftReference)fieldMap.get(cls);
204 EntryField[] efields = null;
205 if (cref != null)
206 efields = (EntryField[])cref.get();
207 if (efields == null) {
208 Field[] fields = cls.getFields();
209 Arrays.sort(fields, comparator);
210 int len = 0;
211 for (int i = 0; i < fields.length; i++) {
212 if ((fields[i].getModifiers() &
213 (Modifier.STATIC|Modifier.FINAL|Modifier.TRANSIENT))
214 == 0)
215 {
216 if (fields[i].getType().isPrimitive())
217 throw new IllegalArgumentException("entry class " +
218 cls.getName() +
219 " has a primitive field");
220 fields[len++] = fields[i];
221 }
222 }
223 efields = new EntryField[len];
224 while (--len >= 0) {
225 efields[len] = new EntryField(fields[len]);
226 }
227 fieldMap.put(cls, new SoftReference(efields));
228 }
229 return efields;
230 }
231 }
232
233
234 private static class FieldComparator implements Comparator {
235 public FieldComparator() {}
236
237
238 public int compare(Object o1, Object o2) {
239 Field f1 = (Field)o1;
240 Field f2 = (Field)o2;
241 if (f1 == f2)
242 return 0;
243 if (f1.getDeclaringClass() == f2.getDeclaringClass())
244 return f1.getName().compareTo(f2.getName());
245 if (f1.getDeclaringClass().isAssignableFrom(
246 f2.getDeclaringClass()))
247 return -1;
248 return 1;
249 }
250 }
251 }