/**
* Copyright 2013 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/
package com.jogamp.opengl.test.bugs;
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.atomic.AtomicInteger;
@SuppressWarnings("serial")
public class DemoBug910ExtendedAWTAppletLifecycleCheck extends Applet {
private static String currentThreadName() { return "["+Thread.currentThread().getName()+", isAWT-EDT "+EventQueue.isDispatchThread()+"]"; }
private static void invoke(final boolean wait, final Runnable r) {
if(EventQueue.isDispatchThread()) {
r.run();
} else {
try {
if(wait) {
EventQueue.invokeAndWait(r);
} else {
EventQueue.invokeLater(r);
}
} catch (final InvocationTargetException e) {
throw new RuntimeException(e.getTargetException());
} catch (final InterruptedException e) {
throw new RuntimeException(e);
}
}
}
private static final String comp2Str(final Component c) {
return c.getClass().getSimpleName()+"[visible "+c.isVisible()+", showing "+c.isShowing()+", valid "+c.isValid()+
", displayable "+c.isDisplayable()+", "+c.getX()+"/"+c.getY()+" "+c.getWidth()+"x"+c.getHeight()+"]";
}
private void println(final String msg) {
System.err.println(msg);
}
private final void checkComponentState(final String msg, final boolean expIsContained, final int expAddNotifyCount, final int expRemoveNotifyCount) {
final int compCount = getComponentCount();
final Component c = 1 <= compCount ? getComponent(0) : null;
final String clazzName = null != c ? c.getName() : "n/a";
final boolean isContained = c == myCanvas;
final String okS = ( expIsContained == isContained &&
expAddNotifyCount == myCanvas.addNotifyCount &&
expRemoveNotifyCount == myCanvas.removeNotifyCount ) ? "OK" : "ERROR";
println("Component-State @ "+msg+": "+okS+
", contained[exp "+expIsContained+", has "+isContained+"]"+(expIsContained!=isContained?"*":"")+
", addNotify[exp "+expAddNotifyCount+", has "+myCanvas.addNotifyCount+"]"+(expAddNotifyCount!=myCanvas.addNotifyCount?"*":"")+
", removeNotify[exp "+expRemoveNotifyCount+", has "+myCanvas.removeNotifyCount+"]"+(expRemoveNotifyCount!=myCanvas.removeNotifyCount?"*":"")+
", compCount "+compCount+", compClazz "+clazzName);
}
AtomicInteger initCount = new AtomicInteger(0);
AtomicInteger startCount = new AtomicInteger(0);
AtomicInteger stopCount = new AtomicInteger(0);
AtomicInteger destroyCount = new AtomicInteger(0);
private final void checkAppletState(final String msg, final boolean expIsActive,
final int expInitCount, final int expStartCount, final int expStopCount, final boolean startStopCountEquals, final int expDestroyCount) {
final boolean isActive = this.isActive();
final String okS = ( expInitCount == initCount.get() &&
expIsActive == isActive &&
expStartCount == startCount.get() &&
expStopCount == stopCount.get() &&
expDestroyCount == destroyCount.get() &&
( !startStopCountEquals || startCount == stopCount ) ) ? "OK" : "ERROR";
println("Applet-State @ "+msg+": "+okS+
", active[exp "+expIsActive+", has "+isActive+"]"+(expIsActive!=isActive?"*":"")+
", init[exp "+expInitCount+", has "+initCount+"]"+(expInitCount!=initCount.get()?"*":"")+
", start[exp "+expStartCount+", has "+startCount+"]"+(expStartCount!=startCount.get()?"*":"")+
", stop[exp "+expStopCount+", has "+stopCount+"]"+(expStopCount!=stopCount.get()?"*":"")+
", start==stop[exp "+startStopCountEquals+", start "+startCount+", stop "+stopCount+"]"+(( startStopCountEquals && startCount != stopCount )?"*":"")+
", destroy[exp "+expDestroyCount+", has "+destroyCount+"]"+(expDestroyCount!=destroyCount.get()?"*":""));
}
private class MyCanvas extends Canvas {
int addNotifyCount = 0;
int removeNotifyCount = 0;
int paintCount = 0;
MyCanvas() {
setBackground( new Color( 200, 200, 255 ) );
}
public String toString() {
return comp2Str(this)+", add/remove[addNotify "+addNotifyCount+", removeCount "+removeNotifyCount+"]";
}
@Override
public void addNotify() {
addNotifyCount++;
println("Applet.Canvas.addNotify() - "+currentThreadName());
if( !EventQueue.isDispatchThread() ) {
println("Applet.Canvas.addNotify() ERROR: Not on AWT-EDT");
}
// Thread.dumpStack();
super.addNotify();
println("Applet.Canvas.addNotify(): "+this);
}
@Override
public void removeNotify() {
removeNotifyCount++;
println("Applet.Canvas.removeNotify() - "+currentThreadName());
println("Applet.Canvas.removeNotify(): "+this);
if( !EventQueue.isDispatchThread() ) {
println("Applet.Canvas.removeNotify() ERROR: Not on AWT-EDT");
}
// Thread.dumpStack();
super.removeNotify();
}
@Override
public void paint(final Graphics g) {
super.paint(g);
paintCount++;
final int width = getWidth();
final int height = getHeight();
final String msg = "The payload Canvas. Paint "+width+"x"+height+" #"+paintCount;
g.setColor(Color.black);
g.drawString(msg, 64, 64);
}
}
MyCanvas myCanvas = null;
@Override
public void init() {
final java.awt.Dimension aSize = getSize();
println("Applet.init() START - applet.size "+aSize+" - "+currentThreadName());
initCount.incrementAndGet();
checkAppletState("init", false /* expIsActive */, 1 /* expInitCount */,
0 /* expStartCount */, 0 /* expStopCount */, true /* startStopCountEquals */,
0 /* expDestroyCount */);
invoke(true, new Runnable() {
public void run() {
setLayout(new BorderLayout());
myCanvas = new MyCanvas();
println("Applet.init(): self "+comp2Str(DemoBug910ExtendedAWTAppletLifecycleCheck.this));
println("Applet.init(): canvas "+comp2Str(myCanvas));
checkComponentState("init-add.pre", false, 0, 0);
add(myCanvas, BorderLayout.CENTER);
validate();
checkComponentState("init-add.post", true, 1, 0);
println("Applet.init(): canvas "+comp2Str(myCanvas));
} } );
println("Applet.init() END - "+currentThreadName());
}
@Override
public void start() {
println("Applet.start() START (isVisible "+isVisible()+", isDisplayable "+isDisplayable()+") - "+currentThreadName());
startCount.incrementAndGet();
checkAppletState("start", true /* expIsActive */, 1 /* expInitCount */,
startCount.get() /* expStartCount */, startCount.get()-1 /* expStopCount */, false /* startStopCountEquals */,
0 /* expDestroyCount */);
invoke(true, new Runnable() {
public void run() {
checkComponentState("start-visible.pre", true, 1, 0);
if( null != myCanvas ) {
myCanvas.setFocusable(true);
myCanvas.requestFocus();
}
checkComponentState("start-visible.post", true, 1, 0);
println("Applet.start(): self "+comp2Str(DemoBug910ExtendedAWTAppletLifecycleCheck.this));
println("Applet.start(): canvas "+comp2Str(myCanvas));
}
});
println("Applet.start() END - "+currentThreadName());
}
@Override
public void stop() {
println("Applet.stop() START - "+currentThreadName());
stopCount.incrementAndGet();
checkAppletState("stop", false /* expIsActive */, 1 /* expInitCount */,
stopCount.get() /* expStartCount */, stopCount.get() /* expStopCount */, true /* startStopCountEquals */,
0 /* expDestroyCount */);
invoke(true, new Runnable() {
public void run() {
checkComponentState("stop", true, 1, 0);
} } );
println("Applet.stop() END - "+currentThreadName());
}
@Override
public void destroy() {
println("Applet.destroy() START - "+currentThreadName());
destroyCount.incrementAndGet();
checkAppletState("destroy", false /* expIsActive */, 1 /* expInitCount */,
startCount.get() /* expStartCount */, stopCount.get() /* expStopCount */, true /* startStopCountEquals */,
1 /* expDestroyCount */);
invoke(true, new Runnable() {
public void run() {
checkComponentState("destroy-remove.pre", true, 1, 0);
remove(myCanvas);
checkComponentState("destroy-remove.post", false, 1, 1);
} } );
println("Applet.destroy() END - "+currentThreadName());
}
}