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;
019:
020: import java.io.File;
021: import java.util.Map;
022: import java.util.TreeMap;
023:
024: import org.eclipse.jdt.internal.compiler.ClassFile;
025: import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
026:
027: import spoon.processing.Builder;
028: import spoon.processing.Environment;
029: import spoon.processing.ProcessingManager;
030: import spoon.reflect.CoreFactory;
031: import spoon.reflect.Factory;
032: import spoon.reflect.declaration.CtSimpleType;
033: import spoon.reflect.visitor.DefaultJavaPrettyPrinter;
034: import spoon.support.DefaultCoreFactory;
035: import spoon.support.RuntimeProcessingManager;
036: import spoon.support.StandardEnvironment;
037: import spoon.support.util.JDTCompiler;
038:
039: /**
040: * A classloader that gets classes from Java source files and process them
041: * before actually loading them.
042: */
043: public class SpoonClassLoader extends ClassLoader {
044:
045: private CoreFactory coreFactory;
046:
047: private Environment environment;
048:
049: private Factory factory;
050:
051: private ProcessingManager processing;
052:
053: private File sourcePath;
054:
055: /**
056: * Constructs a Spoon classloader.
057: */
058: public SpoonClassLoader() {
059: super ();
060: }
061:
062: /**
063: * Constructs a Spoon classloader within the context of a given parent
064: * classloader.
065: */
066: public SpoonClassLoader(ClassLoader parent) {
067: super (parent);
068: }
069:
070: private Class<?> createClass(String qualifiedName) {
071: try {
072: // Process file
073: processJavaFile(qualifiedName);
074: return classcache.get(qualifiedName);
075: } catch (Exception e) {
076:
077: }
078: return null;
079: }
080:
081: /**
082: * Gets the associated (default) core factory.
083: */
084: public CoreFactory getCoreFactory() {
085: if (coreFactory == null) {
086: coreFactory = new DefaultCoreFactory();
087: }
088: return coreFactory;
089: }
090:
091: /**
092: * Gets the associated (standard) environment.
093: */
094: public Environment getEnvironment() {
095: if (environment == null) {
096: environment = new StandardEnvironment();
097: }
098: return environment;
099: }
100:
101: /**
102: * Gets the associated factory.
103: */
104: public Factory getFactory() {
105: if (factory == null) {
106: factory = new Factory(getCoreFactory(), getEnvironment());
107: }
108: return factory;
109: }
110:
111: /**
112: * Gets the processing manager.
113: */
114: public ProcessingManager getProcessingManager() {
115: if (processing == null) {
116: processing = new RuntimeProcessingManager(getFactory());
117: }
118: return processing;
119: }
120:
121: /**
122: * Gets the source path.
123: */
124: public File getSourcePath() {
125: if (sourcePath == null) {
126: sourcePath = new File("");
127: }
128: return sourcePath;
129: }
130:
131: private Map<String, Class<?>> classcache = new TreeMap<String, Class<?>>();
132:
133: /**
134: * Loads a given class from its name.
135: */
136: @Override
137: public Class<?> loadClass(String name)
138: throws ClassNotFoundException {
139:
140: // Look in cache
141: if (classcache.containsKey(name)) {
142: return classcache.get(name);
143: }
144:
145: // Try to gets from spoon factory
146: Class<?> clas = null;
147: clas = createClass(name);
148:
149: // Try to get in system class
150: if (clas == null) {
151: clas = findSystemClass(name);
152: }
153:
154: if (clas == null)
155: throw new ClassNotFoundException(name);
156: return clas;
157: }
158:
159: private void processJavaFile(String qualifiedName) throws Exception {
160: // Try to resolve in model
161: CtSimpleType<?> c = getFactory().Type().get(qualifiedName);
162:
163: // Try to resolve in source path
164: if (c == null) {
165: File f = resolve(qualifiedName);
166: if (f == null || !f.exists())
167: throw new ClassNotFoundException(qualifiedName);
168: Builder builder = getFactory().getBuilder();
169: builder.addInputSource(f);
170: builder.build();
171: c = getFactory().Type().get(qualifiedName);
172: }
173:
174: // not resolved
175: if (c == null)
176: throw new ClassNotFoundException(qualifiedName);
177: // Processing it
178: getProcessingManager().process(c);
179:
180: // Printing it
181: DefaultJavaPrettyPrinter printer = new DefaultJavaPrettyPrinter(
182: getEnvironment());
183: printer.scan(c);
184:
185: String[] tmp = c.getQualifiedName().split("[.]");
186: char[][] pack = new char[tmp.length - 1][];
187:
188: for (int i = 0; i < tmp.length - 1; i++) {
189: pack[i] = tmp[i].toCharArray();
190: }
191:
192: spoon.support.util.BasicCompilationUnit unit = new spoon.support.util.BasicCompilationUnit(
193: printer.toString().toCharArray(), pack, c
194: .getSimpleName()
195: + ".java");
196:
197: JDTCompiler comp = new JDTCompiler();
198: comp.compile(new ICompilationUnit[] { unit });
199:
200: for (ClassFile f : comp.getClassFiles()) {
201: String name = new String(f.fileName()).replace('/', '.');
202: Class<?> cl = defineClass(name, f.getBytes(), 0, f
203: .getBytes().length);
204: classcache.put(name, cl);
205: }
206:
207: }
208:
209: private File resolve(String qualifiedName) {
210: File current = sourcePath;
211: String[] path = qualifiedName.split("[.]");
212: for (String p : path) {
213: for (File f : current.listFiles()) {
214: if (f.getName().equals(p)
215: || f.getName().equals(p + ".java")) {
216: current = f;
217: continue;
218: }
219: }
220: }
221: if (!current.isDirectory())
222: return current;
223: return null;
224: }
225:
226: /**
227: * Sets the core factory.
228: */
229: public void setCoreFactory(CoreFactory coreFactory) {
230: this .coreFactory = coreFactory;
231: }
232:
233: /**
234: * Sets the environment.
235: */
236: public void setEnvironment(Environment environment) {
237: this .environment = environment;
238: }
239:
240: /**
241: * Sets the factory.
242: */
243: public void setFactory(Factory factory) {
244: this .factory = factory;
245: }
246:
247: /**
248: * Sets the used processing manager.
249: */
250: public void setProcessingManager(ProcessingManager processing) {
251: this .processing = processing;
252: }
253:
254: /**
255: * Sets the source path.
256: */
257: public void setSourcePath(File sourcePath) {
258: this.sourcePath = sourcePath;
259: }
260:
261: }
|