changeset 45:fb00d7b147c8

added JungleTree service
author Shoshi TAMAKI
date Tue, 05 Feb 2013 02:04:34 +0900
parents 449d67be0886
children e7d94437ca2f
files src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/DefaultJungle.java src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/DefaultJungleTree.java src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/JungleTreeEditor.java src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/persistent/ChangeListWriter.java src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/persistent/NullJournal.java src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/store/impl/TraversableNodeWrapper.java src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/AtomicReservableReference.java src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/ClonableDefaultNode.java src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/DefaultChangeSet.java src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/DefaultJungleTreeEditor.java src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/DefaultTransactionManager.java src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/TransactionManager.java src/test/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/core/impl/treeeditor/DefaultTreeEditorTest.java src/test/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/tests/util/TestUtil.java
diffstat 14 files changed, 502 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/DefaultJungle.java	Tue Feb 05 02:04:34 2013 +0900
@@ -0,0 +1,49 @@
+package jp.ac.u_ryukyu.ie.cr.shoshi.jungle;
+
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
+
+import fj.data.List;
+
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.persistent.ChangeList;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.persistent.Journal;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.persistent.NullJournal;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.DefaultNode;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.operations.Operation;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction.DefaultChangeSet;
+
+public class DefaultJungle implements Jungle
+{
+	private Journal journal;
+	private ConcurrentHashMap<String,JungleTree> trees;
+	private String uuid;
+	
+	public DefaultJungle(String _uuid)
+	{
+		journal = new NullJournal();
+		trees = new ConcurrentHashMap<String,JungleTree>();
+		uuid = _uuid;
+	}
+
+	@Override
+	public JungleTree getTreeByName(String _name)
+	{
+		return trees.get(_name);
+	}
+
+	@Override
+	public JungleTree createNewTree(String _name)
+	{
+		ChangeList list = new ChangeList(){
+			@Override
+			public Iterator<Operation> iterator() {
+				List<Operation> nil = List.nil();
+				return nil.iterator();
+			}
+		};
+		DefaultNode node = new DefaultNode();
+		DefaultChangeSet set = new DefaultChangeSet(node,null,list,uuid,0);
+		DefaultJungleTree newTree = new DefaultJungleTree(set,uuid,journal.getWriter());
+		return newTree;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/DefaultJungleTree.java	Tue Feb 05 02:04:34 2013 +0900
@@ -0,0 +1,118 @@
+package jp.ac.u_ryukyu.ie.cr.shoshi.jungle;
+
+import java.util.Iterator;
+
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.core.Attributes;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.core.AttributesContainer;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.core.Children;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.core.Node;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.core.Parent;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.persistent.ChangeListWriter;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.ChangeSet;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.DefaultNode;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction.AtomicReservableReference;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction.ClonableDefaultNode;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction.DefaultChangeSet;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction.DefaultJungleTreeEditor;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction.DefaultTransactionManager;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.traverser.DefaultTraverser;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.DefaultEither;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Either;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Error;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.IterableConverter;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.IterableConverter.Converter;
+
+public class DefaultJungleTree implements JungleTree
+{
+	private final AtomicReservableReference<DefaultChangeSet> repository;
+	private final String uuid;
+	private final ChangeListWriter writer;
+	
+	public DefaultJungleTree(DefaultChangeSet _set,String _uuid,ChangeListWriter _writer)
+	{
+		repository = new AtomicReservableReference<DefaultChangeSet>(_set);
+		uuid = _uuid;
+		writer = _writer;
+	}
+
+	@Override
+	public DefaultJungleTreeEditor getTreeEditor()
+	{
+		DefaultChangeSet tip = repository.get();
+		DefaultTransactionManager txManager = new DefaultTransactionManager(writer,tip,repository,uuid);
+		DefaultNode root = tip.getRoot();
+		return new DefaultJungleTreeEditor(root,txManager,new DefaultTraverser());
+	}
+
+	@Override
+	public Node getRootNode()
+	{
+		ChangeSet set = repository.get();
+		return set.getRoot();
+	}
+	
+	public static class NodeWrapper<T extends Parent<T> & AttributesContainer> implements Node
+	{
+		private final T wrap;
+		
+		public NodeWrapper(T _wrap)
+		{
+			wrap = _wrap;
+		}
+
+		@Override
+		public Attributes getAttributes()
+		{
+			return wrap.getAttributes();
+		}
+
+		@Override
+		public Children<Node> getChildren()
+		{
+			Children<T> children = wrap.getChildren();
+			return new ChildrenWrapper<T>(children);
+		}
+		
+		public static class ChildrenWrapper<T extends Parent<T> & AttributesContainer> implements Children<Node>
+		{
+			private Children<T> wrap;
+			
+			public ChildrenWrapper(Children<T> _wrap)
+			{
+				wrap = _wrap;
+			}
+
+			@Override
+			public Iterator<Node> iterator()
+			{
+				Converter<Node,T> converter = new IterableConverter.Converter<Node,T>(){
+					@Override
+					public Node conv(T _b){
+						return new NodeWrapper<T>(_b);
+					}
+				};
+				
+				IterableConverter<Node,T> iterable = new IterableConverter<Node,T>(wrap,converter);
+				return iterable.iterator();
+			}
+
+			@Override
+			public Either<Error,Node> at(int _pos)
+			{
+				Either<Error,T> either = wrap.at(_pos);
+				if(either.isA()){
+					return DefaultEither.newA(either.a());
+				}
+				T node = either.b();
+				Node wrapper = new NodeWrapper<T>(node);
+				return DefaultEither.newB(wrapper);
+			}
+
+			@Override
+			public int size()
+			{
+				return wrap.size();
+			}
+		}
+	}
+}
--- a/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/JungleTreeEditor.java	Sun Feb 03 19:46:04 2013 +0900
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/JungleTreeEditor.java	Tue Feb 05 02:04:34 2013 +0900
@@ -3,7 +3,8 @@
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.Transaction;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.TreeEditor;
 
-public interface JungleTreeEditor<T extends JungleTreeEditor<T>> extends TreeEditor<T> , Transaction<JungleTree>
+public interface JungleTreeEditor<T extends JungleTreeEditor<T>> extends TreeEditor<T> , Transaction<T>
 {
-
+	public String getID();
+	public String getRevision();
 }
--- a/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/persistent/ChangeListWriter.java	Sun Feb 03 19:46:04 2013 +0900
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/persistent/ChangeListWriter.java	Tue Feb 05 02:04:34 2013 +0900
@@ -2,5 +2,5 @@
 
 public interface ChangeListWriter
 {
-	public Result write();
+	public Result write(ChangeList _operations);
 }
--- a/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/persistent/NullJournal.java	Sun Feb 03 19:46:04 2013 +0900
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/persistent/NullJournal.java	Tue Feb 05 02:04:34 2013 +0900
@@ -20,7 +20,7 @@
 	private static class NullChangeListWriter implements ChangeListWriter
 	{
 		@Override
-		public Result write()
+		public Result write(ChangeList _operations)
 		{
 			return Result.SUCCESS;
 		}
--- a/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/store/impl/TraversableNodeWrapper.java	Sun Feb 03 19:46:04 2013 +0900
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/store/impl/TraversableNodeWrapper.java	Tue Feb 05 02:04:34 2013 +0900
@@ -3,6 +3,7 @@
 import java.util.Iterator;
 
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.core.Children;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.core.Parent;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.trasnformer.EditableNode;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.traverser.TraversableNode;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.DefaultEither;
@@ -10,7 +11,7 @@
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Error;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.IterableConverter;
 
-public class TraversableNodeWrapper<T extends EditableNode<T>>
+public class TraversableNodeWrapper<T extends Parent<T>>
 	implements TraversableNode<TraversableNodeWrapper<T>>
 {
 	private final T wrap;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/AtomicReservableReference.java	Tue Feb 05 02:04:34 2013 +0900
@@ -0,0 +1,90 @@
+package jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class AtomicReservableReference<V>
+{
+	public static void main(String _args[])
+	{
+		String hoge = "hoge";
+		String fuga = "fuga";
+		AtomicReservableReference<String> arr = new AtomicReservableReference<String>(hoge);
+		AtomicReservableReference<String>.Reservation r1 = arr.makeReservation(hoge,fuga);
+		AtomicReservableReference<String>.Reservation r2 = arr.makeReservation(hoge,fuga);
+		
+		System.out.println(arr.get());
+		r1.confirm();
+		System.out.println(arr.get());
+	}
+	
+	private AtomicReference<Reservation> reservation;
+	private AtomicBoolean flagReservation;
+	
+	public AtomicReservableReference(V _ref)
+	{
+		reservation = new AtomicReference<Reservation>(new Reservation(_ref,null,true));
+		flagReservation = new AtomicBoolean(false);
+	}
+	
+	public Reservation makeReservation(V _expect,V _update)
+	{
+		if(flagReservation.compareAndSet(false,true)){
+			V value = get();
+			if(value == _expect){
+				Reservation expect = reservation.get();
+				return new Reservation(_update,expect,false);
+			}
+			flagReservation.set(false);
+		}
+		
+		return null;
+	}
+	
+	public void set(V _value)
+	{
+		reservation.set(new Reservation(_value,null,true));
+	}
+	
+	public V get()
+	{
+		Reservation r = reservation.get();
+		return r.get();
+	}
+	
+	public class Reservation
+	{
+		public final Reservation expect;
+		public final AtomicReference<V> ref;
+		public final AtomicBoolean flagConfirmed;
+		
+		public Reservation(V _object,Reservation _expect,boolean _confirmed)
+		{
+			expect = _expect;
+			ref = new AtomicReference<V>(_object);
+			flagConfirmed = new AtomicBoolean(_confirmed);
+		}
+		
+		public V get()
+		{
+			return ref.get();
+		}
+		
+		public void confirm()
+		{
+			if(flagConfirmed.compareAndSet(false,true)){
+				if(reservation.compareAndSet(expect,this) == false){
+					throw new IllegalStateException("foo!");
+				}
+				flagReservation.set(false);
+			}
+		}
+		
+		public void cancel()
+		{
+			if(flagConfirmed.compareAndSet(false,true)){
+				flagReservation.set(true);
+			}
+		}
+	}
+}
--- a/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/ClonableDefaultNode.java	Sun Feb 03 19:46:04 2013 +0900
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/ClonableDefaultNode.java	Tue Feb 05 02:04:34 2013 +0900
@@ -7,6 +7,11 @@
 {
 	private final DefaultNode wrap;
 	
+	public ClonableDefaultNode()
+	{
+		this(new DefaultNode());
+	}
+	
 	public ClonableDefaultNode(DefaultNode _wrap)
 	{
 		wrap = _wrap;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/DefaultChangeSet.java	Tue Feb 05 02:04:34 2013 +0900
@@ -0,0 +1,63 @@
+package jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction;
+
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.core.Node;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.persistent.ChangeList;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.ChangeSet;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.DefaultNode;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.logger.DefaultLogger;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.operations.Operation;
+
+public class DefaultChangeSet implements ChangeSet
+{
+	private final DefaultNode root;
+	private final ChangeSet previous;
+	private final ChangeList changeList;
+	private final String uuid;
+	private final long revision;
+	
+	public DefaultChangeSet(DefaultNode _node,ChangeSet _prev,ChangeList _log,String _uuid,long _revision)
+	{
+		root = _node;
+		previous = _prev;
+		changeList = _log;
+		uuid = _uuid;
+		revision = _revision;
+	}
+
+	@Override
+	public DefaultNode getRoot()
+	{
+		return root;
+	}
+
+	@Override
+	public ChangeSet prev()
+	{
+		return previous;
+	}
+
+	@Override
+	public ChangeList getChangeList()
+	{
+		return changeList;
+	}
+
+	@Override
+	public String uuid()
+	{
+		return uuid;
+	}
+
+	@Override
+	public long revision()
+	{
+		return revision;
+	}
+
+	@Override
+	public Iterable<Operation> getOperations()
+	{
+		return changeList;
+	}
+
+}
--- a/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/DefaultJungleTreeEditor.java	Sun Feb 03 19:46:04 2013 +0900
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/DefaultJungleTreeEditor.java	Tue Feb 05 02:04:34 2013 +0900
@@ -103,18 +103,32 @@
 	}
 
 	@Override
-	public Either<Error,JungleTree> success()
+	public Either<Error,DefaultJungleTreeEditor> success()
 	{
 		LoggingNode<ClonableDefaultNode> loggingNode = editor.getRootNode();
 		Logger log = loggingNode.getLogger();
 		DefaultNode newRoot = loggingNode.getWrapper().getWrapped();
 		
-		Either<Error,JungleTree> either = txManager.commit(newRoot,log);
+		Either<Error,TransactionManager> either = txManager.commit(newRoot,log);
 		if(either.isA()){
 			return DefaultEither.newA(either.a());
 		}
 		
-		return DefaultEither.newB(either.b());
+		TransactionManager newTxManager = either.b();
+		DefaultJungleTreeEditor newTreeEditor = new DefaultJungleTreeEditor(newRoot,newTxManager,traverser);
+		
+		return DefaultEither.newB(newTreeEditor);
 	}
 
+	@Override
+	public String getID()
+	{
+		return txManager.getUUID();
+	}
+
+	@Override
+	public String getRevision()
+	{
+		return Long.toString(txManager.getRevision());
+	}
 }
--- a/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/DefaultTransactionManager.java	Sun Feb 03 19:46:04 2013 +0900
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/DefaultTransactionManager.java	Tue Feb 05 02:04:34 2013 +0900
@@ -1,17 +1,76 @@
 package jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction;
 
+import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicReference;
+
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.JungleTree;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.persistent.ChangeList;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.persistent.ChangeListWriter;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.persistent.Result;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.ChangeSet;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.DefaultNode;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.logger.DefaultLogger;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.logger.Logger;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.operations.Operation;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction.AtomicReservableReference.Reservation;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.DefaultEither;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.DefaultError;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Either;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Error;
 
 public class DefaultTransactionManager implements TransactionManager
 {
+	private final AtomicReservableReference<DefaultChangeSet> repository;
+	private final DefaultChangeSet tip;
+	private final ChangeListWriter writer;
+	private final String uuid;
+	
+	public DefaultTransactionManager(ChangeListWriter _writer,DefaultChangeSet _changeSet,
+			AtomicReservableReference<DefaultChangeSet> _repository,String _uuid)
+	{
+		repository = _repository;
+		tip = _changeSet;
+		writer = _writer;
+		uuid = _uuid;
+	}
+	
 	@Override
-	public Either<Error, JungleTree> commit(DefaultNode _newRoot, Logger _log)
+	public Either<Error,TransactionManager> commit(DefaultNode _newRoot,final Logger _log)
 	{
-		return null;
+		long currentRevision = tip.revision();
+		long nextRevision = currentRevision + 1;
+		
+		ChangeList list = new ChangeList(){
+			@Override
+			public Iterator<Operation> iterator(){
+				return _log.iterator();
+			}
+		};
+		
+		DefaultChangeSet changeSet = new DefaultChangeSet(_newRoot,tip,list,uuid,nextRevision);
+		Reservation reservation = repository.makeReservation(tip,changeSet);
+		if(reservation == null){
+			return DefaultEither.newA((Error)new DefaultError());
+		}
+		Result r = writer.write(list);
+		if(r == Result.SUCCESS){
+			reservation.confirm();
+			TransactionManager txManager = new DefaultTransactionManager(writer,changeSet,repository,uuid);
+			return DefaultEither.newB(txManager);
+		}
+		
+		return DefaultEither.newA((Error)new DefaultError());
 	}
 
+	@Override
+	public String getUUID()
+	{
+		return uuid;
+	}
+
+	@Override
+	public long getRevision()
+	{
+		return tip.revision();
+	}
 }
--- a/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/TransactionManager.java	Sun Feb 03 19:46:04 2013 +0900
+++ b/src/main/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/transaction/TransactionManager.java	Tue Feb 05 02:04:34 2013 +0900
@@ -1,6 +1,5 @@
 package jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction;
 
-import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.JungleTree;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.DefaultNode;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.logger.Logger;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Either;
@@ -8,5 +7,7 @@
 
 public interface TransactionManager
 {
-	public Either<Error,JungleTree> commit(DefaultNode _newRoot,Logger _log);
+	public Either<Error,TransactionManager> commit(DefaultNode _newRoot,Logger _log);
+	public String getUUID();
+	public long getRevision();
 }
--- a/src/test/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/core/impl/treeeditor/DefaultTreeEditorTest.java	Sun Feb 03 19:46:04 2013 +0900
+++ b/src/test/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/core/impl/treeeditor/DefaultTreeEditorTest.java	Tue Feb 05 02:04:34 2013 +0900
@@ -5,9 +5,13 @@
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.DefaultNode;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.DefaultNodePath;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.DefaultTreeEditor;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.TraversableNodeWrapper;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.trasnformer.AppendChildAt;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.tests.util.TestUtil;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction.ClonableDefaultNode;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.traverser.DefaultEvaluator;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.traverser.DefaultTraverser;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.traverser.Traversal;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Either;
 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Error;
 import junit.framework.Assert;
@@ -24,6 +28,49 @@
 	
 	public void testEdittingDoesNotEffectToOtherTree()
 	{
+		ClonableDefaultNode root = TestUtil.createMockTree(3);
+		DefaultTreeEditor<ClonableDefaultNode> editor = new DefaultTreeEditor<ClonableDefaultNode>(root,new DefaultTraverser());
+		DefaultNodePath path = new DefaultNodePath().add(0).add(2);
+		
+		ClonableDefaultNode oldRoot = editor.getRootNode();
+		
+		DefaultTreeEditor<ClonableDefaultNode> currentEditor = editor;
+		String key = "path";
+		
+		for(DefaultNodePath part : path.inits()){
+			ByteBuffer value = ByteBuffer.wrap(part.toString().getBytes());
+			Either<Error, DefaultTreeEditor<ClonableDefaultNode>> either = currentEditor.putAttribute(part,key,value);
+			if(either.isA()){
+				Assert.fail();
+			}
+			currentEditor = either.b();
+		}
+		
+		ClonableDefaultNode newRoot = currentEditor.getRootNode();
+		
+		DefaultTraverser traverser = new DefaultTraverser();
+		for(DefaultNodePath part : path.inits()){
+			Either<Error,Traversal<TraversableNodeWrapper<ClonableDefaultNode>>> either = traverser.traverse(new TraversableNodeWrapper<ClonableDefaultNode>(newRoot),new DefaultEvaluator(part));
+			if(either.isA()){
+				Assert.fail();
+			}
+			ClonableDefaultNode target = either.b().destination().getWrapped();
+			String expected = part.toString();
+			String actual = new String(target.getAttributes().get(key).array());
+			
+			Assert.assertEquals(expected,actual);
+		}
+		
+		for(DefaultNodePath part : path.inits()){
+			Either<Error,Traversal<TraversableNodeWrapper<ClonableDefaultNode>>> either = traverser.traverse(new TraversableNodeWrapper<ClonableDefaultNode>(oldRoot),new DefaultEvaluator(part));
+			if(either.isA()){
+				Assert.fail();
+			}
+			ClonableDefaultNode target = either.b().destination().getWrapped();
+			ByteBuffer actual = target.getAttributes().get(key);
+			
+			Assert.assertNull(actual);
+		}
 		
 	}
 	
@@ -69,6 +116,8 @@
 		DefaultTreeEditor<ClonableDefaultNode> instance = instance();
 		DefaultNodePath path = new DefaultNodePath();
 		
+		ClonableDefaultNode old = instance.getRootNode();
+		
 		String key = "KEY";
 		ByteBuffer value = ByteBuffer.wrap(key.getBytes());
 		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/java/jp/ac/u_ryukyu/ie/cr/shoshi/jungle/tests/util/TestUtil.java	Tue Feb 05 02:04:34 2013 +0900
@@ -0,0 +1,40 @@
+package jp.ac.u_ryukyu.ie.cr.shoshi.jungle.tests.util;
+
+import java.nio.ByteBuffer;
+
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.NodePath;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.DefaultNodePath;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.transaction.ClonableDefaultNode;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Either;
+import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Error;
+
+public class TestUtil
+{
+	public static ClonableDefaultNode createMockTree(int _maxDepth)
+	{
+		return _createMockTree(1,_maxDepth,new DefaultNodePath());
+	}
+	
+	public static ClonableDefaultNode _createMockTree(int _currentDepth,int _maxDepth,NodePath _path)
+	{
+		ClonableDefaultNode parent = new ClonableDefaultNode();
+		Either<Error, ClonableDefaultNode> either = parent.getAttributes().put("KEY",ByteBuffer.wrap(_path.toString().getBytes()));
+		if(either.isA()){
+			return null;
+		}
+		parent = either.b();
+		
+		if(_currentDepth != _maxDepth){
+			for(int i = 0;i <= _currentDepth;i ++){
+				ClonableDefaultNode ch = _createMockTree(_currentDepth + 1,_maxDepth,_path.add(i));
+				either = parent.getChildren().addNewChildAt(i,ch);
+				if(either.isA()){
+					return null;
+				}
+				parent = either.b();
+			}
+		}
+		
+		return parent;
+	}
+}