1 package org.catacomb.interlish.reflect;
2
3 import org.catacomb.be.Instantiator;
4 import org.catacomb.interlish.content.BooleanValue;
5 import org.catacomb.interlish.content.DoubleValue;
6 import org.catacomb.interlish.content.IntegerValue;
7 import org.catacomb.interlish.content.StringValue;
8 import org.catacomb.interlish.resource.ImportContext;
9 import org.catacomb.interlish.resource.ResourceRole;
10 import org.catacomb.interlish.resource.Role;
11 import org.catacomb.interlish.service.ContentLoader;
12 import org.catacomb.interlish.service.ResourceAccess;
13 import org.catacomb.interlish.structure.*;
14 import org.catacomb.report.E;
15
16 import java.lang.reflect.Field;
17 import java.lang.reflect.Modifier;
18 import java.util.ArrayList;
19 import java.util.StringTokenizer;
20
21 import java.lang.reflect.Array;
22
23
24
25 public class ReflectionConstructor implements Constructor {
26
27 ArrayList search = new ArrayList();
28
29 int npkg;
30 String[] pkgs;
31
32 String wkpkg;
33
34 ImportContext importContext;
35
36 Instantiator instantiator;
37
38
39 static ArrayList<String> paths;
40
41 static {
42 paths = new ArrayList<String>();
43 }
44
45 public static void addPath(String s) {
46 paths.add(s);
47 }
48
49
50
51 public ReflectionConstructor() {
52 pkgs = new String[100];
53 npkg = 0;
54 instantiator = new ClassInstantiator();
55 for (String s : paths) {
56 addSearchPackage(s);
57 }
58 }
59
60
61 public ReflectionConstructor(String path) {
62 this();
63 addSearchPackage(path);
64 }
65
66
67 public void setInstantiator(Instantiator inst) {
68 instantiator = inst;
69 }
70
71
72 public void setImportContext(ImportContext ctx) {
73 importContext = ctx;
74 }
75
76
77
78 public void addSearchPackage(String s) {
79 wkpkg = s;
80 pkgs[npkg++] = s;
81 }
82
83
84
85 public void appendContent(Object obj, String s) {
86 E.error(" - reflection instantiator doesn't do appendContent on " + obj);
87 }
88
89
90 public void checkAddPackage(Object oret) {
91 String scl = oret.getClass().getName();
92 if (scl.startsWith("java")) {
93 return;
94 }
95
96 int ild = scl.lastIndexOf(".");
97 String pkg = scl.substring(0, ild);
98 if (pkg.equals(wkpkg)) {
99
100
101 } else {
102 boolean got = false;
103 for (int i = 0; i < npkg; i++) {
104 if (pkgs[i].equals(pkg)) {
105 got = true;
106 break;
107 }
108 }
109 if (!got) {
110 pkgs[npkg++] = pkg;
111
112
113
114 }
115 }
116 }
117
118
119
120 public Object newInstance(String scl) {
121 Object oret = null;
122 Class<?> c = null;
123 boolean fcnm = scl.startsWith("org.");
124 if (scl.indexOf(".") > 0) {
125 c = instantiator.forName(scl, fcnm);
126 }
127
128 if (c == null && !fcnm) {
129 for (int i = 0; i < npkg && c == null; i++) {
130 c = instantiator.forName(pkgs[i] + "." + scl);
131 }
132 }
133
134 if (c == null) {
135 E.error("cant instantiate (class not found): " + scl + "\n" +
136 " instantiator: " + instantiator);
137 E.reportCached();
138
139 if (npkg == 0) {
140 E.info("There are no search packages configured!");
141 }
142 for (int i = 0; i < npkg; i++) {
143 E.info("tried package " + pkgs[i]);
144 }
145
146 if (scl.endsWith("ing")) {
147 (new Exception()).printStackTrace();
148 }
149
150
151 } else {
152 int imod = c.getModifiers();
153 if (Modifier.isAbstract(imod)) {
154 E.error("cant instantiatie " + c + ": it is an abstract class");
155 } else {
156
157 try {
158 oret = c.newInstance();
159 } catch (Exception e) {
160 E.error(" " + e + " instantiating " + c);
161 e.printStackTrace();
162 }
163 }
164 }
165
166 if (oret != null) {
167 checkAddPackage(oret);
168 }
169
170 return oret;
171 }
172
173
174
175 public Object getField(Object ob, String fnm) {
176 Object ret = null;
177
178 boolean hasField = false;
179
180
181 Field[] flds = ob.getClass().getFields();
182 for (int i = 0; i < flds.length; i++) {
183 if (flds[i].getName().equals(fnm)) {
184 hasField = true;
185 break;
186 }
187 }
188
189 if (hasField) {
190 try {
191 Field f = ob.getClass().getField(fnm);
192
193 Class fcl = f.getType();
194
195 if (fcl.equals(String[].class)) {
196 ret = new String[0];
197
198 } else if (fcl.isArray()) {
199 ret = new ArrayList();
200 } else {
201 ret = f.get(ob);
202 }
203
204 if (ret == null) {
205 Class<?> cl = f.getType();
206 ret = cl.newInstance();
207 }
208
209 } catch (Exception e) {
210 E.error("cant get field " + fnm + " on " + ob + " " + "excception= " + e);
211 }
212 }
213
214
215
216
217
218
219
220
221
222 if (!hasField) {
223 if (ob instanceof ArrayList) {
224
225
226 } else {
227
228
229
230
231
232
233
234 }
235 }
236 return ret;
237 }
238
239
240
241 public Object getChildObject(Object parent, String name, Attribute[] attain) {
242 Attribute[] atta = attain;
243 Object child = null;
244
245 if (parent != null) {
246 checkAddPackage(parent);
247 }
248
249
250
251
252
253
254
255 if (atta == null) {
256 atta = new Attribute[0];
257 }
258
259
260
261
262 String classname = null;
263 for (int i = 0; i < atta.length; i++) {
264 Attribute att = atta[i];
265 String attName = att.getName();
266 String attValue = att.getValue();
267
268 if (attName.equals("package")) {
269 StringTokenizer stok = new StringTokenizer(attValue, ", ");
270 while (stok.hasMoreTokens()) {
271 addSearchPackage(stok.nextToken());
272 }
273
274 } else if (attName.equals("archive-hash")) {
275 if (importContext != null) {
276 child = importContext.getRelative(attValue);
277
278 } else {
279 E.debugError("xmlreader found reference to archive file "
280 + " but has no importContext to retrieve object");
281 }
282
283 } else if (attName.equals("class")) {
284 classname = attValue;
285 }
286 }
287
288
289
290 if (child == null && classname != null) {
291 child = newInstance(classname);
292 }
293
294
295
296 if (child == null && parent != null) {
297 child = getField(parent, name);
298 }
299
300
301 if (child == null && name.equals("Role")) {
302 child = new ResourceRole();
303 }
304
305
306 if (child == null) {
307
308
309
310
311 if (ResourceAccess.hasContentLoader()) {
312 ContentLoader cl = ResourceAccess.getContentLoader();
313 if (cl.hasProviderOf(name)) {
314 child = cl.getProviderOf(name);
315 checkAddPackage(child);
316 }
317 }
318 if (child == null) {
319 child = newInstance(name);
320 }
321 }
322
323
324 if (child == null) {
325 E.warning("ReflectionInstantiator failed to get field " + name + " on " + parent + " "
326 + (parent != null ? parent.getClass().toString() : ""));
327 }
328
329
330
331
332
333
334
335 return child;
336 }
337
338
339
340 public void applyAttributes(Object target, Attribute[] atta) {
341
342 for (int i = 0; i < atta.length; i++) {
343 Attribute att = atta[i];
344 setAttributeField(target, att.getName(), att.getValue());
345 }
346 }
347
348
349
350 public boolean setAttributeField(Object target, String name, String arg) {
351 boolean bret = false;
352 if (name.equals("class") || name.equals("package") || name.equals("provides")
353 || name.equals("archive-hash")) {
354
355
356 } else {
357 bret = setField(target, name, arg);
358 }
359
360 return bret;
361 }
362
363
364
365 @SuppressWarnings( { "unchecked" })
366 public boolean setField(Object ob, String sfin, Object argin) {
367 String sf = sfin;
368 Object arg = argin;
369 if (arg instanceof StringValue) {
370 arg = ((StringValue)arg).getString();
371
372 } else if (arg instanceof BooleanValue) {
373 arg = new Boolean(((BooleanValue)arg).getBoolean());
374
375 } else if (arg instanceof IntegerValue) {
376 arg = new Integer(((IntegerValue)arg).getInteger());
377
378 } else if (arg instanceof DoubleValue) {
379 arg = new Double(((DoubleValue)arg).getDouble());
380 }
381
382
383
384
385 if (ob == null) {
386 E.error("null parent for " + sf + " (" + arg + ")");
387 return true;
388 }
389
390 if (arg == null) {
391
392
393 return true;
394 }
395
396 if (arg.equals(ob)) {
397 E.error("ReflectionInstantiator setField: " + "the child is the same as the parent " + ob);
398 return true;
399 }
400
401 int icolon = sf.indexOf(":");
402 if (icolon >= 0) {
403 sf = sf.substring(0, icolon) + "_" + sf.substring(icolon + 1, sf.length());
404 }
405
406 boolean ok = false;
407
408 Class c = ob.getClass();
409 Field f = null;
410 try {
411 f = c.getField(sf);
412 } catch (NoSuchFieldException e) {
413 }
414
415
416
417 if (f == null) {
418 if (ob instanceof ArrayList) {
419 ((ArrayList)ob).add(arg);
420 ok = true;
421
422 } else if (arg instanceof String && ob instanceof AttributeAddableTo) {
423 ((AttributeAddableTo)ob).addAttribute(sf, (String)arg);
424 ok = true;
425
426 } else if (ob instanceof AddableTo && nonPrimitive(arg)) {
427 ((AddableTo)ob).add(arg);
428 ok = true;
429
430
431 } else if (arg instanceof Role) {
432
433 ok = true;
434
435 } else {
436 E.linkToWarning("no such field " + sf, ob);
437 E.reportCached();
438 ok = false;
439 }
440
441 } else {
442
443 if (arg instanceof ArrayList && ((ArrayList)arg).size() == 1) {
444 if (f.getType().isArray()) {
445
446
447 } else {
448
449 for (Object sub : (ArrayList)arg) {
450 arg = sub;
451 }
452 }
453 }
454
455 try {
456 Class ftyp = f.getType();
457 if (ftyp == String.class && arg instanceof String) {
458 f.set(ob, arg);
459
460 } else if (ftyp == Double.TYPE && arg instanceof String) {
461 Double d = new Double((String)arg);
462 f.set(ob, d);
463
464 } else if (ftyp == Double.TYPE && arg instanceof Double) {
465 f.set(ob, arg);
466
467 } else if (ftyp == Boolean.TYPE && arg instanceof Boolean) {
468 f.set(ob, arg);
469
470 } else if (ftyp == Integer.TYPE && arg instanceof Integer) {
471 f.set(ob, arg);
472
473 } else if (f.getType().isArray() && arg instanceof ArrayList) {
474 setArrayField(ob, f, (ArrayList)arg);
475
476 } else {
477 Object onarg = Narrower.narrow(ftyp.getName(), arg);
478
479 if (onarg != null) {
480 f.set(ob, onarg);
481 } else {
482 f.set(ob, arg);
483 }
484 }
485 ok = true;
486 } catch (Exception e) {
487 ok = false;
488 E.error(" cant set field " + sf + " in " + ob + " from typed " +
489 arg.getClass().getName() + " value " + arg + " " + e);
490 }
491 }
492
493
494 return ok;
495 }
496
497
498
499 public void setArrayField(Object obj, Field fld, ArrayList vals) {
500
501
502
503
504
505 try {
506 int nv = vals.size();
507
508 Class acls = fld.getType();
509 Class ccls = acls.getComponentType();
510
511 Object avals = Array.newInstance(ccls, nv);
512 for (int i = 0; i < nv; i++) {
513 Array.set(avals, i, vals.get(i));
514 }
515 fld.set(obj, avals);
516 } catch (Exception ex) {
517 E.error(" - cant setaray field " + fld + " " + vals);
518 }
519 }
520
521
522
523
524 private boolean nonPrimitive(Object arg) {
525 boolean ret = true;
526 if (arg instanceof String || arg instanceof Integer || arg instanceof Double) {
527 ret = false;
528 }
529 return ret;
530 }
531
532
533 public void setIntFromStatic(Object ret, String id, String sv) {
534 String svu = sv.toUpperCase();
535 Object obj = getField(ret, svu);
536 if (obj instanceof Integer) {
537 setField(ret, id, obj);
538 } else {
539 E.error("need an Integer, not " + obj);
540 }
541 }
542
543 }