001    /*
002     * Created on Dec 01, 2008
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
005     * the License. You may obtain a copy of the License at
006     *
007     * http://www.apache.org/licenses/LICENSE-2.0
008     *
009     * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
010     * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
011     * specific language governing permissions and limitations under the License.
012     *
013     * Copyright @2008-2010 the original author or authors.
014     */
015    package org.fest.swing.edt;
016    
017    import static org.fest.reflect.core.Reflection.staticMethod;
018    
019    import javax.swing.*;
020    
021    import org.fest.swing.exception.EdtViolationException;
022    
023    /**
024     * <p>
025     * Fails a test when a Event Dispatch Thread rule violation is detected.<br/>
026     * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How to Use Threads</a> for more info
027     * </p>
028     *
029     * @author Alex Ruiz
030     */
031    public class FailOnThreadViolationRepaintManager extends CheckThreadViolationRepaintManager {
032    
033      /**
034       * Creates a new <code>{@link FailOnThreadViolationRepaintManager}</code> and sets it as the current repaint manager.
035       * <p>
036       * On Sun JVMs, this method will install the new repaint manager the first time only. Once installed, subsequent calls
037       * to this method will not install new repaint managers. This optimization may not work on non-Sun JVMs, since we use
038       * reflection to check if a {@code CheckThreadViolationRepaintManager} is already installed.
039       * </p>
040       * @return the created (and installed) repaint manager.
041       * @see RepaintManager#setCurrentManager(RepaintManager)
042       */
043      public static FailOnThreadViolationRepaintManager install() {
044        Object m = currentRepaintManager();
045        if (m instanceof FailOnThreadViolationRepaintManager) return (FailOnThreadViolationRepaintManager)m;
046        return installNew();
047      }
048    
049      private static Object currentRepaintManager() {
050        try {
051          return staticMethod("appContextGet").withReturnType(Object.class)
052                                              .withParameterTypes(Object.class)
053                                              .in(SwingUtilities.class)
054                                              .invoke(RepaintManager.class);
055        } catch (RuntimeException e) {
056          return null;
057        }
058      }
059    
060      private static FailOnThreadViolationRepaintManager installNew() {
061        FailOnThreadViolationRepaintManager m = new FailOnThreadViolationRepaintManager();
062        setCurrentManager(m);
063        return m;
064      }
065    
066      public FailOnThreadViolationRepaintManager() {}
067    
068      public FailOnThreadViolationRepaintManager(boolean completeCheck) {
069        super(completeCheck);
070      }
071    
072      /**
073       * Throws a <code>{@link EdtViolationException}</code> when a EDT access violation is found.
074       * @param c the component involved in the EDT violation.
075       * @param stackTraceElements stack trace elements to be set to the thrown exception.
076       * @throws EdtViolationException when a EDT access violation is found.
077       */
078      @Override void violationFound(JComponent c, StackTraceElement[] stackTraceElements) {
079        EdtViolationException e = new EdtViolationException("EDT violation detected");
080        if (stackTraceElements != null) e.setStackTrace(stackTraceElements);
081        throw e;
082      }
083    }