View Javadoc

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              // just same as before;
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                 // System.out.println("Reflection instantiator added search package
113                 // " + pkg);
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         // EFF improve
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(); // ADHOC - wrap 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          * if (!hasField && ob instanceof FieldValueProvider) { ret =
217          * ((FieldValueProvider)ob).getFieldValue(fnm); if (ret != null) {
218          * hasField = true; } }
219          */
220 
221 
222         if (!hasField) {
223             if (ob instanceof ArrayList) {
224                 // we're OK - the object will just be added;
225 
226             } else {
227 
228                 // System.out.println("error - cant get field " + fnm + " on " +
229                 // ob);
230                 /*
231                  * Field[] af = ob.getClass().getFields(); for (int i = 0; i <
232                  * af.length; i++) { System.out.println("fld " + i + " " + af[i]); }
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); // EFF inefficient
247         }
248 
249         // Three possibilities:
250         // 1 there is an attribute called class;
251         // 2 the parent has a field called name;
252         // 3 the name is a class name;
253 
254 
255         if (atta == null) {
256             atta = new Attribute[0];
257         }
258 
259 
260         // process special attributes and instantiate child if class is known
261         // (case 1);
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         // not in the above loop because want to parse packages first;
290         if (child == null && classname != null) {
291             child = newInstance(classname);
292         }
293 
294 
295         // dont know the class - the parent may know it; (CASE 2)
296         if (child == null && parent != null) { // / && hasField(parent, name)) {
297             child = getField(parent, name);
298         }
299 
300 
301         if (child == null && name.equals("Role")) {
302             child = new ResourceRole();
303         }
304 
305         // or perhaps the open tag is a class name? (CASE 3)
306         if (child == null) {
307 
308             // ADHOC - dont really want this dependence - pull out providers for
309             // reflector?
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          * POSERR did this do anything useful? if (child instanceof IDd &&
332          * ((IDd)child).getID() == null) { // setAttributeField(child, "id",
333          * name); // System.out.println("autoset id to " + name); }
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             // already done; ADHOC
355 
356         } else {
357             bret = setField(target, name, arg);
358         }
359 
360         return bret;
361     }
362 
363 
364     // ADHOC suppressing warnings
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         // System.out.println("setting field " + sf + " in " + ob + " to " + arg);
385         if (ob == null) {
386             E.error("null parent for " + sf + " (" + arg + ")");
387             return true;
388         }
389 
390         if (arg == null) {
391             // dont think this should be an error? - fine to set something to null on instantiation?
392             // E.error("reflection instantiator has null arg setting " + sf + " in " + ob);
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                 // just ignore these silently....;
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             // POSERR avoids warning but bit silly
443             if (arg instanceof ArrayList && ((ArrayList)arg).size() == 1) {
444                 if (f.getType().isArray()) {
445                     // fine as it is,
446 
447                 } else {
448                     // arg is in a list for packing convenience - get it out
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          * E.missing(); System.out.println("setting array field of " + vals.size() + "
502          * in " + obj + " fnm=" + fld.getName());
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 }