KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > compiler > ClassModel


1 /*****************************************************************************
2  * ClassModel.java
3  *****************************************************************************/

4
5 /* J_LZ_COPYRIGHT_BEGIN *******************************************************
6 * Copyright 2001-2004 Laszlo Systems, Inc. All Rights Reserved. *
7 * Use is subject to license terms. *
8 * J_LZ_COPYRIGHT_END *********************************************************/

9
10 package org.openlaszlo.compiler;
11 import java.util.*;
12 import org.jdom.Element;
13
14 class ClassModel {
15     protected final ViewSchema schema;
16     protected final String JavaDoc className;
17     // This is null for builtin classes
18
protected final ClassModel superclass;
19     // This is null for builtin classes
20
protected final Element definition;
21     protected NodeModel nodeModel;
22     
23     /* If superclass is a predefined system class, just store its name. */
24     protected String JavaDoc superclassName = null;
25     protected boolean hasInputText = false;
26     protected boolean isInputText = false;
27     
28     /* Class or superclass has an <attribute type="text"/> */
29     protected boolean supportsTextAttribute = false;
30     /** Map attribute name to type */
31     protected final Map attributeSpecs = new HashMap();
32     /** Map of method names to arglist */
33     protected final Map methods = new HashMap();
34     protected boolean inline = false;
35     
36     public String JavaDoc toString() {
37         return "ClassModel: className="+className + ", " +
38             "superclass=" + superclass + ", " +
39             "superclassName=" + superclassName + ", " +
40             "hasInputText=" + hasInputText + ", " +
41             "isInputText=" + isInputText + ", " +
42             "definition=" + definition;
43     }
44
45     // Construct a user-defined class
46
ClassModel(String JavaDoc className, ClassModel superclass,
47                ViewSchema schema, Element definition) {
48         this.className = className;
49         this.superclass = superclass;
50         this.definition = definition;
51         this.schema = schema;
52     }
53     
54     // Construct a builtin class
55
ClassModel(String JavaDoc className, ViewSchema schema) {
56         this(className, null, schema, null);
57     }
58     
59     /** Returns true if this is equal to or a subclass of
60      * superclass. */

61     boolean isSubclassOf(ClassModel superclass) {
62         if (this == superclass) return true;
63         if (this.superclass == null) return false;
64         return this.superclass.isSubclassOf(superclass);
65     }
66     
67     boolean isBuiltin() {
68         return superclass == null;
69     }
70     
71     ClassModel getSuperclassModel() {
72         return superclass;
73     }
74     
75     String JavaDoc getSuperclassName() {
76         if (superclassName != null) {
77             return superclassName;
78         } else if (superclass == null) {
79             return null;
80         } else {
81             return superclass.className;
82         }
83     }
84     
85     /** Return the AttributeSpec for the attribute named attrName. If
86      * the attribute is not defined on this class, look up the
87      * superclass chain.
88      */

89     AttributeSpec getAttribute(String JavaDoc attrName) {
90         AttributeSpec attr = (AttributeSpec) attributeSpecs.get(attrName);
91         if (attr != null) {
92             return attr;
93         } else if (superclass != null) {
94             return(superclass.getAttribute(attrName));
95         } else {
96             return null;
97         }
98     }
99
100     /** Find an attribute name which is similar to attrName, or return
101      * null. Used in compiler warnings. */

102     AttributeSpec findSimilarAttribute(String JavaDoc attrName) {
103         for (Iterator iter = attributeSpecs.values().iterator(); iter.hasNext();) {
104             AttributeSpec attr = (AttributeSpec) iter.next();
105             if ((attrName.toLowerCase().equals(attr.name.toLowerCase())) ||
106                 (attrName.toLowerCase().startsWith(attr.name.toLowerCase())) ||
107                 (attrName.toLowerCase().endsWith(attr.name.toLowerCase())) ||
108                 (attr.name.toLowerCase().startsWith(attrName.toLowerCase())) ||
109                 (attr.name.toLowerCase().endsWith(attrName.toLowerCase()))) {
110                 return attr;
111             }
112         }
113         // if that didn't work, try the supeclass
114
if (superclass == null) {
115             return null;
116         } else {
117             return superclass.findSimilarAttribute(attrName);
118         }
119     }
120
121     ViewSchema.Type getAttributeTypeOrException(String JavaDoc attrName)
122         throws UnknownAttributeException
123     {
124         AttributeSpec attr = getAttribute(attrName);
125         if (attr != null) {
126             return attr.type;
127         }
128         // If there is no superclass attribute, use the default static
129
// attribute map
130
ViewSchema.Type type = ViewSchema.getAttributeType(attrName);
131         // Last resort, use default of 'expression' type
132
if (type == null) {
133             throw new UnknownAttributeException();
134         }
135         return type;
136     }
137     
138     ViewSchema.Type getAttributeType(String JavaDoc attrName) {
139         AttributeSpec attr = getAttribute(attrName);
140         if (attr != null) {
141             return attr.type;
142         }
143         // If there is no superclass attribute, use the default static
144
// attribute map
145
ViewSchema.Type type = ViewSchema.getAttributeType(attrName);
146         // Last resort, use default of 'expression' type
147
if (type == null) {
148             type = ViewSchema.EXPRESSION_TYPE;
149         }
150         return type;
151     }
152     
153     void setNodeModel(NodeModel model) {
154         this.nodeModel = model;
155     }
156
157     boolean getInline() {
158         return inline && nodeModel != null;
159     }
160     
161     void setInline(boolean inline) {
162         this.inline = inline;
163     }
164     
165     public static class InlineClassError extends CompilationError {
166         public InlineClassError(ClassModel cm, NodeModel im, String JavaDoc message) {
167             super(
168                 "The class " + cm.className + " has been declared " +
169                 "inline-only but cannot be inlined. " + message + ". " +
170                 "Remove " + cm.className + " from the <?lzc class=\"" +
171                 cm.className + "\"> or " + "<?lzc classes=\"" + cm.className
172                 + "\"> processing instruction to remove this error.",
173                 im.element);
174         }
175     }
176     
177     protected boolean descendantDefinesAttribute(NodeModel model, String JavaDoc name) {
178         for (Iterator iter = model.getChildren().iterator(); iter.hasNext(); ) {
179             NodeModel child = (NodeModel) iter.next();
180             if (child.hasAttribute(name) || descendantDefinesAttribute(child, name))
181                 return true;
182         }
183         return false;
184     }
185     
186     NodeModel applyClass(NodeModel instance) {
187         final String JavaDoc DEFAULTPLACEMENT_ATTR_NAME = "defaultPlacement";
188         final String JavaDoc PLACEMENT_ATTR_NAME = "placement";
189         if (nodeModel == null) throw new RuntimeException JavaDoc("no nodeModel for " + className);
190         if (nodeModel.hasAttribute(DEFAULTPLACEMENT_ATTR_NAME))
191             throw new InlineClassError(this, instance, "The class has a " + DEFAULTPLACEMENT_ATTR_NAME + " attribute");
192         if (instance.hasAttribute(DEFAULTPLACEMENT_ATTR_NAME))
193             throw new InlineClassError(this, instance, "The instance has a " + DEFAULTPLACEMENT_ATTR_NAME + " attribute");
194         if (descendantDefinesAttribute(instance, PLACEMENT_ATTR_NAME))
195             throw new InlineClassError(this, instance, "An element within the instance has a " + PLACEMENT_ATTR_NAME + " attribute");
196         
197         try {
198             // Replace this node by the class model.
199
NodeModel model = (NodeModel) nodeModel.clone();
200             // Set $classrootdepth on children of the class (but not the
201
// instance that it's applied to)
202
setChildrenClassRootDepth(model, 1);
203             model.updateMembers(instance);
204             model.setClassName(getSuperclassName());
205             return model;
206         } catch (CompilationError e) {
207             throw new InlineClassError(this, instance, e.getMessage());
208         }
209     }
210     
211     protected void setChildrenClassRootDepth(NodeModel model, int depth) {
212         final String JavaDoc CLASSROOTDEPTH_ATTRIBUTE_NAME = "$classrootdepth";
213         for (Iterator iter = model.getChildren().iterator(); iter.hasNext(); ) {
214             NodeModel child = (NodeModel) iter.next();
215             // If it has already been set, this child is the result of
216
// a previous inline class expansion with a different
217
// classroot.
218
if (child.hasAttribute(CLASSROOTDEPTH_ATTRIBUTE_NAME))
219                 continue;
220             child.setAttribute(CLASSROOTDEPTH_ATTRIBUTE_NAME,
221                                new Integer JavaDoc(depth));
222             int childDepth = depth;
223             ClassModel childModel = child.getClassModel();
224             // If this is an undefined class, childModel will be null.
225
// This is an error, and other code signals a compiler
226
// warning. This test keeps it from resulting in a stack
227
// trace too.
228
if (childModel != null && childModel.isSubclassOf(schema.getClassModel("state")))
229                 childDepth++;
230             setChildrenClassRootDepth(child, childDepth);
231         }
232     }
233 }
234
Popular Tags