/* * This file is part of aion-emu <aion-emu.com>. * * aion-emu is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * aion-emu is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with aion-emu. If not, see <http://www.gnu.org/licenses/>. */ package com.aionemu.commons.scripting.impl.javacompiler; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.tools.DiagnosticListener; import javax.tools.FileObject; import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaCompiler; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.StandardLocation; import javax.tools.JavaFileObject.Kind; import com.aionemu.commons.scripting.ScriptClassLoader; /** * This class extends manages loaded classes. It is also responsible for tricking compiler. Unfortunally compiler doen't * work with classloaders, so we have to pass class data manually for each compilation. * * @author SoulKeeper */ public class ClassFileManager extends ForwardingJavaFileManager<JavaFileManager> { /** * This map contains classes compiled for this classloader */ private final Map<String, BinaryClass> compiledClasses = new HashMap<String, BinaryClass>(); /** * Classloader that will be used to load compiled classes */ protected ScriptClassLoaderImpl loader; /** * Parent classloader for loader */ protected ScriptClassLoader parentClassLoader; /** * Creates new ClassFileManager. * * @param compiler * that will be used * @param listener * class that will report compilation errors */ public ClassFileManager(JavaCompiler compiler, DiagnosticListener<? super JavaFileObject> listener) { super(compiler.getStandardFileManager(listener, null, null)); } /** * Returns JavaFileObject that will be used to write class data into it by compier * * @param location * not used * @param className * JavaFileObject will have this className * @param kind * not used * @param sibling * not used * @return JavaFileObject that will be uesd to store compiled class data * @throws IOException * never thrown */ @Override public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException { BinaryClass co = new BinaryClass(className); compiledClasses.put(className, co); return co; } /** * Returns classloaded of this ClassFileManager. If not exists, creates new * * @param location * not used * @return classLoader of this ClassFileManager */ @Override public synchronized ScriptClassLoaderImpl getClassLoader(Location location) { if(loader == null) { if(parentClassLoader != null) { loader = new ScriptClassLoaderImpl(this, parentClassLoader); } else { loader = new ScriptClassLoaderImpl(this); } } return loader; } /** * Sets paraentClassLoader for this classLoader * * @param classLoader * parent class loader */ public void setParentClassLoader(ScriptClassLoader classLoader) { this.parentClassLoader = classLoader; } /** * Adds library file. Library file must be a .jar archieve * * @param file * link to jar archieve * @throws IOException * if something goes wrong */ public void addLibrary(File file) throws IOException { ScriptClassLoaderImpl classLoader = getClassLoader(null); classLoader.addLibrary(file); } /** * Adds list of files as libraries. Files must be jar archieves * * @param files * list of jar archives * @throws IOException * if some5thing goes wrong */ public void addLibraries(Iterable<File> files) throws IOException { for(File f : files) { addLibrary(f); } } /** * Returns list of classes that were compiled by conpiler related to this ClassFileManager * * @return list of classes */ public Map<String, BinaryClass> getCompiledClasses() { return compiledClasses; } /** * This method overrides class resolving procedure for compiler. It uses classloaders to resolve classes that * compiler may need during compilation. * * Compiler by itself can't detect them. So we have to use this hack here. * * Hack is used only if compiler requests for classes in classpath. * * @param location * Location to search classes * @param packageName * package to scan for classes * @param kinds * FileTypes to search * @param recurse * not used * @return list of requered files * @throws IOException * if something foes wrong */ @Override public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) throws IOException { Iterable<JavaFileObject> objects = super.list(location, packageName, kinds, recurse); if(StandardLocation.CLASS_PATH.equals(location) && kinds.contains(Kind.CLASS)) { List<JavaFileObject> temp = new ArrayList<JavaFileObject>(); for(JavaFileObject object : objects) { temp.add(object); } temp.addAll(loader.getClassesForPackage(packageName)); objects = temp; } return objects; } }