001: /*
002: * JDynamiTe - Dynamic Template in Java
003: * Copyright (C) 2001 Christophe Bouleau
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
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 GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package cb.jdynamite;
021:
022: import java.util.*;
023: import java.io.*;
024: import cb.jdynamite.analyser.*;
025:
026: /**
027: * JDynamiTe is the unique class you need to parse a template document.
028: * This implementation extends the DefaultDynamicElement class (from package analyser),
029: * so a JDynamiTe object is a "Dynamic Element".
030: * The use is very simple : <br>
031: * First define the input file or input stream (for example an HTML template document)
032: * with the "setInput" method.<br>
033: * Secondly fill and develop this document with a few methods such as "setVariable",
034: * and "parseDynElem".<br>
035: * Finally, after calling the "parse" method to finalize building your dynamic document,
036: * you simply obtain the result with the "toString" method.
037: * <br><br>
038: * See an example in the main method of this class.
039: * <br><br>
040: * <h3>JDynamiTe elements</h3>
041: * There are (only) two elements which make a document a "template" document.
042: * <br><br><b>1) "Variable Element"</b><br>
043: * A "Variable Element" is defined by an identifier in the template document.
044: * Its value can be changed with the JDynamiTe.setValue method.<br>
045: * Example of use: titles, values of cells in tables, etc.
046: * <br><br><b>2) "Dynamic Element"</b><br>
047: * A "Dynamic Element" is a "block" which can be dynamically developed.
048: * It has an identifier, a template definition, and a value.
049: * Its value can be set or developed with the JDynamiTe.parseDynElem and JDynamiTe.setDynElem methods.<br>
050: * Example of use: list, table, enumeration, etc.
051: * <br><br><br>
052: * <h3>Template document syntax</h3>
053: * There are only 3 tags to use JDynamiTe : "Variable" tag, "Begin Dynamic Element" tag, and
054: * "End Dynamic Element" tag. The tag syntax is defined by regular expressions, you can change it in the
055: * analyser.<br>
056: * By default JDynamiTe uses the "DefaultAnalyser" to parse the template documents.
057: * By default, this analyser uses HTML style tags.
058: * <br><br>
059: * <b>1) "Variable" tag:</b> <pre>
060: * {VARNAME} </pre>
061: * means you can use setVariable("VARNAME", aStringValue) in Java code.<br><br>
062: * <b>2) "Begin Dynamic Element" tag:</b> <pre>
063: * <!-- BEGIN DYNAMIC : dynElemName --> </pre>
064: * or <pre>
065: * <!-- BEGIN DYNAMIC BLOCK: dynElemName --> </pre>
066: * means the "dynElemName" Dynamic Element definition begins on the next line.
067: * <br><br>
068: * <b>3) "End Dynamic Element" tag:</b> <pre>
069: * <!-- END DYNAMIC : dynElemName --> </pre>
070: * or <pre>
071: * <!-- END DYNAMIC BLOCK: dynElemName --> </pre>
072: * means the "dynElemName" Dynamic Element definition ends on the previous line.
073: * <br><br>
074: * <b>Identifiers syntax (for Variables and Dynamic Elements):</b><br>
075: * By default, it is a word made up of alphanumeric characters and these four characters:
076: * '.', ':', '_' and '-'
077: *
078: * <br><br><br>
079: * <h3>New concept : "Ignored Element"</h3>
080: * Since JDynamiTe 1.1, this optional element can be used in template documents. An "Ignored Element" is
081: * a "block" which will be completly ignored (skipped during document analysis).<br>
082: * Example of use: it allows the HTML designer to build more realistic pages, with concrete data, giving a
083: * better idea of the possible dynamic page look and feel. An "Ignored Element" can be inserted anywhere in
084: * the template document, even inside "Dynamic Element".<br><br>
085: * <b>"Ignored Element" tags</b> <pre>
086: * <!-- BEGIN IGNORED : ignoredElemName --> </pre>
087: * means an ignored block (skipped during analysis and document output) begins on the next line.
088: * <br><pre>
089: * <!-- END IGNORED : ignoredElemName --> </pre>
090: * means this ignored block ends on the previous line.
091: *
092: * <br><br><br>
093: * <h3>JDynamiTe home page</h3>
094: * JDynamiTe latest versions, news, examples ... at <b>http://jdynamite.sourceforge.net</b>
095: * <br><br><br>
096: * @author Christophe Bouleau
097: */
098: public class JDynamiTe extends DefaultDynamicElement implements
099: ITemplateDocument, Serializable {
100: private Hashtable variables;
101: private Hashtable dynamics;
102: private ITemplateAnalyser analyser;
103:
104: /**
105: * Constructs an empty "JDynamiTe" (Java Dynamic Template) document.
106: */
107: public JDynamiTe() {
108: this ("__topLevel__");
109: }
110:
111: /**
112: * Constructs an empty "JDynamiTe" (Java Dynamic Template) document.
113: *
114: * @param name The name of this "JDynamiTe" document, used for debugging purposes by the
115: * "getTemplateDefinition" method.
116: */
117: public JDynamiTe(String name) {
118: super (name);
119: variables = new Hashtable();
120: dynamics = new Hashtable();
121: recordDynElem(name, this );
122: }
123:
124: /**
125: * Starts the analysis of the input template document.
126: * If no custom "ITemplateAnalyser" was defined, JDynamiTe uses the "DefaultAnalyser".
127: * After this step, all the Variables and Dynamic Elements are identified,
128: * so this JDynamiTe is ready to be developed.
129: * By default all Variables are set to an empty string value.
130: * In addition, Variable identifiers (keys) can be retreived by getVariablesKeys.
131: *
132: * @param reader A BufferedReader to read the input template document.
133: * @exception java.io.IOException If an I/O error occurs.
134: * @see setInput(java.io.InputStream)
135: * @see setInput(java.lang.String)
136: * @see cb.jdynamite.analyser.DefaultAnalyser
137: * @see setAnalyser(ITemplateAnalyser templateAnalyser)
138: * @since JDynamyTe 1.2
139: */
140: public void setInput(BufferedReader reader) throws IOException {
141: if (analyser == null) {
142: analyser = new DefaultAnalyser();
143: }
144: analyser.analyse(this , this , reader);
145: }
146:
147: /**
148: * Starts the analysis of the input template document.
149: * If no custom "ITemplateAnalyser" was defined, JDynamiTe uses the "DefaultAnalyser".
150: * After this step, all the Variables and Dynamic Elements are identified,
151: * so this JDynamiTe is ready to be developed.
152: * By default all Variables are set to an empty string value.
153: * In addition, Variable identifiers (keys) can be retreived by getVariablesKeys.
154: *
155: * @param istream A stream to read the input template document.
156: * @exception java.io.IOException If an I/O error occurs.
157: * @see setInput(java.io.BufferedReader)
158: * @see setInput(java.lang.String)
159: * @see cb.jdynamite.analyser.DefaultAnalyser
160: * @see setAnalyser(ITemplateAnalyser templateAnalyser)
161: */
162: public void setInput(InputStream istream) throws IOException {
163: setInput(new BufferedReader(new InputStreamReader(istream)));
164: }
165:
166: /**
167: * Starts the analysis of the input template document.
168: * If no custom "ITemplateAnalyser" was defined, JDynamiTe uses the "DefaultAnalyser".
169: * After this step, all the Variables and Dynamic Elements are identified,
170: * so this JDynamiTe is ready to be developed.
171: * By default all Variables are set to an empty string value.
172: * In addition, Variable identifiers (keys) can be retreived by getVariablesKeys.
173: *
174: * @param fileName The name of the file which contains the input template document.
175: * @exception java.io.IOException If an I/O error occurs.
176: * @exception java.io.FileNotFoundException Bad filename.
177: * @see setInput(java.io.BufferedReader)
178: * @see setInput(java.io.InputStream)
179: * @see cb.jdynamite.analyser.DefaultAnalyser
180: * @see setAnalyser(ITemplateAnalyser templateAnalyser)
181: */
182: public void setInput(String fileName) throws IOException,
183: FileNotFoundException {
184: FileReader fileReader = new FileReader(fileName);
185: setInput(new BufferedReader(fileReader));
186: fileReader.close();
187: }
188:
189: /**
190: * Returns the value of a variable that was set by setVariable.
191: * A "JDynamiTe" document maintains a list of key/value pairs, which is used when
192: * Dynamic Elements are parsed.
193: *
194: * @param key The key of the variable to retrieve.
195: * @return The value of the variable.
196: * @see setVariable(java.lang.String, java.lang.String)
197: */
198: public String getVariable(String key) {
199: return (String) variables.get(key);
200: }
201:
202: /**
203: * Set the value of a variable.
204: * Overrides its previous value if any.
205: * A "JDynamiTe" document maintains a list of key/value pairs, which is used when
206: * Dynamic Elements are parsed.
207: *
208: * @param key The key of the variable to set.
209: * @param value The new value of this variable.
210: * @see getVariable(java.lang.String)
211: */
212: public void setVariable(String key, String value) {
213: variables.put(key, value);
214: }
215:
216: /**
217: * Returns an enumeration of the template Variable keys in this JDynamiTe document.
218: * A "JDynamiTe" document maintains a list of key/value pairs, which is used when
219: * Dynamic Elements are parsed.
220: * The setInput method build this list (with an empty string as default value)
221: * during the template document analysis. After this step, the setVariable method
222: * is used to set a value to a Variable.
223: * Example of use :
224: * <pre>
225: * Enumeration keys = myJDynamiTeDoc.getVariableKeys();
226: * while (keys.hasMoreElements()) {
227: * String key = keys.nextElement();
228: * System.err.println(keys);
229: * String value = myDatabase.selectValue(key); // get the current value somewhere...
230: * myJDynamiTeDoc.setVariable(key, value); // set the template Variable.
231: * }
232: * </pre>
233: *
234: * @return The value of the variable.
235: * @see setVariable(java.lang.String, java.lang.String)
236: * @see setInput(InputStream istream)
237: * @see setInput(String fileName)
238: * @since JDynamiTe 1.2
239: */
240: public Enumeration getVariableKeys() {
241: return variables.keys();
242: }
243:
244: /**
245: * Returns the "Dynamic Element" identified by a string
246: * (Note: You do not need to directly call this method to use JDynamiTe).
247: * A "JDynamiTe" document maintains a list of "Dynamic Elements".
248: *
249: * @param key The "Dynamic Element" identifier. This is the string defined in the
250: * template document in the "BEGIN DYNAMIC" tag. For example:<pre>
251: * <-- BEGIN DYNAMIC : myList -->
252: * </pre>
253: * Here "myList" identifies the Dynamic Element which begins.
254: * @return The interface of the Dynamic Element.
255: */
256: public IDynamicElement getDynElem(String key) {
257: return (IDynamicElement) dynamics.get(key);
258: }
259:
260: /**
261: * Records a "Dynamic Element" in this "JDynamiTe" Document
262: * (Note: You do not need to directly call this method to use JDynamiTe).
263: * A "JDynamiTe" document maintains a list of "Dynamic Elements".
264: * It is called by the analyser.
265: *
266: * @param key The "Dynamic Element" identifier.
267: * @param value An object that implements the IDynamicElement interface.
268: */
269: public void recordDynElem(String key, IDynamicElement value) {
270: dynamics.put(key, value);
271: }
272:
273: /**
274: * Returns the analyser that parses template documents
275: * (Note: You do not need to directly call this method to use JDynamiTe).
276: *
277: * @return The current analyser.
278: * @see setAnalyser(cb.jdynamite.analyser.ITemplateAnalyser)
279: */
280: public ITemplateAnalyser getAnalyser() {
281: return analyser;
282: }
283:
284: /**
285: * Set the analyser that parses template documents
286: * (Note: You do not need to directly call this method to use JDynamiTe).
287: *
288: * @param templateAnalyser The new analyser.
289: * @see getAnalyser()
290: */
291: public void setAnalyser(ITemplateAnalyser templateAnalyser) {
292: analyser = templateAnalyser;
293: }
294:
295: ///////// utils
296:
297: /**
298: * This is a "key" method you call to append elements to the current value of a Dynamic Element.
299: * These elements are built from the template definition of this Dynamic Element and the current value
300: * of variables (and possibly nested Dynamic Elements). See examples.
301: *
302: * @param elementName The "Dynamic Element" identifier. This is the string defined
303: * in the template document in the "BEGIN DYNAMIC" tag. For example:<pre>
304: * <-- BEGIN DYNAMIC : myList -->
305: * </pre>
306: * Here "myList" identifies the Dynamic Element that begins.
307: */
308: public void parseDynElem(String elementName) {
309: IDynamicElement dynElem = getDynElem(elementName);
310: if (dynElem != null) {
311: dynElem.parse(this );
312: }
313: }
314:
315: /**
316: * Set an arbitrary value to a Dynamic Element. For example, enables emptying a
317: * Dynamic Element if you give an empty string as argument.
318: *
319: * @param elementName The Dynamic Element identifier.
320: * @param value New value for The Dynamic Element
321: */
322: public void setDynElemValue(String elementName, String value) {
323: IDynamicElement dynElem = getDynElem(elementName);
324: if (dynElem != null) {
325: dynElem.setValue(value);
326: }
327: }
328:
329: /**
330: * Calls the parse method inherited from DefaultDynamicElement. As this object is the "top level"
331: * dynamic element, this method enables obtaining the "final" value of this document.
332: * You can use the "toString" method to get this value.
333: *
334: * @see toString()
335: */
336: public void parse() {
337: parse(this );
338: }
339:
340: /**
341: * Returns the value (after parsing) of this JDynamiTe document.
342: * @return Value (after parsing) of this JDynamiTe document
343: */
344: public String toString() {
345: return getValue(this );
346: }
347:
348: /**
349: * For debugging purposes : get the result (structure of the template document) of the analyser parsing.
350: * @return Result (structure of the template document) of the analyser parsing.
351: */
352: public String getTemplateDefinition() {
353: return getDefinition(0);
354: }
355:
356: /**
357: * Reset all Variables and all Dynamic Element values.
358: */
359: public void clearAll() {
360: clearAllVariables();
361: clearAllDynElemValues();
362: }
363:
364: /**
365: * Reset all Variables.
366: */
367: public void clearAllVariables() {
368: variables.clear();
369: }
370:
371: /**
372: * Reset all Dynamic Element values.
373: */
374: public void clearAllDynElemValues() {
375: Collection dynElems = dynamics.values();
376: Iterator iter = dynElems.iterator();
377: while (iter.hasNext()) {
378: IDynamicElement dynElem = (IDynamicElement) iter.next();
379: dynElem.setValue(null);
380: }
381: }
382:
383: /////////////
384:
385: /**
386: * Provides a simple (but sufficient) example of use.
387: * Needs "testTemplate.html" in current directory as a template file.
388: * Writes the result on standard output.
389: */
390: public static void main(String args[]) {
391: JDynamiTe dynamiTe = new JDynamiTe("MyTemplateTest");
392:
393: // 1) Use "setInput" method to define (and analyse) the input template file.
394: try {
395: dynamiTe.setInput("example/testTemplateV1_2.html");
396: } catch (Exception e) {
397: System.err.println(e.getMessage());
398: }
399:
400: // possibly see the template document structure (for debug)
401: String totalDef = dynamiTe.getDefinition(0);
402: System.err.println("\n----- definition -----\n\n" + totalDef
403: + "\n-----\n");
404:
405: System.err.println("\n===== keys =====\n");
406: Enumeration keys = dynamiTe.getVariableKeys();
407: while (keys.hasMoreElements()) {
408: System.err.println("[" + keys.nextElement() + "]");
409: }
410: System.err.println("\n=====\n");
411: //
412:
413: // 2) Use "setVariable" method to give a value to variables.
414: dynamiTe.setVariable("THE_TITLE",
415: "\"Java Dynamic Template\" test");
416:
417: // First table
418: for (int i = 0; i < 6; i++) {
419: dynamiTe.setVariable("COL1", "line_" + i + ",col_1");
420: dynamiTe.setVariable("COL2", "line_" + i + ",col_2");
421: // 3) Use "parseDynElem" to build a Dynamic Element
422: dynamiTe.parseDynElem("mySimpleRow"); // add a row
423: // "parseDynElem" appends the Dynamic Element definition to its current value
424: }
425:
426: // A message
427: java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat(
428: "EEEEEE hh'h'mm'm'ss's'");
429: String dateString = formatter.format(new java.util.Date());
430: dynamiTe.setVariable("A_MESSAGE", "Hello Duke, " + dateString);
431:
432: // An image list
433: for (int px = 0; px < 3; px++) {
434: dynamiTe
435: .setVariable("PICTURE", "images/duke" + px + ".gif");
436: dynamiTe.parseDynElem("somePictures");
437: }
438:
439: // Second table with nested Dynamic Element
440: for (int row = 0; row < 5; row++) {
441: // first group of columns
442: // 4) Use "setDynElemValue" to set or reset the value of a Dynamic Element
443: dynamiTe.setDynElemValue("colX", ""); // reset for each row
444: for (int col = 0; col < 3; col++) {
445: dynamiTe.setVariable("VALUE_X", "line_" + row + ",col_"
446: + col);
447: dynamiTe.parseDynElem("colX"); // add a column
448: }
449: // second group of columns
450: dynamiTe.setDynElemValue("colY", ""); // reset for each row
451: for (int col = 3; col < 5; col++) {
452: dynamiTe.setVariable("VALUE_Y", "line_" + row
453: + ",col(BIS)_" + col);
454: dynamiTe.parseDynElem("colY"); // add a column
455: }
456: dynamiTe.parseDynElem("myBigRow"); // add a row
457: }
458:
459: // 5) Use "parse" to finaly get the value of your Dynamic Template Document
460: dynamiTe.parse();
461: System.out.println(dynamiTe.toString());
462: }
463:
464: ////////////////
465:
466: private static void justForInternalTest(String args[]) {
467: JDynamiTe jDoc = new JDynamiTe("MonDocTemplate");
468:
469: try {
470: jDoc.setInput("body1.html");
471: } catch (Exception e) {
472: System.err.println(e.getMessage());
473: }
474:
475: String totalDef = jDoc.getDefinition(0);
476: System.out.println("\nANALYSE :\n\n" + totalDef
477: + "\n\nFIN ANALYSE\n\n");
478:
479: ///////////// Remplissage
480: jDoc.setVariable("TITRE", "Test de JDynamiTe");
481:
482: for (int i = 0; i < 10; i++) {
483: jDoc.setVariable("PART1", "ligne_" + i + ",col_1");
484: jDoc.setVariable("PART2", "ligne_" + i + ",col_2");
485: jDoc.parseDynElem("elem");
486: }
487:
488: jDoc.setVariable("PICTURE", "images/myPhoto.gif");
489: String option = "classic";
490: if (option.equals("classic")) {
491: jDoc.parseDynElem("pict");
492: } else if (option.equals("arbitraire")) {
493: jDoc.setDynElemValue("pict", "\nVALEUR ARBITRAIRE !!!\n");
494: } else if (option.equals("les deux !")) {
495: jDoc.setDynElemValue("pict", "\nVALEUR ARBITRAIRE !!!\n");
496: jDoc.parseDynElem("pict");
497: }
498:
499: for (int row = 0; row < 5; row++) {
500: jDoc.setDynElemValue("col", "");
501: for (int col = 0; col < 3; col++) {
502: jDoc.setVariable("PARTX", "ligne_" + row + ",col_"
503: + col);
504: jDoc.parseDynElem("col");
505: }
506: jDoc.setDynElemValue("xcl1", "");
507: for (int col = 3; col < 5; col++) {
508: jDoc.setVariable("XPART1", "ligne_" + row + ",col(y)_"
509: + col);
510: jDoc.parseDynElem("xcl1");
511: }
512: jDoc.parseDynElem("row");
513: }
514:
515: jDoc.parse();
516: System.out.println("\njDoc :\n" + jDoc);
517: jDoc.clearAllDynElemValues();
518: jDoc.parse();
519: System.out
520: .println("\njDoc apres clearAllDynElemValues() ET parse() :\n"
521: + jDoc);
522: jDoc.clearAllDynElemValues();
523: jDoc.clearAllVariables();
524: jDoc.parse();
525: System.out
526: .println("\njDoc apres clearAllDynElemValues ET clearAllVariables() ET parse() :\n"
527: + jDoc);
528:
529: ///////////// Remplissage DEUZE
530: jDoc.clearAll();
531:
532: jDoc.setVariable("TITRE", "DEUZE Test de JDynamiTe");
533:
534: for (int i = 0; i < 10; i++) {
535: jDoc.setVariable("PART1", "DEUZE ligne_" + i + ",col_1");
536: jDoc.setVariable("PART2", "DEUZE ligne_" + i + ",col_2");
537: jDoc.parseDynElem("elem");
538: }
539:
540: jDoc.setVariable("PICTURE", "DEUZE images/myPhoto.gif");
541: option = "classic";
542: if (option.equals("classic")) {
543: jDoc.parseDynElem("pict");
544: } else if (option.equals("arbitraire")) {
545: jDoc.setDynElemValue("pict",
546: "DEUZE \nVALEUR ARBITRAIRE !!!\n");
547: } else if (option.equals("les deux !")) {
548: jDoc.setDynElemValue("pict",
549: "DEUZE \nVALEUR ARBITRAIRE !!!\n");
550: jDoc.parseDynElem("pict");
551: }
552:
553: for (int row = 0; row < 5; row++) {
554: jDoc.setDynElemValue("col", "");
555: for (int col = 0; col < 3; col++) {
556: jDoc.setVariable("PARTX", "DEUZE ligne_" + row
557: + ",col_" + col);
558: jDoc.parseDynElem("col");
559: }
560: jDoc.setDynElemValue("xcl1", "");
561: for (int col = 3; col < 5; col++) {
562: jDoc.setVariable("XPART1", "DEUZE ligne_" + row
563: + ",col(y)_" + col);
564: jDoc.parseDynElem("xcl1");
565: }
566: jDoc.parseDynElem("row");
567: }
568:
569: jDoc.parse();
570: System.out.println("\njDoc REUTILISE :\n" + jDoc);
571:
572: }
573: }
|