001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.controls.runtime.generator;
020:
021: import org.apache.tools.ant.BuildException;
022: import org.apache.tools.ant.DirectoryScanner;
023: import org.apache.tools.ant.taskdefs.Javac;
024: import org.apache.tools.ant.types.Commandline;
025: import org.apache.tools.ant.types.Path;
026: import org.apache.tools.ant.util.FileUtils;
027: import org.apache.tools.ant.util.GlobPatternMapper;
028: import org.apache.tools.ant.util.SourceFileScanner;
029:
030: import java.io.File;
031: import java.io.IOException;
032: import java.util.StringTokenizer;
033: import java.util.Vector;
034:
035: /**
036: * The AptTask class defines a custom ANT task for invoking APT-based code generation. It
037: * derives from the <javac> built-in task, so all of the attributes and nested elements of that
038: * task are supported, for source list selection, classpath selection, compiler arguments,
039: * etc. Each of these options will be passed onto APT for processing.
040: * <p>
041: * AptTask also adds some new attributes:
042: * <ul>
043: * <li>gendir - specifies the directory where temporary source files that are produced during
044: * generation will be kept.
045: * <li>srcExtensions - provides a comma-separated list of source file extensions that are
046: * considered valid input to APT. The default value is "*.java".
047: * <li>
048: */
049: public class AptTask extends Javac {
050: /**
051: * The srcExtensions attribute can be set to a comma-separated list of source filename
052: * extensions that are considered to be valid inputs to APT processing.
053: * The default value is "*.java".
054: */
055: public void setSrcExtensions(String srcExts) {
056: StringTokenizer tok = new StringTokenizer(srcExts, ",");
057: while (tok.hasMoreTokens())
058: _srcExts.add(tok.nextToken());
059: }
060:
061: /**
062: * The srcExtensions attribute can be set to a comma-separated list of processor options
063: * (of the form <i>option</i> or <i>option</i><code>=</code><i>value</i>) to be passed to
064: * APT.
065: */
066: public void setProcessorOptions(String processorOptions) {
067: StringTokenizer tok = new StringTokenizer(processorOptions, ",");
068: while (tok.hasMoreTokens())
069: _processorOptions.add(tok.nextToken());
070: }
071:
072: /**
073: * The gendir attribute specifies the name of the output directory for any files generated
074: * as a result of calling APT.
075: */
076: public void setGendir(File genDir) {
077: _genDir = genDir;
078: }
079:
080: /**
081: * The nocompile attribute disables compilation of the input source file list and any
082: * generated sources that are derived from them. The default value is 'false'.
083: */
084: public void setNocompile(boolean nocompile) {
085: _nocompile = nocompile;
086: }
087:
088: /**
089: * The compileByExtension attribute causes each input source extension to be compiled
090: * independently (and sequentially). This is useful when one type of extensio can
091: * possibly depend upon the generation output from another. The default value 'false'.
092: */
093: public void setCompileByExtension(boolean compileByExt) {
094: _compileByExt = compileByExt;
095: }
096:
097: /**
098: * Override the implementation of scanDir, to look for additional files based upon any
099: * specified source extensions
100: */
101: protected void scanDir(File srcDir, File destDir, String[] files,
102: String ext) {
103: // If no source path was specified, we effectively created one by adding the generation
104: // path. Because of this, we need to be sure and add all source dirs to the path too.
105: if (!_hasSourcepath) {
106: Path srcPath = new Path(getProject());
107: srcPath.setLocation(srcDir);
108: Path sp = getSourcepath();
109: sp.append(srcPath);
110: setSourcepath(sp);
111: }
112:
113: GlobPatternMapper m = new GlobPatternMapper();
114: m.setFrom(ext);
115: m.setTo("*.class");
116: SourceFileScanner sfs = new SourceFileScanner(this );
117: if (ext.equals("*.java")) {
118: File[] newFiles = sfs.restrictAsFiles(files, srcDir,
119: destDir, m);
120: if (newFiles.length > 0) {
121: File[] newCompileList = new File[compileList.length
122: + newFiles.length];
123: System.arraycopy(compileList, 0, newCompileList, 0,
124: compileList.length);
125: System.arraycopy(newFiles, 0, newCompileList,
126: compileList.length, newFiles.length);
127: compileList = newCompileList;
128: }
129: } else {
130: String[] newSources = sfs.restrict(files, srcDir, destDir,
131: m);
132: int extLen = ext.length() - 1; // strip wildcard
133: if (newSources.length > 0) {
134: File[] newCompileList = new File[compileList.length
135: + newSources.length];
136: System.arraycopy(compileList, 0, newCompileList, 0,
137: compileList.length);
138: try {
139: FileUtils fileUtils = FileUtils.newFileUtils();
140: for (int j = 0; j < newSources.length; j++) {
141: String toName = newSources[j].substring(0,
142: newSources[j].length() - extLen)
143: + ".java";
144:
145: File srcFile = new File(srcDir, newSources[j]);
146: File dstFile = new File(_genDir, toName);
147: fileUtils.copyFile(srcFile, dstFile, null,
148: true, true);
149: newCompileList[compileList.length + j] = dstFile;
150: }
151: } catch (IOException ioe) {
152: throw new BuildException("Unable to copy " + ext
153: + " file", ioe, getLocation());
154: }
155: compileList = newCompileList;
156: }
157: }
158: }
159:
160: public void execute() throws BuildException {
161: // Ensure that the gendir attribute was specified
162: if (_genDir == null)
163: throw new BuildException(
164: "Missing genDir attribute: must be set to codegen output directory",
165: getLocation());
166:
167: // If no source extension specified, then just process .java files
168: if (_srcExts.size() == 0)
169: _srcExts.add("*.java");
170:
171: // Save whether a user sourcepath was provided, and if so, the paths
172: String[] userSourcepaths = null;
173: _hasSourcepath = getSourcepath() != null;
174: if (_hasSourcepath)
175: userSourcepaths = getSourcepath().list();
176:
177: // The generation dir is always added to the source path for compilation
178: Path genPath = new Path(getProject());
179: genPath.setLocation(_genDir);
180: setSourcepath(genPath);
181:
182: // If the user sourcepath specifies subdirs underneath the srcdir, then we need to add
183: // the corresponding subdirs under the gendir to the source path for compilation.
184: // For example, if the user sourcepath is "<webapp-root>;<webapp-root>\WEB-INF\src",
185: // then the sourcepath for compilation should include "<gen-dir>;<gen-dir>\WEB-INF\src".
186: if (_hasSourcepath) {
187: String srcDirPath = (getSrcdir().list())[0]; // TODO: handle multiple srcdirs
188: for (String p : userSourcepaths) {
189: if (p.startsWith(srcDirPath)
190: && p.length() > srcDirPath.length()) {
191: File genDirElem = new File(_genDir, p
192: .substring(srcDirPath.length() + 1));
193: Path gp = new Path(getProject());
194: gp.setLocation(genDirElem);
195: setSourcepath(gp);
196: }
197: }
198: }
199:
200: //
201: // Select the executable (apt) and set fork = true
202: //
203: setExecutable("apt");
204: setFork(true);
205:
206: //
207: // Specify the code generation output directory to APT
208: //
209: Commandline.Argument arg = createCompilerArg();
210: arg.setValue("-s");
211: arg = createCompilerArg();
212: arg.setFile(_genDir);
213:
214: //add the -nocompile flag if set to true
215: if (_nocompile) {
216: Commandline.Argument ncarg = createCompilerArg();
217: ncarg.setValue("-nocompile");
218: }
219:
220: //
221: // Add processor options.
222: //
223: for (Object i : _processorOptions) {
224: Commandline.Argument optionArg = createCompilerArg();
225: optionArg.setValue("-A" + i);
226: }
227:
228: checkParameters();
229: resetFileLists();
230:
231: // Iterate through the list of input extensions, matching/dependency checking based
232: // upon the input list.
233: for (int j = 0; j < _srcExts.size(); j++) {
234: String ext = (String) _srcExts.get(j);
235: Vector<File> inputFiles = new Vector<File>();
236:
237: // scan source directories and dest directory to build up
238: // compile lists
239: String[] list = getSrcdir().list();
240: File destDir = getDestdir();
241: for (int i = 0; i < list.length; i++) {
242: File srcFile = getProject().resolveFile(list[i]);
243: if (!srcFile.exists()) {
244: throw new BuildException("srcdir \""
245: + srcFile.getPath() + "\" does not exist!",
246: getLocation());
247: }
248:
249: //
250: // The base <javac> algorithm is tweaked here, to allow <src> elements
251: // to contain a list of files _or_ a list of directories to scan.
252: //
253: if (srcFile.isDirectory()) {
254: DirectoryScanner ds = this
255: .getDirectoryScanner(srcFile);
256: String[] files = ds.getIncludedFiles();
257: scanDir(srcFile, destDir != null ? destDir
258: : srcFile, files, ext);
259: } else {
260: //
261: // BUGBUG: Because these bypass scanning, they also bypass dependency chks :(
262: //
263: if (srcFile.getPath().endsWith(ext.substring(1)))
264: inputFiles.add(srcFile);
265: }
266: }
267:
268: if (inputFiles.size() != 0) {
269: File[] newCompileList = new File[compileList.length
270: + inputFiles.size()];
271: inputFiles.toArray(newCompileList);
272: System.arraycopy(compileList, 0, newCompileList,
273: inputFiles.size(), compileList.length);
274: compileList = newCompileList;
275: }
276:
277: //
278: // If processing/compiling on a per-extension basis, then handle the current list,
279: // then reset the list fo files to compile before moving to the next extension
280: //
281: if (_compileByExt) {
282: compile();
283: resetFileLists();
284: }
285: }
286:
287: //
288: // If not processing on a per-extension basis, then compile the entire aggregated list
289: //
290: if (!_compileByExt)
291: compile();
292: }
293:
294: protected boolean _nocompile = false;
295: protected boolean _compileByExt = false;
296: protected boolean _hasSourcepath;
297: protected File _genDir;
298: protected Vector/*<String>*/_srcExts = new Vector/*<String>*/();
299: protected Vector/*<String>*/_processorOptions = new Vector/*<String>*/();
300: }
|