/*
* 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;
}
}