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.util.ArrayList;
022: import java.util.List;
023:
024: import org.eclipse.jdt.internal.compiler.ClassFile;
025: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
026: import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
027:
028: import spoon.processing.AbstractProcessor;
029: import spoon.processing.FileGenerator;
030: import spoon.reflect.Factory;
031: import spoon.reflect.declaration.CtSimpleType;
032: import spoon.support.util.ClassFileUtil;
033: import spoon.support.util.JDTCompiler;
034:
035: /**
036: * This class defines a processor that generates class files from the metamodel.
037: */
038: public class ByteCodeOutputProcessor extends
039: AbstractProcessor<CtSimpleType<?>> implements
040: FileGenerator<CtSimpleType<?>> {
041:
042: /**
043: * Extension for class files (.class).
044: */
045: public static final String CLASS_EXT = ".class";
046:
047: private File outputDir;
048:
049: private List<ICompilationUnit> units = new ArrayList<ICompilationUnit>();
050:
051: private List<File> printed = new ArrayList<File>();
052:
053: private List<String> printedTypes = new ArrayList<String>();
054:
055: private JavaOutputProcessor javaPrinter;
056:
057: /**
058: * Creates a new processor for generating Java source files.
059: *
060: * @param outputDirectory
061: * the root output directory
062: */
063: public ByteCodeOutputProcessor(JavaOutputProcessor javaPrinter,
064: File outputDirectory) {
065: outputDir = outputDirectory;
066: this .javaPrinter = javaPrinter;
067: }
068:
069: public List<File> getCreatedFiles() {
070: return printed;
071: }
072:
073: public File getOutputDirectory() {
074: return outputDir;
075: }
076:
077: /**
078: * Tells if the source is Java 1.4 or lower.
079: */
080: public long getJavaCompliance() {
081: switch (getFactory().getEnvironment().getComplianceLevel()) {
082: case 1:
083: return ClassFileConstants.JDK1_1;
084: case 2:
085: return ClassFileConstants.JDK1_2;
086: case 3:
087: return ClassFileConstants.JDK1_3;
088: case 4:
089: return ClassFileConstants.JDK1_4;
090: case 5:
091: return ClassFileConstants.JDK1_5;
092: case 6:
093: return ClassFileConstants.JDK1_6;
094: }
095: return ClassFileConstants.JDK1_5;
096: }
097:
098: public void process(CtSimpleType<?> element) {
099: if (!element.isTopLevel()) {
100: return;
101: }
102: // Create Java code and create ICompilationUnit
103: javaPrinter.getCreatedFiles().clear();
104: javaPrinter.createJavaFile(element);
105:
106: for (File f : javaPrinter.getCreatedFiles()) {
107: try {
108: units.add(JDTCompiler.getUnit(element
109: .getQualifiedName(), f));
110: } catch (Exception e) {
111: e.printStackTrace();
112: }
113: }
114:
115: }
116:
117: @Override
118: public void processingDone() {
119: try {
120: // Do compilation
121: JDTCompiler compiler = new JDTCompiler();
122: compiler.getCompilerOption().sourceLevel = getJavaCompliance();
123: compiler.getCompilerOption().targetJDK = getJavaCompliance();
124: compiler.compile(units.toArray(new ICompilationUnit[0]));
125:
126: getOutputDirectory().mkdirs();
127:
128: for (ClassFile f : compiler.getClassFiles()) {
129: String fileName = new String(f.fileName()).replace('/',
130: File.separatorChar)
131: + CLASS_EXT;
132: // System.out.println("--- adjusting "+fileName);
133: ClassFileUtil.adjustLineNumbers(f.getBytes(),
134: f.headerOffset + f.methodCountOffset - 1,
135: javaPrinter.getLineNumberMappings().get(
136: new String(f.fileName()).replace('/',
137: '.')));
138: ClassFileUtil.writeToDisk(true, getOutputDirectory()
139: .getAbsolutePath(), fileName, f.getBytes());
140:
141: printed.add(new File(getOutputDirectory(), fileName));
142: printedTypes.add(new String(f.fileName()).replace('/',
143: '.'));
144: }
145: } catch (Exception e) {
146: e.printStackTrace();
147: }
148:
149: }
150:
151: public void setOutputDirectory(File directory) {
152: outputDir = directory;
153: }
154:
155: @Override
156: public void setFactory(Factory factory) {
157: super.setFactory(factory);
158: javaPrinter.setFactory(factory);
159: }
160: }
|