KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ejen > EjenTemplateNode


1 //
2
// Ejen (code generation system)
3
// Copyright (C) 2001, 2002 François Wolff (ejen@noos.fr).
4
//
5
// This file is part of Ejen.
6
//
7
// Ejen is free software; you can redistribute it and/or modify
8
// it under the terms of the GNU General Public License as published by
9
// the Free Software Foundation; either version 2 of the License, or
10
// (at your option) any later version.
11
//
12
// Ejen is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
// GNU General Public License for more details.
16
//
17
// You should have received a copy of the GNU General Public License
18
// along with Ejen; if not, write to the Free Software
19
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
//
21
package org.ejen;
22
23 import org.ejen.util.XSLUtil;
24 import java.util.Properties JavaDoc;
25 import java.io.File JavaDoc;
26 import java.io.OutputStream JavaDoc;
27 import java.io.FileOutputStream JavaDoc;
28 import java.io.StringWriter JavaDoc;
29 import javax.xml.transform.stream.StreamResult JavaDoc;
30 import javax.xml.transform.dom.DOMSource JavaDoc;
31 import org.w3c.dom.NodeList JavaDoc;
32 import org.apache.xpath.XPathAPI;
33 import org.apache.xalan.transformer.TransformerImpl;
34 import org.apache.xalan.processor.StylesheetHandler;
35
36 /**
37  * Template node class.
38  * <p>
39  * A template node uses the current in memory DOM tree to create resulting
40  * text files (XML, HTML, source code, ...).
41  * <p>
42  * <table class="usage">
43  * <tr><th class="usage">Usage (ant build file)</th></tr>
44  * <tr><td class="usage"><pre><code>
45  * &lt;?xml version="1.0" encoding="UTF-8"?&gt;
46  *
47  * &lt;project name="generate" default="build"&gt;
48  *
49  * &lt;taskdef name="ejen" classname="org.ejen.EjenTask"/&gt;
50  *
51  * &lt;target name="build"&gt;
52  * &lt;{@link org.ejen.EjenTask ejen} ...&gt;
53  * ...
54  * <b>&lt;template {@link org.ejen.EjenStylesheetNode#setFile(String) file}="filter.xml"
55  * [{@link #setForeach(String) foreach}="/ejen/entity-bean"]
56  * [{@link #setFilepattern(String) filepattern}="EJB_{&#064;table-name}Bean.java"]&gt;</b>
57  * ...
58  * [&lt;{@link org.ejen.EjenIncludeNode include} .../&gt;]
59  * [&lt;{@link org.ejen.EjenImportNode import} .../&gt;]
60  * [&lt;{@link org.ejen.EjenParamNode param} .../&gt;]
61  * ...
62  * <b>&lt;/template&gt;</b>
63  * ...
64  * &lt;/ejen&gt;
65  * &lt;/target&gt;
66  *
67  * &lt;/project&gt;
68  * </code></pre></td></tr></table>
69  * <p>
70  * <b>Parent nodes</b>:
71  * <ul>
72  * <li>{@link org.ejen.EjenTask ejen}
73  * </ul>
74  * @author F. Wolff
75  * @version 1.0
76  */

