KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > fractal > julia > loader > BasicLoader


1 /***
2  * Julia: France Telecom's implementation of the Fractal API
3  * Copyright (C) 2001-2002 France Telecom R&D
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Contact: Eric.Bruneton@rd.francetelecom.com
20  *
21  * Author: Eric Bruneton
22  */

23
24 package org.objectweb.fractal.julia.loader;
25
26 import java.io.FileInputStream JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.InputStream JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.Map JavaDoc;
33
34 /**
35  * Provides a basic implementation of the {@link Loader} interface. This
36  * implementation loads the required classes from the class path.
37  * <br>
38  * <br>
39  * <b>Requirements</b>
40  * <ul>
41  * <li>none.</li>
42  * </ul>
43  */

44
45 public class BasicLoader implements Loader {
46
47   // -------------------------------------------------------------------------
48
// PUBLIC constructor (needed for bootstrap)
49
// -------------------------------------------------------------------------
50

51   public BasicLoader () {
52   }
53
54   // -------------------------------------------------------------------------
55
// Fields and methods added and overriden by the mixin class
56
// -------------------------------------------------------------------------
57

58   /**
59    * The value of the 'julia.config' system property. This property is a list
60    * of configuration file names.
61    */

62
63   private String JavaDoc config;
64
65   /**
66    * The value of the 'julia.loader.gen.check' system property. This property
67    * indicates whether or not the class parameters of the generated classes must
68    * be checked.
69    */

70
71   private boolean checkClassParameters;
72
73   /**
74    * The value of the 'julia.loader.gen.pkg' system property. This property
75    * indicates the package that contains the classes generated by Julia.
76    */

77
78   private String JavaDoc genPkg;
79
80   /**
81    * A map associating variable names to {@link Tree} values.
82    */

83
84   private Map JavaDoc definitions;
85
86   /**
87    * A transient stream used to parse trees.
88    */

89
90   private InputStream JavaDoc is;
91
92   /**
93    * Current line number in {@link #is is}.
94    */

95
96   private int line;
97
98   /**
99    * Last character read from {@link #is is}.
100    */

101
102   private int car;
103
104   // -------------------------------------------------------------------------
105
// Implementation of the Loader interface
106
// -------------------------------------------------------------------------
107

108   public void init (final Map JavaDoc context) throws Exception JavaDoc {
109     if (context.get("julia.config") != null) {
110       config = (String JavaDoc)context.get("julia.config");
111     } else if (System.getProperty("julia.config") != null) {
112       config = System.getProperty("julia.config");
113     } else {
114       throw new Exception JavaDoc(
115         "The julia.config system property is not defined");
116     }
117     
118     if (context.get("julia.loader.check") != null) {
119       checkClassParameters = true;
120     } else if (System.getProperty("julia.loader.check") != null) {
121       checkClassParameters = true;
122     }
123     
124     genPkg = "org.objectweb.fractal.julia.generated";
125     if (context.get("julia.loader.gen.pkg") != null) {
126       genPkg = (String JavaDoc)context.get("julia.loader.gen.pkg");
127     } else if (System.getProperty("julia.loader.gen.pkg") != null) {
128       genPkg = System.getProperty("julia.loader.gen.pkg");
129     }
130   }
131
132   public Tree loadTree (final String JavaDoc name) throws Exception JavaDoc {
133     if (definitions == null) {
134       definitions = new HashMap JavaDoc();
135       int b = 0;
136       int i;
137       do {
138         i = config.indexOf(',', b);
139         String JavaDoc file;
140         if (i == -1) {
141           file = config.substring(b);
142         } else {
143           file = config.substring(b, i);
144           b = i + 1;
145         }
146         InputStream JavaDoc is;
147         try {
148           is = getInputStream(file);
149         } catch (IOException JavaDoc ioe) {
150           is = getClass().getResourceAsStream("/" + file);
151           if (is == null) {
152             throw new Exception JavaDoc("Cannot find or open the '" + file + "' file");
153           }
154         }
155         try {
156           line = 1;
157           while (true) {
158             Tree def;
159             try {
160               def = parseTree(is);
161             } catch (Throwable JavaDoc e) {
162               throw new Exception JavaDoc(
163                 "File '" + file + "', line " + line + ": " + e.getMessage());
164             }
165             if (def == null) {
166               break;
167             } else {
168               definitions.put(def.getSubTree(0).toString(), def.getSubTree(1));
169             }
170           }
171         } finally {
172           try {
173             is.close();
174           } catch (IOException JavaDoc ignored) {
175           }
176         }
177       } while (i != -1);
178     }
179     Tree t = (Tree)definitions.get(name);
180     if (t == null) {
181       throw new Exception JavaDoc(
182         "Cannot find the '" + name +
183         "' descriptor in the '" + config +
184         "' file(s) specified in the julia.loader.config system property");
185     }
186     return t;
187   }
188
189   public Tree evalTree (final Tree tree, final Map JavaDoc context)
190     throws Exception JavaDoc
191   {
192     if (tree.getSize() == 0) {
193       String JavaDoc var = tree.toString();
194       if (var.startsWith("'")) {
195         var = var.substring(1);
196         Tree val = (Tree)context.get(var);
197         if (val == null) {
198           val = loadTree(var);
199         }
200         if (val == null) {
201           throw new Exception JavaDoc(var);
202         }
203         if (!val.toString().equals("QUOTE")) {
204           return evalTree(val, context);
205         }
206       }
207       return tree;
208     } else {
209       boolean ok = true;
210       Tree[] subTrees = tree.getSubTrees();
211       for (int i = 0; i < subTrees.length; ++i) {
212         Tree oldSubTree = subTrees[i];
213         Tree newSubTree = evalTree(oldSubTree, context);
214         if (newSubTree != oldSubTree) {
215           if (ok) {
216             Tree[] newSubTrees = new Tree[subTrees.length];
217             System.arraycopy(subTrees, 0, newSubTrees, 0, subTrees.length);
218             subTrees = newSubTrees;
219             ok = false;
220           }
221           subTrees[i] = newSubTree;
222         }
223       }
224       return (ok ? tree : new Tree(subTrees));
225     }
226   }
227
228   public Object JavaDoc newObject (final Tree objectDescriptor, final Object JavaDoc loader)
229     throws Exception JavaDoc
230   {
231     if (objectDescriptor.getSize() == 0) {
232       return loadClass(objectDescriptor.toString(), loader).newInstance();
233     } else {
234       Object JavaDoc o;
235       o = loadClass(objectDescriptor.getSubTree(0), loader).newInstance();
236       if (objectDescriptor.getSize() > 1) {
237         Tree[] trees = objectDescriptor.getSubTrees();
238         Tree[] args = new Tree[trees.length - 1];
239         System.arraycopy(trees, 1, args, 0, args.length);
240         ((Initializable)o).initialize(new Tree(args));
241       }
242       return o;
243     }
244   }
245
246   public Class JavaDoc loadClass (final String JavaDoc name, final Object JavaDoc loader)
247     throws ClassNotFoundException JavaDoc
248   {
249     return Class.forName(name);
250   }
251
252   public Class JavaDoc loadClass (final Tree classDescriptor, final Object JavaDoc loader)
253     throws ClassNotFoundException JavaDoc
254   {
255     if (classDescriptor.getSize() == 0) {
256       return loadClass(classDescriptor.toString(), loader);
257     }
258     int n = 0;
259     String JavaDoc s = genPkg + ".C" + Integer.toHexString(classDescriptor.hashCode()) + "_";
260     while (true) {
261       String JavaDoc name = s + n;
262       Class JavaDoc c;
263       try {
264         c = loadClass(name, loader);
265       } catch (ClassNotFoundException JavaDoc e) {
266         return generateClass(name, classDescriptor, loader);
267       }
268       if (!checkClassParameters) {
269         return c;
270       }
271       try {
272         Generated gen = (Generated)c.newInstance();
273         if (gen != null &&
274             classDescriptor.equals(gen.getFcGeneratorParameters()))
275         {
276           return c;
277         }
278       } catch (Exception JavaDoc ignored) {
279       }
280       ++n;
281     }
282   }
283
284   // -------------------------------------------------------------------------
285
// Utility methods: tree parsing
286
// -------------------------------------------------------------------------
287

288   /*
289    * Convenience method used for J2ME conversion
290    * (FileInputStream not available in CLDC API).
291    */

292
293   private InputStream JavaDoc getInputStream (String JavaDoc file) throws IOException JavaDoc {
294     return new FileInputStream JavaDoc(file);
295   }
296
297   /**
298    * Creates a tree by parsing the given input stream. This method can be called
299    * several times on the same stream, in order to parse several consecutive
300    * trees, but <i>only</i> if the there is at least one space, tab or return
301    * character between these trees.
302    *
303    * @param is the input stream to be parsed. This input stream must use a LISP
304    * like syntax, with single line comments beginning with '#', as in the
305    * following example:
306    * <pre>
307    * ( # foo
308    * foo
309    * # bar
310    * (bar foo)
311    * )</pre>
312    * @return the tree parsed from the given input stream, or <tt>null</tt> if
313    * the end of the stream has been reached.
314    * @throws IOException if an I/O exception occurs during parsing.
315    * @throws Exception if a syntax error is found.
316    */

317
318   private Tree parseTree (final InputStream JavaDoc is) throws Exception JavaDoc {
319     try {
320       this.is = is;
321       read();
322       parseSpaces();
323       if (car == -1) {
324         return null;
325       } else {
326         return parseTree();
327       }
328     } finally {
329       this.is = null;
330     }
331   }
332
333   /**
334    * Recursive method to parse a tree. The first character of the tree to be
335    * parsed is supposed to have already been read, and available in {@link #car
336    * car}. After parsing, the character immediately following the parsed tree
337    * is also supposed to have already been parsed, and available in {@link #car
338    * car}.
339    *
340    * @return a tree parsed from the {@link #is is} stream.
341    * @throws IOException if an I/O exception occurs during parsing.
342    * @throws Exception if a syntax error is found.
343    */

344
345   private Tree parseTree () throws IOException JavaDoc, Exception JavaDoc {
346     int c = car;
347     if (c == -1) {
348       throw new Exception JavaDoc("Unexpected end of file");
349     } else if (c == ')') {
350       throw new Exception JavaDoc("Unmatched closing parenthesis");
351     } else if (c == '(') {
352       // parses a tree of the form "(subTree1 ... subTreeN)"
353
read();
354       List JavaDoc subTrees = new ArrayList JavaDoc();
355       while (true) {
356         c = parseSpaces();
357         if (c == ')') {
358           read();
359           return new Tree((Tree[])subTrees.toArray(new Tree[subTrees.size()]));
360         } else {
361           subTrees.add(parseTree());
362         }
363       }
364     } else {
365       // parses a tree of the form "tree"
366
StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
367       while (true) {
368         buf.append((char)c);
369         c = read();
370         if (c == -1 || c == ' ' || c == '\t' || c == '\n' ||
371             c == '\r' || c == '#' || c == '(' || c == ')')
372         {
373           car = c;
374           return new Tree(buf.toString());
375         }
376       }
377     }
378   }
379
380   /**
381    * Parses spaces and comments until a non space character is found.
382    *
383    * @return the first non space character found, which is also stored in
384    * {@link #car car}.
385    * @throws IOException if I/O exception occurs during parsing.
386    */

387
388   private int parseSpaces () throws IOException JavaDoc {
389     int c = car;
390     while (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '#') {
391       if (c == '#') {
392         // parses a single line comment
393
do {
394           c = read();
395         } while (c != '\n' && c != '\r');
396       }
397       c = read();
398     }
399     return car = c;
400   }
401
402   /**
403    * Reads a char in {@link #is} and updates {@link #line} if needed.
404    *
405    * @return a char read from {@link #is}.
406    * @throws IOException if I/O exception occurs during reading.
407    */

408
409   private int read () throws IOException JavaDoc {
410     car = is.read();
411     if (car == '\n' || car == '\r') {
412       ++line;
413     }
414     return car;
415   }
416
417   // -------------------------------------------------------------------------
418
// Utility methods: class generation
419
// -------------------------------------------------------------------------
420

421   /**
422    * Generates the class whose descriptor is given, with the given name. The
423    * generated class must implement the {@link Generated} interface,
424    * and its {@link Generated#getFcGeneratorParameters getFcGeneratorParameters}
425    * method must return <tt>classDescriptor.toString()</tt>. The default
426    * implementation of this method throws an exception.
427    *
428    * @param name the name of the class to be generated.
429    * @param classDescriptor the descriptor of the class to be generated. This
430    * descriptor <i>must</i> be of the form "(objectDescriptor arg1 ...
431    * argN)" (see {@link #loadClass(Tree) loadClass}).
432    * @param loader an optional class loader to load auxiliary classes.
433    * @return a class named <tt>name</tt> and whose content is described by the
434    * given class descriptor.
435    * @throws ClassNotFoundException if a problem occurs during the generation
436    * of the class.
437    */

438
439   protected Class JavaDoc generateClass (
440     final String JavaDoc name,
441     final Tree classDescriptor,
442     final Object JavaDoc loader) throws ClassNotFoundException JavaDoc
443   {
444     throw new ClassNotFoundException JavaDoc(name);
445   }
446
447   // -------------------------------------------------------------------------
448
// Fields and methods required by the mixin class in the base class
449
// -------------------------------------------------------------------------
450

451 }
452
Popular Tags