File: FileList.java

package info (click to toggle)
libglazedlists-java 1.9.1-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 3,012 kB
  • sloc: java: 22,561; xml: 940; makefile: 5
file content (133 lines) | stat: -rw-r--r-- 4,822 bytes parent folder | download | duplicates (3)
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
/* Glazed Lists                                                 (c) 2003-2006 */
/* http://publicobject.com/glazedlists/                      publicobject.com,*/
/*                                                     O'Dell Engineering Ltd.*/
package ca.odell.glazedlists.io;

// the core Glazed Lists packages
import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.TransformedList;
import ca.odell.glazedlists.event.ListEvent;
import ca.odell.glazedlists.impl.io.Bufferlo;
import ca.odell.glazedlists.impl.io.ListEventToBytes;
import ca.odell.glazedlists.impl.pmap.Chunk;
import ca.odell.glazedlists.impl.pmap.PersistentMap;
import ca.odell.glazedlists.util.concurrent.ReadWriteLock;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * An {@link EventList} that is persisted to disk.
 *
 * <p><font size="5"><strong><font color="#FF0000">Warning:</font></strong> This
 * class is a technology preview and is subject to API changes.</font>
 *
 * <p><table border="1" width="100%" cellpadding="3" cellspacing="0">
 * <tr class="TableHeadingColor"><td colspan=2><font size="+2"><b>EventList Overview</b></font></td></tr>
 * <tr><td class="TableSubHeadingColor"><b>Writable:</b></td><td>yes</td></tr>
 * <tr><td class="TableSubHeadingColor"><b>Concurrency:</b></td><td>Requires {@link ReadWriteLock} for every access, even for single-threaded use</td></tr>
 * <tr><td class="TableSubHeadingColor"><b>Performance:</b></td><td>N/A</td></tr>
 * <tr><td class="TableSubHeadingColor"><b>Memory:</b></td><td>O(N)</td></tr>
 * <tr><td class="TableSubHeadingColor"><b>Unit Tests:</b></td><td>N/A</td></tr>
 * <tr><td class="TableSubHeadingColor"><b>Issues:</b></td><td>N/A</td></tr>
 * </table>
 *
 * @author <a href="mailto:jesse@swank.ca">Jesse Wilson</a>
 */
public final class FileList extends TransformedList {

    /** the destination file, just for user convenience */
    private File file = null;

    /** how bytes are encoded and decoded */
    private ByteCoder byteCoder;

    /** the underlying storage of ListEvents */
    private PersistentMap storage = null;

    /** the ID of the next update to write to disc */
    private int nextUpdateId = 81;

    /** whether this list can be modified */
    private boolean writable = true;

    /**
     * Create a {@link FileList} that stores its data in the specified file.
     */
    public FileList(File file, ByteCoder byteCoder) throws IOException {
        super(new BasicEventList());
        this.file = file;
        this.byteCoder = byteCoder;

        // store the updates in a persistent map
        storage = new PersistentMap(file);

        // sequence the updates
        SortedMap sequentialUpdates = new TreeMap();
        for(Iterator k = storage.keySet().iterator(); k.hasNext(); ) {
            Integer key = (Integer)k.next();
            Bufferlo valueBuffer = ((Chunk)storage.get(key)).getValue();
            sequentialUpdates.put(key, valueBuffer);
        }

        // replay all the updates from the file
        for(Iterator u = sequentialUpdates.keySet().iterator(); u.hasNext(); ) {
            Integer key = (Integer)u.next();
            Bufferlo update = (Bufferlo)sequentialUpdates.get(key);
            ListEventToBytes.toListEvent(update, this, byteCoder);
        }

        // prepare the next update id to use
        if(!sequentialUpdates.isEmpty()) {
            nextUpdateId = ((Integer)sequentialUpdates.lastKey()).intValue() + 1;
        }

        // now that we're up-to-date, listen for further events
        source.addListEventListener(this);
    }

    /** {@inheritDoc} */
    @Override
    public boolean isWritable() {
        return writable;
    }

    /** {@inheritDoc} */
    @Override
    public void listChanged(ListEvent listChanges) {
        // write the change to disc
        try {
            ListEvent listChangesCopy = listChanges.copy();
            Bufferlo listChangesBytes = ListEventToBytes.toBytes(listChangesCopy, byteCoder);
            storage.put(new Integer(nextUpdateId), new Chunk(listChangesBytes));
            nextUpdateId++;

        } catch(IOException e) {
            throw new IllegalStateException(e.getMessage());
        }

        // forward the event to interested listeners
        updates.forwardEvent(listChanges);
    }

    /**
     * Closes this FileList so that it consumes no disc resources. The list may
     * continue to be read until it is {@link #dispose() disposed}.
     */
    public void close() {
        if(storage != null) storage.close();
        storage = null;
        writable = false;
    }

    /** {@inheritDoc} */
    @Override
    public void dispose() {
        close();
        super.dispose();
    }
}