KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > xdoclet > GenerationManager


1 /*
2  * Copyright (c) 2001, 2002 The XDoclet team
3  * All rights reserved.
4  */

5 package xdoclet;
6
7 import java.io.File JavaDoc;
8 import java.net.URL JavaDoc;
9 import java.text.MessageFormat JavaDoc;
10 import java.util.ArrayList JavaDoc;
11 import java.util.Arrays JavaDoc;
12
13 import java.util.HashMap JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.List JavaDoc;
16 import java.util.Map JavaDoc;
17
18 import org.apache.commons.logging.Log;
19 import xjavadoc.XClass;
20 import xjavadoc.XJavaDoc;
21
22 import xdoclet.loader.ModuleFinder;
23 import xdoclet.tagshandler.AbstractProgramElementTagsHandler;
24 import xdoclet.tagshandler.PackageTagsHandler;
25 import xdoclet.template.TemplateEngine;
26 import xdoclet.template.TemplateException;
27 import xdoclet.template.TemplateParser;
28 import xdoclet.util.LogUtil;
29
30 /**
31  * Verify if the generation is needed for Java files and Xml files based templates.
32  *
33  * @author Vincent Harcq (vincent.harcq@hubmethods.com)
34  * @created March 30, 2002
35  * @version $Revision: 1.19 $
36  */

