View Javadoc

1   package org.textensor.xml;
2   
3   
4   import java.lang.reflect.Field;
5   import java.lang.reflect.Modifier;
6   import java.util.ArrayList;
7   import java.util.StringTokenizer;
8   
9   import org.textensor.report.E;
10  import org.textensor.stochdiff.inter.AddableTo;
11  import org.textensor.stochdiff.inter.XMLContainer;
12  
13  
14  
15  public class ReflectionInstantiator {
16  
17      ArrayList search = new ArrayList();
18  
19      int npkg;
20      String[] pkgs;
21  
22      String wkpkg;
23  
24  
25      public ReflectionInstantiator() {
26          pkgs = new String[100];
27          npkg = 0;
28      }
29  
30  
31      public ReflectionInstantiator(String path) {
32          this();
33          addSearchPackage(path);
34      }
35  
36  
37  
38  
39      public void addSearchPackage(String s) {
40          wkpkg = s;
41          pkgs[npkg++] = s;
42      }
43  
44  
45      public void appendContent(Object obj, String s) {
46          if (obj instanceof XMLContainer) {
47              ((XMLContainer)obj).appendContent(s);
48          } else {
49              E.error(" - reflection instantiator doesn't do appendContent on " +
50                      obj + "(" + obj.getClass() +  ") while trying to append " + s);
51          }
52      }
53  
54  
55      public void checkAddPackage(Object oret) {
56          String scl = oret.getClass().getName();
57          if (scl.startsWith("java")) {
58              return;
59          }
60  
61          int ild = scl.lastIndexOf(".");
62          String pkg = scl.substring(0, ild);
63          if (pkg.equals(wkpkg)) {
64              // just same as before;
65  
66          } else {
67              boolean got = false;
68              for (int i = 0; i < npkg; i++) {
69                  if (pkgs[i].equals(pkg)) {
70                      got = true;
71                      break;
72                  }
73              }
74              if (!got) {
75                  pkgs[npkg++] = pkg;
76  
77                  // System.out.println("Reflection instantiator added search package
78                  // " + pkg);
79              }
80          }
81      }
82  
83  
84  
85      public Object newInstance(String scl) {
86          Object oret = null;
87          Class<?> c = null;
88  
89          // TODO this is for the neuroml meta namespace - genralize
90          if (scl.indexOf(":") > 0) {
91              scl = scl.substring(0, scl.indexOf(":"));
92          }
93  
94          if (scl.indexOf(".") > 0) {
95              try {
96                  c = Class.forName(scl);
97              } catch (Exception e) {
98              }
99          }
100 
101         if (c == null) {
102             for (int i = 0; i < npkg && c == null; i++) {
103                 try {
104                     c = Class.forName(pkgs[i] + "." + scl);
105                 } catch (Exception e) {
106                 }
107             }
108         }
109 
110         if (c == null) {
111             E.error("cant instantiate (class not found): " + scl);
112             E.reportCached();
113 
114             for (int i = 0; i < npkg; i++) {
115                 E.info("tried package " + pkgs[i]);
116             }
117 
118             if (scl.endsWith("ing")) {
119                 (new Exception()).printStackTrace();
120             }
121 
122 
123         } else {
124             int imod = c.getModifiers();
125             if (Modifier.isAbstract(imod)) {
126                 E.error("cant instantiatie " + c + ":  it is an abstract class");
127             } else {
128 
129                 try {
130                     oret = c.newInstance();
131                 } catch (Exception e) {
132                     E.error(" " + e + " instantiating " + c);
133                     e.printStackTrace();
134                 }
135             }
136         }
137 
138         if (oret != null) {
139             checkAddPackage(oret);
140         }
141 
142         return oret;
143     }
144 
145 
146 
147     public Object getField(Object ob, String fnm) {
148         Object ret = null;
149 
150         boolean hasField = false;
151 
152         // EFF improve
153         Field[] flds = ob.getClass().getFields();
154         for (int i = 0; i < flds.length; i++) {
155             if (flds[i].getName().equals(fnm)) {
156                 hasField = true;
157                 break;
158             }
159         }
160 
161         if (hasField) {
162             try {
163                 Field f = ob.getClass().getField(fnm);
164 
165                 Class fcl = f.getType();
166 
167                 if (fcl.equals(String[].class)) {
168                     ret = new String[0];
169 
170                 } else if (fcl.isArray()) {
171                     ret = new ArrayList(); // ADHOC - wrap ArrayList?
172                 } else {
173                     ret = f.get(ob);
174                 }
175 
176                 if (ret == null) {
177                     Class<?> cl = f.getType();
178                     ret = cl.newInstance();
179                 }
180 
181             } catch (Exception e) {
182                 E.error("cant get field " + fnm + " on " + ob + " " + "excception= " + e);
183             }
184         }
185 
186 
187         /*
188          * if (!hasField && ob instanceof FieldValueProvider) { ret =
189          * ((FieldValueProvider)ob).getFieldValue(fnm); if (ret != null) {
190          * hasField = true; } }
191          */
192 
193 
194         if (!hasField) {
195             if (ob instanceof ArrayList) {
196                 // we're OK - the object will just be added;
197 
198             } else {
199 
200                 // System.out.println("error - cant get field " + fnm + " on " +
201                 // ob);
202                 /*
203                  * Field[] af = ob.getClass().getFields(); for (int i = 0; i <
204                  * af.length; i++) { System.out.println("fld " + i + " " + af[i]); }
205                  */
206             }
207         }
208         return ret;
209     }
210 
211 
212 
213     public Object getChildObject(Object parent, String name, Attribute[] atta) {
214         Object child = null;
215 
216         if (parent != null) {
217             checkAddPackage(parent); // EFF inefficient
218         }
219 
220         // Three possibilities:
221         // 1 there is an attribute called class;
222         // 2 the parent has a field called name;
223         // 3 the name is a class name;
224 
225 
226         if (atta == null) {
227             atta = new Attribute[0];
228         }
229 
230 
231         // process special attributes and instantiate child if class is known
232         // (case 1);
233         String classname = null;
234         for (int i = 0; i < atta.length; i++) {
235             Attribute att = atta[i];
236             String attName = att.getName();
237             String attValue = att.getValue();
238 
239             if (attName.equals("package")) {
240                 StringTokenizer stok = new StringTokenizer(attValue, ", ");
241                 while (stok.hasMoreTokens()) {
242                     addSearchPackage(stok.nextToken());
243                 }
244 
245             } else if (attName.equals("archive-hash")) {
246 
247                 E.debugError("xmlreader found reference to archive file "
248                              + " but has no importContext to retrieve object");
249 
250 
251             } else if (attName.equals("class")) {
252                 classname = attValue;
253             }
254         }
255 
256 
257         // not in the above loop because want to parse packages first;
258         if (child == null && classname != null) {
259             child = newInstance(classname);
260         }
261 
262 
263         // dont know the class - the parent may know it; (CASE 2)
264         if (child == null && parent != null) { // / && hasField(parent, name)) {
265             child = getField(parent, name);
266         }
267 
268 
269         // or perhaps the open tag is a class name? (CASE 3)
270 
271         if (child == null) {
272             child = newInstance(name);
273 
274         }
275 
276 
277         if (child == null) {
278             E.warning("ReflectionInstantiator failed to get field " + name + " on " + parent + " "
279                       + (parent != null ? parent.getClass().toString() : ""));
280         }
281 
282 
283         /* POSERR did this do anything useful?
284         if (child instanceof IDd && ((IDd)child).getID() == null) {
285            //         setAttributeField(child, "id", name);
286             // System.out.println("autoset id to " + name);
287         }
288         */
289         return child;
290     }
291 
292 
293 
294     public void applyAttributes(Object target, Attribute[] atta) {
295 
296         for (int i = 0; i < atta.length; i++) {
297             Attribute att = atta[i];
298             setAttributeField(target, att.getName(), att.getValue());
299         }
300     }
301 
302 
303 
304     public boolean setAttributeField(Object target, String name, String arg) {
305         boolean bret = false;
306         if (name.equals("class") || name.equals("package") || name.equals("provides")
307                 || name.equals("archive-hash")) {
308             // already done; ADHOC
309 
310         } else {
311             bret = setField(target, name, arg);
312         }
313 
314         return bret;
315     }
316 
317 
318     // ADHOC suppressing warnings
319     @SuppressWarnings( { "unchecked" })
320     public boolean setField(Object ob, String sf, Object arg) {
321 
322         //  E.info("setting field " + sf + " in " + ob + " to " + arg);
323         if (ob == null) {
324             E.error("null parent for " + sf + " (" + arg + ")");
325             return true;
326         }
327 
328         if (arg == null) {
329             E.error("reflection instantiator has null arg setting " + sf + " in " + ob);
330             return true;
331         }
332 
333         if (arg.equals(ob)) {
334             E.error("ReflectionInstantiator setField: " + "the child is the same as the parent " + ob);
335             return true;
336         }
337 
338         int icolon = sf.indexOf(":");
339         if (icolon >= 0) {
340             sf = sf.substring(0, icolon) + "_" + sf.substring(icolon + 1, sf.length());
341         }
342 
343         boolean ok = false;
344 
345         Class c = ob.getClass();
346         Field f = null;
347         try {
348             f = c.getField(sf);
349         } catch (NoSuchFieldException e) {
350         }
351 
352 
353 
354         if (f == null) {
355             if (ob instanceof ArrayList) {
356                 ((ArrayList)ob).add(arg);
357                 ok = true;
358 
359                 /*
360                 } else if (arg instanceof String && ob instanceof AttributeAddableTo) {
361                 ((AttributeAddableTo)ob).addAttribute(sf, (String)arg);
362                 ok = true;
363                 */
364 
365             } else if (ob instanceof AddableTo && nonPrimitive(arg)) {
366                 ((AddableTo)ob).add(arg);
367                 ok = true;
368 
369             } else {
370                 E.oneLineWarning("no such field " + sf + " on " + ob + "while settting " + arg);
371                 E.reportCached();
372                 ok = false;
373             }
374 
375         } else {
376             // POSERR avoids warning but bit silly
377             if (arg instanceof ArrayList && ((ArrayList)arg).size() == 1) {
378                 for (Object sub : (ArrayList)arg) {
379                     arg = sub;
380                 }
381             }
382 
383             try {
384                 Class ftyp = f.getType();
385                 if (ftyp == String.class && arg instanceof String) {
386                     f.set(ob, arg);
387 
388                 } else if (ftyp == Double.TYPE  && arg instanceof String) {
389                     Double d = new Double((String)arg);
390                     f.set(ob, d);
391 
392                 } else if (ftyp == Integer.TYPE  && arg instanceof String) {
393                     Integer ig = new Integer((String)arg);
394                     f.set(ob, ig);
395 
396 
397 
398                 } else if (ftyp == Double.TYPE  && arg instanceof Double) {
399                     f.set(ob, arg);
400 
401                 } else if (ftyp == Boolean.TYPE && arg instanceof Boolean) {
402                     f.set(ob, arg);
403 
404                 } else if (ftyp == Integer.TYPE && arg instanceof Integer) {
405                     f.set(ob, arg);
406 
407                 } else if (f.getType().isArray() && arg instanceof ArrayList) {
408                     setArrayField(ob, f, (ArrayList)arg);
409 
410                 } else {
411                     Object onarg = Narrower.narrow(ftyp.getName(), arg);
412 
413                     if (onarg != null) {
414                         f.set(ob, onarg);
415                     } else {
416                         f.set(ob, arg);
417                     }
418                 }
419                 ok = true;
420             } catch (Exception e) {
421                 ok = false;
422                 E.error(" cant set field " + sf + " in " + ob + " from value " + arg + " " + e);
423             }
424         }
425 
426 
427         return ok;
428     }
429 
430 
431 
432     public void setArrayField(Object obj, Field fld, ArrayList vals) {
433 
434         E.missing();
435 
436         System.out.println("setting array field of " + vals.size() + " in " + obj + " fnm="
437                            + fld.getName());
438 
439         /*
440          * try { int nv = vals.size();
441          *
442          * Class acls = fld.getType(); Class ccls = acls.getComponentType();
443          *
444          * Object avals = Array.newInstance(ccls, nv); for (int i = 0; i < nv;
445          * i++) { Array.set(avals, i, vals.get(i)); } fld.set(obj, avals); } catch
446          * (Exception ex) { E.error(" - cant setaray field " + fld + " " + vals); }
447          */
448     }
449 
450 
451     private boolean nonPrimitive(Object arg) {
452         boolean ret = true;
453         if (arg instanceof String || arg instanceof Integer || arg instanceof Double) {
454             ret = false;
455         }
456         return ret;
457     }
458 
459 
460     public void setIntFromStatic(Object ret, String id, String sv) {
461         String svu = sv.toUpperCase();
462         Object obj = getField(ret, svu);
463         if (obj instanceof Integer) {
464             setField(ret, id, obj);
465         } else {
466             E.error("need an Integer, not  " + obj);
467         }
468     }
469 
470 }