1/*
2 * Copyright (c) 2012, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24import java.io.File;
25import java.io.IOException;
26import java.net.URI;
27import java.net.URISyntaxException;
28import java.util.Arrays;
29import java.util.Iterator;
30
31import javax.tools.Diagnostic;
32import javax.tools.DiagnosticCollector;
33import javax.tools.JavaCompiler;
34import javax.tools.JavaCompiler.CompilationTask;
35import javax.tools.JavaFileObject;
36import javax.tools.SimpleJavaFileObject;
37import javax.tools.StandardJavaFileManager;
38import javax.tools.StandardLocation;
39import javax.tools.ToolProvider;
40
41import com.sun.source.util.JavacTask;
42
43public class Helper {
44
45    enum ContentVars {
46
47        IMPORTCONTAINERSTMTS("\nimport java.lang.annotation.Repeatable;\n"),
48        IMPORTDEPRECATED("import java.lang.Deprecated;\n"),
49        IMPORTDOCUMENTED("import java.lang.annotation.Documented;\n"),
50        IMPORTINHERITED("import java.lang.annotation.Inherited;\n"),
51        IMPORTRETENTION("import java.lang.annotation.Retention;\n"
52        + "\nimport java.lang.annotation.RetentionPolicy;\n"),
53        IMPORTSTMTS("import java.lang.annotation.*;\n"),
54        IMPORTEXPECTED("import expectedFiles.*;\n"),
55        REPEATABLE("\n@Repeatable(FooContainer.class)\n"),
56        CONTAINER("@interface FooContainer {\n" + "  Foo[] value();\n}\n"),
57        BASE("@interface Foo {int value() default Integer.MAX_VALUE;}\n"),
58        BASEANNO("@Foo(0)"),
59        LEGACYCONTAINER("@FooContainer(value = {@Foo(1), @Foo(2)})\n"),
60        REPEATABLEANNO("\n@Foo(1) @Foo(2)"),
61        DEPRECATED("\n@Deprecated"),
62        DOCUMENTED("\n@Documented"),
63        INHERITED("\n@Inherited"),
64        TARGET("\n@Target(#VAL)\n"),
65        RETENTION("@Retention(RetentionPolicy.#VAL)\n"),
66        RETENTIONRUNTIME("@Retention(RetentionPolicy.RUNTIME)\n");
67        private String val;
68
69        private ContentVars(String val) {
70            this.val = val;
71        }
72
73        public String getVal() {
74            return val;
75        }
76    }
77
78    // Create and compile FileObject using values for className and contents
79    public static boolean compileCode(String className, String contents,
80            DiagnosticCollector<JavaFileObject> diagnostics) {
81        boolean ok = false;
82        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
83        if (compiler == null) {
84            throw new RuntimeException("can't get javax.tools.JavaCompiler!");
85        }
86
87        JavaFileObject file = getFile(className, contents);
88        Iterable<? extends JavaFileObject> compilationUnit = Arrays.asList(file);
89
90        CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnit);
91        ok = task.call();
92        return ok;
93    }
94    // Compile a list of FileObjects
95    // Used when packages are needed and classes need to be loaded at runtime
96    static File destDir = new File(System.getProperty("user.dir"));
97
98    public static boolean compileCode(DiagnosticCollector<JavaFileObject> diagnostics, Iterable<? extends JavaFileObject> files) {
99        boolean ok = false;
100        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
101        if (compiler == null) {
102            throw new RuntimeException("can't get javax.tools.JavaCompiler!");
103        }
104
105        try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
106            // Assuming filesCount can maximum be 2 and if true, one file is package-info.java
107            if (isPkgInfoPresent(files)) {
108                JavacTask task = (JavacTask) compiler.getTask(null, fm, diagnostics, null, null, files);
109                try {
110                    fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(destDir));
111                    task.generate();
112                } catch (IOException ioe) {
113                    throw new RuntimeException("Compilation failed for package level tests", ioe);
114                }
115                int err = 0;
116                for (Diagnostic<? extends JavaFileObject> d : diagnostics.getDiagnostics()) {
117                    if(d.getKind() == Diagnostic.Kind.ERROR) {
118                      err++;
119                    }
120                }
121                ok = (err == 0);
122            } else {
123                CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, files);
124                ok = task.call();
125            }
126            return ok;
127        } catch (IOException e) {
128            throw new Error(e);
129        }
130    }
131
132    static private boolean isPkgInfoPresent(Iterable<? extends JavaFileObject> files) {
133        Iterator<? extends JavaFileObject> itr = files.iterator();
134        while (itr.hasNext()) {
135            String name = itr.next().getName();
136            if (name.contains("package-info")) {
137                return true;
138            }
139        }
140        return false;
141    }
142    /* String template where /*<TYPE>*/ /*gets replaced by repeating anno
143     * Used to generate test src for combo tests
144     *   - BasicSyntaxCombo.java
145     *   - TargetAnnoCombo.java
146     */
147
148    public static final String template =
149            "/*PACKAGE*/\n"
150            + "//pkg test;\n\n"
151            + "/*ANNODATA*/\n" // import statements, declaration of Foo/FooContainer
152            + "/*TYPE*/ //class\n"
153            + "class #ClassName {\n"
154            + "  /*FIELD*/ //instance var\n"
155            + "  public int x = 0;\n\n"
156            + "  /*FIELD*/ //Enum constants\n"
157            + "  TestEnum testEnum;\n\n"
158            + "  /*FIELD*/ // Static field\n"
159            + "  public static int num;\n\n"
160            + "  /*STATIC_INI*/\n"
161            + "  static { \n" + "num = 10; \n  }\n\n"
162            + "  /*CONSTRUCTOR*/\n"
163            + "  #ClassName() {}\n\n"
164            + "  /*INSTANCE_INI*/\n"
165            + "  { \n x = 10; \n }"
166            + "  /*INNER_CLASS*/\n"
167            + "  class innerClass {}\n"
168            + "  /*METHOD*/\n"
169            + "  void bar(/*PARAMETER*/ int baz) {\n"
170            + "    /*LOCAL_VARIABLE*/\n"
171            + "    int y = 0;\n"
172            + "  }\n"
173            + "}\n\n"
174            + "/*TYPE*/ //Enum\n"
175            + "enum TestEnum {}\n\n"
176            + "/*TYPE*/ //Interface\n"
177            + "interface TestInterface {}\n\n"
178            + "/*TYPE*/\n"
179            + "/*ANNOTATION_TYPE*/\n"
180            + "@interface TestAnnotationType{}\n"
181            + "class TestPkg {}\n"
182            + "class TestTypeAnno </*TYPE_PARAMETER*/ T extends Object> {\n"
183            + "  String /*TYPE_USE*/[] arr;\n"
184            + "}";
185
186    static JavaFileObject getFile(String name, String code) {
187        JavaFileObject o = null;
188        try {
189            o = new JavaStringFileObject(name, code);
190        } catch (URISyntaxException e) {
191            throw new RuntimeException(e);
192        }
193        return o;
194    }
195
196    static class JavaStringFileObject extends SimpleJavaFileObject {
197
198        final String theCode;
199
200        public JavaStringFileObject(String fileName, String theCode) throws URISyntaxException {
201            super(new URI("string:///" + fileName.replace('.', '/') + ".java"), Kind.SOURCE);
202            this.theCode = theCode;
203        }
204
205        @Override
206        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
207            return theCode;
208        }
209    }
210}
211