001: /* *****************************************************************************
002: * ToplevelCompiler.java
003: * ****************************************************************************/
004:
005: /* J_LZ_COPYRIGHT_BEGIN *******************************************************
006: * Copyright 2001-2007 Laszlo Systems, Inc. All Rights Reserved. *
007: * Use is subject to license terms. *
008: * J_LZ_COPYRIGHT_END *********************************************************/
009:
010: package org.openlaszlo.compiler;
011:
012: import java.util.*;
013: import java.io.*;
014:
015: import org.jdom.Element;
016: import org.openlaszlo.compiler.ViewCompiler.*;
017: import org.openlaszlo.server.*;
018: import org.openlaszlo.utils.*;
019: import org.jdom.*;
020: import org.apache.log4j.*;
021:
022: /** Compiler for <code>canvas</code> and <code>library</code> elements.
023: */
024: abstract class ToplevelCompiler extends ElementCompiler {
025: /** Logger */
026: private static Logger mLogger = Logger
027: .getLogger(ToplevelCompiler.class);
028:
029: ToplevelCompiler(CompilationEnvironment env) {
030: super (env);
031: }
032:
033: /** Returns true if the element is capable of acting as a toplevel
034: * element. This is independent of whether it's positioned as a
035: * toplevel element; CompilerUtils.isTopLevel() tests for position
036: * as well. */
037: static boolean isElement(Element element) {
038: return CanvasCompiler.isElement(element)
039: || LibraryCompiler.isElement(element);
040: }
041:
042: public void compile(Element element) {
043: // Check if children are valid tags to be contained
044: mEnv.checkValidChildContainment(element);
045:
046: for (Iterator iter = element.getChildren().iterator(); iter
047: .hasNext();) {
048: Element child = (Element) iter.next();
049: if (!NodeModel.isPropertyElement(child)) {
050: Compiler.compileElement(child, mEnv);
051: }
052: }
053: }
054:
055: /** Parses out user class definitions.
056: *
057: * <p>
058: * Iterates the direct children of the top level of the DOM tree and
059: * look for elements named "class", find the "name" and "extends"
060: * attributes, and enter them in the ViewSchema.
061: *
062: * @param visited {canonical filenames} for libraries whose
063: * schemas have been visited; used to prevent recursive
064: * processing.
065: *
066: */
067: void updateSchema(Element element, ViewSchema schema, Set visited) {
068: Iterator iterator = element.getChildren().iterator();
069: while (iterator.hasNext()) {
070: Element child = (Element) iterator.next();
071: if (!NodeModel.isPropertyElement(child)) {
072: Compiler.updateSchema(child, mEnv, schema, visited);
073: }
074: }
075: }
076:
077: /** This also collects "attribute", "method", and HTML element
078: * names, but that's okay since none of them has an autoinclude
079: * entry.
080: */
081: static void collectReferences(CompilationEnvironment env,
082: Element element, Set defined, Set referenced,
083: Map libsVisited) {
084: ElementCompiler compiler = Compiler.getElementCompiler(element,
085: env);
086: ViewCompiler.collectLayoutElement(element, referenced);
087: if (compiler instanceof ToplevelCompiler) {
088: Set libStart = null;
089: Set libFound = null;
090: Element library = null;
091: File libFile = null;
092: if (compiler instanceof LibraryCompiler
093: || compiler instanceof ImportCompiler) {
094: libStart = new LinkedHashSet(libsVisited.keySet());
095: libFound = new LinkedHashSet(libStart);
096: library = LibraryCompiler.resolveLibraryElement(
097: element, env, libFound);
098: if (library == element) {
099: // Not an external library
100: library = null;
101: }
102: if (library != null) {
103: element = library;
104: try {
105: libFile = new File(Parser
106: .getSourcePathname(library))
107: .getCanonicalFile();
108: libsVisited.put(libFile, null);
109: } catch (IOException f) {
110: assert false : "Can't happen";
111: }
112: }
113: }
114: for (Iterator iter = element.getChildren().iterator(); iter
115: .hasNext();) {
116: collectReferences(env, (Element) iter.next(), defined,
117: referenced, libsVisited);
118: }
119: if (library != null) {
120: Set includes = new LinkedHashSet(libsVisited.keySet());
121: includes.removeAll(libStart);
122: libsVisited.put(libFile, includes);
123: }
124: } else if (compiler instanceof ClassCompiler
125: || compiler instanceof InterfaceCompiler) {
126: String name = element.getAttributeValue("name");
127: if (name != null) {
128: defined.add(name);
129: }
130: String super class = element.getAttributeValue("extends");
131: if (super class != null) {
132: referenced.add(super class);
133: }
134: ViewCompiler.collectElementNames(element, referenced);
135: } else if (compiler instanceof ViewCompiler) {
136: ViewCompiler.collectElementNames(element, referenced);
137: }
138: }
139:
140: static List getLibraries(CompilationEnvironment env,
141: Element element, Map explanations, Map autoIncluded,
142: Map visited) {
143: String librariesAttr = element.getAttributeValue("libraries");
144: assert librariesAttr == null : "unsupported attribute `libraries`";
145: List libraryNames = new ArrayList();
146: String base = new File(Parser.getSourcePathname(element))
147: .getParent();
148:
149: // figure out which tags are referenced but not defined, and
150: // look up their libraries in the autoincludes file
151: {
152: Set defined = new HashSet();
153: Set referenced = new HashSet();
154: collectReferences(env, element, defined, referenced,
155: visited);
156: // keep the keys sorted so the order is deterministic for qa
157: Set additionalLibraries = new TreeSet();
158: Map autoincludes = env.getSchema().sAutoincludes;
159: Map canonicalAuto = new HashMap();
160: try {
161: for (Iterator iter = autoincludes.keySet().iterator(); iter
162: .hasNext();) {
163: String key = (String) iter.next();
164: canonicalAuto.put(key, env.resolveLibrary(
165: (String) autoincludes.get(key), base)
166: .getCanonicalFile());
167: }
168: } catch (IOException e) {
169: throw new CompilationError(element, e);
170: }
171: // iterate undefined references
172: for (Iterator iter = referenced.iterator(); iter.hasNext();) {
173: String key = (String) iter.next();
174: if (autoincludes.containsKey(key)) {
175: String value = (String) autoincludes.get(key);
176: // Ensure that a library that was explicitly
177: // included that would have been auto-included is
178: // emitted where the auto-include would have been.
179: if (defined.contains(key)) {
180: File canonical = (File) canonicalAuto.get(key);
181: if (visited.containsKey(canonical)) {
182: // Annotate as explicit
183: if (explanations != null) {
184: explanations.put(value,
185: "explicit include");
186: }
187: // but include as auto
188: additionalLibraries.add(value);
189: }
190: } else {
191: if (explanations != null) {
192: explanations.put(value, "reference to <"
193: + key + "> tag");
194: }
195: additionalLibraries.add(value);
196: }
197: }
198: }
199: // If not linking, consider all external libraries as
200: // 'auto'
201: if (autoIncluded != null) {
202: try {
203: String basePrefix = (new File((base != null) ? base
204: : ".")).getCanonicalPath();
205: for (Iterator i = visited.keySet().iterator(); i
206: .hasNext();) {
207: File file = (File) i.next();
208: String path = file.getCanonicalPath();
209: if (!path.startsWith(basePrefix)) {
210: autoIncluded.put(file, visited.get(file));
211: }
212: }
213: } catch (IOException e) {
214: throw new CompilationError(element, e);
215: }
216: }
217: libraryNames.addAll(additionalLibraries);
218: }
219: // Turn the library names into pathnames
220: List libraries = new ArrayList();
221: for (Iterator iter = libraryNames.iterator(); iter.hasNext();) {
222: String name = (String) iter.next();
223: try {
224: File file = env.resolveLibrary(name, base)
225: .getCanonicalFile();
226: libraries.add(file);
227: if (autoIncluded != null) {
228: autoIncluded.put(file, visited.get(file));
229: }
230: } catch (IOException e) {
231: throw new CompilationError(element, e);
232: }
233: }
234:
235: // add the debugger, if canvas debug=true
236: if (env.getBooleanProperty(env.DEBUG_PROPERTY)) {
237: if (explanations != null) {
238: explanations.put("debugger",
239: "the canvas debug attribute is true");
240: }
241: String pathname = LPS.getComponentsDirectory()
242: + File.separator + "debugger" + File.separator
243: + "library.lzx";
244: libraries.add(new File(pathname));
245: }
246: return libraries;
247: }
248:
249: static List getLibraries(CompilationEnvironment env,
250: Element element, Map explanations, Set autoIncluded,
251: Set visited) {
252: Map externalMap = null;
253: Map visitedMap = null;
254: if (autoIncluded != null) {
255: externalMap = new LinkedHashMap();
256: }
257: if (visited != null) {
258: visitedMap = new LinkedHashMap();
259: }
260: List libs = getLibraries(env, element, explanations,
261: externalMap, visitedMap);
262: if (autoIncluded != null) {
263: autoIncluded.addAll(externalMap.keySet());
264: }
265: if (visited != null) {
266: visited.addAll(visitedMap.keySet());
267: }
268: return libs;
269: }
270:
271: List getLibraries(Element element) {
272: return getLibraries(mEnv, element, null, null, new HashSet());
273: }
274:
275: static String getBaseLibraryName(CompilationEnvironment env) {
276: return LPS.getLFCname(env.getRuntime(), env
277: .getBooleanProperty(env.DEBUG_PROPERTY), env
278: .getBooleanProperty(env.PROFILE_PROPERTY), env
279: .getBooleanProperty(env.BACKTRACE_PROPERTY));
280: }
281:
282: static void handleAutoincludes(CompilationEnvironment env,
283: Element element) {
284: // import required libraries, and collect explanations as to
285: // why they were required
286: Canvas canvas = env.getCanvas();
287:
288: Map explanations = new HashMap();
289: for (Iterator iter = getLibraries(env, element, explanations,
290: null, new HashSet()).iterator(); iter.hasNext();) {
291: File file = (File) iter.next();
292: Compiler.importLibrary(file, env);
293: }
294:
295: Element info;
296: // canvas info += <include name= explanation= [size=]/> for LFC
297: if (env.isSWF()) {
298: String baseLibraryName = getBaseLibraryName(env);
299: String baseLibraryBecause = "Required for all applications";
300: info = new Element("include");
301: info.setAttribute("name", baseLibraryName);
302: info.setAttribute("explanation", baseLibraryBecause);
303: try {
304: info.setAttribute("size", ""
305: + FileUtils.getSize(env.resolveLibrary(
306: baseLibraryName, "")));
307: } catch (Exception e) {
308: mLogger.error(
309: /* (non-Javadoc)
310: * @i18n.test
311: * @org-mes="exception getting library size"
312: */
313: org.openlaszlo.i18n.LaszloMessages.getMessage(
314: ToplevelCompiler.class.getName(),
315: "051018-228"), e);
316: }
317: canvas.addInfo(info);
318: }
319:
320: // canvas info += <include name= explanation=/> for each library
321: for (Iterator iter = explanations.entrySet().iterator(); iter
322: .hasNext();) {
323: Map.Entry entry = (Map.Entry) iter.next();
324: info = new Element("include");
325: info.setAttribute("name", entry.getKey().toString());
326: info.setAttribute("explanation", entry.getValue()
327: .toString());
328: canvas.addInfo(info);
329: }
330: }
331:
332: }
|