/* This file is part of leafdigital leafChat. leafChat 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. leafChat 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 leafChat. If not, see <http://www.gnu.org/licenses/>. Copyright 2011 Samuel Marshall. */ package leafchat.core; import java.util.*; import leafchat.core.api.*; /** Context for a plugin */ public class PluginContextProvider implements PluginContext { /** Plugin this is context for */ private Plugin p; /** Registered message owners */ private List<MsgOwner> messageOwners = new LinkedList<MsgOwner>(); /** Requests for messages made by this plugin */ private List<MessageRequest> messageRequests = new LinkedList<MessageRequest>(); /** List of singletons owned by this plugin */ private List<SingletonRegistration> singletons = new LinkedList<SingletonRegistration>(); /** List of factories owned by this plugin */ private List<FactoryRegistration> factories = new LinkedList<FactoryRegistration>(); /** List of message classes owned by this plugin */ private List<Class<? extends Msg>> extraMessageClasses = new LinkedList<Class<? extends Msg>>(); /** * @param pmOwner PluginManager that created this * @param p Plugin for which this is a context */ public PluginContextProvider(PluginManager pmOwner,Plugin p) { this.p=p; log("Plugin init (for "+getPluginClassLoader()+")"); } @Override public void log(String sText) { log(sText,null); } @Override public void log(String sText,Throwable t) { SingletonManager.get().get(SystemLog.class).log( p,sText,t); } @Override public void logDebug(String text) { logDebug(text,null); } @Override public void logDebug(String text,Throwable t) { if(getPluginClassLoader()==null || getPluginClassLoader().getInfo().isDebug()) SingletonManager.get().get(SystemLog.class).log( p,text,t); } /** * @return Classloader for plugin */ PluginClassLoader getPluginClassLoader() { try { return (PluginClassLoader)p.getClass().getClassLoader(); } catch(ClassCastException cce) // Only for IDE startup { return null; } } /** * Closes the plugin and remove all its events etc. * @return List of any errors that happened during close */ public Throwable[] close() { log("Initiating close"); // Track all errors that occur during close, instead of letting them // interfere with the close process List<Throwable> errors = new LinkedList<Throwable>(); // Inform plugin it's being closed try { p.close(); } catch(Throwable t) { errors.add(t); } // Remove message classes synchronized(extraMessageClasses) { for(Class<? extends Msg> c : extraMessageClasses) { MessageManager.get().unregisterMessageClass(c); } } // Remove message owners synchronized(messageOwners) { for(Iterator<MsgOwner> i=messageOwners.iterator();i.hasNext();) { MsgOwner mo = i.next(); try { log("Removing message owner for: "+mo.getMessageClass().getName()); MessageManager.get().unregisterOwner(mo); } catch (Throwable t) { errors.add(t); } i.remove(); } } // Remove message requests synchronized(messageRequests) { for(Iterator<MessageRequest> i=messageRequests.iterator();i.hasNext();) { MessageRequest mr = i.next(); log("Removing message request: "+mr.cMessage.getName()); MessageManager.get().unrequestMessages(mr.cMessage,mr.oTarget,mr.iRequestID); i.remove(); } } // Remove singletons synchronized(singletons) { for(Iterator<SingletonRegistration> i=singletons.iterator();i.hasNext();) { SingletonRegistration sr = i.next(); try { log("Removing singleton for: "+sr.cInterface.getName()); SingletonManager.get().remove(sr.cInterface, sr.cInterface.cast(sr.s)); } catch(Throwable t) { errors.add(t); } } } // Remove factories synchronized(factories) { for(Iterator<FactoryRegistration> i=factories.iterator(); i.hasNext();) { FactoryRegistration fr = i.next(); try { FactoryManager.get().remove(fr.cInterface,fr.f); } catch(Throwable t) { errors.add(t); } } } // Close other bits try { PluginManager.get().firePluginUnload(p); } catch(Throwable t) { errors.add(t); } log("Close complete. Errors: " + errors.size()); return errors.toArray(new Throwable[errors.size()]); } @Override public void registerMessageOwner(MsgOwner mo) { log("Registering as message owner for: "+mo.getMessageClass().getName()); MessageManager.get().registerOwner(mo); synchronized(messageOwners) { messageOwners.add(mo); } } @Override public void registerExtraMessageClass(Class<? extends Msg> c) { MessageManager.get().registerMessageClass(c); synchronized(extraMessageClasses) { extraMessageClasses.add(c); } } @Override public int requestMessages(Class<? extends Msg> msgClass, Object oTarget, MessageFilter mf, int iPriority) { log("Requesting messages: "+msgClass.getName()); int iRequestID=MessageManager.get().requestMessages(msgClass,oTarget,mf, iPriority); synchronized(messageRequests) { MessageRequest mr=new MessageRequest(); mr.cMessage=msgClass; mr.oTarget=oTarget; mr.iRequestID=iRequestID; messageRequests.add(mr); } return iRequestID; } @Override public int requestMessages(Class<? extends Msg> cMessage, Object oTarget, int iPriority) { return requestMessages(cMessage,oTarget,null, iPriority); } @Override public int requestMessages(Class<? extends Msg> cMessage, Object oTarget) { return requestMessages(cMessage,oTarget,null,Msg.PRIORITY_NORMAL); } @Override public int requestMessages(Class<? extends Msg> cMessage, Object oTarget,MessageFilter mf) { return requestMessages(cMessage,oTarget,mf,Msg.PRIORITY_NORMAL); } @Override public void unrequestMessages(Class<? extends Msg> cMessage, Object oTarget, int iRequestID) { synchronized(messageRequests) { for(Iterator<MessageRequest> i=messageRequests.iterator(); i.hasNext(); ) { MessageRequest mr = i.next(); if( (iRequestID==ALLREQUESTS || mr.iRequestID==iRequestID) && (cMessage==null || mr.cMessage.equals(cMessage)) && mr.oTarget==oTarget) { log("Removing message request for: "+mr.cMessage.getName()); MessageManager.get().unrequestMessages(mr.cMessage,mr.oTarget,mr.iRequestID); i.remove(); } } } } @Override public boolean dispatchExternalMessage(Class<? extends Msg> cMessage, Msg m, boolean bImmediate) throws GeneralException { return MessageManager.get().externalDispatch(cMessage,m, true); } @Override public <C extends Singleton> void registerSingleton(Class<C> cInterface, C s) { log("Registering singleton for: "+cInterface.getName()); SingletonManager.get().add(cInterface,s); synchronized(singletons) { SingletonRegistration sr=new SingletonRegistration(); sr.cInterface=cInterface; sr.s=s; singletons.add(sr); } } @Override public void registerFactory(Class<? extends FactoryObject> cInterface, Factory f) { log("Registering factory for: "+cInterface.getName()); FactoryManager.get().add(cInterface,f); synchronized(factories) { FactoryRegistration fr=new FactoryRegistration(); fr.cInterface=cInterface; fr.f=f; factories.add(fr); } } @Override public<C extends Singleton> C getSingle(Class<C> cInterface) { return SingletonManager.get().get(cInterface); } @Override public Object getSingleton(Class<? extends Singleton> cInterface) { return SingletonManager.get().get(cInterface); } @Override public<C extends FactoryObject> C newFactoryObject(Class<C> cInterface) throws GeneralException { return FactoryManager.get().newInstance(cInterface); } @Override public Object newInstance(Class<? extends FactoryObject> cInterface) throws GeneralException { return FactoryManager.get().newInstance(cInterface); } @Override public void dispatchMsgToTarget(Msg m,Object oTarget) throws GeneralException { MessageManager.get().dispatchMessageToTarget(m,oTarget); } @Override public Plugin getPlugin() { return p; } @Override public void yield(Runnable r) { MessageManager.get().yield(r); } @Override public MessageInfo getMessageInfo(Class<? extends Msg> c) throws BugException { return MessageManager.get().getMessageInfo(c); } } class MessageRequest { Class<? extends Msg> cMessage; Object oTarget; int iRequestID; } class SingletonRegistration { Class<? extends Singleton> cInterface; Singleton s; } class FactoryRegistration { Class<? extends FactoryObject> cInterface; Factory f; }