Mercurial > hg > Members > shoshi > TreeCMSv2
view src/treecms/memory/OnMemoryTreeEditor.java @ 9:17ed97ca9960
commit
author | shoshi |
---|---|
date | Mon, 18 Apr 2011 01:07:27 +0900 |
parents | f96193babac0 |
children |
line wrap: on
line source
package treecms.memory; import java.util.List; import treecms.api.Forest; import treecms.api.Node; import treecms.api.NodeData; import treecms.api.TreeEditor; import treecms.merger.Merger; import treecms.merger.ReplaceMerger; import treecms.tree.util.NodePathFinder; import treecms.tree.util.PathNotFoundException; /** * 木構造を非破壊的に編集するオンメモリの実装です。 * @author shoshi */ final class OnMemoryTreeEditor implements TreeEditor { private OnMemoryTree m_tree; private OnMemoryNode m_backup; private OnMemoryNode m_root; /** * コンストラクタです。 * @param _tree 監視の対象とするOnMemoryTree */ public OnMemoryTreeEditor(OnMemoryTree _tree) { m_root = (OnMemoryNode)_tree.getRoot(); m_backup = m_root; } /** * 変更を元の木構造にコミットします。この操作はコミット先が先にアップデートされていた場合は失敗します * @param _force trueの場合は強制的に置き換えます。 * @return コミットが成功した場合true */ @Override public boolean commit(boolean _force) { return m_tree.compareAndSwapRootNode(m_backup,m_root,_force); } /** * 監視している木構造のルートと自身のルートに上書きします。 * @return true */ @Override public boolean pull() { m_root = (OnMemoryNode)m_tree.getRoot(); m_backup = m_root; return true; } /** * 監視している木構造が更新されていないか確認します。 * @return 更新されている場合true、されていない場合はfalse */ @Override public boolean check() { if(m_tree.getRoot().getID().equals(m_root.getID())){ return false; } return true; } /** * 監視している木構造の内容を自分の木構造にマージします * 最新版の木構造とマージする場合は、先にpull()を実行してください。 */ @Override public void merge() { Merger merger = new ReplaceMerger(); m_root = (OnMemoryNode)merger.merge(m_backup,m_root); } /** * 木構造を非破壊的に更新します. * @param _target 更新する対象 * @param _newData 更新に適用されるNodeData * @param _path 対象ノードまでのパス * @return 更新されたNode * @throws ルートNodeから_targetまでのパスが見つからない場合、PathNotFoundException */ @Override public Node updateTree(Node _target,NodeData _newData,Node[] _path) throws PathNotFoundException { //パスの正当性の検証 if(_path == null){ throw new NullPointerException("_path is null"); } if(_path.length == 0){ throw new PathNotFoundException("node path is empty"); }else{ //ここでごちゃごちゃする if(!m_root.getID().equals(_path[0].getID())){ throw new PathNotFoundException("wrong root node"); } int size = _path.length; Node prev = _path[0]; //重そう for(int i = 1;i < size;i ++){ if(!prev.children().contains(_path[i])){ throw new PathNotFoundException("invalid node path"); } } } return _updateTree(_target,_newData,_path); } /** * 木構造を非破壊的に更新します. * @param _target 更新する対象 * @param _newData 更新に適用されるNodeData * @return 更新されたNode * @throws ルートNodeから_targetまでのパスが見つからない場合、PathNotFoundException */ @Override public Node updateTree(Node _target,NodeData _newData) throws PathNotFoundException { NodePathFinder finder = new NodePathFinder(m_root,_target); List<Node> path = finder.list(); return _updateTree(_target,_newData,(Node[])path.toArray()); } private Node _updateTree(Node _target,NodeData _newData,Node[] _path) { Forest forest = m_root.getForest(); /* * 改良する必要がある、ランダムアクセスの性能はデータ構造による。 * とりあえず、配列使っとく */ Node ret = forest.create(_newData); Node prev = ret; for(int i = _path.length-1;i >= 0;i --){ Node prevParent = _path[i]; //prevの親 NodeData data = prevParent.getData(); //子供をOrderdSetにすれば早いかもね NodeData newData = new NodeData(); newData.putAll(data.getAll()); for(Node child : data.children()){ //UUIDに対応するノードを削除し、追加する if(child.getID().isFamily(prev.getID())){ newData.add(prev); }else{ newData.add(child); } } prev = forest.create(newData); } m_root = (OnMemoryNode)prev; return ret; } /* private LinkedList<OnMemoryNode> findAndClone(OnMemoryNode _parent,OnMemoryNode _target,NodeData _newData) { OnMemoryForest forest = (OnMemoryForest)_target.getForest(); if(_parent.getID().equals(_target.getID())){ LinkedList<OnMemoryNode> path = new LinkedList<OnMemoryNode>(); OnMemoryNode clone = forest.createNode(_target.getID().update(),_newData); path.addFirst(clone); return path; } for(Node child : _parent.children()){ LinkedList<OnMemoryNode> path = findAndClone((OnMemoryNode)child,_target,_newData); if(path != null){ path.addFirst(_parent); return path; } } return null; } */ /** * ルートNodeを取得します。 * @return この木構造のルートNode * */ @Override public Node getRoot() { return m_root; } }