37 public class GenerationManager
38 {
39     private final static File JavaDoc newestJar = ModuleFinder.getNewestFileOnClassPath();
40
41     private static Map JavaDoc parserDb = null;
42
43     private final TemplateSubTask subTask;
44
45     private boolean guessGenerationNeeded = true;
46
47     private XJavaDoc _xJavaDoc;
48
49     /**
50      * Describe what the GenerationManager constructor does
51      *
52      * @param subTask Describe what the parameter does
53      * @param xJavaDoc
54      */

55     public GenerationManager(XJavaDoc xJavaDoc, TemplateSubTask subTask)
56     {
57         if (xJavaDoc == null) {
58             throw new IllegalArgumentException JavaDoc("xJavaDoc can't be null");
59         }
60         _xJavaDoc = xJavaDoc;
61         this.subTask = subTask;
62     }
63
64     /**
65      * Return (and construct) the template database. It is a map between a <code>String</code> representing the template
66      * file and an array of <String> representing the merge files that are part of the generation.
67      *
68      * @return the <code>Map</code>
69      */

70     private static Map JavaDoc getParserDb()
71     {
72         if (parserDb == null) {
73             parserDb = new HashMap JavaDoc();
74         }
75         return parserDb;
76     }
77
78     /**
79      * During parsing we build the Template database. We store it on file.
80      *
81      * @param templateURL the template file
82      * @param files the merge files involved in the generation
83      */

84     private static void updateParserDb(URL JavaDoc templateURL, String JavaDoc[] files)
85     {
86         // Merge existing list with new list
87
String JavaDoc[] mergeFiles = (String JavaDoc[]) getParserDb().get(new File JavaDoc(templateURL.getFile()).getName());
88         List JavaDoc complete = new ArrayList JavaDoc(Arrays.asList(files));
89
90         if (mergeFiles != null) {
91             for (int j = 0; j < mergeFiles.length; j++) {
92                 String JavaDoc file = mergeFiles[j];
93
94                 if (!complete.contains(file)) {
95                     complete.add(file);
96                 }
97             }
98         }
99         getParserDb().put(new File JavaDoc(templateURL.getFile()).getName(), complete.toArray(new String JavaDoc[complete.size()]));
100     }
101
102     /**
103      * Gets the GuessGenerationNeeded attribute of the GenerationManager object
104      *
105      * @return The GuessGenerationNeeded value
106      */

107     public boolean isGuessGenerationNeeded()
108     {
109         return guessGenerationNeeded;
110     }
111
112     /**
113      * Test if a Java source mmust be generated or not depending of timestamp of elements involved.
114      *
115      * @param clazz the Class from wich we generate
116      * @param file the File that will be generated
117      * @param withTemplate
118      * @return true if generation is needed
119      * @exception XDocletException
120      */

121     public boolean isGenerationNeeded(XClass clazz, File JavaDoc file, boolean withTemplate)
122          throws XDocletException
123     {
124         Log log = LogUtil.getLog(GenerationManager.class, "generation");
125
126         if (subTask.getContext().isForce()) {
127             log.debug("Force generation enabled");
128             return true;
129         }
130
131         if (isGuessGenerationNeeded() == false) {
132             log.debug("guessGenerationNeeded enabled");
133             return true;
134         }
135
136         // 1. Check whether a file on classpath is newer than the destination file
137
if (isClasspathNewerThanFile(file))
138             return true;
139
140         // 2. Check whether the class (or any superclass) is newer than the destination file
141
if (isClassHierarchyNewerThanFile(clazz, file))
142             return true;
143
144         // 3. Check whether the template file or any merge files are newer than the destination file
145
if (isTemplateNewerThanFile(withTemplate, file))
146             return true;
147
148         return false;
149     }
150
151     /**
152      * Verify if the generation of a file to generate is needed because either the Template used to generate the file
153      * have a later timestamp, or because ALL the Java sources imported in this task have a sooner timestamp. This is
154      * used to test if xml files generation is needed.
155      *
156      * @param file The file to check
157      * @return true if the generation is needed
158      * @exception XDocletException
159      */

160     public boolean isGenerationNeeded(File JavaDoc file)
161          throws XDocletException
162     {
163         Log log = LogUtil.getLog(GenerationManager.class, "generation");
164
165         log.debug("Generation need check for " + file.getName());
166
167         if (subTask.getContext().isForce()) {
168             log.debug("Force generation enabled");
169             return true;
170         }
171
172         if (isGuessGenerationNeeded() == false) {
173             log.debug("guessGenerationNeeded enabled");
174             return true;
175         }
176
177         // 1. Check on Jar timestamp
178
if (isClasspathNewerThanFile(file) == true)
179             return true;
180
181         // 2. Check the timestamp of template file and merge files
182
if (isGenerationNeeded(file, subTask.getTemplateURL())) {
183             return true;
184         }
185
186         log.debug("Generation need check for " + file.getName());
187
188         // 3. Check Timestamp of all java sources in sourcepath
189

190         for (Iterator JavaDoc i = _xJavaDoc.getSourceClasses().iterator(); i.hasNext(); ) {
191             if (isGenerationNeeded((XClass) i.next(), file, false)) {
192                 return true;
193             }
194         }
195
196         return false;
197     }
198
199     /**
200      * Sets the GuessGenerationNeeded attribute of the GenerationManager object.
201      *
202      * @param guessGenerationNeeded The new GuessGenerationNeeded value
203      */

204     public void setGuessGenerationNeeded(boolean guessGenerationNeeded)
205     {
206         this.guessGenerationNeeded = guessGenerationNeeded;
207     }
208
209     private boolean isClassHierarchyNewerThanFile(XClass clazz, File JavaDoc file)
210     {
211         Log log = LogUtil.getLog(GenerationManager.class, "generation");
212
213         while (clazz != null) {
214             if (clazz.getQualifiedName().equals("java.lang.Object")) {
215                 return false;
216             }
217             if (file.lastModified() < clazz.lastModified()) {
218                 if (log.isDebugEnabled()) {
219                     log.debug("Generation needed for '" + file.getAbsolutePath() + "' because " + clazz.getQualifiedName() + " is newer (it's in the class hierarchy)");
220                 }
221                 return true;
222             }
223             clazz = clazz.getSuperclass();
224         }
225
226         return false;
227     }
228
229     private boolean isTemplateNewerThanFile(boolean withTemplate, File JavaDoc file) throws XDocletException
230     {
231         Log log = LogUtil.getLog(GenerationManager.class, "generation");
232
233         log.debug("Checking template. withTemplate=" + withTemplate);
234
235         if (withTemplate) {
236             if (isGenerationNeeded(file, subTask.getTemplateURL())) {
237                 if (log.isDebugEnabled()) {
238                     log.debug("Generation needed for '" + file.getAbsolutePath() + "' because template file is newer.");
239                 }
240
241                 return true;
242             }
243         }
244
245         return false;
246     }
247
248     private boolean isClasspathNewerThanFile(File JavaDoc file)
249     {
250         Log log = LogUtil.getLog(GenerationManager.class, "generation");
251
252         if (file.lastModified() < newestJar.lastModified()) {
253             if (log.isDebugEnabled()) {
254                 log.debug("Generation needed for '" + file.getAbsolutePath() + "' because " + newestJar.getName() + " is newer.");
255             }
256             return true;
257         }
258
259         if (log.isDebugEnabled()) {
260             log.debug("No files on classpath are newer than '" + file.getAbsolutePath() + "'");
261         }
262
263         return false;
264     }
265
266     /**
267      * Verify if the generation of a file is needed because either the template file has a sooner timestamp, or because
268      * one of the merge files have a sooner timestamp
269      *
270      * @param file The file to generate
271      * @param templateURL the Template file to use
272      * @return true if generation is needed.
273      * @exception XDocletException
274      */

275     private boolean isGenerationNeeded(File JavaDoc file, URL JavaDoc templateURL)
276          throws XDocletException
277     {
278         Log log = LogUtil.getLog(GenerationManager.class, "xml");
279
280         if (log.isDebugEnabled()) {
281             log.debug("Generation need check for " + file.getAbsolutePath());
282         }
283
284         // 1. Check Timestamp of Template file
285
File JavaDoc templateFile = new File JavaDoc(subTask.getTemplateURL().getFile());
286
287         if (templateFile.exists() && file.lastModified() < templateFile.lastModified()) {
288             if (log.isDebugEnabled()) {
289                 log.debug("Generation needed for '" + file.getAbsolutePath() + "' because of timestamp of " + subTask.getTemplateURL());
290             }
291             return true;
292         }
293         if (log.isDebugEnabled()) {
294             log.debug("Reject file '" + file.getAbsolutePath() + "' because of timestamp of " + subTask.getTemplateURL());
295         }
296
297         // 2. Check timestamp of Merge files found inside Template
298
String JavaDoc[] files;
299
300         if (getParserDb().get(templateFile) == null) {
301             TemplateEngine the_engine = subTask.getEngine();
302             TemplateParser the_parser = TemplateParser.getParserInstance();
303
304             subTask.setEngine(the_parser);
305
306             // Why is setOutput called here? We're only checking _IF_ we're going to generate! (Aslak)
307
the_parser.setOutput(file);
308             the_parser.setTemplateURL(templateURL);
309
310             try {
311                 the_parser.start();
312             }
313             catch (TemplateException e) {
314                 throw new XDocletException(e, e.toString());
315             }
316
317             files = the_parser.getMergeFiles();
318             if (files != null) {
319                 updateParserDb(templateURL, files);
320             }
321
322             //restore
323
subTask.setEngine(the_engine);
324         }
325         else {
326             files = (String JavaDoc[]) getParserDb().get(new File JavaDoc(templateURL.getFile()).getName());
327             for (int i = 0; i < files.length; i++) {
328                 if (log.isDebugEnabled()) {
329                     log.debug(templateURL.getFile() + " : " + files[i]);
330                 }
331             }
332         }
333
334         log.debug("Number of Merge files involved = " + files.length);
335
336         for (int i = 0; i < files.length; i++) {
337             String JavaDoc mergeFilePattern = files[i];
338             List JavaDoc mergeFiles = new ArrayList JavaDoc();
339
340             if (mergeFilePattern.indexOf("{0}") != -1) {
341
342                 for (Iterator JavaDoc j = _xJavaDoc.getSourceClasses().iterator(); j.hasNext(); ) {
343                     XClass aClass = (XClass) j.next();
344                     String JavaDoc ejbName = MessageFormat.format(mergeFilePattern, new Object JavaDoc[]{AbstractProgramElementTagsHandler.getClassNameFor(aClass)});
345                     String JavaDoc mergeFileName = PackageTagsHandler.packageNameAsPathFor(aClass.getContainingPackage()) + File.separator + ejbName;
346
347                     if (subTask.getMergeDir() != null)
348                         mergeFiles.add(new File JavaDoc(subTask.getMergeDir(), mergeFileName));
349                 }
350             }
351             else {
352                 if (subTask.getMergeDir() != null)
353                     mergeFiles.add(new File JavaDoc(subTask.getMergeDir(), mergeFilePattern));
354             }
355             for (Iterator JavaDoc iterator = mergeFiles.iterator(); iterator.hasNext(); ) {
356                 File JavaDoc mergeFile = (File JavaDoc) iterator.next();
357
358                 log.debug("Generation check for '" + file.getAbsolutePath() + "' because of " + mergeFile.getName());
359
360                 if (mergeFile.exists()) {
361                     if (file.lastModified() < mergeFile.lastModified()) {
362                         log.debug("Generation needed for '" + file.getAbsolutePath() + "' because of timestamp of " + mergeFile.getName());
363                         return true;
364                     }
365                     log.debug("Reject file '" + file.getAbsolutePath() + "' because of timestamp of " + mergeFile.getName());
366                 }
367             }
368         }
369         return false;
370     }
371 }
372
Popular Tags