Mercurial > hg > Members > shoshi > TreeCMSv2
comparison src/treecms/tree/util/NodeChildrenImpl.java @ 20:084de6909451
commit
author | shoshi |
---|---|
date | Wed, 01 Jun 2011 15:35:50 +0900 |
parents | 168deb591f21 |
children | f3150b37f9be |
comparison
equal
deleted
inserted
replaced
19:019ca5abb1f0 | 20:084de6909451 |
---|---|
1 package treecms.tree.util; | 1 package treecms.tree.util; |
2 | 2 |
3 import java.util.ArrayList; | |
4 import java.util.Collections; | 3 import java.util.Collections; |
5 import java.util.HashSet; | 4 import java.util.HashMap; |
5 import java.util.List; | |
6 import java.util.Map; | |
6 import java.util.Set; | 7 import java.util.Set; |
7 import java.util.List; | 8 import java.util.concurrent.ConcurrentHashMap; |
8 import treecms.api.Node; | 9 import java.util.concurrent.CopyOnWriteArrayList; |
9 import treecms.api.NodeChildren; | 10 import treecms.api.NodeChildren; |
10 | 11 import treecms.api.NodeContext; |
11 /** | 12 import treecms.api.NodeID; |
12 * 子供ノードを格納するため専用のリストです.java.util.List<T>は継承しておりません. | 13 |
13 * 子供ノードのリストには リスト内に同じUUIDを持つNodeが存在 してはいけません. | 14 public class NodeChildrenImpl<T extends NodeContext & NodeChildren<T>> implements NodeChildren<T> |
14 * @author shoshi | |
15 */ | |
16 public class NodeChildrenImpl<T extends Node<T>> implements NodeChildren<T> | |
17 { | 15 { |
18 private List<T> m_list; | 16 private final Map<String,T> m_map; |
19 private Set<String> m_set; | 17 private final List<T> m_list; |
18 private final List<T> m_readOnlyList; | |
20 | 19 |
21 public NodeChildrenImpl() | 20 public NodeChildrenImpl() |
22 { | 21 { |
23 m_list = new ArrayList<T>(); | 22 m_map = new ConcurrentHashMap<String,T>(); |
24 m_set = new HashSet<String>(); | 23 m_list = new CopyOnWriteArrayList<T>(); |
24 m_readOnlyList = Collections.unmodifiableList(m_list); | |
25 } | 25 } |
26 | 26 |
27 public NodeChildrenImpl(T... _args) | 27 public NodeChildrenImpl(T... _args) |
28 { | 28 { |
29 this(); | 29 this(); |
30 for(T i : _args){ | 30 for(T i : _args){ |
31 if(!add(i)){ | 31 String fid = i.getID().getFamilyID(); |
32 throw new IllegalArgumentException("duplicate Node UUID at "+i.getID().getUUID()); | 32 if(!m_map.containsKey(fid)){ |
33 m_map.put(fid,i); | |
34 m_list.add(i); | |
33 } | 35 } |
34 } | 36 } |
35 } | 37 } |
36 | 38 |
37 public NodeChildrenImpl(NodeChildren<T> _list) | 39 public NodeChildrenImpl(NodeChildren<T> _list) |
38 { | 40 { |
39 this(); | 41 this(); |
40 | 42 |
41 if(_list != null){ | 43 if(_list != null){ |
42 addAll(_list); | 44 addAll(_list); |
43 } | 45 }else{ |
44 } | 46 throw new NullPointerException("_list is null"); |
45 | 47 } |
46 public List<T> getList() | 48 } |
47 { | 49 |
48 return Collections.unmodifiableList(m_list); | 50 @Override |
49 } | 51 public synchronized List<T> getList() |
50 | 52 { |
51 public Set<String> getUUIDSet() | 53 return m_readOnlyList; |
52 { | 54 } |
53 return Collections.unmodifiableSet(m_set); | 55 |
54 } | 56 @Override |
55 | 57 public synchronized T replace(T _node) |
56 @Override | 58 { |
57 public T replace(T _newChild) | 59 String fid = _node.getID().getFamilyID(); |
58 { | 60 |
59 String uuid = _newChild.getID().getUUID(); | 61 T old = m_map.get(fid); |
60 int size = m_list.size(); | 62 |
61 for(int i = 0;i < size;i ++){ | 63 if(old != null){ |
62 T n = m_list.get(i); | 64 m_map.put(fid,_node); |
63 if(uuid.equals(n.getID().getUUID())){ | 65 |
64 //_newChildと同一なUUIDを見つけた | 66 //find index of _node , better put index with node in the map? |
65 return m_list.set(i,_newChild); | 67 int size = m_list.size(); |
66 } | 68 for(int i = 0;i < size;i ++){ |
67 } | 69 T n = m_list.get(i); |
68 //見つからなかった | 70 NodeID nid = n.getID(); |
71 if(nid.isFamily(nid)){ | |
72 m_list.set(i,_node); | |
73 return old; | |
74 } | |
75 } | |
76 | |
77 throw new IllegalStateException("FamilyID is found on the map but not found on the list"); | |
78 } | |
69 return null; | 79 return null; |
70 } | 80 } |
71 | 81 |
72 /** | 82 @Override |
73 * このリストに新しく子供を追加します. | 83 public synchronized boolean add(T _n) |
74 * @param _n | 84 { |
75 * @return 追加に成功した場合true | 85 if(!m_map.containsKey(_n.getID().getFamilyID())){ |
76 */ | 86 m_map.put(_n.getID().getFamilyID(),_n); |
77 public boolean add(T _n) | 87 return m_list.add(_n); |
78 { | |
79 if(m_set.contains(_n.getID().getUUID())){ | |
80 return false; | |
81 } | |
82 | |
83 m_set.add(_n.getID().getUUID()); | |
84 m_list.add(_n); | |
85 return true; | |
86 } | |
87 | |
88 /** | |
89 * _listに含まれている子供がすべてこのリストに含まれない場合にのみ、要素をすべて追加します。 | |
90 * @param _list | |
91 * @return 追加に成功した場合true | |
92 */ | |
93 public boolean addAll(NodeChildren<T> _list) | |
94 { | |
95 if(Collections.disjoint(m_set,_list.getUUIDSet())){ | |
96 //共通要素がない | |
97 m_set.addAll(_list.getUUIDSet()); | |
98 m_list.addAll(_list.getList()); | |
99 return true; | |
100 } | 88 } |
101 return false; | 89 return false; |
102 } | 90 } |
103 | 91 |
104 /** | 92 @Override |
105 * 指定されたNodeID | 93 public synchronized boolean addAll(NodeChildren<T> _list) |
106 * @param _id | 94 { |
107 * @return 子供ノード | 95 if(Collections.disjoint(getFamilyIDSet(),_list.getFamilyIDSet())){ |
108 */ | 96 |
109 public T get(String _uuid) | 97 HashMap<String,T> map = new HashMap<String,T>(); |
110 { | 98 for(T item : _list.getList()){ |
111 for(T n : m_list){ | 99 NodeID id = item.getID(); |
112 String uuid = n.getID().getUUID(); | 100 map.put(id.getFamilyID(),item); |
113 if(uuid.equals(_uuid)){ | 101 } |
114 return n; | 102 |
115 } | 103 return m_list.addAll(_list.getList()); |
116 } | 104 } |
117 | 105 return false; |
118 return null; | 106 } |
119 } | 107 |
120 | 108 @Override |
121 /** | 109 public synchronized T get(int _index) |
122 * 指定された_indexの場所に位置する子供を削除します | |
123 * @param _index | |
124 * @return 消される子供ノード | |
125 */ | |
126 public T get(int _index) | |
127 { | 110 { |
128 return m_list.get(_index); | 111 return m_list.get(_index); |
129 } | 112 } |
130 | 113 |
131 /** | 114 @Override |
132 * 指定されたUUIDを持つ子どもを削除します | 115 public synchronized T get(String _familyID) |
133 * @param _id | 116 { |
134 * @return 削除される子供ノード | 117 return m_map.get(_familyID); |
135 */ | 118 } |
136 public T remove(String _uuid) | 119 |
137 { | 120 @Override |
138 int size = m_list.size(); | 121 public synchronized T remove(int _index) |
139 | 122 { |
140 for(int i = 0;i < size;i ++){ | 123 T n = m_list.remove(_index); |
141 String uuid = m_list.get(i).getID().getUUID(); | 124 NodeID id = n.getID(); |
142 if(uuid.equals(_uuid)){ | 125 if(m_map.remove(id.getFamilyID()) != null){ |
143 //NodeIDのUUIDが一致した | 126 return n; |
144 return m_list.remove(i); | 127 } |
145 } | 128 |
146 } | 129 throw new IllegalStateException(""); |
147 | 130 } |
148 return null; | 131 |
149 } | 132 @Override |
150 | 133 public synchronized boolean contains(NodeID _id) |
151 /** | 134 { |
152 * 指定された場所の子供ノードを削除します | 135 T n = m_map.get(_id); |
153 * @param _index | 136 NodeID id = n.getID(); |
154 * @return 削除された子供ノード | 137 return id.equals(_id); |
155 */ | 138 } |
156 public T remove(int _index) | 139 |
157 { | 140 @Override |
158 return m_list.remove(_index); | 141 public synchronized void clearChildren() |
159 } | 142 { |
160 | 143 m_map.clear(); |
161 /** | |
162 * このリストに指定されたUUIDを持つNodeがあるか確認します | |
163 * @param _id | |
164 * @return 存在する場合true | |
165 */ | |
166 public boolean contains(String _uuid) | |
167 { | |
168 return m_set.contains(_uuid); | |
169 } | |
170 | |
171 /** | |
172 * 指定された二つのUUID(_uuid1,_uuid2)がリスト上に存在する場合、その二つの順番を入れ替えます | |
173 * @param _uuid1 String | |
174 * @param _uuid2 String | |
175 * @return 成功した場合はtrue,NodeIDが見つからなかった場合はfalse | |
176 */ | |
177 public boolean swap(String _uuid1,String _uuid2) | |
178 { | |
179 /* | |
180 * 二つのNodeIDの位置を求める | |
181 */ | |
182 int index1 = -1; | |
183 int index2 = -1; | |
184 | |
185 int size = m_list.size(); | |
186 for(int i = 0;i < size && (index1 == -1 || index2 == 1);i ++){ | |
187 String uuid = m_list.get(i).getID().getUUID(); | |
188 if(uuid.equals(_uuid1)){ | |
189 index1 = i; | |
190 continue; | |
191 } | |
192 | |
193 if(uuid.equals(_uuid2)){ | |
194 index2 = i; | |
195 continue; | |
196 } | |
197 } | |
198 | |
199 /* | |
200 * Collection.swapを使って入れ替える | |
201 */ | |
202 if(index1 != -1 && index2 != -1){ | |
203 Collections.swap(m_list,index1,index2); | |
204 return true; | |
205 } | |
206 | |
207 //NodeIDがリスト上になかった | |
208 return false; | |
209 } | |
210 | |
211 /** | |
212 * 子供ノードのリストをクリアします | |
213 */ | |
214 public void clearChildren() | |
215 { | |
216 m_set.clear(); | |
217 m_list.clear(); | 144 m_list.clear(); |
218 } | 145 } |
219 | 146 |
220 @SuppressWarnings("unchecked") | 147 @SuppressWarnings("unchecked") |
221 @Override | 148 @Override |
222 public boolean equals(Object _o) | 149 public synchronized boolean equals(Object _o) |
223 { | 150 { |
224 NodeChildrenImpl<T> list = (NodeChildrenImpl<T>)_o; | 151 NodeChildrenImpl<T> list = (NodeChildrenImpl<T>)_o; |
225 return m_list.equals(list.m_list); | 152 return m_list.equals(list.m_list); |
226 } | 153 } |
227 | 154 |
228 @Override | 155 @Override |
229 public int hashCode() | 156 public synchronized int hashCode() |
230 { | 157 { |
231 int result = 17; | 158 int result = 17; |
232 result = 37*result + m_list.hashCode(); | 159 result = 37*result + m_list.hashCode(); |
233 result = 37*result + m_set.hashCode(); | 160 result = 37*result + m_map.hashCode(); |
234 return result; | 161 return result; |
235 } | 162 } |
163 | |
164 @Override | |
165 public synchronized Set<String> getFamilyIDSet() | |
166 { | |
167 return m_map.keySet(); | |
168 } | |
169 | |
170 @Override | |
171 public synchronized T remove(String _fid) | |
172 { | |
173 return m_map.remove(_fid); | |
174 } | |
175 | |
176 @Override | |
177 public synchronized boolean swap(String _fid1, String _fid2) | |
178 { | |
179 if(m_map.containsKey(_fid1) && m_map.containsKey(_fid2)){ | |
180 int index1,index2; | |
181 index1 = index2 = -1; | |
182 int size = m_list.size(); | |
183 for(int i = 0;i < size;i ++){ | |
184 T n = m_list.get(i); | |
185 String fid = n.getID().getFamilyID(); | |
186 | |
187 if(fid.equals(_fid1)){ | |
188 index1 = i; | |
189 }else if(fid.equals(_fid2)){ | |
190 index2 = i; | |
191 } | |
192 | |
193 if(index1 != -1 && index2 != -1){ | |
194 Collections.swap(m_list, index1, index2); | |
195 return true; | |
196 } | |
197 } | |
198 } | |
199 return false; | |
200 } | |
236 } | 201 } |