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 *
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 * @param pattern
99 */
100 public void setCopytodest(String pattern) {
101 m_includePattern = pattern;
102 }
103
104 /***
105 * <task destdir=..>
106 *
107 * @param destdir
108 */
109 public void setDestdir(File destdir) {
110 m_destdir = destdir;
111 }
112
113
114
115 public Path createProperties() {
116 if (m_propertiesNested == null)
117 m_propertiesNested = new Path(getProject());
118 return m_propertiesNested.createPath();
119 }
120
121 public Path createSrc() {
122 if (m_src == null)
123 m_src = new Path(getProject());
124 return m_src.createPath();
125 }
126
127 public void setSrcdir(Path srcDir) {
128 if (m_src == null)
129 m_src = srcDir;
130 else
131 m_src.append(srcDir);
132 }
133
134 public void setSourcepath(Path sourcepath) {
135 if (m_src == null)
136 m_src = sourcepath;
137 else
138 m_src.append(sourcepath);
139 }
140
141 public Path createSourcepath() {
142 if (m_src == null)
143 m_src = new Path(getProject());
144 return m_src.createPath();
145 }
146
147 public void setSourcepathRef(Reference r) {
148 createSourcepath().setRefid(r);
149 }
150
151
152
153
154 public void setClasspath(Path classpath) {
155 if (m_classpath == null)
156 m_classpath = classpath;
157 else
158 m_classpath.append(classpath);
159 }
160
161 public Path createClasspath() {
162 if (m_classpath == null)
163 m_classpath = new Path(getProject());
164 return m_classpath.createPath();
165 }
166
167 public void setClasspathRef(Reference r) {
168 createClasspath().setRefid(r);
169 }
170
171
172
173 public void addFileset(FileSet fileset) {
174 m_filesets.add(fileset);
175 }
176
177
178
179 public void execute() throws BuildException {
180 try {
181 if (m_classpath == null) {
182 throw new BuildException("No classes specified [<classpath, classpath=.. classpathref=..]");
183 }
184 if (m_destdir == null && m_classpath.list().length > 1) {
185 throw new BuildException(
186 "When using more than one classpath directory, it is mandatory to specify [destdir=..]"
187 );
188 }
189 if (m_filesets.size() == 0 && (m_src == null || m_src.size() == 0)) {
190 throw new BuildException("No source specified [<include, <sourcepath, srcdir=..]");
191 }
192 if (m_properties != null && !m_properties.exists() && !m_properties.isFile()) {
193 throw new BuildException("properties file specified but not a valid file [" + m_properties + "]");
194 }
195 List allProperties = new ArrayList();
196 allProperties.add(m_properties.getAbsolutePath());
197 allProperties.addAll(getDirectories(m_propertiesNested));
198
199
200 List srcDirs = getDirectories(m_src);
201 List srcFiles = getFilesetFiles(m_filesets);
202 List classpathDirs = getDirectories(m_classpath);
203
204 if (m_verbose) {
205 System.out.println("Source dir : " + dump(srcDirs));
206 System.out.println("Source files : " + dump(srcFiles));
207 System.out.println("Classpath : " + dump(classpathDirs));
208 System.out.println("Destdir : " + m_destdir);
209 System.out.println("Properties : " + dump(allProperties));
210 System.out.println("Copytodest : " + m_includePattern);
211 }
212
213 AnnotationC.compile(
214 m_verbose,
215 (String[])srcDirs.toArray(new String[]{}),
216 (String[])srcFiles.toArray(new String[]{}),
217 (String[])classpathDirs.toArray(new String[]{}),
218 m_destdir == null ? null : m_destdir.getAbsolutePath(),
219 (String[])allProperties.toArray(new String[]{})
220 );
221
222 if (m_destdir != null) {
223 if (m_verbose) {
224 System.out.println("Copying residual files to dest dir...");
225 }
226 copySourcesToDest();
227 }
228
229 } catch (Exception e) {
230 e.printStackTrace();
231 throw new BuildException(e);
232 }
233 }
234
235 private List getFilesetFiles(List filesets) throws BuildException {
236 List files = new ArrayList();
237 for (Iterator iterator = filesets.iterator(); iterator.hasNext();) {
238 FileSet fileset = (FileSet) iterator.next();
239 DirectoryScanner ds = fileset.getDirectoryScanner(getProject());
240 for (int i = 0; i < ds.getIncludedFiles().length; i++) {
241 String file = ds.getIncludedFiles()[i];
242 files.add(ds.getBasedir() + File.separator + file);
243 }
244 }
245 return files;
246 }
247
248 private List getDirectories(Path path) throws BuildException {
249 List dirs = new ArrayList();
250 if (path == null)
251 return dirs;
252 for (int i = 0; i < path.list().length; i++) {
253 File dir = getProject().resolveFile(path.list()[i]);
254 if (!dir.exists()) {
255 throw new BuildException(" \"" + dir.getPath() + "\" does not exist!", getLocation());
256 }
257 dirs.add(dir.getAbsolutePath());
258 }
259 return dirs;
260 }
261
262 private String dump(List strings) {
263 StringBuffer sb = new StringBuffer();
264 for (Iterator iterator = strings.iterator(); iterator.hasNext();) {
265 Object o = (Object) iterator.next();
266 sb.append(o.toString()).append(File.pathSeparator);
267 }
268 return sb.toString();
269 }
270
271 private void copySourcesToDest() throws BuildException {
272 Copy copy = new Copy();
273
274 copy.setProject(getProject());
275 copy.setTodir(m_destdir);
276 copy.setOverwrite(false);
277 copy.setTaskName("copy");
278 copy.setVerbose(m_verbose);
279
280 List sourceDir = getDirectories(m_src);
281 for (Iterator iterator = sourceDir.iterator(); iterator.hasNext();) {
282 String dir = (String) iterator.next();
283 FileSet anonFs = new FileSet();
284 anonFs.setIncludes(CLASS_PATTERN);
285 if (m_includePattern != null) {
286 anonFs.setIncludes(m_includePattern);
287 }
288 anonFs.setDir(new File(dir));
289 copy.addFileset(anonFs);
290 }
291 copy.execute();
292 }
293
294 }