001 /*
002 * Copyright 2001-2013 Stephen Colebourne
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.joda.beans.gen;
017
018 import java.io.BufferedReader;
019 import java.io.BufferedWriter;
020 import java.io.File;
021 import java.io.FileInputStream;
022 import java.io.FileOutputStream;
023 import java.io.InputStreamReader;
024 import java.io.OutputStreamWriter;
025 import java.io.PrintWriter;
026 import java.util.ArrayList;
027 import java.util.List;
028
029 /**
030 * Code generator for the beans.
031 * <p>
032 * This reads in a {@code .java} file, parses it, and writes out an updated version.
033 *
034 * @author Stephen Colebourne
035 */
036 public class BeanCodeGen {
037
038 /**
039 * Main.
040 * @param args the arguments, not null
041 */
042 public static void main(String[] args) {
043 String indent = " ";
044 String prefix = "";
045 boolean recurse = false;
046 int verbosity = 1;
047 boolean write = true;
048 File file = null;
049 try {
050 if (args.length == 0) {
051 throw new RuntimeException();
052 }
053 for (int i = 0; i < args.length - 1; i++) {
054 if (args[i].startsWith("-indent=tab")) {
055 indent = "\t";
056 } else if (args[i].startsWith("-indent=")) {
057 indent = " ".substring(0, Integer.parseInt(args[i].substring(8)));
058 } else if (args[i].startsWith("-prefix=")) {
059 prefix = args[i].substring(8);
060 } else if (args[i].equals("-R")) {
061 recurse = true;
062 } else if (args[i].startsWith("-v=")) {
063 verbosity = Integer.parseInt(args[i].substring(3));
064 } else if (args[i].equals("-nowrite")) {
065 write = false;
066 }
067 }
068 file = new File(args[args.length - 1]);
069 } catch (Exception ex) {
070 System.out.println("Code generator");
071 System.out.println(" Usage java org.joda.beans.gen.BeanCodeGen [file]");
072 System.out.println(" Options");
073 System.out.println(" -R process all files recursively, default false");
074 System.out.println(" -indent=tab use a tab for indenting, default 4 spaces");
075 System.out.println(" -indent=[n] use n spaces for indenting, default 4");
076 System.out.println(" -prefix=[p] field prefix of p should be removed, no default");
077 System.out.println(" -verbose=[v] output logging with verbosity from 0 to 3, default 1");
078 System.out.println(" -nowrite output messages rather than writing, default is to write");
079 System.exit(0);
080 }
081 try {
082 List<File> files = findFiles(file, recurse);
083 int changed = 0;
084 for (File child : files) {
085 BeanCodeGen gen = new BeanCodeGen(child, indent, prefix, verbosity, write);
086 changed += (gen.process() ? 1 : 0);
087 }
088 System.out.println("Finished, found " + changed + " changed files");
089 System.exit(0);
090 } catch (Exception ex) {
091 System.out.println();
092 ex.printStackTrace(System.out);
093 System.exit(1);
094 }
095 }
096
097 private static List<File> findFiles(final File parent, boolean recurse) {
098 final List<File> result = new ArrayList<File>();
099 if (parent.isDirectory()) {
100 File[] files = parent.listFiles();
101 for (File child : files) {
102 if (child.isFile() && child.getName().endsWith(".java")) {
103 result.add(child);
104 }
105 }
106 if (recurse) {
107 for (File child : files) {
108 if (child.isDirectory() && child.getName().startsWith(".") == false) {
109 result.addAll(findFiles(child, recurse));
110 }
111 }
112 }
113 } else {
114 if (parent.getName().endsWith(".java")) {
115 result.add(parent);
116 }
117 }
118 return result;
119 }
120
121 //-----------------------------------------------------------------------
122 /** The file to process. */
123 private final File file;
124 /** The indent to use. */
125 private final String indent;
126 /** The prefix to use. */
127 private final String prefix;
128 /** The verbosity level. */
129 private final int verbosity;
130 /** Whether to write or not. */
131 private final boolean write;
132
133 /**
134 * Creates the generator for a single bean.
135 * <p>
136 * To generate, use {@link #process()}.
137 *
138 * @param file the file to process, not null
139 * @param indent the indent to use, not null
140 * @param prefix the prefix to use, not null
141 * @param verbosity the verbosity
142 * @param write whether to write or not
143 */
144 public BeanCodeGen(File file, String indent, String prefix, int verbosity, boolean write) {
145 this.file = file;
146 this.indent = indent;
147 this.prefix = prefix;
148 this.verbosity = verbosity;
149 this.write = write;
150 }
151
152 //-----------------------------------------------------------------------
153 /**
154 * Processes the bean, generating the code.
155 * @return true if changed
156 */
157 public boolean process() throws Exception {
158 List<String> original = readFile();
159 List<String> content = new ArrayList<String>(original);
160 BeanGen gen;
161 try {
162 gen = new BeanGen(content, indent, prefix);
163 } catch (Exception ex) {
164 throw new RuntimeException("Error in bean: " + file, ex);
165 }
166 if (gen.isBean() ) {
167 if (verbosity >= 2) {
168 System.out.print(file + " [processing]");
169 }
170 gen.process();
171 if (content.equals(original) == false) {
172 if (write) {
173 if (verbosity >= 2) {
174 System.out.println(" [writing]");
175 } else if (verbosity == 1) {
176 System.out.println(file + " [writing]");
177 }
178 writeFile(content);
179 } else {
180 if (verbosity >= 2) {
181 System.out.println(" [changed not written]");
182 } else if (verbosity == 1) {
183 System.out.println(file + " [changed not written]");
184 }
185 }
186 return true;
187 } else {
188 if (verbosity >= 2) {
189 System.out.println(" [no change]");
190 }
191 }
192 } else {
193 if (verbosity == 3) {
194 System.out.println(file + " [ignored]");
195 }
196 }
197 return false;
198 }
199
200 //-----------------------------------------------------------------------
201 private List<String> readFile() throws Exception {
202 List<String> content = new ArrayList<String>(100);
203 BufferedReader is = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
204 try {
205 String line;
206 while ((line = is.readLine()) != null) {
207 content.add(line);
208 }
209 return content;
210 } finally {
211 is.close();
212 }
213 }
214
215 private void writeFile(List<String> content) throws Exception {
216 PrintWriter os = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")));
217 try {
218 for (String line : content) {
219 os.println(line);
220 }
221 } finally {
222 os.close();
223 }
224 }
225
226 }