1 /* 2 * Copyright (c) 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 package compiler.compilercontrol.share; 25 26 import java.io.FileNotFoundException; 27 import java.io.PrintStream; 28 import java.util.Objects; 29 import java.util.Stack; 30 31 /** 32 * Simple JSON file writer 33 */ 34 public class JSONFile { 35 private final Stack<Element> stack; 36 private final String fileName; 37 private final PrintStream out; 38 private int spaces; 39 40 /** 41 * JSON element 42 */ 43 public enum Element { 44 OBJECT, 45 ARRAY, 46 PAIR, 47 VALUE 48 } 49 50 /** 51 * Constructor. Creates file with default name 52 */ 53 public JSONFile() { 54 this("directives_file.json"); 55 } 56 57 /** 58 * Constructor 59 * 60 * @param fileName file name 61 */ 62 public JSONFile(String fileName) { 63 this.spaces = 0; 64 this.stack = new Stack<>(); 65 this.fileName = fileName; 66 try { 67 out = new PrintStream(fileName); 68 } catch (FileNotFoundException e) { 69 throw new Error("TESTBUG: can't open/create file " + fileName, e); 70 } 71 } 72 73 /** 74 * Gets file name 75 * 76 * @return file name string 77 */ 78 public String getFileName() { 79 return fileName; 80 } 81 82 /** 83 * Gets current JSON element in the file. 84 * The element is a current {@linkplain Element} 85 * that was written into a file. 86 * 87 * @return the type of the current element, 88 * or null if there are nothing written 89 */ 90 public Element getElement() { 91 if (stack.empty()) { 92 return null; 93 } 94 return stack.peek(); 95 } 96 97 /** 98 * Writes given type with a value to file. 99 * Note that only PAIR and VALUE types accept a single value parameter. 100 * OBJECT and ARRAY do not have a value 101 * 102 * @param element JSON element type 103 * @param value element's value 104 * @return this file instance 105 */ 106 public JSONFile write(Element element, String... value) { 107 if (value.length > 1) { 108 throw new Error("TESTBUG: Unexpected value length: " 109 + value.length); 110 } 111 if (!stack.empty()) { 112 if (stack.peek() == Element.VALUE) { 113 out.print(", "); 114 stack.pop(); 115 } 116 } 117 switch (element) { 118 case OBJECT: 119 out.print("{"); 120 spaces++; 121 stack.push(Element.VALUE); 122 break; 123 case ARRAY: 124 out.print("["); 125 stack.push(Element.VALUE); 126 break; 127 case PAIR: 128 fillSpaces(); 129 Objects.requireNonNull(value, "TESTBUG: " + element 130 + "requires a value to be set"); 131 out.print(value[0] + ": "); 132 break; 133 case VALUE: 134 Objects.requireNonNull(value, "TESTBUG: " + element 135 + "requires a value to be set"); 136 out.print(value[0]); 137 break; 138 } 139 stack.push(element); 140 return this; 141 } 142 143 private void fillSpaces() { 144 out.println(); 145 for (int i = 0; i < spaces; i++) { 146 // Fill with spaces to be more readable 147 out.print(" "); 148 } 149 } 150 151 /** 152 * Ends current object or array of {@linkplain Element} 153 * 154 * @return this file instance 155 */ 156 public JSONFile end() { 157 if (!stack.empty()) { 158 Element prev = stack.pop(); 159 while (prev != Element.OBJECT && prev != Element.ARRAY 160 && !stack.empty()) { 161 prev = stack.pop(); 162 } 163 switch (prev) { 164 case OBJECT: 165 spaces--; 166 fillSpaces(); 167 out.print("}"); 168 break; 169 case ARRAY: 170 out.print("]"); 171 break; 172 default: 173 throw new Error("TESTBUG: Incorrect end. " + 174 "Wrong type found: " + prev); 175 } 176 } else { 177 throw new Error("TESTBUG: Incorrect end. Empty stack"); 178 } 179 return this; 180 } 181 }