1 /*
2  * Copyright (c) 2006, 2015, 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 
24 /*
25  * @test
26  * @bug 6380018 6453386 6457283
27  * @summary Test that the constraints guaranteed by the Filer and maintained
28  * @author  Joseph D. Darcy
29  * @library /tools/javac/lib
30  * @modules java.compiler
31  *          jdk.compiler
32  * @build TestFilerConstraints
33  * @compile -encoding iso-8859-1 -processor TestFilerConstraints -proc:only TestFilerConstraints.java
34  */
35 
36 import java.util.Set;
37 import javax.annotation.processing.*;
38 import javax.lang.model.SourceVersion;
39 import static javax.lang.model.SourceVersion.*;
40 import javax.lang.model.element.*;
41 import javax.lang.model.util.*;
42 import static javax.lang.model.util.ElementFilter.*;
43 import static javax.tools.Diagnostic.Kind.*;
44 import static javax.tools.StandardLocation.*;
45 
46 import java.io.*;
47 import java.nio.charset.Charset;
48 
49 /**
50  * A processor that verifies the explicit and implicit constraints in
51  * the Filer contract are maintained:
52  *
53  * <blockquote>
54  *
55  *  During each run of an annotation processing tool, a file with a
56  *  given pathname may be created only once. If that file already
57  *  exists before the first attempt to create it, the old contents
58  *  will be deleted. Any subsequent attempt to create the same file
59  *  during a run will throw a FilerException, as will attempting to
60  *  open both a class file and source file for the same type name.
61  *
62  * </blockquote>
63  *
64  * Specific checks will include:
65  *
66  * <ul>
67  *
68  * <li> Source and class files can be written to from either a Writer or an OutputStream.
69  *
70  * <li> Calling close multiple times does not re-register the file for
71  * processing.
72  *
73  * </ul>
74  */
75 public class TestFilerConstraints extends JavacTestingAbstractProcessor {
76     private int round = 0;
77 
78     private PrintWriter  pw_src1 = null;
79     private PrintWriter  pw_src2 = null;
80     private OutputStream os_classFile1 = null;
81     private      Writer  pw_classFile2 = null;
82 
process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)83     public boolean process(Set<? extends TypeElement> annotations,
84                            RoundEnvironment roundEnv) {
85         round++;
86 
87         try {
88             switch(round) {
89                 // Open two source files
90             case 1:
91                 pw_src1 = new PrintWriter(filer.createSourceFile("Src1").openWriter());
92                 pw_src1.println("class Src1 {}");
93                 pw_src1.close();
94 
95                 // Hold open across rounds
96                 pw_src2 = new PrintWriter(new OutputStreamWriter(filer.createSourceFile("Src2").openOutputStream()));
97                 break;
98 
99             case 2:
100                 testExpectedType(roundEnv, "Src1");
101 
102                 // Close Src1 a second time
103                 pw_src1.close();
104 
105                 pw_src2.println("class Src2 {}");
106                 pw_src2.close();
107 
108                 break;
109 
110             case 3:
111                 testExpectedType(roundEnv, "Src2");
112 
113                 // Close Src2 a second time
114                 pw_src2.close();
115 
116                 os_classFile1 = filer.createClassFile("ClassFile1").openOutputStream();
117                 for (int value : classFile1Bytes)
118                     os_classFile1.write((byte)value);
119                 os_classFile1.close();
120 
121                 break;
122 
123             case 4:
124                 testExpectedType(roundEnv, "ClassFile1");
125 
126                 // Close a second time
127                 os_classFile1.close();
128 
129                 testReopening();
130 
131                 pw_classFile2 = new PrintWriter(filer.createClassFile("ClassFile2",
132                                                                       (Element[])null).openWriter());
133 
134                 for(int byteVal : classFile2Bytes) {
135                     // int value = (0xff00 & (classFile2Bytes[i]<<8)) | classFile2Bytes[i+1];
136                     // System.out.print(Integer.toHexString(value));
137                     //if ((i % 4) == 0)
138                     // System.out.println();
139                     pw_classFile2.write((char) (0xff & byteVal));
140                 }
141                 pw_classFile2.close();
142 
143                 break;
144 
145 
146 
147             case 5:
148                 testExpectedType(roundEnv, "ClassFile2");
149                 // Close a second time
150                 pw_classFile2.close();
151 
152 
153                 break;
154 
155             case 6:
156                 if (!roundEnv.processingOver() && !roundEnv.errorRaised())
157                     throw new RuntimeException("Bad round state: " + roundEnv);
158                 break;
159 
160             default:
161                 throw new RuntimeException("Unexpected round number!");
162             }
163         } catch (IOException ioe) {
164             throw new RuntimeException(ioe);
165         }
166 
167         return true;
168     }
169 
170     /**
171      * Test that the single expected expected type, name, is the root
172      * element.
173      */
testExpectedType(RoundEnvironment roundEnv, String name)174     private void testExpectedType(RoundEnvironment roundEnv, String name) {
175         if (!roundEnv.getRootElements().isEmpty()) {
176             for(TypeElement type : typesIn(roundEnv.getRootElements())) {
177                 if (!name.contentEquals(type.getSimpleName()))
178                     throw new RuntimeException("Unexpected type " +  type.getSimpleName());
179             }
180         } else
181             throw new RuntimeException("Unexpected empty root elements.");
182     }
183 
testReopening()184     private void testReopening() throws IOException {
185         String[] names = {"Src1", "Src2", "ClassFile1"};
186         for (String name : names) {
187             try {
188                 filer.createSourceFile(name);
189                 throw new RuntimeException("Opened a source file for type " + name);
190             } catch (FilerException fe) {;}
191 
192             try {
193                 filer.createClassFile(name);
194                 throw new RuntimeException("Opened a class file for type " + name);
195             } catch (FilerException fe) {;}
196         }
197 
198         // Try to open a resource over a source file
199         try {
200             filer.createResource(SOURCE_OUTPUT, "", "Src1.java");
201             throw new RuntimeException("Opened a text file over Src1.java!");
202         } catch (FilerException fe) {;}
203 
204         // Try to open a resource over a class file
205         try {
206             filer.createResource(CLASS_OUTPUT, "", "ClassFile1.class");
207             throw new RuntimeException("Opened a text file over Src1.java!");
208         } catch (FilerException fe) {;}
209 
210     }
211 
212     private int[] classFile1Bytes =
213     {202, 254, 186, 190,   0,   0,   0,  50,
214        0,  13,  10,   0,   3,   0,  10,   7,
215        0,  11,   7,   0,  12,   1,   0,   6,
216       60, 105, 110, 105, 116,  62,   1,   0,
217        3,  40,  41,  86,   1,   0,   4,  67,
218      111, 100, 101,   1,   0,  15,  76, 105,
219      110, 101,  78, 117, 109,  98, 101, 114,
220       84,  97,  98, 108, 101,   1,   0,  10,
221       83, 111, 117, 114,  99, 101,  70, 105,
222      108, 101,   1,   0,  15,  67, 108,  97,
223      115, 115,  70, 105, 108, 101,  49,  46,
224      106,  97, 118,  97,  12,   0,   4,   0,
225        5,   1,   0,  10,  67, 108,  97, 115,
226      115,  70, 105, 108, 101,  49,   1,   0,
227       16, 106,  97, 118,  97,  47, 108,  97,
228      110, 103,  47,  79,  98, 106, 101,  99,
229      116,   0,  33,   0,   2,   0,   3,   0,
230        0,   0,   0,   0,   1,   0,   1,   0,
231        4,   0,   5,   0,   1,   0,   6,   0,
232        0,   0,  29,   0,   1,   0,   1,   0,
233        0,   0,   5,  42, 183,   0,   1, 177,
234        0,   0,   0,   1,   0,   7,   0,   0,
235        0,   6,   0,   1,   0,   0,   0,   1,
236        0,   1,   0,   8,   0,   0,   0,   2,
237        0,   9,};
238 
239     private int[] classFile2Bytes =
240     {202, 254, 186, 190,   0,   0,   0,  50,
241        0,  13,  10,   0,   3,   0,  10,   7,
242        0,  11,   7,   0,  12,   1,   0,   6,
243       60, 105, 110, 105, 116,  62,   1,   0,
244        3,  40,  41,  86,   1,   0,   4,  67,
245      111, 100, 101,   1,   0,  15,  76, 105,
246      110, 101,  78, 117, 109,  98, 101, 114,
247       84,  97,  98, 108, 101,   1,   0,  10,
248       83, 111, 117, 114,  99, 101,  70, 105,
249      108, 101,   1,   0,  15,  67, 108,  97,
250      115, 115,  70, 105, 108, 101,  50,  46,
251      106,  97, 118,  97,  12,   0,   4,   0,
252        5,   1,   0,  10,  67, 108,  97, 115,
253      115,  70, 105, 108, 101,  50,   1,   0,
254       16, 106,  97, 118,  97,  47, 108,  97,
255      110, 103,  47,  79,  98, 106, 101,  99,
256      116,   0,  33,   0,   2,   0,   3,   0,
257        0,   0,   0,   0,   1,   0,   1,   0,
258        4,   0,   5,   0,   1,   0,   6,   0,
259        0,   0,  29,   0,   1,   0,   1,   0,
260        0,   0,   5,  42, 183,   0,   1, 177,
261        0,   0,   0,   1,   0,   7,   0,   0,
262        0,   6,   0,   1,   0,   0,   0,   1,
263        0,   1,   0,   8,   0,   0,   0,   2,
264        0,   9,};
265 }
266