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}