package PluginLoader.Implementation; import AgentSystemPluginAPI.Contract.IAgentSystem; import AgentSystemPluginAPI.Contract.IAgentSystemPluginDescriptor; import AgentSystemPluginAPI.Contract.TAgentSystemDescription; import AgentSystemPluginAPI.Services.IPluginServiceProvider; import EnvironmentPluginAPI.Exceptions.TechnicalException; import EnvironmentPluginAPI.Contract.IActionDescription; import EnvironmentPluginAPI.CustomNetworkMessages.IActionDescriptionMessage; import EnvironmentPluginAPI.CustomNetworkMessages.NetworkMessage; import NetworkAdapter.Interface.IClientNetworkAdapter; import NetworkAdapter.Messages.DefaultActionDescriptionMessage; import PluginLoader.Interface.Exceptions.PluginNotReadableException; import PluginLoader.Interface.IAgentSystemPluginLoader; import ZeroTypes.Settings.AppSettings; import ZeroTypes.Settings.SettingException; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * This class implements all logic affiliated with the loading of agent system plugins. */ public class AgentSystemPluginLoaderUseCase implements IAgentSystemPluginLoader { private final IClientNetworkAdapter clientNetworkAdapter; private Map<TAgentSystemDescription, File> aiPluginPaths; private PluginHelper pluginHelper; private Constructor customActionDescriptionMessage; private IAgentSystemPluginDescriptor loadedPlugin; private ClassLoader usedClassLoader; public AgentSystemPluginLoaderUseCase(IClientNetworkAdapter clientNetworkAdapter) throws TechnicalException, SettingException, PluginNotReadableException { this.clientNetworkAdapter = clientNetworkAdapter; pluginHelper = new PluginHelper(); listAvailableAgentSystemPlugins(); } public List<TAgentSystemDescription> listAvailableAgentSystemPlugins() throws TechnicalException, PluginNotReadableException, SettingException { pluginHelper = new PluginHelper(); aiPluginPaths = new Hashtable<TAgentSystemDescription, File>(); List<TAgentSystemDescription> result = new LinkedList<TAgentSystemDescription>(); // Load all plugins recursively from the directory specified in the config file. try { List<String> allJars = pluginHelper.findJarsRecursively(AppSettings.getString("agentSystemPluginDirectory")); for (String jarPath : allJars) { //look for the first class that abides the contract that is not the interface itself for (Class c : pluginHelper.listClassesFromJar(jarPath)) { if (IAgentSystemPluginDescriptor.class != c && IAgentSystemPluginDescriptor.class.isAssignableFrom(c)) { //save available AgentSystemDescriptor description and it's directory TAgentSystemDescription tmp = ((IAgentSystemPluginDescriptor) c.newInstance()).getDescription(); result.add(tmp); aiPluginPaths.put(tmp, new File(jarPath)); break; } } } } catch (InstantiationException e) { throw new TechnicalException("Unable to load Class from plugin. Reason: \n\n" + e); } catch (IllegalAccessException e) { throw new TechnicalException("Unable to load Class from plugin. Reason: \n\n" + e); } return result; } public void loadAgentSystemPlugin(TAgentSystemDescription agentSystem) throws TechnicalException, PluginNotReadableException { customActionDescriptionMessage = null; try { // Load all classes from the jar where this plugin is located Plugin plugin = pluginHelper.loadJar(aiPluginPaths.get(agentSystem).getPath()); //search for the first class that abides the contract that is not the interface itself for (Class c : plugin) { if (!IAgentSystemPluginDescriptor.class.equals(c) && IAgentSystemPluginDescriptor.class.isAssignableFrom(c)) { //save available AgentSystemDescriptor description and it's directory loadedPlugin = (IAgentSystemPluginDescriptor) c.newInstance(); continue; } if (!IActionDescriptionMessage.class.equals(c) && IActionDescriptionMessage.class.isAssignableFrom(c)) { //examine constructors customActionDescriptionMessage = pluginHelper.findSuitableConstructor(c, int.class, IActionDescription.class); if (customActionDescriptionMessage == null) { throw new PluginNotReadableException("A custom action description message was found, but didn't provide the needed constructor => (int clientId, A extends IActionDescription state).", aiPluginPaths.get(agentSystem).getPath()); } } } if (loadedPlugin != null) { clientNetworkAdapter.setContextClassLoader(plugin.getClassLoader()); usedClassLoader = plugin.getClassLoader(); } else { throw new PluginNotReadableException("Plugin didn't provide a descriptor: ", aiPluginPaths.get(agentSystem).getPath()); } } catch (InstantiationException e) { throw new TechnicalException("Unable to load Class from '" + aiPluginPaths.get(agentSystem) + "' Reason: \n\n" + e); } catch (IllegalAccessException e) { throw new TechnicalException("Unable to load Class from '" + aiPluginPaths.get(agentSystem) + "' Reason: \n\n" + e); } } @Override public ClassLoader getUsedClassLoader() { return usedClassLoader; } @Override public IAgentSystem createAgentSystemInstance(IPluginServiceProvider serviceProvider) throws TechnicalException { return loadedPlugin.getInstance(serviceProvider); } public File getAgentSystemPluginPath(TAgentSystemDescription agentSystemDescription) throws TechnicalException, PluginNotReadableException { if (aiPluginPaths == null) { throw new UnsupportedOperationException("protocol violated: listAvailableAgentSystems must be called before this method."); } return aiPluginPaths.get(agentSystemDescription).getParentFile(); } public NetworkMessage createActionDescriptionMessage(int clientId, IActionDescription actionDescription) { if (customActionDescriptionMessage != null) { try { //TODO: needs better exception handling return (NetworkMessage) customActionDescriptionMessage.newInstance(clientId, actionDescription); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } return new DefaultActionDescriptionMessage(0, actionDescription); } }