1/*
2 * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package anttasks;
27
28import genstubs.GenStubs;
29
30import java.io.*;
31import java.util.*;
32
33import org.apache.tools.ant.BuildException;
34import org.apache.tools.ant.DirectoryScanner;
35import org.apache.tools.ant.taskdefs.MatchingTask;
36import org.apache.tools.ant.types.Path;
37import org.apache.tools.ant.types.Reference;
38
39/**
40 * Files are specified with an implicit fileset, using srcdir as a base directory.
41 * The set of files to be included is specified with an includes attribute or
42 * nested <includes> set. However, unlike a normal fileset, an empty includes attribute
43 * means "no files" instead of "all files".  The Ant task also accepts "fork=true" and
44 * classpath attribute or nested <classpath> element to run GenStubs in a separate VM
45 * with the specified path. This is likely necessary if a JDK 7 parser is required to read the
46 * JDK 7 input files.
47 */
48public class GenStubsTask extends MatchingTask {
49    private File srcDir;
50    private File destDir;
51    private boolean fork;
52    private Path classpath;
53    private String includes;
54
55    public void setSrcDir(File dir) {
56        this.srcDir = dir;
57    }
58
59    public void setDestDir(File dir) {
60        this.destDir = dir;
61    }
62
63    public void setFork(boolean v) {
64        this.fork = v;
65    }
66
67    public void setClasspath(Path cp) {
68        if (classpath == null)
69            classpath = cp;
70        else
71            classpath.append(cp);
72    }
73
74    public Path createClasspath() {
75        if (classpath == null) {
76            classpath = new Path(getProject());
77        }
78        return classpath.createPath();
79    }
80
81    public void setClasspathRef(Reference r) {
82        createClasspath().setRefid(r);
83    }
84
85    @Override
86    public void setIncludes(String includes) {
87        super.setIncludes(includes);
88        this.includes = includes;
89    }
90
91    @Override
92    public void execute() {
93        if (includes != null && includes.trim().isEmpty())
94            return;
95
96        DirectoryScanner s = getDirectoryScanner(srcDir);
97        String[] files = s.getIncludedFiles();
98//            System.err.println("Ant.execute: srcDir " + srcDir);
99//            System.err.println("Ant.execute: destDir " + destDir);
100//            System.err.println("Ant.execute: files " + Arrays.asList(files));
101
102        files = filter(srcDir, destDir, files);
103        if (files.length == 0)
104            return;
105        System.out.println("Generating " + files.length + " stub files to " + destDir);
106
107        List<String> classNames = new ArrayList<>();
108        for (String file: files) {
109            classNames.add(file.replaceAll(".java$", "").replace('/', '.'));
110        }
111
112        if (!fork) {
113            GenStubs m = new GenStubs();
114            boolean ok = m.run(srcDir.getPath(), destDir, classNames);
115            if (!ok)
116                throw new BuildException("genstubs failed");
117        } else {
118            List<String> cmd = new ArrayList<>();
119            String java_home = System.getProperty("java.home");
120            cmd.add(new File(new File(java_home, "bin"), "java").getPath());
121            if (classpath != null)
122                cmd.add("-Xbootclasspath/p:" + classpath);
123            cmd.add(GenStubs.class.getName());
124            cmd.add("-sourcepath");
125            cmd.add(srcDir.getPath());
126            cmd.add("-s");
127            cmd.add(destDir.getPath());
128            cmd.addAll(classNames);
129            //System.err.println("GenStubs exec " + cmd);
130            ProcessBuilder pb = new ProcessBuilder(cmd);
131            pb.redirectErrorStream(true);
132            try {
133                Process p = pb.start();
134                try (BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
135                    String line;
136                    while ((line = in.readLine()) != null)
137                        System.out.println(line);
138                }
139                int rc = p.waitFor();
140                if (rc != 0)
141                    throw new BuildException("genstubs failed");
142            } catch (IOException | InterruptedException e) {
143                throw new BuildException("genstubs failed", e);
144            }
145        }
146    }
147
148    String[] filter(File srcDir, File destDir, String[] files) {
149        List<String> results = new ArrayList<String>();
150        for (String f: files) {
151            long srcTime = new File(srcDir, f).lastModified();
152            long destTime = new File(destDir, f).lastModified();
153            if (srcTime > destTime)
154                results.add(f);
155        }
156        return results.toArray(new String[results.size()]);
157    }
158}
159