1 /*************1**************************************************************************
2 * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved. *
3 * http://aspectwerkz.codehaus.org *
4 * ---------------------------------------------------------------------------------- *
5 * The software in this package is published under the terms of the LGPL license *
6 * a copy of which has been included with this distribution in the license.txt file. *
7 **************************************************************************************/
8 package org.codehaus.aspectwerkz.annotation;
9
10
11 import java.io.BufferedReader;
12 import java.io.File;
13 import java.io.FileReader;
14 import java.io.IOException;
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.Iterator;
18
19 import org.apache.tools.ant.BuildException;
20 import org.apache.tools.ant.DirectoryScanner;
21 import org.apache.tools.ant.Project;
22 import org.apache.tools.ant.Task;
23 import org.apache.tools.ant.taskdefs.MatchingTask;
24 import org.apache.tools.ant.taskdefs.Copy;
25 import org.apache.tools.ant.types.FileSet;
26 import org.apache.tools.ant.types.Path;
27 import org.apache.tools.ant.types.Reference;
28
29 /***
30 * AnnotationC Ant task.
31 * <p/>
32 * Use the following parameters to configure the task:
33 * <ul>
34 * <li>verbose: [optional] flag marking the task verbosity [true / false]</li>
35 * <li>properties: [optional] path to a properties file when user-defined annoations are to be used</li>
36 * <li>destdir: [optional unless input classes are in more than one path] directory where to put annnotated class files</li>
37 * <li>copytodest: [optional] filename pattern to copy extra resources like dtd, xml, or properties files that were found
38 * in the input classes path(s). By defaults, only ".class" files will be handled. It is ignored if "destdir" is not set.</li>
39 * </ul>
40 * <p/>
41 * Use the following parameters to configure the classpath to point to the classes to be weaved. Those can be specified
42 * with nested elements as well / instead:
43 * <ul>
44 * <li>properties path=..: extra path to a properties file when user-defined annoations are to be used</li>
45 * <li>classpath: classpath of classes to annotated, as well as classpath to discover user-defined annotations if any</li>
46 * <li>classpathref: classpath reference of classes to annotated, as well as classpath to discover user-defined annotations if any</li>
47 * <li>srcdir: directory where to find annotated java source files</li>
48 * <li>sourcepath: path where to find annotated java source files</li>
49 * <li>sourcepathref: path reference where to find annotated java source files</li>
50 * </ul>
51 * <p/>
52 * Nested elements are similar to the "javac" task when you configure a classpath and a sourcepath:
53 * <ul>
54 * <li>classpath: Path-like structure of classes to annotated, as well as classpath to discover user-defined annotations if any</li>
55 * <li>src: single path entry of annotated java source files</li>
56 * <li>sourcepath: Path-like structure of annotated java source files</li>
57 * <li>fileset: fileset to contain annotated java source files</li>
58 * </ul>
59 * <p/>
60 *
61 * @author <a href='mailto:the_mindstorm@evolva.ro'>the_mindstorm(at)evolva(dot)ro</a>
62 * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
63 */
64 public class AnnotationCTask extends Task {
65
66 private final static String CLASS_PATTERN = "**/*.class";
67
68
69 private boolean m_verbose;
70 private String m_includePattern;
71 private Path m_classpath;
72 private Path m_src;
73 private File m_properties;
74 private Path m_propertiesNested;
75 private File m_destdir;
76 private List m_filesets = new ArrayList();
77
78 /***
79 * <task properties=..>
80 *
81 * @param annotationFile
82 */
83 public void setProperties(File annotationFile) {
84 m_properties = annotationFile;
85 }
86
87 /***
88 * <task verbose=..>
89 *
90 * @param isVerbose
91 */
92 public void setVerbose(boolean isVerbose) {
93 m_verbose = isVerbose;
94 }
95
96 /***
97 * <task copytodest="** slash *">
98 *
99 * @param pattern
100 */
101 public void setCopytodest(String pattern) {
102 m_includePattern = pattern;
103 }
104
105 /***
106 * <task destdir=..>
107 *
108 * @param destdir
109 */
110 public void setDestdir(File destdir) {
111 m_destdir = destdir;
112 }
113
114
115
116 public Path createProperties() {
117 if (m_propertiesNested == null) {
118 m_propertiesNested = new Path(getProject());
119 }
120 return m_propertiesNested.createPath();
121 }
122
123 public Path createSrc() {
124 if (m_src == null) {
125 m_src = new Path(getProject());
126 }
127 return m_src.createPath();
128 }
129
130 public void setSrcdir(Path srcDir) {
131 if (m_src == null) {
132 m_src = srcDir;
133 } else {
134 m_src.append(srcDir);
135 }
136 }
137
138 public void setSourcepath(Path sourcepath) {
139 if (m_src == null) {
140 m_src = sourcepath;
141 } else {
142 m_src.append(sourcepath);
143 }
144 }
145
146 public Path createSourcepath() {
147 if (m_src == null) {
148 m_src = new Path(getProject());
149 }
150 return m_src.createPath();
151 }
152
153 public void setSourcepathRef(Reference r) {
154 createSourcepath().setRefid(r);
155 }
156
157
158
159
160 public void setClasspath(Path classpath) {
161 if (m_classpath == null) {
162 m_classpath = classpath;
163 } else {
164 m_classpath.append(classpath);
165 }
166 }
167
168 public Path createClasspath() {
169 if (m_classpath == null) {
170 m_classpath = new Path(getProject());
171 }
172 return m_classpath.createPath();
173 }
174
175 public void setClasspathRef(Reference r) {
176 createClasspath().setRefid(r);
177 }
178
179
180
181 public void addFileset(FileSet fileset) {
182 m_filesets.add(fileset);
183 }
184
185
186
187 public void execute() throws BuildException {
188 try {
189 if (m_classpath == null) {
190 throw new BuildException("No classes specified [<classpath, classpath=.. classpathref=..]");
191 }
192 if (m_destdir == null && m_classpath.list().length > 1) {
193 throw new BuildException(
194 "When using more than one classpath directory, it is mandatory to specify [destdir=..]"
195 );
196 }
197 if (m_filesets.size() == 0 && (m_src == null || m_src.size() == 0)) {
198 throw new BuildException("No source specified [<include, <sourcepath, srcdir=..]");
199 }
200 if (m_properties != null && !m_properties.exists() && !m_properties.isFile()) {
201 throw new BuildException("properties file specified but not a valid file [" + m_properties + "]");
202 }
203 List allProperties = new ArrayList();
204 if (m_properties != null) {
205 allProperties.add(m_properties.getAbsolutePath());
206 }
207 if (m_propertiesNested != null) {
208 allProperties.addAll(getDirectories(m_propertiesNested));
209 }
210
211
212 List srcDirs = getDirectories(m_src);
213 List srcFiles = getFilesetFiles(m_filesets);
214 List classpathDirs = getDirectories(m_classpath);
215
216 if (m_verbose) {
217 System.out.println("Source dir : " + dump(srcDirs));
218 System.out.println("Source files : " + dump(srcFiles));
219 System.out.println("Classpath : " + dump(classpathDirs));
220 System.out.println("Destdir : " + m_destdir);
221 System.out.println("Properties : " + dump(allProperties));
222 System.out.println("Copytodest : " + m_includePattern);
223 }
224
225 AnnotationC.compile(
226 m_verbose,
227 (String[]) srcDirs.toArray(new String[]{}),
228 (String[]) srcFiles.toArray(new String[]{}),
229 (String[]) classpathDirs.toArray(new String[]{}),
230 m_destdir == null ? null : m_destdir.getAbsolutePath(),
231 (String[]) allProperties.toArray(new String[]{})
232
233 );
234
235 if (m_destdir != null) {
236 if (m_verbose) {
237 System.out.println("Copying residual files to dest dir...");
238 }
239 copySourcesToDest();
240 }
241
242 } catch (Exception e) {
243 e.printStackTrace();
244 throw new BuildException(e);
245 }
246 }
247
248 private List getFilesetFiles(List filesets) throws BuildException {
249 List files = new ArrayList();
250 for (Iterator iterator = filesets.iterator(); iterator.hasNext();) {
251 FileSet fileset = (FileSet) iterator.next();
252 DirectoryScanner ds = fileset.getDirectoryScanner(getProject());
253 for (int i = 0; i < ds.getIncludedFiles().length; i++) {
254 String file = ds.getIncludedFiles()[i];
255 files.add(ds.getBasedir() + File.separator + file);
256 }
257 }
258 return files;
259 }
260
261 private List getDirectories(Path path) throws BuildException {
262 List dirs = new ArrayList();
263 if (path == null) {
264 return dirs;
265 }
266 for (int i = 0; i < path.list().length; i++) {
267 File dir = getProject().resolveFile(path.list()[i]);
268 if (!dir.exists()) {
269 throw new BuildException(" \"" + dir.getPath() + "\" does not exist!", getLocation());
270 }
271 dirs.add(dir.getAbsolutePath());
272 }
273 return dirs;
274 }
275
276 private String dump(List strings) {
277 StringBuffer sb = new StringBuffer();
278 for (Iterator iterator = strings.iterator(); iterator.hasNext();) {
279 Object o = (Object) iterator.next();
280 sb.append(o.toString()).append(File.pathSeparator);
281 }
282 return sb.toString();
283 }
284
285 private void copySourcesToDest() throws BuildException {
286 Copy copy = new Copy();
287
288 copy.setProject(getProject());
289 copy.setTodir(m_destdir);
290 copy.setOverwrite(false);
291 copy.setTaskName("copy");
292 copy.setVerbose(m_verbose);
293
294 List sourceDir = getDirectories(m_src);
295 for (Iterator iterator = sourceDir.iterator(); iterator.hasNext();) {
296 String dir = (String) iterator.next();
297 FileSet anonFs = new FileSet();
298 anonFs.setIncludes(CLASS_PATTERN);
299 if (m_includePattern != null) {
300 anonFs.setIncludes(m_includePattern);
301 }
302 anonFs.setDir(new File(dir));
303 copy.addFileset(anonFs);
304 }
305 copy.execute();
306 }
307
308 }