77 public class EjenTemplateNode extends EjenStylesheetNode {
78     protected String JavaDoc _foreach = null;
79     protected String JavaDoc _filepattern = null;
80     protected String JavaDoc _outdated = null;
81
82     /**
83      * Returns the name of this EjenTemplateNode (always "template").
84      * @return the name of this EjenTemplateNode.
85      */

86     public String JavaDoc nodeName() {
87         return "template";
88     }
89
90     /**
91      * Returns all non null attributes of this EjenTemplateNode.
92      * @return non null attributes of this EjenTemplateNode.
93      */

94     public Properties JavaDoc getAttributes() {
95         Properties JavaDoc attrs = super.getAttributes();
96
97         if (_foreach != null) {
98             attrs.setProperty("foreach", _foreach);
99         }
100         if (_filepattern != null) {
101             attrs.setProperty("filepattern", _filepattern);
102         }
103         if (_outdated != null) {
104             attrs.setProperty("outdated", _outdated);
105         }
106         return attrs;
107     }
108
109     /**
110      * <b>[optional/AVT]</b> - sets the foreach attribute. This attribute
111      * allows iterative applications of this template stylesheet to a sub-nodes
112      * set of the current in memory DOM tree.
113      * <p>
114      * Suppose you have the following DOM tree in memory:
115      * <table class="usage">
116      * <tr><td class="usage"><pre><code>
117      * &lt;?xml version="1.0" encoding="iso-8859-1"?&gt;
118      * &lt;ejen&gt;
119      * &lt;name&gt;Name1&lt;/name&gt;
120      * &lt;name&gt;Name2&lt;/name&gt;
121      * &lt;name&gt;Name3&lt;/name&gt;
122      * ...
123      * &lt;/ejen&gt;
124      * </code></pre></td></tr></table>
125      * You want to generate text files with the following structure:
126      * <table class="usage">
127      * <tr><td class="usage"><pre><code>
128      * Dear &lt;Name...&gt;,
129      * Obviously, you are reading a meaningless letter.
130      * Best regards.
131      * </code></pre></td></tr></table>
132      * You can use this template stylesheet (with the foreach attribute set to "/ejen/name"):
133      * <table class="usage">
134      * <tr><td class="usage"><pre><code>
135      * &lt;?xml version="1.0" encoding="iso-8859-1"?&gt;
136      * &lt;xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
137      * version="1.0"&gt;
138      * &lt;xsl:output method="text" encoding="iso-8859-1"/&gt;
139      * <b>&lt;xsl:template match="name"&gt;&lt;!--
140      * --&gt;Dear &lt;xsl:value-of select="."/&gt;,
141      * Obviously, you are reading a meaningless letter.
142      * Best regards.&lt;!--
143      * --&gt;&lt;/xsl:template&gt;</b>
144      * &lt;/xsl:stylesheet&gt;
145      * </code></pre></td></tr></table>
146      * Note that comments in this template are only for carriage return control
147      * purposes (we want neither a carriage return before "Dear", nor after "regards.").
148      * <p>
149      * If this attribute is used, a parameter whose name is "root" and value is the root
150      * node of the current DOM tree is always and automaticaly passed to the template
151      * stylesheet (you may have the line "<code>&lt;xsl:param name"root"/&gt;</code>" in
152      * the stylesheet).
153      * <p>
154      * See the {@link #setFilepattern(String) filepattern} for output file naming.
155      * <p>
156      * @param foreach foreach String (default is null, meaning "apply this template
157      * stylesheet to the entire current DOM tree").
158      */

159     public void setForeach(String JavaDoc foreach) {
160         _foreach = foreach;
161     }
162
163     /**
164      * <b>[optional/AVT]</b> - sets the filepattern attribute. This attribute
165      * allows basic file output naming setting and is relative to the foreach
166      * attribute (if foreach attribute is not used, filepattern will be relative
167      * to the root node of the current in memory DOM tree).
168      * <p>
169      * Suppose what is supposed {@link #setForeach(String) here}. You want to
170      * generate text files whose names are: Name1.txt, Name2.txt,
171      * Name3.txt... Then, you can use this filepattern: "{.}.txt".
172      * <p>
173      * If this basic file output naming mechanism is not sufficient, you may still
174      * use the Xalan
175      * <a HREF="http://xml.apache.org/xalan-j/apidocs/org/apache/xalan/lib/Redirect.html">Redirect</a>
176      * extension.
177      * <p>
178      * @param filepattern filepattern String (default is null, meaning "let the
179      * template do whatever it wants").
180      */

181     public void setFilepattern(String JavaDoc filepattern) {
182         _filepattern = filepattern;
183     }
184
185     /**
186      * <b>[optional/AVT]</b> - sets the outdate attribute.
187      * @param outdate if that attribute is "true" output file will generate only
188      * if source file is newer then output file, otherwise output file generate always
189      */

190     public void setOutdated(String JavaDoc outdate) {
191         _outdated = outdate;
192     }
193     
194     /**
195      * Executes this EjenTemplateNode.
196      * @throws org.ejen.EjenException if something goes wrong...
197      */

198     public void process() {
199         super.process();
200         TransformerImpl ti = null;
201         DOMSource JavaDoc src = null;
202
203         try {
204             ti = (TransformerImpl) (getFromContext(CTX_TRANSFORMER_IMPL));
205             src = (DOMSource JavaDoc) (getFromGlobalContext(CTX_DOM_SOURCE));
206         } catch (Exception JavaDoc e) {
207             throw new EjenException(this, null, e);
208         }
209         if (ti == null) {
210             throw new EjenException(this,
211                     "no '" + CTX_TRANSFORMER_IMPL + "' in context");
212         }
213         if (src == null) {
214             throw new EjenException(this,
215                     "no '" + CTX_DOM_SOURCE + "' in global context");
216         }
217         if (_foreach != null) {
218             NodeList JavaDoc nl = null;
219
220             try {
221                 ti.setParameter("root", src.getNode());
222                 nl = XPathAPI.selectNodeList(src.getNode(),
223                         evaluateAVT(ti, _foreach));
224             } catch (Exception JavaDoc e) {
225                 throw new EjenException(this,
226                         "invalid 'foreach' attribute: " + _foreach, e);
227             }
228             for (int i = 0; i < nl.getLength(); i++) {
229                 DOMSource JavaDoc nodeSrc = null;
230
231                 try {
232                     nodeSrc = new DOMSource JavaDoc(nl.item(i));
233                 } catch (Exception JavaDoc e) {
234                     throw new EjenException(this,
235                             "invalid 'foreach' attribute: " + _foreach, e);
236                 }
237                 processTemplateStreamResult(ti, nodeSrc);
238             }
239         } else {
240             processTemplateStreamResult(ti, src);
241         }
242     }
243
244     /**
245      * Creates the output file, based on the filepattern attribute.
246      * @param ti the TransformerImpl to use for the transformation.
247      * @param src the DOMSource to be transformed.
248      * @throws org.ejen.EjenException if something goes wrong...
249      */

250     private void processTemplateStreamResult(TransformerImpl ti, DOMSource JavaDoc src) {
251         StylesheetHandler sh = null;
252
253         try {
254             sh = (StylesheetHandler) (getFromGlobalContext(CTX_STYLESHEET_HANDLER));
255         } catch (Exception JavaDoc e) {
256             throw new EjenException(this, null, e);
257         }
258         if (sh == null) {
259             throw new EjenException(this,
260                     "no '" + CTX_STYLESHEET_HANDLER + "' in context");
261         }
262         OutputStream JavaDoc outputs = null;
263
264         try {
265             StreamResult JavaDoc sres = null;
266
267             if (_filepattern != null) {
268                 // Cannot use evaluateAVT(ti, _filepattern) because _filepattern is
269
// an AVT relative to _foreach...
270
String JavaDoc fileName = XSLUtil.evaluateAttribute(sh,
271                         ti.getXPathContext(), src.getNode(), _filepattern);
272                 boolean flag = false;
273
274                 if (_outdated != null && _outdated.equals("true")) {
275                     flag = true;
276                 }
277                 if (!flag || outdated(fileName)) {
278                     sendMessageEvent("Creating '" + fileName + "'");
279                     File JavaDoc f = new File JavaDoc(fileName);
280                     File JavaDoc pf = f.getParentFile();
281
282                     if (pf != null) {
283                         pf.mkdirs();
284                     }
285                     outputs = new FileOutputStream JavaDoc(f.getPath());
286                     sres = new StreamResult JavaDoc(outputs);
287                 } else {
288                     return;
289                 }
290             } else {
291                 sres = new StreamResult JavaDoc(new StringWriter JavaDoc());
292             }
293             ti.transform(src, sres);
294         } catch (Exception JavaDoc e) {
295             throw new EjenException(this, null, e);
296         }
297         finally {
298             if (outputs != null) {
299                 try {
300                     outputs.close();
301                 } catch (Exception JavaDoc e) {}
302                 finally {
303                     outputs = null;
304                 }
305             }
306         }
307     }
308     
309     /**
310      * Check if source file is newer than output file.
311      * @param fileName file name of output file.
312      */

313     protected boolean outdated(String JavaDoc fileName) {
314         File JavaDoc srcFile = new File JavaDoc((String JavaDoc) getFromGlobalContext("DOM_SOURCE_FILE"));
315         File JavaDoc genFile = new File JavaDoc(fileName);
316
317         if (!genFile.exists() || !srcFile.exists()) { // files not exist
318
return true;
319         }
320         long slm = srcFile.lastModified();
321
322         if (slm == 0L) { // source file not exist or I/O error
323
return true;
324         }
325         long glm = genFile.lastModified();
326
327         if (glm == 0L) { // generating file not exist
328
return true;
329         }
330         return slm >= glm; // source file is newer than generating file
331
}
332 }
333
Popular Tags