/* ******************************************************************************
* Copyright (c) 2006-2016 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
/**
*
*/
package org.xmind.core.internal.experiments;
import java.io.*;
import java.lang.Thread.*;
import java.util.*;
import org.xmind.core.*;
import junit.framework.*;
/**
* @author Frank Shaka
*
*/
public class ConcurrentModificationTest {
private static final int SAVE_ITER_COUNT = 100000;
public static void main(String[] args) throws Exception {
new ConcurrentModificationTest().run();
}
private static interface Modifier {
String getName();
void modify(IWorkbook workbook);
}
private static final Random rand = new Random();
private static Modifier[] modifiers = new Modifier[] {
// add topic
new Modifier() {
public String getName() {
return "add topic";
}
public void modify(IWorkbook workbook) {
ITopic topic = workbook.createTopic();
ITopic r = workbook.getPrimarySheet().getRootTopic();
List<ITopic> children = r.getChildren(ITopic.ATTACHED);
int size = children.size();
int number = size + 1;
topic.setTitleText("Topic " + number);
r.add(topic, size <= 0 ? -1 : rand.nextInt(size), ITopic.ATTACHED);
}
},
// modify title
new Modifier() {
public String getName() {
return "modify title";
}
public void modify(IWorkbook workbook) {
ITopic r = workbook.getPrimarySheet().getRootTopic();
List<ITopic> children = r.getChildren(ITopic.ATTACHED);
if (children.isEmpty())
return;
ITopic t = children.get(rand.nextInt(children.size()));
t.setTitleText(UUID.randomUUID().toString());
}
},
// delete topic
new Modifier() {
public String getName() {
return "delete topic";
}
public void modify(IWorkbook workbook) {
ITopic r = workbook.getPrimarySheet().getRootTopic();
List<ITopic> children = r.getChildren(ITopic.ATTACHED);
if (children.isEmpty())
return;
ITopic t = children.get(rand.nextInt(children.size()));
r.remove(t);
}
}
};
private byte[] data;
private IWorkbook workbook;
private Thread modificationThread;
private Thread savingThread;
private boolean done;
private volatile boolean saving;
private int saveCount = 0;
private int modificaitonCount = 0;
private int concurrentModificationCount = 0;
public void run() throws Exception {
data = null;
done = false;
workbook = Core.getWorkbookBuilder().createWorkbook();
UncaughtExceptionHandler errHandler = new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
e.printStackTrace();
modificationThread.interrupt();
savingThread.interrupt();
}
};
modificationThread = new Thread(new Runnable() {
@Override
public void run() {
modify();
}
});
modificationThread.setName("ModificationThread");
modificationThread.setUncaughtExceptionHandler(errHandler);
saving = false;
savingThread = new Thread(new Runnable() {
@Override
public void run() {
save();
}
});
savingThread.setName("SavingThread");
savingThread.setUncaughtExceptionHandler(errHandler);
modificationThread.start();
savingThread.start();
System.out.println("Started");
modificationThread.join();
savingThread.join();
testLoad();
System.out.println("Test passes!");
System.out.println("Save Count: " + saveCount);
System.out.println("Modification Count: " + modificaitonCount);
System.out.println("Concurrent modifications: " + concurrentModificationCount);
}
private void modify() {
try {
while (!done) {
Modifier m = modifiers[rand.nextInt(modifiers.length)];
// System.out.println(m.getName());
if (saving) {
concurrentModificationCount += 1;
// System.out.println("Concurrent modification detected");
}
m.modify(workbook);
modificaitonCount += 1;
Thread.sleep(2);
}
} catch (InterruptedException e) {
}
}
private void save() {
try {
for (int i = 0; i < SAVE_ITER_COUNT; i++) {
testLoad();
try {
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
ISerializer ser = Core.getWorkbookBuilder().newSerializer();
saving = true;
try {
ser.setWorkbook(workbook);
ser.setOutputStream(output);
ser.serialize(null);
} finally {
saving = false;
}
} finally {
output.close();
}
data = output.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
saveCount += 1;
Thread.sleep(0);
}
} catch (InterruptedException e) {
} finally {
done = true;
}
}
private void testLoad() {
if (data == null) {
return;
}
try {
ByteArrayInputStream input = new ByteArrayInputStream(data);
try {
IDeserializer des = Core.getWorkbookBuilder().newDeserializer();
des.setInputStream(input);
des.deserialize(null);
} finally {
input.close();
}
} catch (Exception e) {
e.printStackTrace();
throw new AssertionFailedError(e.getMessage());
}
}
}