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.FileNotFoundException;
022: import java.io.IOException;
023: import java.io.PrintStream;
024: import java.util.ArrayList;
025: import java.util.HashMap;
026: import java.util.List;
027: import java.util.Map;
028:
029: import spoon.processing.AbstractProcessor;
030: import spoon.processing.FileGenerator;
031: import spoon.reflect.cu.CompilationUnit;
032: import spoon.reflect.declaration.CtPackage;
033: import spoon.reflect.declaration.CtSimpleType;
034: import spoon.reflect.visitor.DefaultJavaPrettyPrinter;
035: import spoon.reflect.visitor.FragmentDrivenJavaPrettyPrinter;
036: import spoon.reflect.visitor.PrettyPrinter;
037:
038: /**
039: * A processor that generates compilable Java source files from the meta-model.
040: */
041: public class JavaOutputProcessor extends
042: AbstractProcessor<CtSimpleType<?>> implements
043: FileGenerator<CtSimpleType<?>> {
044: File directory;
045:
046: List<File> printedFiles = new ArrayList<File>();
047:
048: boolean writePackageAnnotationFile = true;
049:
050: /**
051: * Creates a new processor for generating Java source files.
052: *
053: * @param outputDirectory
054: * the root output directory
055: */
056: public JavaOutputProcessor(File outputDirectory) {
057: this .directory = outputDirectory;
058: }
059:
060: public List<File> getCreatedFiles() {
061: return printedFiles;
062: }
063:
064: public File getOutputDirectory() {
065: return directory;
066: }
067:
068: @Override
069: public void init() {
070: // Skip loading properties
071: // super.init();
072: }
073:
074: Map<String, Map<Integer, Integer>> lineNumberMappings = new HashMap<String, Map<Integer, Integer>>();
075:
076: /**
077: * Creates the Java file associated to the given element.
078: */
079: public void createJavaFile(CtSimpleType<?> element) {
080:
081: CompilationUnit cu = null;
082: if (element.getPosition() != null)
083: cu = element.getPosition().getCompilationUnit();
084:
085: // skip non-main types
086: if (cu != null && cu.getMainType() != element)
087: return;
088:
089: List<CtSimpleType<?>> toBePrinted = new ArrayList<CtSimpleType<?>>();
090:
091: if (cu == null) {
092: toBePrinted.add(element);
093: } else {
094: toBePrinted.addAll(cu.getDeclaredTypes());
095: }
096:
097: PrettyPrinter printer = null;
098:
099: if (getEnvironment().isUsingSourceCodeFragments()) {
100: try {
101: printer = new FragmentDrivenJavaPrettyPrinter(
102: getEnvironment(), element.getPosition()
103: .getCompilationUnit());
104: } catch (Exception e) {
105: e.printStackTrace();
106: printer = null;
107: }
108: }
109: if (printer == null) {
110: printer = new DefaultJavaPrettyPrinter(getEnvironment());
111: printer.calculate(cu, toBePrinted);
112: }
113:
114: CtPackage pack = element.getPackage();
115: PrintStream stream = null;
116:
117: // Check output directory
118: if (directory == null)
119: throw new RuntimeException(
120: "You should set output directory before printing");
121: // Create spooned dir
122: if (directory.isFile())
123: throw new RuntimeException("Output must be a directory");
124: if (!directory.exists()) {
125: if (!directory.mkdirs())
126: throw new RuntimeException(
127: "Error creating output directory");
128: }
129:
130: // create package directory
131: File packageDir;
132: if (pack.getQualifiedName().equals(
133: CtPackage.TOP_LEVEL_PACKAGE_NAME)) {
134: packageDir = new File(directory.getAbsolutePath());
135: } else {
136: // Create current package dir
137: packageDir = new File(directory.getAbsolutePath()
138: + File.separatorChar
139: + pack.getQualifiedName().replace('.',
140: File.separatorChar));
141: }
142: if (!packageDir.exists()) {
143: if (!packageDir.mkdirs())
144: throw new RuntimeException(
145: "Error creating output directory");
146: }
147:
148: // Create package annotation file
149: if (writePackageAnnotationFile
150: && element.getPackage().getAnnotations().size() > 0) {
151: File packageAnnot = new File(packageDir.getAbsolutePath()
152: + File.separatorChar
153: + DefaultJavaPrettyPrinter.JAVA_PACKAGE_DECLARATION);
154: if (!printedFiles.contains(packageAnnot))
155: printedFiles.add(packageAnnot);
156: try {
157: stream = new PrintStream(packageAnnot);
158: stream.println(printer.getPackageDeclaration());
159: stream.close();
160: } catch (FileNotFoundException e) {
161: e.printStackTrace();
162: } finally {
163: if (stream != null)
164: stream.close();
165: }
166: }
167:
168: // print type
169: try {
170: File file = new File(packageDir.getAbsolutePath()
171: + File.separatorChar + element.getSimpleName()
172: + DefaultJavaPrettyPrinter.JAVA_FILE_EXTENSION);
173: file.createNewFile();
174: if (!printedFiles.contains(file)) {
175: printedFiles.add(file);
176: }
177: stream = new PrintStream(file);
178: stream.print(printer.getResult());
179: for (CtSimpleType<?> t : toBePrinted) {
180: lineNumberMappings.put(t.getQualifiedName(), printer
181: .getLineNumberMapping());
182: }
183: stream.close();
184: } catch (FileNotFoundException e) {
185: e.printStackTrace();
186: } catch (IOException e) {
187: e.printStackTrace();
188: } finally {
189: if (stream != null)
190: stream.close();
191: }
192:
193: }
194:
195: /**
196: * Creates a source file for each processed top-level type and pretty prints
197: * its contents.
198: */
199: public void process(CtSimpleType<?> type) {
200: if (type.isTopLevel())
201: createJavaFile(type);
202: }
203:
204: public void setOutputDirectory(File directory) {
205: this .directory = directory;
206: }
207:
208: public Map<String, Map<Integer, Integer>> getLineNumberMappings() {
209: return lineNumberMappings;
210: }
211:
212: }
|