-
Notifications
You must be signed in to change notification settings - Fork 8
/
XasTests.java
328 lines (293 loc) · 11.6 KB
/
XasTests.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
/*
* Copyright 2005--2008 Helsinki Institute for Information Technology
*
* This file is a part of Fuego middleware. Fuego middleware is free
* software; you can redistribute it and/or modify it under the terms
* of the MIT license, included as the file MIT-LICENSE in the Fuego
* middleware source distribution. If you did not receive the MIT
* license with the distribution, write to the Fuego Core project at
* fuego-raxs-users@hoslab.cs.helsinki.fi.
*/
package fc.xml.xmlr.test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import java.util.Stack;
import junit.framework.Assert;
import junit.framework.TestCase;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
import fc.util.IOExceptionTrap;
import fc.util.log.Log;
import fc.xml.xas.AttributeNode;
import fc.xml.xas.EndTag;
import fc.xml.xas.Item;
import fc.xml.xas.ItemSource;
import fc.xml.xas.ItemTarget;
import fc.xml.xas.ItemTransform;
import fc.xml.xas.Qname;
import fc.xml.xas.StartTag;
import fc.xml.xas.XasFragment;
import fc.xml.xas.XmlOutput;
import fc.xml.xas.XmlPullSource;
import fc.xml.xas.index.Document;
import fc.xml.xas.typing.TypedItem;
import fc.xml.xmlr.Key;
import fc.xml.xmlr.RefTree;
import fc.xml.xmlr.RefTreeNode;
import fc.xml.xmlr.XmlrDebug;
import fc.xml.xmlr.model.KeyIdentificationModel;
import fc.xml.xmlr.model.KeyModel;
import fc.xml.xmlr.model.StringKey;
import fc.xml.xmlr.model.TreeModel;
import fc.xml.xmlr.test.RandomDirectoryTree.DirectoryEntry;
import fc.xml.xmlr.xas.DeweyKey;
import fc.xml.xmlr.xas.DeweyXasSource;
import fc.xml.xmlr.xas.IdAttributeXasSource;
import fc.xml.xmlr.xas.PeekableItemSource;
import fc.xml.xmlr.xas.UniformXasCodec;
import fc.xml.xmlr.xas.XasRefTree;
import fc.xml.xmlr.xas.XasSerialization;
public class XasTests extends TestCase implements IOExceptionTrap {
// Stringkey generator
private RandomDirectoryTree.KeyGen kg = new RandomDirectoryTree.KeyGen(0) {
public Key next() {
return StringKey.createKey(this.id++) ;
}
};
public XasTests() {
super("XMLR XAS tests");
}
public void testCodecCycle() throws IOException {
int RND_SEED=314*42;
double DIRP=0.05;
long TSIZE=50;long DSIZE=5;double DPROB=0.1;double VAR=5.0;double DVAR=2.0;
RefTree dt = RandomDirectoryTree.randomDirTree(TSIZE,DSIZE,DPROB,VAR,DVAR,
new Random(RND_SEED),kg);
ByteArrayOutputStream out = new ByteArrayOutputStream();
XmlOutput t = new XmlOutput(out,"UTF-8");
TreeModel tm = TreeModel.createIdAsStringKey(new DirTreeModel());
XasSerialization.writeTree(dt,t,tm);
t.flush();
Log.debug("Encoded XML ", new String( out.toByteArray() ) );
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
ItemSource is = new XmlPullSource(new KXmlParser(),in);
RefTree dt2 =
XasSerialization.readTree(is, tm );
Assert.assertTrue("Round-tripped trees do not match",
XmlrDebug.treeComp(dt,dt2));
//Log.info("Original tree");
//TreeUtil.dumpTree(dt);
//Log.info("Re-read tree");
//TreeUtil.dumpTree(dt2);
}
public void testXasRefTree() throws IOException {
// Build a tree to read...
Log.setLogger(new fc.util.log.SysoutLogger());
int RND_SEED=314*42;
double DIRP=0.05;
long TSIZE=5000;long DSIZE=50;double DPROB=0.1;double VAR=5.0;double DVAR=2.0;
RefTree dt = RandomDirectoryTree.randomDirTree(TSIZE,DSIZE,DPROB,VAR,DVAR,
new Random(RND_SEED),kg);
//dewify(dt.getRoot(),fc.xml.xas.index.DeweyKey.initial());
RefTree dtd = new DeweyKeyedRefTree(dt,DeweyKey.ROOT_KEY.child(0));
//TreeUtil.dumpTree(dtd);
ByteArrayOutputStream out = new ByteArrayOutputStream();
XmlOutput xo = new XmlOutput(out,"UTF-8");
XasSerialization.writeTree(dt,xo,
TreeModel.createIdAsStringKey( new DirTreeModel() ) );
xo.flush();
// Build Xas doc on the stream
XmlPullParser parser = new KXmlParser();
ItemSource is = new XmlPullSource(parser,
new ByteArrayInputStream(out.toByteArray()) );
XasFragment basedocf = convert(is);
Document basedoc=new Document(basedocf);
basedocf.treeify(); // TODO: 4JK: Shouldn't need to do this...
DirTreeModel dtm = new DirTreeModel(KeyIdentificationModel.ID_AS_STRINGKEY);
// NOTE: ugly override to DirTreeModel to get right getId() to the content
// Try the dewey-keyed variant
XasRefTree tt =
new XasRefTree(DeweyXasSource.createForRootTag(basedoc),dtm);
tt.setTrap(this);
Log.debug("Testing Dewey tree..");
//XmlrDebug.dumpTree(tt);
Assert.assertTrue("Re-parsed Dewey tree does not match original",
XmlrDebug.treeComp(dtd, tt ));
//TreeUtil.dumpTree(t);
// And now the id-keyed
Log.debug("Making id tree..");
IdAttributeXasSource ixas = new IdAttributeXasSource.MemoryIdIndexSource
(basedoc, IdAttributeXasSource.getRootPointer(basedoc));
XasRefTree t = new XasRefTree(ixas,dtm);
t.setTrap(this);
//XmlrDebug.dumpTree(t);
//XmlrDebug.dumpTree(dt);
Log.debug("Testing id tree..");
Assert.assertTrue("Re-parsed id tree does not match original",
XmlrDebug.treeComp(dt, t ));
Log.debug("done..");
t=null;tt=null;
System.runFinalization();
}
public void testDeweyAddressableTree() throws Exception {
XmlPullParser parser = new KXmlParser();
ItemSource is = new XmlPullSource(parser,
new FileInputStream("test/ebook/linux-intro.xml"));
XasFragment basedocf = convert(is);
Document basedoc=new Document(basedocf);
basedocf.treeify(); // TODO: 4JK: Shouldn't need to do this...
// Try the dewey-keyed variant
XasRefTree t = new XasRefTree( new DeweyXasSource( basedoc ),
UniformXasCodec.ITEM_CODEC);
/*DeweyXasRefTree t = new DeweyXasRefTree( basedoc,
XasSerialization.ITEM);*/
t.setTrap(this);
DeweyKey k = DeweyKey.createKey("/2/3/1/0");
RefTreeNode n = t.getNode(k);
Log.info("Node at "+k+" is "+n);
Log.info("Key at "+k+" is "+n.getId());
Log.info("Content at "+k+" is "+(n != null ? n.getContent() : null));
t=null;
System.runFinalization();
//Thread.sleep(2000);
}
// TODO Some sort of convenience method from ItemSource to Fragment
private static XasFragment convert (ItemSource source) throws IOException {
List<Item> items = new ArrayList<Item>();
Item item = source.next();
Item firstItem = item;
while (item != null) {
items.add(item);
item = source.next();
}
// TODO: 4JK: This copies the list items;there should be a constructor
// that builds on top of an existing list
return new XasFragment(items, firstItem);
}
// TODO: 4JK Make some sort of base classes for easy write of
// 1-n and n-1 transforms (in the former case, filtering at append() is
// easy, in the latter at next()
// This is a simple try at this
public abstract static class AbstractItemTransform implements ItemTransform {
protected Queue<Item> queue = new LinkedList<Item>();
public boolean hasItems () {
return queue.peek() != null;
}
public Item next () throws IOException {
return queue.poll();
}
public abstract void append (Item item) throws IOException;
}
public static class EntryDecoder extends AbstractItemTransform {
public static final Qname DUMMY_TYPE=new Qname("","");
public static final Qname ID_ATTR=new Qname("","id");
public static final Qname NAME_ATTR=new Qname("","name");
public void append(Item i) throws IOException {
if( i.getType() == Item.START_TAG ) {
StartTag t = (StartTag) i;
String ts = t.getName().getName();
String id = t.getAttribute(ID_ATTR).getValue().toString();
AttributeNode name = t.getAttribute(NAME_ATTR);
DirectoryEntry de = new
DirectoryEntry( StringKey.createKey(id),
name == null ? null : name.getValue().toString(),
"file".equals(ts) ? DirectoryEntry.FILE : ("tree".equals(ts) ?
DirectoryEntry.TREE : DirectoryEntry.DIR ));
queue.offer(i);
queue.offer(new TypedItem(DUMMY_TYPE,de));
} else {
queue.offer(i);
//Log.info("Skipping item ",i);
}
}
}
public static class EntryEncoder extends AbstractItemTransform {
private Stack<StartTag> openTags = new Stack<StartTag>();
public void append(Item i) throws IOException {
if( i.getType() == Item.START_TAG )
return; // Just ignore it...
else if( i.getType() == TypedItem.TYPED ) {
TypedItem t = (TypedItem) i;
if( !(t.getValue() instanceof DirectoryEntry ) )
throw new IOException("Cannot encode data "+t.getValue().getClass());
DirectoryEntry de = (DirectoryEntry) t.getValue();
StartTag st = new StartTag(new Qname("",
de.getType() == DirectoryEntry.FILE ? "file" :
(de.getType() == DirectoryEntry.TREE ? "tree" : "directory" )));
st.addAttribute(EntryDecoder.ID_ATTR,de.getId().toString());
if( de.getName() != null ) // <tree> has no name
st.addAttribute(EntryDecoder.NAME_ATTR,de.getName());
openTags.push(st);
queue.offer(st);
//queue.offer(new Text("\n")); // For prettyprinting
} else if( i.getType() == Item.END_TAG ) {
// Add end tag matching the last emitted start one
// (id we didn't encode type in tag name, this wouldn't be necessary,
// and we could just use a standard name here)
/*if( openTags.isEmpty() ) {
Log.warning("Empty stack",i);
return;
}*/
StartTag t = openTags.pop();
queue.offer(new EndTag(t.getName()));
} else {
queue.offer(i);
//Log.warning("Unexpected item",i);
}
}
}
public static class DirTreeModel implements UniformXasCodec {
KeyModel okim = null; // Overriding kim to get proper class for
// de.getId(), when the node key is not correct
EntryDecoder ed = new EntryDecoder();
public DirTreeModel(KeyModel okim) {
this.okim = okim;
}
public DirTreeModel() {
}
public Object decode(PeekableItemSource is, KeyIdentificationModel kim)
throws IOException {
//assert kim != null;
// A bit kludge-ish .. we way we re-use the sequence encoder...
Item i = is.next();
ed.append(i);
ed.next(); // The untouched ST
// FIXME: A dummy wrapper node for the content is really a bit ugly
// OTOH, we quite nicely got key decode here!
TypedItem ti = (TypedItem) ed.next();
DirectoryEntry de = null;
if(ti != null) {
de = (DirectoryEntry) ti.getValue();
//de.setId((okim == null ? kim : okim) .identify(i));
de.setId((okim == null ? kim : okim).makeKey(de.getId().toString()));
}
return de;
}
public void encode(ItemTarget t, RefTreeNode n, StartTag context) throws IOException {
DirectoryEntry e = (DirectoryEntry) n.getContent();
StartTag st = new StartTag(new Qname("",
e.getType() == DirectoryEntry.FILE ? "file" :
(e.getType() == DirectoryEntry.DIR ? "directory" : "tree")),context);
if(e.getType() != DirectoryEntry.TREE )
st.addAttribute( EntryDecoder.NAME_ATTR, e.getName());
st.addAttribute( EntryDecoder.ID_ATTR, e.getId().toString());
t.append(st);
}
public int size() {
return 1;
}
}
public void trap(IOException ex) {
Log.fatal("An I/O error occurred",ex);
Assert.fail();
}
}
// arch-tag: c2f3eec0-3c2f-4faf-8f62-fc1e73d1e2d2
//