/* 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 2012 Samuel Marshall. */ package leafchat.startup; import java.io.*; import java.nio.channels.FileLock; import javax.swing.*; import util.*; import leafchat.core.*; import leafchat.core.api.*; /** First class that is loaded by the StartupClassLoader */ public class StartupHandler { private static boolean doneInit; protected SplashScreen ss; private SystemLogSingleton log; protected void classloaderInit(PluginManager pm) { ((StartupClassLoader)(getClass().getClassLoader())).setAPIClassLocator(pm); } protected void pluginInit(PluginManager pm) throws GeneralException { pm.init(ss); } /** * Sends REQUESTSHUTDOWN. * @return True if it's ok to shutdown */ public static boolean sendRequestShutdownMsg() { SystemStateMsg request=new SystemStateMsg(SystemStateMsg.REQUESTSHUTDOWN); try { MessageManager.get().externalDispatch(SystemStateMsg.class, request,false); MessageManager.get().flush(); } catch(Throwable t) { ErrorMsg.report("Error when requesting shutdown",t); } return !request.isStopped(); } /** * Sends SHUTDOWN. * @param exitAfterwards If true, exits as soon as messages finish */ public static void sendShutdownMsg(boolean exitAfterwards) { try { MessageManager.get().externalDispatch(SystemStateMsg.class, new SystemStateMsg(SystemStateMsg.SHUTDOWN),false); MessageManager.get().flush(); } catch(Throwable t) { ErrorMsg.report("Error when shutting down",t); } // Exit once the messages have finished if(exitAfterwards) System.exit(0); } static void initStatics(boolean ideStartup) { // Do static init if(doneInit) return; doneInit=true; StartupClassLoader.setIdeStartup(ideStartup); PlatformUtils.setUserFolder("leafChat"); TimeUtils.setErrorHandler(new ErrorHandler() { @Override public void reportError(Throwable t) { ErrorMsg.report( "An error occurred inside a timed method",t); } }); } private MinuteMsgOwner minutes; /** Just used to stop you running two copies at once. Held open for duration of run. */ private static RandomAccessFile lockFile; private static FileLock lock; /** * Initialise app. */ public StartupHandler() { initStatics(false); // Prevent multiple runs by same user try { lockFile=new RandomAccessFile( new File(PlatformUtils.getUserFolder(),"lockfile"),"rw"); lock=lockFile.getChannel().tryLock(); if(lock==null) { JOptionPane.showMessageDialog(null, "You can only run one copy of leafChat at a time.", "Already running",JOptionPane.INFORMATION_MESSAGE); System.exit(0); } } catch(IOException e) { handleError(e); } // Get plugin manager PluginManager pm=PluginManager.get(); // Tell the classloader to search plugin APIs as well classloaderInit(pm); // Set L&F try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch(Exception t) { handleError(t); } // Create splash screen try { ss=new SplashScreen(); } catch(IOException t) { handleError(t); } // Init Mac platform support if(PlatformUtils.isMac()) { // Try using the new version first try { Class.forName("com.apple.eawt.QuitHandler"); Class.forName("leafchat.startup.MacPlatformNew"); } catch(ClassNotFoundException t) { // Okay, now use the new version try { Class.forName("leafchat.startup.MacPlatformOld"); } catch(ClassNotFoundException t2) { handleError(t2); } } } // Set up system-provided singletons etc. try { log=new SystemLogSingleton(); SingletonManager.get().add(SystemLog.class,log); SingletonManager.get().add(PluginList.class,PluginManager.get()); MessageManager.get().registerOwner(new ErrorMsgOwner()); MessageManager.get().registerOwner(new SystemStateMsgOwner()); minutes=new MinuteMsgOwner(); MessageManager.get().registerOwner(minutes); MessageManager.get().requestMessages(SystemStateMsg.class,this,null, Msg.PRIORITY_LAST); MessageManager.get().requestMessages(SystemStateMsg.class,new SplashCloser(),null, Msg.PRIORITY_NORMAL); MessageManager.get().requestMessages(ErrorMsg.class,this,null, Msg.PRIORITY_LAST); } catch(Throwable t) { handleError(t); } // Load all plugins try { pluginInit(pm); } catch(Throwable t) { handleError(t); } ss.setText("Loaded, starting system..."); try { MessageManager.get().externalDispatch(SystemStateMsg.class, new SystemStateMsg(SystemStateMsg.PLUGINSLOADED), false); } catch(Throwable t) { handleError(t); } } /** * Class that closes splash screen. */ public class SplashCloser { /** * Message: System state message (close splash when UIREADY). * @param msg Message * @throws GeneralException */ public void msg(SystemStateMsg msg) throws GeneralException { if(msg.getType() == SystemStateMsg.UIREADY || msg.getType() == SystemStateMsg.LICENSEDIALOG) { // Get rid of splash screen and remove request ss.dispose(); MessageManager.get().unrequestMessages(SystemStateMsg.class,this,PluginContext.ALLREQUESTS); } } } private void handleError(Throwable t) { if(log!=null) { log.log(null,"Error on startup",t); } else { t.printStackTrace(); try { PrintWriter pw=new PrintWriter(new OutputStreamWriter( new FileOutputStream(new File(PlatformUtils.getUserFolder(),SystemLogSingleton.SYSTEMLOG)),"UTF-8")); t.printStackTrace(pw); pw.close(); } catch(Throwable t2) { System.err.println("Unable to save error"); } } JOptionPane.showMessageDialog(null, "An error has occurred. Logged in: "+new File(PlatformUtils.getUserFolder(),SystemLogSingleton.SYSTEMLOG).getPath(), "Error on startup",JOptionPane.ERROR_MESSAGE); System.exit(0); } /** * Message: System state. * @param msg Message * @throws GeneralException */ public void msg(SystemStateMsg msg) throws GeneralException { if(msg.getType()==SystemStateMsg.SHUTDOWN) { PluginManager.get().close(); ((SystemLogSingleton)(SingletonManager.get().get(SystemLog.class))).close(); System.exit(0); } if(msg.getType()==SystemStateMsg.UIREADY) { minutes.setUIReady(); } } @Override public String toString() { return "Startup handler"; } /** * Message: Error message (logs it to SystemLog). * @param msg Message * @throws GeneralException */ public void msg(ErrorMsg msg) throws GeneralException { if(msg.isHandled()) return; msg.markHandled(); (SingletonManager.get().get(SystemLog.class)).log( this,"Error: "+msg.getMessage(),msg.getException()); } }