001: /*
002: * Definition.java February 2006
003: *
004: * Copyright (C) 2006, Niall Gallagher <niallg@users.sf.net>
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: * GNU Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General
016: * Public License along with this library; if not, write to the
017: * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
018: * Boston, MA 02111-1307 USA
019: */
020:
021: package simple.page.translate;
022:
023: import simple.page.Workspace;
024: import java.util.ArrayList;
025: import java.util.Stack;
026: import java.util.List;
027: import java.util.Date;
028: import java.io.File;
029:
030: /**
031: * A <code>Definition</code> object is used to gather information
032: * regarding a JSP source file. During translation, a JSP source file
033: * undergoes a lexical analysis phase, where the file is broken up
034: * into digestable tokens. These tokens are parsed and used in the
035: * building phase of translation. As the building phase progresses
036: * data is placed into a definition so that it can be used in a
037: * generation step. For example, take the following token.
038: * <pre>
039: *
040: * <%@ page import="java.util.List,
041: * java.util.Iterator,
042: * java.util.Map" %>
043: *
044: * </pre>
045: * When parsed, this generates a list of import packages, which will
046: * be needed in the generation phase to compose the Java or Groovy
047: * source file. So, during building, each import can be added to the
048: * JSP <code>Definition</code>, where it can be later retrieved and
049: * used by the source code generator. For more information on how
050: * this object is used see the <code>Builder</code> object.
051: *
052: * @author Niall Gallagher
053: *
054: * @see simple.page.translate.Builder
055: */
056: class Definition implements Source {
057:
058: /**
059: * Contains a list of libraries used by the root JSP source.
060: */
061: private ArrayList imports;
062:
063: /**
064: * Contains a list of code and print statements to generate.
065: */
066: private ArrayList contents;
067:
068: /**
069: * Contains the member functions and fields used by the page.
070: */
071: private ArrayList fields;
072:
073: /**
074: * Represents the workspace this object is generate within.
075: */
076: private Workspace project;
077:
078: /**
079: * Contains information regarding the generated class file.
080: */
081: private Target target;
082:
083: /**
084: * Keeps track of the current context of the evaluated JSP.
085: */
086: private Stack stack;
087:
088: /**
089: * Keeps track of all included files used by the root JSP.
090: */
091: private Tracker files;
092:
093: /**
094: * This specifies the runtime language used by the JSP page.
095: */
096: private String runtime;
097:
098: /**
099: * This is the character encoding the page will write with.
100: */
101: private String charset;
102:
103: /**
104: * This is the MIME type of the JSP page source contents.
105: */
106: private String type;
107:
108: /**
109: * Constructor for the <code>Definition</code> object. This is used
110: * to create an object for collecting tokens parsed from the JSP
111: * source file. This is used when translating the page into a Java
112: * or Groovy JSP source. Information, such as the imorts, includes
113: * code segments, runtime language, and so on. This object is used
114: * in the translation and generation phase of the JSP processing.
115: *
116: * @param target this is the URI path to the translated JSP file
117: */
118: public Definition(Workspace project, String target) {
119: this .target = new Target(project, target);
120: this .files = new Tracker(project);
121: this .contents = new ArrayList();
122: this .imports = new ArrayList();
123: this .fields = new ArrayList();
124: this .stack = new Stack();
125: this .project = project;
126: }
127:
128: /**
129: * This provides a key component for the JSP engine, which is used
130: * to determine when a JSP page or its includes have expired. This
131: * allows background compilation, and ensures that pages can be
132: * edited and deployed without restarting the server.
133: *
134: * @return this returns a monitor to the referenced JSP sources
135: */
136: public Reference getReference() {
137: return files;
138: }
139:
140: /**
141: * This is used to acquire the source file generated. This is used
142: * by the generator to create the source file. This makes use of
143: * the language token to identify the name of the source file. For
144: * eample if the runtime language is Groovy the file extension
145: * would be ".groovy" and ".java" when using the Java language.
146: * This will also contain the directory to be used for the source.
147: * <p>
148: * The source file name is typically extracted using the data
149: * taken from the JSP source file. For example, the JSP source
150: * file "/example/demo/Test.jsp" would translate to a source
151: * file name "/example/demo/TestPage.java" if the language was
152: * Java. For groovy the file extension would be ".groovy".
153: *
154: * @return this returns the file system path for the source file
155: */
156: public File getSource() {
157: return project.getBuildFile(target.getDirectory() + getName()
158: + "." + getLanguage());
159: }
160:
161: /**
162: * This is the directory the JSP source file. This is used in
163: * the genration and compilation phase to determine if a
164: * directory needs to be created to host the generated source.
165: * The generation and build files, that is, the ".java" and
166: * ".class" files use a mirror of the JSP directory.
167: *
168: * @return this returns the directory used by the JSP file
169: */
170: public File getDirectory() {
171: return project.getBuildFile(target.getDirectory());
172: }
173:
174: /**
175: * This is used to acqure the name of the generated class file.
176: * This is the name of the class as it appears within the source.
177: * For example a class name such as <code>ExamplePage</code> can
178: * be used when generating the source JSP "/demo/Example.jsp".
179: * Typically this appends <code>Page</code> to the JSP file name,
180: * however this feature may be overloaded to avoid collisions.
181: *
182: * @return this returns the name of the class generated
183: */
184: public String getName() {
185: return target.getName();
186: }
187:
188: /**
189: * This is the fully qualified class name of the generated class.
190: * This contains the class name and package, in a "." seperated
191: * string. Typically the package name is taken from the path of
192: * the generated JSP source. For example "/demo/Example.jsp" will
193: * have the fully qualified name <code>demo.ExamplePage</code>.
194: * <p>
195: * This is used in the compilation phase, so that the generated
196: * class can be loaded with a class loader and then instantiated
197: * and used to serve content for a request.
198: *
199: * @return this returns the fully qualified package name
200: */
201: public String getTarget() {
202: return target.getTarget();
203: }
204:
205: /**
206: * This is used to acquire the package name for the class file.
207: * The generator uses this to declare the package name of the
208: * source file. This is required so that there is a namespace
209: * for the generated page, which avoids name collisions. This
210: * is taken from the source JSP file, so "/a/b/c/Demo.jsp"
211: * would contain the package <code>a.b.c</code>.
212: *
213: * @return this returns the package for the source generated
214: */
215: public String getPackage() {
216: return target.getPackage();
217: }
218:
219: /**
220: * This is used to acquire a context for includes when the scope
221: * of the JSP changes. This allows relative include paths to be
222: * used, for instance if a path such as "../File.jsp" was used it
223: * would require the that the includers parent directory contains
224: * that source file. This is fine for a single heirarchy of JSP
225: * includes, however consider the case where the includes are.
226: * <pre>
227: *
228: * <%@ include file="../File.jsp" %>
229: * <%@ include file="../Example.jsp" %>
230: *
231: * </pre>
232: * So above, the main source JSP includes "File.jsp" from its
233: * parent directory. Following that "File.jsp" includes the file
234: * "Example.jsp" from its parent directory. It is obvoius from
235: * this that "Example.jsp" is not in the root JSP files parent
236: * directory, relative to the root it is "../../Example.jsp". So
237: * context must change so includes can cascade well.
238: *
239: * @return this returns a stack that remembers the JSP context
240: */
241: public Stack getContext() {
242: return stack;
243: }
244:
245: /**
246: * This is used to acquire the imports specified within the JSP
247: * file. The imports acquired from the <code>List</code> object
248: * provided are used in the generation phase of translation.
249: * The source produced via translation must contain all imports
250: * for objects used by the JSP. This will provide a unique set
251: * of imports from the root JSP and all included JSP files.
252: *
253: * @return this returns the imports to be used in the source
254: */
255: public List getImports() {
256: return imports;
257: }
258:
259: /**
260: * Add an import line to the document definition. The imports
261: * added to the document definition should be fully complete.
262: * This means requires the the building phase produces some
263: * code that is used to generate the resulting source file.
264: * <pre>
265: *
266: * import java.util.List;
267: * import java.util.Iterator;
268: *
269: * </pre>
270: * The above tokens are examples of import lines that may be
271: * included as imports. This are directly usable by both the
272: * Java and Groovy source files, without modification.
273: *
274: * @param library this is an import to be added to the source
275: */
276: public void addImport(String library) {
277: imports.add(library);
278: }
279:
280: /**
281: * This retrieves the list of declaration blocks included within
282: * the JSP source. Declarations are segments within the source
283: * that provide member fields and functions to the resulting Java
284: * or Groovy file generated. Member functions and fields will be
285: * accessable from the class to perform repetitive tasks.
286: *
287: * @return this provides a list of the declarations specified
288: */
289: public List getDeclarations() {
290: return fields;
291: }
292:
293: /**
294: * Add a declaration block to the document definition. This is
295: * used to insert member methods and fields to the generated Java
296: * or Groovy source file. Declarations are defined within the JSP
297: * source file using the <code><%!</code> tag. For example.
298: * <pre>
299: *
300: * public String escape(String url) {
301: * return new URLEncoder.encode(url, "UTF-8");
302: * }
303: *
304: * </pre>
305: * The above example declaration block could be added to the
306: * document and later generated as part of the Java or Groovy
307: * source file, where it could be conviniently used.
308: *
309: * @param field this is used to add functions or fields
310: */
311: public void addDeclaration(String field) {
312: fields.add(field);
313: }
314:
315: /**
316: * This is used to acquire the lines, which are to be used within
317: * the main page method. The will provide code segments and print
318: * statements, which are used to provide the contents for the
319: * resulting request. During translation the JSP unescaped text
320: * is converted into <code>print</code> statements to that it
321: * can be compiled in such a way that it emits the text.
322: *
323: * @return pring statements and code segments for the body
324: */
325: public List getContents() {
326: return contents;
327: }
328:
329: /**
330: * Add a code or print statement to to the definition. Each block
331: * of code added to the definition must be in order of appearnce,
332: * and all must be valid Groovy and Java statements. JSP text is
333: * typically escaped as a <code>print</code> statement.
334: * <pre>
335: *
336: * out.print("%lt;b>Example Text</b>\n");
337: *
338: * </pre>
339: * The above statement is an example of a <code>print</code>
340: * statement generated from some JSP markup. All contents in the
341: * provided list are in order of appearence.
342: *
343: * @param token code statement or block to add to the definition
344: */
345: public void addContent(String token) {
346: contents.add(token);
347: }
348:
349: /**
350: * This provides the list of JSP files that be been used to compose
351: * the resulting source. The included files are identified using
352: * a URI path that references a file from the <code>Context</code>
353: * used. This allows a cascading context to search for the file,
354: * such that the file can move and change context, allowing the
355: * translator and compiler to initiate compilation again.
356: *
357: * @return this returns a list of URI paths for JSP includes
358: */
359: public List getIncludes() {
360: return files.getIncludes();
361: }
362:
363: /**
364: * This is used to include other JSP files or text files, which
365: * can be translated and compiled into the resulting source. The
366: * included file is monitored by the JSP engine so that if the
367: * file changes it can be compiled back in to the source.
368: * <pre>
369: *
370: * <%@ include file="../Relative.jsp" %>
371: * <%@ include file="/path/Absolute.jsp" %>
372: *
373: * </pre>
374: * All included files must be absolute so that its details can
375: * be retrieved using a <code>Context</code> object. This allows
376: * the modification times for the source to be determined.
377: *
378: * @param target an absolute path to the included JSP file
379: */
380: public void addInclude(String target) {
381: files.addInclude(target);
382: }
383:
384: /**
385: * This is used to determine the language the JSP has been written
386: * in. This can be set to "groovy" or "java" with the "language"
387: * attribute for the "page" token. This is used by the generator
388: * and compiler to determine how to create an compile the source.
389: * <pre>
390: *
391: * <%@ page language="groovy" %>
392: *
393: * </pre>
394: * The above is an example of how the "language" attribute can
395: * be used from within a JSP page. If this attribute is not
396: * specified the runtime language defaults to Java.
397: *
398: * @return the runtime language used by the JSP source
399: */
400: public String getLanguage() {
401: if (runtime == null) {
402: return "java";
403: }
404: return runtime;
405: }
406:
407: /**
408: * Specify the language that this page is using. Typically this
409: * will be used if the runtime language is Groovy. If this is
410: * not set the language defaults to Java. Once set the page can
411: * be generated and compiled using the specified language. This
412: * takes either "groovy" or "java" as this are supported.
413: *
414: * @param runtime this is the runtime language used by the JSP
415: */
416: public void setLanguage(String runtime) {
417: this .runtime = runtime;
418: }
419:
420: /**
421: * This is used to acquire the charset for the page. Typically
422: * this will be null, and defaults to "UTF-8" within the
423: * generated page. The charset provided by this must be a Java
424: * supported character encoding, for example "ISO-8858-1".
425: * <pre>
426: *
427: * <%@ page contentType="text/xhtml; charset=UTF-8" %>
428: *
429: * </pre>
430: * The charset is extracted from the content type specification.
431: * The "charset" attribute within the content type directive is
432: * optional, and again if not specified it defaults to "UTF-8".
433: *
434: * @return provides the charset specified or null for UTF-8
435: */
436: public String getCharset() {
437: return charset;
438: }
439:
440: /**
441: * This is used to specify the character encoding used for the
442: * page. The charset specified must be a valid Java encoding
443: * such as UTF-8, ISO-8859-1, UCS2, and so on. If this has
444: * not been set the default character encoding is UTF-8.
445: *
446: * @param charset valid character encoding used for the JSP
447: */
448: public void setCharset(String charset) {
449: this .charset = charset;
450: }
451:
452: /**
453: * This is used to acquire the MIME type for the page. This
454: * like the charset is taken from the "page" directive. If no
455: * type is specified, that is, if this returns null, then the
456: * file extension is used to acquire the MIME type.
457: * <pre>
458: *
459: * <%@ page contentType="text/xhtml; charset=UTF-8" %>
460: *
461: * </pre>
462: * The MIME type is extracted from the "contentType" attribute
463: * within the page directive. This should be a valid type as
464: * is acceptable within the HTTP Content-Type header.
465: *
466: * @return this returns null, or the MIME type of the JSP
467: */
468: public String getType() {
469: return type;
470: }
471:
472: /**
473: * This is used to specify the MIME type encoding used for the
474: * JSP. This MIME type must be valid and acceptable as a value
475: * for the HTTP Content-Type header. If no MIME type is
476: * specified, then the file extension is used to map the type.
477: *
478: * @param type this is the token used to specify the type
479: */
480: public void setType(String type) {
481: this .type = type;
482: }
483:
484: /**
485: * This is used to provide the modification date for the source
486: * translation. This is useful for debugging issues as it is
487: * possible to determine the version of the JSP source was used
488: * to convert the page to either Groovy or Java source.
489: *
490: * @return this returns the date the source was translated
491: */
492: public Date getDate() {
493: return new Date();
494: }
495: }
|