KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jfun > yan > xml > Compiler


1 package jfun.yan.xml;
2
3 import java.beans.IntrospectionException JavaDoc;
4 import java.io.IOException JavaDoc;
5 import java.io.InputStream JavaDoc;
6 import java.net.MalformedURLException JavaDoc;
7
8 import java.util.ArrayList JavaDoc;
9 import java.util.HashMap JavaDoc;
10 import java.util.HashSet JavaDoc;
11 import java.util.Iterator JavaDoc;
12 import java.util.List JavaDoc;
13 import java.util.Map JavaDoc;
14 import java.util.Properties JavaDoc;
15 import java.util.Set JavaDoc;
16
17 import jfun.util.dict.Dict;
18
19 import jfun.yan.ParameterBinder;
20 import jfun.yan.PropertyBinder;
21 import jfun.yan.util.resource.ResourceLoader;
22 import jfun.yan.util.resource.ResourceLoaders;
23
24 final class Compiler extends Constants{
25   private static final Set JavaDoc reserved_tagnames = MyUtil.getNameSet(
26       new String JavaDoc[]{SEQUENCE, LOCAL, BINDER, FUNCTION, CALLCC, EXPAND, MACRO}
27   );
28   private static final Set JavaDoc reserved_keys = MyUtil.getNameSet(
29       new String JavaDoc[]{NULL}
30   );
31   private final Interpreter interpreter;
32   private static final Set JavaDoc module_attributes =
33     MyUtil.getNameSet(new String JavaDoc[]{NAME, DESCRIPTION, DEPENDS, EXPORT, HIDE});
34   private static final Set JavaDoc body_attributes =
35     MyUtil.getNameSet(new String JavaDoc[]{AUTOWIRE, SINGLETON, EAGER_INSTANTIATED, EAGER_INSTANTIATED2});
36   private final String JavaDoc list_separator = ",";
37   private final String JavaDoc map_separator = ",";
38
39   Compiler(Interpreter interpreter) {
40     this.interpreter = interpreter;
41   }
42   private Set JavaDoc getExportKeys(String JavaDoc export){
43     final String JavaDoc[] export_names = NutsUtils.split(export, list_separator);
44     final HashSet JavaDoc result = new HashSet JavaDoc();
45     for(int i=0; i<export_names.length; i++){
46       final String JavaDoc key = export_names[i];
47       result.add(key);
48     }
49     return result;
50   }
51   //null is returned for wildcard
52
private String JavaDoc[] compileFilterKeys(String JavaDoc keys, Location loc){
53     keys = keys.trim();
54     if(WILDCARD.equals(keys)){
55       return null;
56     }
57     final String JavaDoc[] result = NutsUtils.split(keys, list_separator);
58     final Set JavaDoc cache = new HashSet JavaDoc();
59     for(int i=0; i<result.length; i++){
60       final String JavaDoc name = result[i];
61       if(cache.contains(name)){
62         throw new ConfigurationException("<" + IMPORT + "> - duplicate name: "
63             + name, loc);
64       }
65       if(WILDCARD.equals(name)){
66         throw new ConfigurationException("<" + IMPORT + "> - wildcard cannot be combined with other keys",
67             loc);
68       }
69       if(name.endsWith(WILDCARD)){
70         final String JavaDoc name0 = name.substring(0, name.length()-1);
71         checkIdentifier(name0, loc);
72       }
73       else{
74         checkIdentifier(name, loc);
75       }
76       cache.add(name);
77     }
78     return result;
79   }
80   private Filter getExportFilter(String JavaDoc exports, String JavaDoc hidden, Location loc){
81     if(exports==null){
82       exports = "*";
83     }
84     return getKeyFilter(null, exports, hidden, loc);
85   }
86   private Filter getKeyFilter(String JavaDoc prefix, String JavaDoc includes,
87       String JavaDoc excludes,
88       Location loc){
89     if(includes==null){
90       //include nothing.
91
return new Filter(new String JavaDoc[0],
92           excludes==null?new String JavaDoc[0]: compileFilterKeys(excludes, loc));
93     }
94     includes = includes.trim();
95     if(excludes==null){
96       excludes = "";
97     }
98     return new Filter(compileFilterKeys(includes, loc), compileFilterKeys(excludes, loc));
99   }
100   private void checkImport(Import imp, IdChecker idchecker, Location loc){
101     String JavaDoc prefix = imp.getPrefix();
102     final String JavaDoc[] keys = imp.getKeys();
103     for(int i=0; i<keys.length; i++){
104       final String JavaDoc key = keys[i];
105       idchecker.checkId(prefix+key, loc);
106     }
107   }
108   private Module compileImportedModule(Tag tag)
109   throws IOException JavaDoc, CyclicModuleDependencyException{
110     final Location loc = tag.getLocation();
111     final String JavaDoc resource = tag.getAttribute(RESOURCE);
112     if(resource != null){
113       MyUtil.assertAttributes(tag, MyUtil.getNameSet(new String JavaDoc[]{
114           RESOURCE, CLASSPATH, NAMESPACE, INCLUDES, EXCLUDES
115       }));
116       final ClassLoader JavaDoc cloader = getClassLoader(tag);
117       return interpreter.interpretResource(getResourceLoader(cloader), resource, null);
118     }
119     else{
120       MyUtil.assertAttributes(tag, MyUtil.getNameSet(new String JavaDoc[]{
121           FILE, NAMESPACE, INCLUDES, EXCLUDES
122       }));
123       final String JavaDoc filename = tag.getAttribute(FILE);
124       if(filename==null)
125         throw new ConfigurationException("either " + RESOURCE+ " or " + FILE
126             +" has to be specified for <"
127             + IMPORT + ">", loc);
128       return interpreter.interpretFile(filename, loc);
129     }
130   }
131
132   private Import compileImportTag(Tag tag, IdChecker checker)
133   throws IOException JavaDoc, CyclicModuleDependencyException{
134     final String JavaDoc includes_str = MyUtil.getMandatory(tag, INCLUDES);
135     final String JavaDoc excludes_str = tag.getAttribute(EXCLUDES);
136     final String JavaDoc namespace = tag.getAttribute(NAMESPACE);
137     final String JavaDoc prefix = namespace==null?"":namespace+".";
138     final Filter imports = getKeyFilter(prefix, includes_str, excludes_str,
139         tag.getLocation());
140     final Module imported = compileImportedModule(tag);
141     final Import ret =
142       new Import(prefix, imports, imported, tag.getLocation());
143     checkImport(ret, checker, tag.getLocation());
144     return ret;
145   }
146   private static void checkIdentifier(String JavaDoc id, Location loc){
147     if(reserved_keys.contains(id)){
148       throw new ConfigurationException("\""+id+"\""
149           + " is reserved.", loc);
150     }
151     if(!NutsUtils.isValidId(id)){
152       throw new ConfigurationException("\""+id+"\""
153           + " is not a valid id.", loc);
154     }
155   }
156   private static final class GlobalIdChecker implements IdChecker{
157     private final Location dep_loc;
158     private final Set JavaDoc dependencies;
159     private final HashMap JavaDoc imports = new HashMap JavaDoc();
160     private boolean importing = true;
161     GlobalIdChecker(String JavaDoc[] dependencies, Location loc){
162       this.dependencies = MyUtil.getNameSet(dependencies);
163       this.dep_loc = loc;
164     }
165     public void checkId(String JavaDoc id, Location loc){
166       checkIdentifier(id, loc);
167       if(dependencies.contains(id)){
168         throw new ConfigurationException("\""+id+"\""
169             + " duplicates with declared dependency name.", loc);
170       }
171       final Location duploc = (Location)imports.get(id);
172       if(duploc!=null){
173         throw new ConfigurationException("\""+id+"\"" +
174             " duplicates with an imported name at line "
175             + duploc.getLineNo(), loc);
176       }
177       if(importing)
178         imports.put(id, loc);
179     }
180     void importDone(){
181       importing = false;
182     }
183   }
184   private static void checkMandatories(Tag tag, String JavaDoc[] names){
185     for(int i=0; i<names.length; i++){
186       final String JavaDoc name = names[i];
187       MyUtil.getMandatory(tag, name);
188     }
189   }
190   private void populateNutTag(Tag tag, Map JavaDoc nuts){
191     final Location subloc = tag.getLocation();
192     try{
193       populateNut(nuts, tag);
194     }
195     catch(NoClassDefFoundError JavaDoc e){
196       throw new ConfigurationException(e, subloc);
197     }
198     catch(ClassNotFoundException JavaDoc e){
199       throw new ConfigurationException("nut class not found: "+e.getMessage(), subloc);
200     }
201     catch(IntrospectionException JavaDoc e){
202       throw new ConfigurationException("invalid nut class: "+e.getMessage(), subloc);
203     }
204   }
205   Module compileModule(Object JavaDoc id, Node node){
206     if(node instanceof Tag){
207       return compileModuleTag(id, (Tag)node);
208     }
209     else{
210       throw new ConfigurationException("tag expected", node.getLocation());
211     }
212   }
213   private static Dict seedImports(Dict ctxt, Import[] imports){
214     final ArrayList JavaDoc keys = new ArrayList JavaDoc();
215     final ArrayList JavaDoc stmts = new ArrayList JavaDoc();
216     for(int i=0; i<imports.length; i++){
217       final Import imp = imports[i];
218       final String JavaDoc[] exports = imp.getKeys();
219       final String JavaDoc prefix = imp.getPrefix();
220       for(int j=0; j<exports.length; j++){
221         final String JavaDoc key = prefix+exports[j];
222         keys.add(key);
223         stmts.add(new Bound(key, imp.getLocation()));
224       }
225     }
226     return ctxt.puts(keys.toArray(), stmts.toArray());
227   }
228   Module compileModuleTag(Object JavaDoc id, Tag tag){
229     final Location loc = tag.getLocation();
230     if(!MODULE.equals(tag.getName())){
231       throw new ConfigurationException("the top level tag has to be "
232           +MODULE, loc);
233     }
234     MyUtil.assertAttributes(tag, module_attributes);
235     checkMandatories(tag, new String JavaDoc[]{NAME});
236     final String JavaDoc name = tag.getAttribute(NAME);
237     final String JavaDoc desc = tag.getAttribute(DESCRIPTION);
238     final String JavaDoc export_str = tag.getAttribute(EXPORT);
239     final String JavaDoc hide_str = tag.getAttribute(HIDE);
240     final Filter filter = getExportFilter(export_str, hide_str, loc);
241     final StringPredicate exports = filter.getPredicate();//getExported(export);
242
final String JavaDoc[] dependencies = getDependencies(tag.getAttribute(DEPENDS),
243         tag.getLocation());
244     final GlobalIdChecker idchecker = new GlobalIdChecker(dependencies,
245         tag.getLocation());
246     final List JavaDoc subnodes = tag.getSubNodes();
247     
248     final ArrayList JavaDoc importlist = new ArrayList JavaDoc();
249     final HashMap JavaDoc nuts = new HashMap JavaDoc();
250     final int nodecount = subnodes.size();
251     int nodenum = 0;
252     for(; nodenum<nodecount; nodenum++){
253       final Node n = (Node)subnodes.get(nodenum);
254       if(n instanceof Tag){
255         final Tag t = (Tag)n;
256         final String JavaDoc tagname = t.getName();
257         if(IMPORT.equals(tagname)){
258           try{
259             importlist.add(compileImportTag(t, idchecker));
260           }
261           catch(IOException JavaDoc e){
262             throw new ConfigurationException("import failed. "+e.getMessage(),
263                 t.getLocation());
264           }
265           catch(CyclicModuleDependencyException e){
266             e.push(n.getLocation());
267             throw e;
268           }
269           continue;
270         }
271         else if(NUT.equals(tagname)){
272           populateNutTag(t, nuts);
273           continue;
274         }
275       }
276       break;
277     }
278     idchecker.importDone();
279     //load standard nuts
280
loadNuts(nuts);
281     
282     final Import[] imports = new Import[importlist.size()];
283     importlist.toArray(imports);
284     final Statements stmts =
285       compileModuleStatements(id, tag, dependencies,
286           imports, nodenum, nuts, idchecker);
287     return new ModuleBuilder(id, name, desc,
288         dependencies, imports, stmts, exports)
289         .build(interpreter, interpreter.getFrame());
290   }
291   
292   private void loadNuts(final HashMap JavaDoc nuts) {
293     final Map JavaDoc external_nuts = interpreter.getExternalNuts();
294     for(Iterator JavaDoc it=external_nuts.keySet().iterator(); it.hasNext();){
295       final Object JavaDoc key = it.next();
296       if(nuts.containsKey(key)) continue;
297       nuts.put(key, external_nuts.get(key));
298     }
299     final String JavaDoc properties_file = "jfun/yan/xml/nuts/nuts.properties";
300     try{
301       loadNuts(getClass().getClassLoader(),
302         properties_file, nuts);
303     }
304     catch(Exception JavaDoc e){
305       e.printStackTrace();
306       throw new IllegalStateException JavaDoc("could not load " + properties_file);
307     }
308   }
309   private Statements compileModuleStatements(Object JavaDoc module_id, Tag tag,
310       final String JavaDoc[] dependencies,
311       final Import[] imports, int nodenum,
312       final HashMap JavaDoc nuts, final GlobalIdChecker idchecker) {
313     final List JavaDoc subnodes = tag.getSubNodes();
314     final int nodecount = subnodes.size();
315     if(nodenum < nodecount){
316       final Node node = (Node)subnodes.get(nodenum);
317       if(node instanceof Tag){
318         final Tag t = (Tag)node;
319         final String JavaDoc tagname = t.getName();
320         if(BODY.equals(tagname)){
321           final Statements body =
322             compileBody(module_id, t, dependencies, imports, nuts,
323                 tag.getLocation(), idchecker);
324           if(nodenum < nodecount-1){
325             throw new ConfigurationException("<"+BODY+"> should be the last sub-element of <"+MODULE+">",
326                 t.getLocation());
327           }
328           return body;
329         }
330         else{
331           throw new ConfigurationException("unknown tag <"+t.getName()+">",
332               t.getLocation());
333         }
334       }
335       else{
336         throw new ConfigurationException("character data no supported.",
337             node.getLocation());
338       }
339     }
340     return new Statements(new String JavaDoc[0], new Stmt[0]);
341   }
342   private Statements compileBody(final Object JavaDoc module_id,
343       final Tag tag, final String JavaDoc[] dependencies,
344       final Import[] imports, final HashMap JavaDoc nuts, final Location loc, final GlobalIdChecker idchecker) {
345     final Stmt[] deps = new Stmt[dependencies.length];
346     
347     for(int i=0; i<dependencies.length; i++){
348       deps[i] = new Bound(dependencies[i], loc);
349     }
350     Dict ctxt = interpreter.getInitialCompileContext()
351       .puts(dependencies, deps);
352     ctxt = seedImports(ctxt, imports);
353     return compileBody(module_id, nuts, tag, idchecker,
354         ctxt);
355   }
356   private boolean parseEagerMode(Tag tag){
357     final String JavaDoc eager_mode_name = MyUtil.getEagerMode(tag);
358     if(eager_mode_name==null) return false;
359     final Boolean JavaDoc result = NutsUtils.toBoolean(eager_mode_name);
360     if(result==null)
361       throw new ConfigurationException("Unrecognized eager init value: "+eager_mode_name,
362           tag.getLocation());
363     return result.booleanValue();
364   }
365   private Statements compileBody(
366       Object JavaDoc module_id, Map JavaDoc nuts, Tag tag,
367       IdChecker idchecker, Dict initial_ctxt){
368     MyUtil.assertAttributes(tag, body_attributes);
369     
370     final String JavaDoc autowire = tag.getAttribute(AUTOWIRE);
371     final Location loc = tag.getLocation();
372     final ParameterBinder param_wiring = MyUtil.getParamWiring(autowire,
373         interpreter.getCustomWiringModes(), loc,
374         interpreter.getParameterWiring());
375     final PropertyBinder prop_wiring = MyUtil.getPropWiring(autowire,
376         interpreter.getCustomWiringModes(), loc,
377         interpreter.getPropertyWiring());
378     final SingletonMode singleton =
379       MyUtil.getSingletonStrategy(tag.getAttribute(SINGLETON), loc,
380           interpreter.getSingletonMode());
381     
382     final boolean default_eager_mode = parseEagerMode(tag);
383     //final Runtime runtime = new Runtime(manager, cloader);
384
final Statements stmts = new BodyCompiler(interpreter, module_id,
385         //interpreter.getClassloader(),
386
//interpreter.getLifecycleManager(),
387
//interpreter.getBaseDir(),
388
nuts, list_separator, map_separator,
389         new WiringMode(param_wiring, prop_wiring, singleton),
390         //interpreter.getCustomWiringModes(),
391
//interpreter.getServices(),
392
reserved_keys,
393         default_eager_mode)
394       .compileStatements(tag, initial_ctxt, idchecker,
395           tag.getName(), tag.getSubNodes());
396     return stmts;
397   }
398   private String JavaDoc[] getDependencies(String JavaDoc s, Location loc){
399     if(s==null) return new String JavaDoc[0];
400     final String JavaDoc[] keys = NutsUtils.split(s, list_separator);
401     final HashSet JavaDoc buf = new HashSet JavaDoc(keys.length);
402     for(int i=0; i<keys.length;i++){
403       final String JavaDoc key = keys[i];
404       if(reserved_keys.contains(key)){
405         throw new ConfigurationException("dependency name reserved: "+key, loc);
406       }
407       if(buf.contains(key)){
408         throw new ConfigurationException("duplicate dependency name: "+key, loc);
409       }
410       checkIdentifier(key, loc);
411     }
412     return keys;
413   }
414   private ClassLoader JavaDoc getClassLoader(Tag tag){
415     final String JavaDoc classpath = tag.getAttribute(CLASSPATH);
416     final ClassLoader JavaDoc cloader = getClass().getClassLoader();
417     try{
418       return NutsUtils.getClassLoader(cloader, classpath,
419           interpreter.getBaseDir());
420     }
421     catch(MalformedURLException JavaDoc e){
422       throw new ConfigurationException("invalid classpath",
423           tag.getLocation());
424     }
425   }
426   private void populateNut(Map JavaDoc nuts, Tag tag)
427   throws ClassNotFoundException JavaDoc, IntrospectionException JavaDoc{
428     final String JavaDoc nutname = MyUtil.getMandatory(tag, NAME);
429     final String JavaDoc classname = MyUtil.getMandatory(tag, CLASS);
430     final Location loc = tag.getLocation();
431     if(reserved_tagnames.contains(nutname)){
432       throw new ConfigurationException("nut name "+nutname+" is reserved, try a different name.",
433           loc);
434     }
435     if(nuts.containsKey(nutname)){
436       throw new ConfigurationException("nut name "+nutname+" is already used, try a different name.",
437           loc);
438     }
439     //we use a separate class loader than the one used to load components.
440
final ClassLoader JavaDoc cloader = getClassLoader(tag);
441     final Class JavaDoc nutclass = cloader.loadClass(classname);
442     nuts.put(nutname, interpreter.getIntrospector().getNutDescriptor(nutclass));
443   }
444   private StringPredicate getExported(String JavaDoc export){
445     if(export==null || WILDCARD.equals(export.trim())){
446       return StringPredicates.always();
447     }
448     else{
449       final Set JavaDoc exports = getExportKeys(export);
450       return StringPredicates.in(exports);
451     }
452   }
453   private ResourceLoader getResourceLoader(ClassLoader JavaDoc cloader){
454     return ResourceLoaders.or(cloader, interpreter.getResourceLoader());
455   }
456   private void loadNuts(ClassLoader JavaDoc loader,
457       String JavaDoc resource, Map JavaDoc nuts)
458   throws IOException JavaDoc, ClassNotFoundException JavaDoc, IntrospectionException JavaDoc{
459     final ResourceLoader rloader = getResourceLoader(loader);
460     final InputStream JavaDoc in = rloader.getResourceAsStream(resource);
461     if(in == null)
462       throw new IllegalStateException JavaDoc("could not find "
463         + resource);
464     try{
465       final Properties JavaDoc props = new Properties JavaDoc();
466       props.load(in);
467       for(Iterator JavaDoc it=props.keySet().iterator(); it.hasNext();){
468         final String JavaDoc key = (String JavaDoc)it.next();
469         if(nuts.containsKey(key))
470           continue;
471         String JavaDoc classname = props.getProperty(key);
472         if(classname.indexOf('.')<0){
473           classname = "jfun.yan.xml.nuts."+classname;
474         }
475         final Class JavaDoc nutclass = loader.loadClass(classname);
476         nuts.put(key, interpreter.getIntrospector().getNutDescriptor(nutclass));
477       }
478     }
479     finally{
480       in.close();
481     }
482   }
483 }
484
Popular Tags