/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo 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. * * OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.application; import java.awt.AWTEvent; import java.awt.HeadlessException; import java.awt.Image; import java.awt.Toolkit; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.AdvancedPrefs; import org.openflexo.Flexo; import org.openflexo.GeneralPreferences; import org.openflexo.br.view.JIRAIssueReportDialog; import org.openflexo.ch.DefaultHelpRetriever; import org.openflexo.components.ProgressWindow; import org.openflexo.drm.DocResourceManager; import org.openflexo.foundation.FlexoModelObject; import org.openflexo.foundation.action.InvalidParametersException; import org.openflexo.foundation.action.NotImplementedException; import org.openflexo.help.FlexoHelp; import org.openflexo.icon.IconLibrary; import org.openflexo.jedit.JEditTextArea; import org.openflexo.localization.FlexoLocalization; import org.openflexo.logging.FlexoLoggingManager; import org.openflexo.module.ModuleLoader; import org.openflexo.module.UserType; import org.openflexo.toolbox.ToolBox; import org.openflexo.utils.CancelException; import org.openflexo.utils.TooManyFailedAttemptException; import org.openflexo.view.FlexoDialog; import org.openflexo.view.FlexoFrame; import org.openflexo.view.controller.FlexoController; /** * Represents the current Flexo Application * * Contains only one public static method that should be invoked before to do anything else on GUI. * * NB: to be portable on other OS than MacOSX, dynamic instanciation of * * <pre> * com.apple.eawt.Application * </pre> * * must be performed here. * * @author sguerin */ public class FlexoApplication { protected static final Logger logger = Logger.getLogger(FlexoApplication.class.getPackage().getName()); private static boolean isInitialized = false; private static Object application; private static FlexoApplicationAdapter applicationAdapter; public static EventProcessor eventProcessor; private static byte[] mem = new byte[1024 * 1024]; public static void installEventQueue() { eventProcessor = new EventProcessor(); } public static void initialize(ModuleLoader moduleLoader) { if (isInitialized) { return; } isInitialized = true; JEditTextArea.DIALOG_FACTORY = FlexoDialog.DIALOG_FACTORY; try { if (ToolBox.getPLATFORM() == ToolBox.MACOS) { application = Class.forName("com.apple.eawt.Application").newInstance(); Method enablePrefMenu = application.getClass().getMethod("setEnabledPreferencesMenu", new Class[] { boolean.class }); enablePrefMenu.invoke(application, new Object[] { new Boolean(true) }); // ((com.apple.eawt.Application)application).setEnabledPreferencesMenu(true); Method enableAboutMenu = application.getClass().getMethod("setEnabledAboutMenu", new Class[] { boolean.class }); enableAboutMenu.invoke(application, new Object[] { new Boolean(true) }); // ((com.apple.eawt.Application)application).setDockIconImage(ModuleLoader.getUserType().getIconImage().getImage()); Method setDockIconImage = application.getClass().getMethod("setDockIconImage", new Class[] { Image.class }); setDockIconImage.invoke(application, new Object[] { IconLibrary.OPENFLEXO_NOTEXT_128.getImage() }); applicationAdapter = new FlexoApplicationAdapter(moduleLoader); Method addApplicationListener = application.getClass().getMethod("addApplicationListener", new Class[] { Class.forName("com.apple.eawt.ApplicationListener") }); addApplicationListener.invoke(application, new Object[] { applicationAdapter }); // ((com.apple.eawt.Application)application).addApplicationListener(applicationAdapter); } } catch (Exception e) { e.printStackTrace(); } FlexoHelp.configure(GeneralPreferences.getLanguage().getIdentifier(), UserType.getCurrentUserType().getIdentifier()); FlexoHelp.reloadHelpSet(); FlexoModelObject.setCurrentUserIdentifier(GeneralPreferences.getUserIdentifier());// Loads the preferences AdvancedPrefs.getEnableUndoManager(); // just load advanced prefs FlexoModelObject.setHelpRetriever(new DefaultHelpRetriever(DocResourceManager.instance())); // Thread myThread = new Thread(new FocusOwnerDisplayer()); // myThread.start(); } public static class EventProcessor extends java.awt.EventQueue { private EventPreprocessor _preprocessor = null; private boolean isReportingBug = false; private Vector<String> exceptions = new Vector<String>(); public EventPreprocessor getPreprocessor() { return _preprocessor; } public void setPreprocessor(EventPreprocessor preprocessor) { _preprocessor = preprocessor; } public EventProcessor() { Toolkit.getDefaultToolkit().getSystemEventQueue().push(this); } private synchronized boolean testAndSetIsReportingBug() { if (isReportingBug) { return true; } else { isReportingBug = true; return false; } } private synchronized void resetIsReportingBug() { isReportingBug = false; } @Override protected void dispatchEvent(AWTEvent e) { try { if (_preprocessor != null) { _preprocessor.preprocessEvent(e); } super.dispatchEvent(e); // if (e instanceof SunDropTargetEvent) { logger.info("dispatchEvent() "+e+" in "+e.getSource()); } /* * if (e instanceof KeyEvent) printFocusedComponent(); */ } catch (Throwable exception) { // logger.info("ProgressWindow.hasInstance()="+ProgressWindow.hasInstance()); if (ProgressWindow.hasInstance()) { ProgressWindow.hideProgressWindow(); } if (exception instanceof OutOfMemoryError) { if (mem != null) { mem = null; } } if (exception instanceof CancelException || exception.getCause() instanceof CancelException) { return; } if (exception instanceof TooManyFailedAttemptException || exception.getCause() instanceof TooManyFailedAttemptException) { FlexoController.showError(FlexoLocalization.localizedForKey("too_many_failed_attempt_to_authenticate_to_proxy")); return; } if (!isIgnorable(exception)) { // all uncaught awt thread exceptions will ultimately be // caught here if (exception instanceof Exception) { FlexoLoggingManager.instance().unhandledException((Exception) exception); } // FlexoLoggingManager.getMainLogger().unhandledException(exception); if (logger.isLoggable(Level.SEVERE)) { logger.log(Level.SEVERE, "Unexpected exception: " + exception.getClass().getName() + ":" + exception.getMessage(), exception); } String message = ""; try { if (exception instanceof InvalidParametersException) { message = "InvalidParametersException: " + exception.getMessage() + ". Edit a bug report ?"; } else if (exception instanceof NotImplementedException) { message = FlexoLocalization.localizedForKey("feature_not_implemented:_") + exception.getMessage() + " " + FlexoLocalization.localizedForKey("would_you_like_to_send_a_report"); } else { message = FlexoLocalization.localizedForKey("unexpected_exception_occured") + " " + FlexoLocalization.localizedForKey("would_you_like_to_send_a_report"); } } catch (RuntimeException e3) {// This catch is here in case the localization layer has crashed e3.printStackTrace(); if (exception instanceof InvalidParametersException) { message = "InvalidParametersException: " + exception.getMessage() + ". Edit a bug report ?"; } else if (exception instanceof NotImplementedException) { message = "Feature not implemented: " + exception.getMessage() + ". Edit a bug report ?"; } else { message = "Unexpected exception occured: " + exception.getClass().getName() + ". Edit a bug report ?"; } } if (exception instanceof Exception) { if (!testAndSetIsReportingBug()) { try { if (FlexoController.confirm(message)) { FlexoFrame frame = FlexoFrame.getActiveFrame(false); JIRAIssueReportDialog.newBugReport((Exception) exception, frame != null ? frame.getModule() : null, frame != null ? frame.getController().getProject() : null); } } catch (HeadlessException e1) { e1.printStackTrace(); } catch (Exception e2) { e2.printStackTrace(); } finally { resetIsReportingBug(); } } else { if (logger.isLoggable(Level.SEVERE)) { logger.severe("Already reporting a bug. Ignoring another exception: " + exception); } } } } else { if (logger.isLoggable(Level.INFO)) { logger.info("Ignoring exception: " + exception); } } } } // Usefull to debug across AWT event queue /* * public void postEvent(AWTEvent e) { super.postEvent(e); if ((e instanceof ComponentEvent) && (e.getID() == * ComponentEvent.COMPONENT_SHOWN)) { logger.info("postEvent: "+e); } } */ private void printFocusedComponent() { try { Class c = Class.forName("org.openflexo.wkf.view.WKFFrame"); Field f = c.getField("frame"); Object o = f.get(null); c = o.getClass(); Method m = c.getMethod("printFocusedComponent", new Class[] {}); m.invoke(o, new Object[] {}); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Determines if exception can be ignored. */ private boolean isIgnorable(Throwable exception) { if (Flexo.isDemoMode()) { return true; } StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); exception.printStackTrace(pw); pw.flush(); String bug = sw.toString(); return isIgnorable(exception, bug); } /** * Determines if the message can be ignored. (Note: this code comes from Gnutella). */ private boolean isIgnorable(Throwable bug, String msg) { // OutOfMemory error should definitely not be ignored. First, they can give a hint on where there is a problem. Secondly, // if we ran out of memory, Flexo will not work anymore and bogus behaviour will appear everywhere. So definitely, no, we don't // ignore. if (bug instanceof OutOfMemoryError) { return false; } // We are going to store 100 exceptions (although it is not going to hold a lot) // and we ignore the ones with identical stacktraces if (!exceptions.contains(msg)) { exceptions.add(msg); if (exceptions.size() > 100) { exceptions.remove(100); } } else { return true; } // no bug? kinda impossible, but shouldn't report. if (msg == null) { return true; } // if the bug came from the FileChooser (Windows or Metal) // or the AquaDirectoryModel, ignore it. if (bug instanceof NullPointerException && (msg.indexOf("MetalFileChooserUI") != -1 || msg.indexOf("WindowsFileChooserUI") != -1 || msg .indexOf("AquaDirectoryModel") != -1)) { return true; } // See Bug DS-016 if (bug instanceof ArrayIndexOutOfBoundsException && msg.indexOf("SunDisplayChanger") != -1) { return true; } // An other swing known bug ! if (bug instanceof ClassCastException && msg.indexOf("apple.laf.AquaImageFactory.drawTextBorder") != -1) { return true; } // if we're not somewhere in the bug, ignore it. // no need for us to debug sun's internal errors. if (msg.indexOf("org.openflexo") == -1) { if (logger.isLoggable(Level.WARNING)) { logger.warning("Internal JVM Exception occured. See logs for details."); } bug.printStackTrace(); return true; } else { // Same for exceptions where denali appear only as // org.openflexo.application.FlexoApplication$EventProcessor.dispatchEvent() int index = msg.indexOf("org.openflexo"); String searchedString = "org.openflexo.application.FlexoApplication$EventProcessor.dispatchEvent"; if (msg.substring(index, index + searchedString.length()).equals(searchedString)) { if (msg.indexOf("org.openflexo", index + 1) == -1) { // The only occurence of org.openflexo was in searchedString if (logger.isLoggable(Level.WARNING)) { logger.warning("Internal JVM Exception occured. See logs for details."); } bug.printStackTrace(); return true; } } } return false; } } public interface EventPreprocessor { public void preprocessEvent(AWTEvent e); } }