KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > fractal > adl > xml > XMLNodeClassLoader


1 /***
2  * Fractal ADL Parser
3  * Copyright (C) 2002-2004 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.adl.xml;
25
26 import org.objectweb.fractal.adl.NodeClassLoader;
27
28 import org.objectweb.asm.Type;
29 import org.objectweb.asm.ClassWriter;
30 import org.objectweb.asm.CodeVisitor;
31 import org.objectweb.asm.Label;
32
33 import java.util.Map JavaDoc;
34 import java.util.HashMap JavaDoc;
35 import java.util.Set JavaDoc;
36 import java.util.HashSet JavaDoc;
37 import java.lang.reflect.Method JavaDoc;
38
39 /**
40  * A {@link NodeClassLoader} that generates {@link XMLNode} node classes.
41  */

42
43 class XMLNodeClassLoader extends NodeClassLoader {
44
45   // --------------------------------------------------------------------------
46
// AST node definitions
47
// --------------------------------------------------------------------------
48

49   /**
50    * Stores the set of AST interfaces that each AST node must implement.
51    * Keys are AST node names, values are sets of internal interface names.
52    */

53
54   private Map JavaDoc astItfs;
55
56   // --------------------------------------------------------------------------
57
// Mapping between AST names and XML names
58
// --------------------------------------------------------------------------
59

60   /**
61    * Stores the AST node names corresponding to each XML element name.
62    * Keys are XML element names, values are AST node names.
63    */

64
65   private Map JavaDoc astNodes;
66
67   /**
68    * Stores the XML element names corresponding to each AST node name.
69    * Keys are AST node names, values are XML element names.
70    */

71
72   private Map JavaDoc xmlElements;
73
74   /**
75    * Stores the AST attribute names corresponding to each XML attribute name.
76    * Keys are XML node.attribute names, values are AST attribute names.
77    */

78
79   private Map JavaDoc astAttributes;
80
81   /**
82    * Stores the XML attribute names corresponding to each AST attribute name.
83    * Keys are AST node.attribute names, values are XML attribute names.
84    */

85
86   private Map JavaDoc xmlAttributes;
87
88   // --------------------------------------------------------------------------
89
// Constructor
90
// --------------------------------------------------------------------------
91

92   public XMLNodeClassLoader (final ClassLoader JavaDoc parent) {
93     super(parent);
94     astItfs = new HashMap JavaDoc();
95     astNodes = new HashMap JavaDoc();
96     xmlElements = new HashMap JavaDoc();
97     astAttributes = new HashMap JavaDoc();
98     xmlAttributes = new HashMap JavaDoc();
99   }
100
101   // --------------------------------------------------------------------------
102
// Mapping initialization and accessor methods
103
// --------------------------------------------------------------------------
104

105   void addASTNodeInterface (final String JavaDoc astNode, final String JavaDoc itf) {
106     Set JavaDoc s = (Set JavaDoc)astItfs.get(astNode);
107     if (s == null) {
108       s = new HashSet JavaDoc();
109       astItfs.put(astNode, s);
110     }
111     s.add(itf.replace('.', '/'));
112   }
113
114   void addASTNodeMapping (final String JavaDoc astName, final String JavaDoc xmlName) {
115     xmlElements.put(astName, xmlName);
116     astNodes.put(xmlName, astName);
117   }
118
119   void addASTAttributeMapping (final String JavaDoc astName, final String JavaDoc xmlName) {
120     xmlAttributes.put(astName, xmlName.substring(xmlName.indexOf('.') + 1));
121     astAttributes.put(xmlName, astName.substring(astName.indexOf('.') + 1));
122   }
123
124   String JavaDoc getASTName (final String JavaDoc xmlElement) {
125     String JavaDoc astName = (String JavaDoc)astNodes.get(xmlElement);
126     return astName == null ? xmlElement : astName;
127   }
128
129   String JavaDoc getXMLElement (final String JavaDoc astNode) {
130     String JavaDoc xmlElement = (String JavaDoc)xmlElements.get(astNode);
131     return xmlElement == null ? astNode : xmlElement;
132   }
133
134   String JavaDoc getASTAttribute (final String JavaDoc xmlNode, final String JavaDoc xmlAttr) {
135     String JavaDoc astAttribute = (String JavaDoc)astAttributes.get(xmlNode + "." + xmlAttr);
136     return astAttribute == null ? xmlAttr : astAttribute;
137   }
138
139   String JavaDoc getXMLAttribute (final String JavaDoc astNode, final String JavaDoc astAttr) {
140     String JavaDoc xmlAttribute = (String JavaDoc)xmlAttributes.get(astNode + "." + astAttr);
141     return xmlAttribute == null ? astAttr : xmlAttribute;
142   }
143
144   String JavaDoc getASTClassName (final String JavaDoc xmlElement) {
145     String JavaDoc astNode = (String JavaDoc)astNodes.get(xmlElement);
146     if (astNode == null) {
147       astNode = xmlElement;
148     }
149     return getASTClass(astNode);
150   }
151
152   // --------------------------------------------------------------------------
153
// Overriden ClassLoader method
154
// --------------------------------------------------------------------------
155

156   protected Class JavaDoc findClass (final String JavaDoc name) throws ClassNotFoundException JavaDoc {
157     if (isASTClass(name)) {
158       byte[] b = generateClass(getASTNode(name));
159       /* DEBUG
160       try {
161         java.io.FileOutputStream fos =
162           new java.io.FileOutputStream(name + ".class");
163         fos.write(b);
164         fos.close();
165       } catch (Exception _) {
166       }
167       */

168       return defineClass(name, b);
169     }
170     return super.findClass(name);
171   }
172
173   // --------------------------------------------------------------------------
174
// Class generation methods
175
// --------------------------------------------------------------------------
176

177   private byte[] generateClass (final String JavaDoc astNodeName)
178     throws ClassNotFoundException JavaDoc
179   {
180     String JavaDoc owner = getASTClass(astNodeName).replace('.', '/');
181     String JavaDoc xmlNode = Type.getInternalName(XMLNode.class);
182     Set JavaDoc itfSet = (Set JavaDoc)astItfs.get(astNodeName);
183     String JavaDoc[] itfs = (String JavaDoc[])itfSet.toArray(new String JavaDoc[itfSet.size()]);
184
185     ClassWriter cw = generateClass(getASTClassName(astNodeName), astNodeName, xmlNode, itfs);
186
187     CodeVisitor xsa = cw.visitMethod(
188       ACC_PUBLIC,
189       "xmlSetAttributes",
190       "(Lorg/xml/sax/Attributes;)V",
191       null,
192       null);
193
194     CodeVisitor xan = cw.visitMethod(
195       ACC_PUBLIC,
196       "xmlAddNode",
197       "(Ljava/lang/String;L" + xmlNode + ";)V",
198       null,
199       null);
200     Label xanEnd = new Label();
201
202     Set JavaDoc methods = new HashSet JavaDoc();
203     for (int i = 0; i < itfs.length; ++i) {
204       Method JavaDoc[] meths = loadClass(itfs[i].replace('/', '.')).getMethods();
205       for (int j = 0; j < meths.length; ++j) {
206         Method JavaDoc meth = meths[j];
207         String JavaDoc name = meth.getName();
208         String JavaDoc desc = Type.getMethodDescriptor(meth);
209
210         if (methods.contains(name + desc)) {
211           continue;
212         }
213         methods.add(name + desc);
214
215         if (name.startsWith("get")) {
216           String JavaDoc field = getFieldName(name, 3);
217
218           if (desc.startsWith("()[")) {
219             // case of a getter method for a sub node with arity * or +
220
String JavaDoc fieldDesc = "Ljava/util/List;";
221             generateAddNodesMethod(
222               xan, owner, name, field, fieldDesc, xanEnd, true);
223           } else {
224             // case of a getter method for a sub node with arity 1 or ?
225
String JavaDoc fieldDesc = desc.substring(2);
226
227             if (fieldDesc.equals("Ljava/lang/String;")) {
228               // case of an attribute:
229
// generates code in "xmlSetAttributes"
230
xsa.visitVarInsn(ALOAD, 0);
231               xsa.visitVarInsn(ALOAD, 1);
232               xsa.visitLdcInsn(
233                 getXMLAttribute(astNodeName, getASTName(name, true)));
234               xsa.visitMethodInsn(
235                 INVOKEINTERFACE,
236                 "org/xml/sax/Attributes",
237                 "getValue",
238                 "(Ljava/lang/String;)Ljava/lang/String;");
239               xsa.visitFieldInsn(PUTFIELD, owner, field, fieldDesc);
240             } else {
241               // case of a sub node:
242
generateAddNodeMethod(
243                 xan, owner, name, field, fieldDesc, xanEnd, true);
244             }
245           }
246         }
247       }
248     }
249
250     xsa.visitInsn(RETURN);
251     xsa.visitMaxs(0, 0);
252
253     xan.visitLabel(xanEnd);
254     xan.visitInsn(RETURN);
255     xan.visitMaxs(0, 0);
256
257     return cw.toByteArray();
258   }
259
260   private void generateAddNodeMethod (
261     final CodeVisitor cv,
262     final String JavaDoc owner, final String JavaDoc name,
263     final String JavaDoc field, final String JavaDoc fieldDesc,
264     final Label end, final boolean add)
265   {
266     String JavaDoc s = getASTName(name, true);
267     Label l = generateIf(cv, getXMLElement(s));
268     cv.visitVarInsn(ALOAD, 0);
269     if (add) {
270       cv.visitVarInsn(ALOAD, 2);
271       cv.visitTypeInsn(
272         CHECKCAST, fieldDesc.substring(1, fieldDesc.length() - 1));
273     } else {
274       cv.visitInsn(ACONST_NULL);
275     }
276     cv.visitFieldInsn(PUTFIELD, owner, field, fieldDesc);
277     cv.visitJumpInsn(GOTO, end);
278     cv.visitLabel(l);
279   }
280
281   private void generateAddNodesMethod (
282     final CodeVisitor cv,
283     final String JavaDoc owner, final String JavaDoc name,
284     final String JavaDoc field, final String JavaDoc fieldDesc,
285     final Label end, final boolean add)
286   {
287     String JavaDoc s = getASTName(name, false);
288     Label l = generateIf(cv, getXMLElement(s));
289     cv.visitVarInsn(ALOAD, 0);
290     cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc);
291     cv.visitVarInsn(ALOAD, 2);
292     cv.visitMethodInsn(
293       INVOKEINTERFACE,
294       "java/util/List",
295       add ? "add" : "remove",
296       add ? "(Ljava/lang/Object;)Z" : "(Ljava/lang/Object;)Z");
297     cv.visitInsn(POP);
298     cv.visitJumpInsn(GOTO, end);
299     cv.visitLabel(l);
300   }
301   
302   private Label generateIf (final CodeVisitor cv, final String JavaDoc name) {
303     Label l = new Label();
304     cv.visitVarInsn(ALOAD, 1);
305     cv.visitLdcInsn(name);
306     cv.visitMethodInsn(
307       INVOKEVIRTUAL,
308       "java/lang/Object",
309       "equals",
310       "(Ljava/lang/Object;)Z");
311     cv.visitJumpInsn(IFEQ, l);
312     return l;
313   }
314
315   // --------------------------------------------------------------------------
316
// Naming rules
317
// --------------------------------------------------------------------------
318

319   private final static String JavaDoc PKG = "org.objectweb.fractal.adl.ast.xml.";
320   
321   private static String JavaDoc getASTClass (final String JavaDoc astNodeName) {
322     return PKG + astNodeName + "Impl";
323   }
324   
325   private static boolean isASTClass (final String JavaDoc name) {
326     return name.startsWith(PKG) && name.endsWith("Impl");
327   }
328
329   private static String JavaDoc getASTNode (final String JavaDoc astClassName) {
330     return astClassName.substring(PKG.length(), astClassName.length() - 4);
331   }
332 }
333
Popular Tags