blob: 4f4ce8dd557b558c9990f68a7d3f5622a638661e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2012 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0, which accompanies this distribution
* and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.common.utility.tests.internal.command;
import org.eclipse.jpt.common.utility.ExceptionHandler;
import org.eclipse.jpt.common.utility.command.Command;
import org.eclipse.jpt.common.utility.command.RepeatingCommand;
import org.eclipse.jpt.common.utility.internal.CollectingExceptionHandler;
import org.eclipse.jpt.common.utility.internal.CollectionTools;
import org.eclipse.jpt.common.utility.internal.ConsumerThreadCoordinator;
import org.eclipse.jpt.common.utility.internal.ReflectionTools;
import org.eclipse.jpt.common.utility.internal.command.AsynchronousRepeatingCommandWrapper;
import org.eclipse.jpt.common.utility.tests.internal.MultiThreadedTestCase;
import org.eclipse.jpt.common.utility.tests.internal.TestTools;
@SuppressWarnings("nls")
public class AsynchronousRepeatingCommandWrapperTests
extends MultiThreadedTestCase
{
PrimaryModel1 primaryModel1;
SecondaryModel1 secondaryModel1;
Command command1;
RepeatingCommand repeatingCommand1;
PrimaryModel2 primaryModel2;
SecondaryModel2 secondaryModel2;
Command command2;
RepeatingCommand repeatingCommand2;
public AsynchronousRepeatingCommandWrapperTests(String name) {
super(name);
}
@Override
protected void setUp() throws Exception {
super.setUp();
this.primaryModel1 = new PrimaryModel1();
this.secondaryModel1 = new SecondaryModel1(this.primaryModel1);
this.command1 = new SynchronizeSecondaryModelCommand1(this.secondaryModel1);
this.repeatingCommand1 = new AsynchronousRepeatingCommandWrapper(this.command1, this.buildThreadFactory(), null, ExceptionHandler.Runtime.instance());
this.primaryModel1.setSynchronizer(this.repeatingCommand1);
this.primaryModel2 = new PrimaryModel2();
this.secondaryModel2 = new SecondaryModel2(this.primaryModel2);
this.command2 = new SynchronizeSecondaryModelCommand2(this.primaryModel2, this.secondaryModel2);
this.repeatingCommand2 = new AsynchronousRepeatingCommandWrapper(this.command2, this.buildThreadFactory(), null, ExceptionHandler.Runtime.instance());
this.primaryModel2.setSynchronizer(this.repeatingCommand2);
}
@Override
protected void tearDown() throws Exception {
this.repeatingCommand1.stop();
this.repeatingCommand2.stop();
super.tearDown();
}
public void testInitialization() {
assertEquals(4, this.secondaryModel1.getDoubleCount());
}
public void testToString() {
assertNotNull(this.repeatingCommand1.toString());
}
public void testChange() throws Exception {
assertEquals(4, this.secondaryModel1.getDoubleCount());
this.primaryModel1.setCount(7);
this.sleep(TICK);
this.repeatingCommand1.stop();
this.sleep(TICK);
assertEquals(14, this.secondaryModel1.getDoubleCount());
// re-start so tear-down works
this.repeatingCommand1.start();
}
public void testStart() throws Exception {
assertEquals(4, this.secondaryModel1.getDoubleCount());
this.primaryModel1.setSynchronizer(RepeatingCommand.Null.instance());
this.primaryModel1.setCount(7);
assertEquals(4, this.secondaryModel1.getDoubleCount());
this.primaryModel1.setSynchronizer(this.repeatingCommand1);
// the async synchronizer does not synchronize at start-up
assertEquals(4, this.secondaryModel1.getDoubleCount());
this.primaryModel1.setCount(8);
this.sleep(TICK);
this.repeatingCommand1.stop();
this.sleep(TICK);
assertEquals(16, this.secondaryModel1.getDoubleCount());
// re-start so tear-down works
this.repeatingCommand1.start();
}
public void testStop() throws Exception {
assertEquals(4, this.secondaryModel1.getDoubleCount());
this.primaryModel1.dispose();
this.primaryModel1.setCount(7);
assertEquals(4, this.secondaryModel1.getDoubleCount());
// re-start so tear-down works
this.repeatingCommand1.start();
}
public void testDoubleStart() throws Exception {
assertEquals(4, this.secondaryModel1.getDoubleCount());
boolean exCaught = false;
try {
this.primaryModel1.startSynchronizer();
fail();
} catch (IllegalStateException ex) {
exCaught = true;
}
assertTrue(exCaught);
this.primaryModel1.setCount(7);
this.sleep(TICK);
this.repeatingCommand1.stop();
this.sleep(TICK);
assertEquals(14, this.secondaryModel1.getDoubleCount());
// re-start so tear-down works
this.repeatingCommand1.start();
}
public void testDoubleStop() throws Exception {
assertEquals(4, this.secondaryModel1.getDoubleCount());
this.primaryModel1.dispose();
boolean exCaught = false;
try {
this.primaryModel1.dispose();
fail();
} catch (IllegalStateException ex) {
exCaught = true;
}
assertTrue(exCaught);
this.primaryModel1.setCount(7);
assertEquals(4, this.secondaryModel1.getDoubleCount());
// re-start so tear-down works
this.repeatingCommand1.start();
}
public void testRecursiveChange() throws Exception {
assertEquals(4, this.secondaryModel2.getDoubleCount());
this.primaryModel2.setCount(7);
this.sleep(TICK);
assertEquals(10, this.primaryModel2.getCountPlus3());
assertEquals(14, this.secondaryModel2.getDoubleCount());
this.sleep(TICK);
assertEquals(20, this.secondaryModel2.getDoubleCountPlus3());
}
public void testNullCommand() {
boolean exCaught = false;
try {
RepeatingCommand s = new AsynchronousRepeatingCommandWrapper(null, this.buildThreadFactory(), null, ExceptionHandler.Runtime.instance());
fail("bogus: " + s);
} catch (NullPointerException ex) {
exCaught = true;
}
assertTrue(exCaught);
}
public void testThreadName() throws Exception {
RepeatingCommand s = new AsynchronousRepeatingCommandWrapper(this.command1, this.buildThreadFactory(), "sync", ExceptionHandler.Runtime.instance());
s.start();
ConsumerThreadCoordinator ctc = (ConsumerThreadCoordinator) ReflectionTools.getFieldValue(s, "consumerThreadCoordinator");
Thread t = (Thread) ReflectionTools.getFieldValue(ctc, "thread");
assertEquals("sync", t.getName());
s.stop();
}
public void testExecuteCalledBeforeStart() throws Exception {
SimpleCommand command = new SimpleCommand();
RepeatingCommand synchronizer = new AsynchronousRepeatingCommandWrapper(command, this.buildThreadFactory(), null, ExceptionHandler.Runtime.instance());
synchronizer.execute();
synchronizer.start();
this.sleep(TICK);
synchronizer.stop();
assertEquals(1, command.count);
}
public class SimpleCommand implements Command {
int count = 0;
public void execute() {
this.count++;
}
}
public void testException() throws Exception {
BogusCommand command = new BogusCommand();
CollectingExceptionHandler exHandler = new CollectingExceptionHandler();
RepeatingCommand synchronizer = new AsynchronousRepeatingCommandWrapper(command, this.buildThreadFactory(), null, exHandler);
synchronizer.start();
synchronizer.execute();
this.sleep(TICK);
synchronizer.execute();
this.sleep(TICK);
synchronizer.stop();
assertEquals(2, CollectionTools.size(exHandler.getExceptions()));
assertEquals(2, command.count);
}
public class BogusCommand implements Command {
int count = 0;
public void execute() {
this.count++;
throw new NullPointerException();
}
}
/**
* Make sure the <code>DEBUG</code> constant is <code>false</code>
* before checking in the code.
*/
public void testDEBUG() {
TestTools.assertFalseDEBUG(AsynchronousRepeatingCommandWrapper.class);
}
// ********** synchronize commands **********
public static class SynchronizeSecondaryModelCommand1
implements Command
{
private final SecondaryModel1 secondaryModel;
public SynchronizeSecondaryModelCommand1(SecondaryModel1 secondaryModel) {
super();
this.secondaryModel = secondaryModel;
}
public void execute() {
this.secondaryModel.synchronize();
}
}
/**
* the primary model (subclass) has to synchronize with itself (superclass)
*/
public static class SynchronizeSecondaryModelCommand2
extends SynchronizeSecondaryModelCommand1
{
private final PrimaryModel2 primaryModel;
public SynchronizeSecondaryModelCommand2(PrimaryModel2 primaryModel, SecondaryModel2 secondaryModel) {
super(secondaryModel);
this.primaryModel = primaryModel;
}
@Override
public void execute() {
super.execute();
this.primaryModel.synchronize();
}
}
// ********** primary models **********
/**
* this object will call the synchronizer whenever its count changes,
* allowing interested parties to synchronize with the change
*/
public static class PrimaryModel1 {
protected RepeatingCommand synchronizer;
protected int count = 2;
public PrimaryModel1() {
super();
this.setSynchronizer_(RepeatingCommand.Null.instance());
}
public int getCount() {
return this.count;
}
public void setCount(int count) {
if (count != this.count) {
this.count = count;
this.stateChanged();
}
}
protected void stateChanged() {
this.synchronizer.execute();
}
public void setSynchronizer(RepeatingCommand synchronizer) throws InterruptedException {
if (synchronizer == null) {
throw new NullPointerException();
}
this.synchronizer.stop();
this.setSynchronizer_(synchronizer);
}
protected void setSynchronizer_(RepeatingCommand synchronizer) {
this.synchronizer = synchronizer;
this.synchronizer.start();
}
public void startSynchronizer() {
this.synchronizer.start(); // this should cause an exception
}
public void dispose() throws InterruptedException {
this.synchronizer.stop();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName());
sb.append('(');
this.toString(sb);
sb.append(')');
return sb.toString();
}
public void toString(StringBuilder sb) {
sb.append("count=");
sb.append(this.count);
}
}
/**
* This model synchronizes with itself, triggering a recursive synchronization
* with the change. Whenever the [inherited] 'count' changes, 'countPlus3'
* is updated appropriately and another synchronize is initiated if appropriate.
*/
public static class PrimaryModel2
extends PrimaryModel1
{
private int countPlus3 = 0;
public PrimaryModel2() {
super();
this.countPlus3 = this.count + 3;
}
public int getCountPlus3() {
return this.countPlus3;
}
protected void setCountPlus3(int countPlus3) {
if (countPlus3 != this.countPlus3) {
this.countPlus3 = countPlus3;
this.stateChanged();
}
}
// synchronize with itself, so to speak
public void synchronize() {
this.setCountPlus3(this.count + 3);
}
@Override
public void toString(StringBuilder sb) {
super.toString(sb);
sb.append(", countPlus3=");
sb.append(this.countPlus3);
}
}
// ********** secondary models **********
/**
* This dependent object updates its 'doubleCount' whenever the
* PrimaryModel1's 'count' changes, via the 'synchronizer'.
*/
public static class SecondaryModel1 {
protected final PrimaryModel1 primaryModel;
protected int doubleCount = 0;
public SecondaryModel1(PrimaryModel1 primaryModel) {
super();
this.primaryModel = primaryModel;
this.synchronize();
}
public void synchronize() {
this.doubleCount = this.primaryModel.getCount() * 2;
}
public int getDoubleCount() {
return this.doubleCount;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName());
sb.append('(');
this.toString(sb);
sb.append(')');
return sb.toString();
}
public void toString(StringBuilder sb) {
sb.append("doubleCount=");
sb.append(this.doubleCount);
}
}
public static class SecondaryModel2
extends SecondaryModel1
{
private int doubleCountPlus3 = 0;
public SecondaryModel2(PrimaryModel2 extendedPrimaryModel) {
super(extendedPrimaryModel);
}
protected PrimaryModel2 getExtendedPrimaryModel() {
return (PrimaryModel2) this.primaryModel;
}
@Override
public void synchronize() {
super.synchronize();
int temp = this.getExtendedPrimaryModel().getCountPlus3() * 2;
if (this.doubleCountPlus3 != temp) {
this.doubleCountPlus3 = temp;
}
}
public int getDoubleCountPlus3() {
return this.doubleCountPlus3;
}
@Override
public void toString(StringBuilder sb) {
super.toString(sb);
sb.append(", doubleCountPlus3=");
sb.append(this.doubleCountPlus3);
}
}
}