124
|
1 package app.bbs;
|
|
2
|
|
3 import java.io.File;
|
|
4 import java.io.FileNotFoundException;
|
|
5 import java.io.IOException;
|
|
6 import java.nio.ByteBuffer;
|
|
7 import java.util.Date;
|
|
8 import java.util.concurrent.atomic.AtomicInteger;
|
|
9
|
|
10 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.Jungle;
|
|
11 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.JungleTree;
|
|
12 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.JungleTreeEditor;
|
125
|
13 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.bbs.BoardMessage;
|
124
|
14 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.core.Children;
|
|
15 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.core.Node;
|
|
16 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.persistent.ChangeList;
|
|
17 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.persistent.ChangeListReader;
|
|
18 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.DefaultNodePath;
|
|
19 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.impl.DefaultTreeEditor;
|
|
20 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.trasnformer.EditableNode;
|
|
21 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.store.trasnformer.NodeEditor;
|
|
22 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.traverser.DefaultTraverser;
|
|
23 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.DefaultEither;
|
|
24 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Either;
|
|
25 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.Error;
|
|
26 import jp.ac.u_ryukyu.ie.cr.shoshi.jungle.util.IterableConverter;
|
|
27 import alice.jungle.core.NetworkDefaultJungle;
|
|
28 import alice.jungle.persistent.PersistentJournal;
|
|
29 import alice.jungle.transaction.JungleUpdater;
|
|
30
|
|
31 public class PersistentJungleBulletinBoard implements NetworkBulletinBoard
|
|
32 {
|
|
33 private final Jungle jungle;
|
|
34 private final PersistentJournal journal;
|
|
35 private final String LOG_DIR = "./log";
|
|
36
|
|
37 public PersistentJungleBulletinBoard(String _uuid) throws FileNotFoundException
|
|
38 {
|
|
39 journal = new PersistentJournal();
|
|
40 jungle = new NetworkDefaultJungle(journal, _uuid,new DefaultTreeEditor(new DefaultTraverser()));
|
|
41 BullentInBoardJungleManager.setJungle(jungle);
|
|
42 }
|
|
43
|
|
44 public void init() {
|
|
45 checkAndCreateLogDirectory();
|
|
46 try {
|
|
47 commitLogRecover();
|
|
48 } catch (IOException e) {
|
|
49 e.printStackTrace();
|
|
50 }
|
|
51 }
|
|
52
|
|
53 public void checkAndCreateLogDirectory() {
|
|
54 File logFile = new File(LOG_DIR);
|
|
55 if(!logFile.exists()) {
|
|
56 logFile.mkdir();
|
|
57 return;
|
|
58 }
|
|
59 if (logFile.isFile()) {
|
|
60 logFile.delete();
|
|
61 logFile.mkdir();
|
|
62 }
|
|
63 }
|
|
64
|
|
65 public void commitLogRecover() throws IOException {
|
|
66 File[] logFiles = new File(LOG_DIR).listFiles();
|
|
67 for(File logFile : logFiles) {
|
|
68 commitLogRecover(logFile);
|
|
69 logFile.delete();
|
|
70 }
|
|
71 if(jungle.getTreeByName("boards") == null) {
|
|
72 jungle.createNewTree("boards");
|
|
73 }
|
|
74 }
|
|
75
|
|
76 private void commitLogRecover(File logFile) throws IOException {
|
|
77 journal.setInputFile(logFile);
|
|
78 ChangeListReader reader = journal.getReader();
|
|
79 if (reader == null) return;
|
|
80 for (ChangeList chList : reader) {
|
|
81 String treeName = chList.getTreeName();
|
|
82 JungleTree tree = jungle.getTreeByName(treeName);
|
|
83 if(tree == null) {
|
|
84 tree = jungle.createNewTree(treeName);
|
|
85 }
|
|
86 JungleTreeEditor editor = tree.getLocalTreeEditor();
|
|
87 Either<Error, JungleTreeEditor> either = JungleUpdater.edit(editor, chList);
|
|
88 editor = either.b();
|
|
89 if(either.isA()) {
|
|
90 throw new IOException("Failed commit log recovery");
|
|
91 }
|
|
92 editor.success();
|
|
93 }
|
|
94 }
|
|
95
|
|
96 public Iterable<String> getBoards()
|
|
97 {
|
|
98 JungleTree tree = jungle.getTreeByName("boards");
|
|
99 Node node = tree.getRootNode();
|
|
100 Children<Node> chs = node.getChildren();
|
|
101
|
|
102 IterableConverter.Converter<String,Node> converter = new IterableConverter.Converter<String,Node>(){
|
|
103 public String conv(Node _b) {
|
|
104 ByteBuffer e = _b.getAttributes().get("name");
|
|
105 return new String(e.array());
|
|
106 }
|
|
107 };
|
|
108
|
|
109 return new IterableConverter<String,Node>(chs,converter);
|
|
110 }
|
|
111
|
|
112 public void createBoards(final String _name,final String _author,final String _initMessage,final String _editKey)
|
|
113 {
|
|
114 if(null == jungle.createNewTree(_name)){
|
|
115 throw new IllegalStateException();
|
|
116 }
|
|
117
|
|
118 JungleTree tree = jungle.getTreeByName("boards");
|
|
119 JungleTreeEditor editor = tree.getTreeEditor();
|
|
120 DefaultNodePath root = new DefaultNodePath();
|
|
121 Either<Error,JungleTreeEditor> either = editor.addNewChildAt(root,0);
|
|
122 if(either.isA()){
|
|
123 throw new IllegalStateException();
|
|
124 }
|
|
125 editor = either.b();
|
|
126
|
|
127 either = editor.putAttribute(root.add(0),"name",ByteBuffer.wrap(_name.getBytes()));
|
|
128 if(either.isA()){
|
|
129 throw new IllegalStateException();
|
|
130 }
|
|
131 editor = either.b();
|
130
|
132 final long timestamp = new Date().getTime();
|
|
133 ByteBuffer tBuffer = ByteBuffer.allocate(16);
|
|
134 either = editor.putAttribute(root.add(0),"timestamp", tBuffer.putLong(timestamp));
|
|
135 if(either.isA()){
|
|
136 throw new IllegalStateException();
|
|
137 }
|
|
138 editor = either.b();
|
124
|
139 Either<Error,JungleTreeEditor> result = editor.success();
|
|
140 if(result.isA()){
|
|
141 throw new IllegalStateException();
|
|
142 }
|
|
143
|
|
144
|
|
145 tree = jungle.getTreeByName(_name);
|
|
146 editor = tree.getTreeEditor();
|
|
147 either = editor.addNewChildAt(root,0);
|
|
148 if(either.isA()){
|
|
149 throw new IllegalStateException();
|
|
150 }
|
|
151 editor = either.b();
|
|
152
|
|
153 NodeEditor e = new NodeEditor(){
|
|
154 public <T extends EditableNode<T>> Either<Error, T> edit(T _e){
|
|
155 _e = _e.getAttributes().put("author",ByteBuffer.wrap(_author.getBytes())).b();
|
|
156 _e = _e.getAttributes().put("mes",ByteBuffer.wrap(_initMessage.getBytes())).b();
|
|
157 _e = _e.getAttributes().put("key",ByteBuffer.wrap(_editKey.getBytes())).b();
|
130
|
158 ByteBuffer tBuffer2 = ByteBuffer.allocate(16);
|
|
159 _e = _e.getAttributes().put("timestamp",tBuffer2.putLong(timestamp)).b();
|
124
|
160 return DefaultEither.newB(_e);
|
|
161 }
|
|
162 };
|
|
163
|
|
164 either = editor.edit(root.add(0),e);
|
|
165 if(either.isA()){
|
|
166 throw new IllegalStateException();
|
|
167 }
|
|
168 editor = either.b();
|
|
169 editor.success();
|
|
170 }
|
|
171
|
|
172 public void createBoardMessage(final String _board,final String _author,final String _message,final String _editKey)
|
|
173 {
|
|
174 JungleTree tree = jungle.getTreeByName(_board);
|
|
175 if(tree == null){
|
|
176 throw new IllegalStateException();
|
|
177 }
|
|
178
|
|
179 Either<Error, JungleTreeEditor> either;
|
|
180 do{
|
|
181 Node node = tree.getRootNode();
|
|
182 int size = node.getChildren().size();
|
|
183 DefaultNodePath path = new DefaultNodePath();
|
|
184
|
|
185 JungleTreeEditor editor = tree.getTreeEditor();
|
|
186 either = editor.addNewChildAt(path,size);
|
|
187 if(either.isA()){
|
|
188 throw new IllegalStateException();
|
|
189 }
|
|
190 editor = either.b();
|
|
191 final long timestamp = new Date().getTime();
|
|
192 NodeEditor e = new NodeEditor(){
|
|
193 public <T extends EditableNode<T>> Either<Error, T> edit(T _e){
|
|
194 _e = _e.getAttributes().put("author",ByteBuffer.wrap(_author.getBytes())).b();
|
|
195 _e = _e.getAttributes().put("mes",ByteBuffer.wrap(_message.getBytes())).b();
|
|
196 _e = _e.getAttributes().put("key",ByteBuffer.wrap(_editKey.getBytes())).b();
|
|
197 ByteBuffer tBuffer = ByteBuffer.allocate(16);
|
|
198 _e = _e.getAttributes().put("timestamp",tBuffer.putLong(timestamp)).b();
|
|
199 return DefaultEither.newB(_e);
|
|
200 }
|
|
201 };
|
|
202 path = path.add(size);
|
|
203 either = editor.edit(path,e);
|
|
204 if(either.isA()){
|
|
205 throw new IllegalStateException();
|
|
206 }
|
|
207 editor = either.b();
|
|
208 either = editor.success();
|
|
209
|
|
210 }while(either.isA());
|
|
211 }
|
|
212
|
|
213 public void editMessage(String _board,String _uuid,final String _author,final String _message,final String _editKey)
|
|
214 {
|
|
215 for(;;) {
|
|
216 DefaultNodePath path = new DefaultNodePath();
|
|
217 path = path.add(Integer.parseInt(_uuid));
|
|
218
|
|
219 JungleTree tree = jungle.getTreeByName(_board);
|
|
220 JungleTreeEditor editor = tree.getTreeEditor();
|
|
221 final long timestamp = new Date().getTime();
|
|
222 NodeEditor e = new NodeEditor(){
|
|
223 public <T extends EditableNode<T>> Either<Error, T> edit(T _e){
|
|
224 _e = _e.getAttributes().put("author",ByteBuffer.wrap(_author.getBytes())).b();
|
|
225 _e = _e.getAttributes().put("mes",ByteBuffer.wrap(_message.getBytes())).b();
|
|
226 _e = _e.getAttributes().put("key",ByteBuffer.wrap(_editKey.getBytes())).b();
|
|
227 ByteBuffer tBuffer = ByteBuffer.allocate(16);
|
|
228 _e = _e.getAttributes().put("timestamp",tBuffer.putLong(timestamp)).b();
|
|
229 return DefaultEither.newB(_e);
|
|
230 }
|
|
231 };
|
|
232
|
|
233 Either<Error, JungleTreeEditor> either = editor.edit(path,e);
|
|
234 if(either.isA()){
|
|
235 throw new IllegalStateException();
|
|
236 }
|
|
237 editor = either.b();
|
|
238 either = editor.success();
|
|
239 if(!either.isA()) {
|
|
240 return;
|
|
241 }
|
|
242 }
|
|
243
|
|
244 }
|
|
245
|
|
246 public Iterable<BoardMessage> getMessages(String _boardName)
|
|
247 {
|
|
248 JungleTree tree = jungle.getTreeByName(_boardName);
|
|
249 Node node = tree.getRootNode();
|
|
250 Children<Node> chs = node.getChildren();
|
|
251
|
|
252 final AtomicInteger counter = new AtomicInteger(0);
|
|
253 IterableConverter.Converter<BoardMessage,Node> converter = new IterableConverter.Converter<BoardMessage,Node>(){
|
|
254 public BoardMessage conv(Node _b) {
|
|
255 String uuid = Integer.toString(counter.get());
|
|
256 String author = new String(_b.getAttributes().get("author").array());
|
|
257 String message = new String(_b.getAttributes().get("mes").array());
|
|
258 counter.incrementAndGet();
|
|
259 return new BoardMessageImpl(author,message,uuid);
|
|
260 }
|
|
261 };
|
|
262 return new IterableConverter<BoardMessage,Node>(chs,converter);
|
|
263 }
|
|
264
|
|
265
|
|
266
|
|
267 private static class BoardMessageImpl implements BoardMessage
|
|
268 {
|
|
269 private final String author;
|
|
270 private final String message;
|
|
271 private final String uuid;
|
|
272
|
|
273 public BoardMessageImpl(String _author,String _message,String _uuid)
|
|
274 {
|
|
275 author = _author;
|
|
276 message = _message;
|
|
277 uuid = _uuid;
|
|
278 }
|
|
279
|
|
280 public String getAuthor()
|
|
281 {
|
|
282 return author;
|
|
283 }
|
|
284
|
|
285 public String getMessage()
|
|
286 {
|
|
287 return message;
|
|
288 }
|
|
289
|
|
290 public String getUUID()
|
|
291 {
|
|
292 return uuid;
|
|
293 }
|
|
294 }
|
|
295
|
|
296
|
|
297
|
|
298 }
|