001/*
002 * Trident - A Multithreaded Server Alternative
003 * Copyright 2014 The TridentSDK Team
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package net.tridentsdk.server.plugin;
019
020import net.tridentsdk.event.Listener;
021import net.tridentsdk.plugin.PluginLoader;
022import net.tridentsdk.plugin.cmd.Command;
023import net.tridentsdk.registry.Registered;
024import net.tridentsdk.util.TridentLogger;
025
026import java.io.File;
027import java.lang.reflect.Field;
028import java.lang.reflect.Modifier;
029import java.net.MalformedURLException;
030import java.net.URL;
031import java.net.URLClassLoader;
032import java.util.Map;
033import java.util.concurrent.ConcurrentHashMap;
034
035public class PluginClassLoader extends URLClassLoader implements PluginLoader {
036    final Map<String, Class<?>> locallyLoaded = new ConcurrentHashMap<>();
037
038    PluginClassLoader(File pluginFile, ClassLoader loader) throws MalformedURLException {
039        super(new URL[]{pluginFile.toURI().toURL()}, loader);
040    }
041
042    @Override
043    public void link(Class<?> c) {
044        super.resolveClass(c);
045    }
046
047    @Override
048    public Class<?> defineClass(String name, byte[] source) {
049        return super.defineClass(name, source, 0, source.length);
050    }
051
052    @Override
053    public void putClass(Class<?> cls) {
054        locallyLoaded.put(cls.getName(), cls);
055    }
056
057    @Override
058    public void unloadClasses() {
059        for (Class<?> cls : locallyLoaded.values()) {
060            if (Listener.class.isAssignableFrom(cls)) {
061                Registered.events().unregister(cls.asSubclass(Listener.class));
062            }
063
064            if (Command.class.isAssignableFrom(cls)) {
065                Registered.commands().unregister(cls.asSubclass(Command.class));
066            }
067
068            for (Field field : cls.getDeclaredFields()) {
069                // Simply remove all the object references
070                // primitive types are OK
071                if (field.getType().isAssignableFrom(Object.class) && Modifier.isStatic(field.getModifiers())) {
072                    field.setAccessible(true);
073                    try {
074                        field.set(null, null);
075                    } catch (IllegalAccessException e) {
076                        TridentLogger.get().error(e);
077                    }
078                } // TODO instance held fields
079            }
080        }
081        locallyLoaded.clear();
082    }
083
084    public Map<String, Class<?>> loadedClasses() {
085        return locallyLoaded;
086    }
087}