/*
OrpheusMS: MapleStory Private Server based on OdinMS
Copyright (C) 2012 Aaron Weiss <aaron@deviant-core.net>
Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package client.command.external;
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import tools.MapleLogger;
/**
* @author Aaron Weiss
*/
public class CommandLoader {
private static CommandLoader instance;
private static boolean initialized = false;
protected AbstractCommandProcessor commandProcessor;
protected final ArrayList<Class<? extends Commands>> commands = new ArrayList<Class<? extends Commands>>();
public boolean loadCommands(String file) throws FileNotFoundException, CommandLoaderException {
return this.loadCommands(new File(file));
}
public boolean loadCommands(String file, boolean ignoreIncorrectFiles) throws FileNotFoundException, CommandLoaderException {
return this.loadCommands(new File(file), ignoreIncorrectFiles);
}
public boolean loadCommands(File file) throws FileNotFoundException, CommandLoaderException {
return this.loadCommands(file, true);
}
public boolean loadCommands(File file, boolean ignoreIncorrectFiles) throws FileNotFoundException, CommandLoaderException {
return this.load(file, ignoreIncorrectFiles, 1);
}
public boolean loadCommandProcessor(String file) throws FileNotFoundException, CommandLoaderException {
return this.loadCommandProcessor(new File(file));
}
public boolean loadCommandProcessor(String file, boolean ignoreIncorrectFiles) throws FileNotFoundException, CommandLoaderException {
return this.loadCommandProcessor(new File(file), ignoreIncorrectFiles);
}
public boolean loadCommandProcessor(File file) throws FileNotFoundException, CommandLoaderException {
return this.loadCommandProcessor(file, true);
}
public boolean loadCommandProcessor(File file, boolean ignoreIncorrectFiles) throws FileNotFoundException, CommandLoaderException {
return this.load(file, ignoreIncorrectFiles, 2);
}
public boolean load(String file) throws FileNotFoundException, CommandLoaderException {
return this.load(new File(file));
}
public boolean load(String file, boolean ignoreIncorrectFiles) throws FileNotFoundException, CommandLoaderException {
return this.load(new File(file), ignoreIncorrectFiles);
}
public boolean load(File file) throws FileNotFoundException, CommandLoaderException {
return this.load(file, true);
}
public boolean load(File file, boolean ignoreIncorrectFiles) throws FileNotFoundException, CommandLoaderException {
return this.load(file, true, 0);
}
protected boolean load(File file, boolean ignoreIncorrectFiles, int loadType) throws FileNotFoundException, CommandLoaderException {
if (!file.exists()) {
throw new FileNotFoundException("CommandLoader: Could not find file: " + file.getName());
} else if (file.isDirectory()) {
boolean ret = true;
for (File f : file.listFiles()) {
ret = ret & load(f, ignoreIncorrectFiles, loadType);
}
} else if (file.isFile()) {
if (file.getName().endsWith("jar")) {
try {
JarFile jf = new JarFile(file);
if (loadType == 0) {
initialized = (loadCommands(jf) && loadCommandProcessor(jf)) || initialized;
return initialized;
} else if (loadType == 1) {
initialized = loadCommands(jf) || initialized;
return initialized;
} else if (loadType == 2) {
initialized = loadCommandProcessor(jf) || initialized;
return initialized;
} else {
throw new CommandLoaderException(4, "CommandLoader: Invalid loadType.");
}
} catch (NoSuchMethodException ex) {
MapleLogger.print(MapleLogger.EXCEPTION_CAUGHT, ex);
throw new CommandLoaderException(2, "CommandLoader: Constructor missing from AbstractCommandProcessor.");
} catch (CommandLoaderException ex) { // because otherwise the part after would be huge...
throw new CommandLoaderException(ex.getIdentifier(), ex.getMessage()); // throw 'er up
} catch (Exception ex) {
MapleLogger.print(MapleLogger.EXCEPTION_CAUGHT, ex);
throw new CommandLoaderException(-1, "CommandLoader: Unknown error occurred while loading: " + file.getName());
}
} else if (!ignoreIncorrectFiles) {
throw new CommandLoaderException(1, "CommandLoader: File is not a jar: " + file.getName());
}
}
return false;
}
protected boolean loadCommands(JarFile jarFile) {
Enumeration<JarEntry> e = jarFile.entries();
while (e.hasMoreElements()) {
try {
JarEntry je = e.nextElement();
if (je.getName().endsWith(".class") && !je.isDirectory() && !je.getName().contains("$")) {
String classPath = je.getName().substring(0, je.getName().lastIndexOf(".class"));
String className = classPath.replace('/', '.');
Class<?> jarClass = Class.forName(className);
Class<? extends Commands> cmdClass = jarClass.asSubclass(Commands.class);
commands.add(cmdClass);
}
} catch (ClassNotFoundException ex) {
MapleLogger.print(MapleLogger.EXCEPTION_CAUGHT, ex); // something stupid happened.
} catch (ClassCastException ex) {
continue; // don't worry about it.
}
}
return true;
}
protected boolean loadCommandProcessor(JarFile jarFile) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, CommandLoaderException {
Enumeration<JarEntry> e = jarFile.entries();
while (e.hasMoreElements()) {
try {
JarEntry je = e.nextElement();
if (je.getName().endsWith(".class") && !je.isDirectory() && !je.getName().contains("$")) {
String classPath = je.getName().substring(0, je.getName().lastIndexOf(".class"));
String className = classPath.replace('/', '.');
Class<?> jarClass = Class.forName(className);
Class<? extends AbstractCommandProcessor> cpClass = jarClass.asSubclass(AbstractCommandProcessor.class);
Constructor<? extends AbstractCommandProcessor> cpConstructor = cpClass.getConstructor();
commandProcessor = cpConstructor.newInstance();
}
} catch (ClassNotFoundException ex) {
MapleLogger.print(MapleLogger.EXCEPTION_CAUGHT, ex); // something stupid happened.
} catch (ClassCastException ex) {
continue; // don't worry about it.
}
}
if (commandProcessor == null) throw new CommandLoaderException(3, "CommandLoader: CommandProcessor not found.");
return (commandProcessor != null);
}
public void clear() {
commandProcessor = null;
commands.clear();
System.gc();
}
public AbstractCommandProcessor getCommandProcessor() {
return commandProcessor;
}
public ArrayList<Class<? extends Commands>> getCommands() {
return commands;
}
public static CommandLoader getInstance() {
if (instance == null) instance = new CommandLoader();
return instance;
}
public static boolean isInitialized() {
return initialized;
}
public static void clean() {
instance.clear();
instance = null;
initialized = false;
System.gc();
}
}