001: /*
002: * Spoon - http://spoon.gforge.inria.fr/
003: * Copyright (C) 2006 INRIA Futurs <renaud.pawlak@inria.fr>
004: *
005: * This software is governed by the CeCILL-C License under French law and
006: * abiding by the rules of distribution of free software. You can use, modify
007: * and/or redistribute the software under the terms of the CeCILL-C license as
008: * circulated by CEA, CNRS and INRIA at http://www.cecill.info.
009: *
010: * This program is distributed in the hope that it will be useful, but WITHOUT
011: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
012: * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
013: *
014: * The fact that you are presently reading this means that you have had
015: * knowledge of the CeCILL-C license and that you accept its terms.
016: */
017:
018: package spoon.support;
019:
020: import java.io.File;
021: import java.io.FileInputStream;
022: import java.io.FileNotFoundException;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.io.Serializable;
026: import java.util.Map;
027: import java.util.TreeMap;
028:
029: import org.xml.sax.SAXException;
030:
031: import spoon.processing.Environment;
032: import spoon.processing.FileGenerator;
033: import spoon.processing.ProblemFixer;
034: import spoon.processing.ProcessingManager;
035: import spoon.processing.Processor;
036: import spoon.processing.ProcessorProperties;
037: import spoon.processing.Severity;
038: import spoon.reflect.Factory;
039: import spoon.reflect.cu.SourcePosition;
040: import spoon.reflect.declaration.CtElement;
041: import spoon.reflect.declaration.CtExecutable;
042: import spoon.reflect.declaration.CtSimpleType;
043: import spoon.support.processing.XmlProcessorProperties;
044:
045: /**
046: * This class implements a simple Spoon environment that reports messages in the
047: * standard output stream (Java-compliant).
048: */
049: public class StandardEnvironment implements Serializable, Environment {
050:
051: /**
052: * The processors' properties files extension (.xml)
053: */
054: public static final String PROPERTIES_EXT = ".xml";
055:
056: private static final long serialVersionUID = 1L;
057:
058: private boolean debug = false;
059:
060: private FileGenerator<? extends CtElement> defaultFileGenerator;
061:
062: private int errorCount = 0;
063:
064: private transient Factory factory;
065:
066: ProcessingManager manager;
067:
068: private boolean processingStopped = false;
069:
070: private boolean verbose = false;
071:
072: private int warningCount = 0;
073:
074: private File xmlRootFolder;
075:
076: /**
077: * Creates a new environment with a <code>null</code> default file
078: * generator.
079: */
080: public StandardEnvironment() {
081: }
082:
083: /**
084: * Creates a new environment.
085: */
086: public StandardEnvironment(
087: FileGenerator<? extends CtElement> defaultFileGenerator) {
088: this .defaultFileGenerator = defaultFileGenerator;
089: }
090:
091: public void debugMessage(String message) {
092: if (isDebug()) {
093: System.out.println(message);
094: }
095: }
096:
097: public FileGenerator<? extends CtElement> getDefaultFileGenerator() {
098: return defaultFileGenerator;
099: }
100:
101: public Factory getFactory() {
102: return factory;
103: }
104:
105: public ProcessingManager getManager() {
106: return manager;
107: }
108:
109: Map<String, ProcessorProperties> processorProperties = new TreeMap<String, ProcessorProperties>();
110:
111: public ProcessorProperties getProcessorProperties(
112: String processorName) throws FileNotFoundException,
113: IOException, SAXException {
114: if (processorProperties.containsKey(processorName)) {
115: return processorProperties.get(processorName);
116: }
117:
118: InputStream in = getPropertyStream(processorName);
119: XmlProcessorProperties prop = null;
120: try {
121: prop = new XmlProcessorProperties(getFactory(),
122: processorName, in);
123: } catch (SAXException e) {
124: throw new RuntimeException(e);
125: }
126: processorProperties.put(processorName, prop);
127: return prop;
128: }
129:
130: private InputStream getPropertyStream(String processorName)
131: throws FileNotFoundException {
132: for (File child : getXmlRootFolder().listFiles()) {
133: if (child.getName().equals(processorName + PROPERTIES_EXT)) {
134: return new FileInputStream(child);
135: }
136: }
137: throw new FileNotFoundException();
138: }
139:
140: /**
141: * Gets the root folder where the processors' XML configuration files are
142: * located.
143: */
144: public File getXmlRootFolder() {
145: if (xmlRootFolder == null) {
146: xmlRootFolder = new File(".");
147: }
148: return xmlRootFolder;
149: }
150:
151: public boolean isDebug() {
152: return debug;
153: }
154:
155: /**
156: * Tells if the processing is stopped, generally because one of the
157: * processors called {@link #setProcessingStopped(boolean)} after reporting
158: * an error.
159: */
160: public boolean isProcessingStopped() {
161: return processingStopped;
162: }
163:
164: /**
165: * Returns true if Spoon is in verbose mode.
166: */
167: public boolean isVerbose() {
168: return verbose;
169: }
170:
171: private void prefix(StringBuffer buffer, Severity severity) {
172: // Prefix message
173: switch (severity) {
174: case ERROR:
175: buffer.append("error: ");
176: errorCount++;
177: break;
178: case WARNING:
179: buffer.append("warning: ");
180: warningCount++;
181: break;
182: case MESSAGE:
183: break;
184: }
185: }
186:
187: private void print(StringBuffer buffer, Severity severity) {
188: switch (severity) {
189: case ERROR:
190: case WARNING:
191: System.out.println(buffer.toString());
192: break;
193: default:
194: if (isVerbose()) {
195: System.out.println(buffer.toString());
196: }
197: }
198: }
199:
200: public void report(Processor<?> processor, Severity severity,
201: CtElement element, String message) {
202: StringBuffer buffer = new StringBuffer();
203:
204: prefix(buffer, severity);
205:
206: // Adding message
207: buffer.append(message);
208:
209: // Add sourceposition (javac format)
210: CtSimpleType<?> type = (element instanceof CtSimpleType) ? (CtSimpleType<?>) element
211: : element.getParent(CtSimpleType.class);
212: SourcePosition sp = element.getPosition();
213:
214: if (sp == null) {
215: buffer.append(" (Unknown Source)");
216: } else {
217: buffer.append(" at " + type.getQualifiedName() + ".");
218: CtExecutable<?> exe = (element instanceof CtExecutable) ? (CtExecutable<?>) element
219: : element.getParent(CtExecutable.class);
220: if (exe != null) {
221: buffer.append(exe.getSimpleName());
222: }
223: buffer.append("(" + sp.getFile().getName() + ":"
224: + sp.getLine() + ")");
225: }
226:
227: print(buffer, severity);
228: }
229:
230: public void report(Processor<?> processor, Severity severity,
231: String message) {
232: StringBuffer buffer = new StringBuffer();
233:
234: prefix(buffer, severity);
235: // Adding message
236: buffer.append(message);
237: print(buffer, severity);
238: }
239:
240: /**
241: * This method should be called to report the end of the processing.
242: */
243: public void reportEnd() {
244: if (!isVerbose()) {
245: return;
246: }
247: System.out.print("end of processing: ");
248: if (warningCount > 0) {
249: System.out.print(warningCount + " warning");
250: if (warningCount > 1) {
251: System.out.print("s");
252: }
253: if (errorCount > 0) {
254: System.out.print(", ");
255: }
256: }
257: if (errorCount > 0) {
258: System.out.print(errorCount + " error");
259: if (errorCount > 1) {
260: System.out.print("s");
261: }
262: }
263: if ((errorCount + warningCount) > 0) {
264: System.out.print("\n");
265: } else {
266: System.out.println("no errors, no warnings");
267: }
268: }
269:
270: public void reportProgressMessage(String message) {
271: if (!isVerbose()) {
272: return;
273: }
274: System.out.println(message);
275: }
276:
277: public void setDebug(boolean debug) {
278: this .debug = debug;
279: }
280:
281: public void setDefaultFileGenerator(
282: FileGenerator<? extends CtElement> defaultFileGenerator) {
283: this .defaultFileGenerator = defaultFileGenerator;
284: defaultFileGenerator.setFactory(getFactory());
285: }
286:
287: public void setFactory(Factory factory) {
288: this .factory = factory;
289: }
290:
291: public void setManager(ProcessingManager manager) {
292: this .manager = manager;
293: }
294:
295: public void setProcessingStopped(boolean processingStopped) {
296: this .processingStopped = processingStopped;
297: }
298:
299: public void setVerbose(boolean verbose) {
300: this .verbose = verbose;
301: }
302:
303: /**
304: * Sets the root folder where the processors' XML configuration files are
305: * located.
306: */
307: public void setXmlRootFolder(File xmlRootFolder) {
308: this .xmlRootFolder = xmlRootFolder;
309: }
310:
311: int complianceLevel = 5;
312:
313: public int getComplianceLevel() {
314: return complianceLevel;
315: }
316:
317: public void setComplianceLevel(int level) {
318: complianceLevel = level;
319: }
320:
321: public void setProcessorProperties(String processorName,
322: ProcessorProperties prop) {
323: processorProperties.put(processorName, prop);
324: }
325:
326: public void report(Processor<?> processor, Severity severity,
327: CtElement element, String message, ProblemFixer<?>... fix) {
328: // Fix not (yet) used in command-line mode
329: report(processor, severity, element, message);
330: }
331:
332: public boolean isUsingSourceCodeFragments() {
333: return useSourceCodeFragments;
334: }
335:
336: boolean useSourceCodeFragments = false;
337:
338: public void useSourceCodeFragments(boolean b) {
339: useSourceCodeFragments = b;
340: }
341:
342: boolean useTabulations = false;
343:
344: public boolean isUsingTabulations() {
345: return useTabulations;
346: }
347:
348: public void useTabulations(boolean tabulation) {
349: useTabulations = tabulation;
350: }
351:
352: int tabulationSize = 4;
353:
354: public int getTabulationSize() {
355: return tabulationSize;
356: }
357:
358: public void setTabulationSize(int tabulationSize) {
359: this .tabulationSize = tabulationSize;
360: }
361:
362: public String getSourcePath() {
363: return ".";
364: }
365:
366: }
|