24 |
import java.io.IOException; |
import java.io.IOException; |
25 |
import java.util.*; |
import java.util.*; |
26 |
|
|
27 |
|
/** A "place" a <code>Version</code> can be loaded from and saved to. |
28 |
|
* The current implementation of this interface represents |
29 |
|
* a Storm pointer: Loading gets the latest version this pointer |
30 |
|
* points to, and saving puts the new version into the Storm pool, |
31 |
|
* setting the pointer to it. (The additional complexity of choosing |
32 |
|
* between current versions has to be handled by the <code>Filer</code>.) |
33 |
|
* <p> |
34 |
|
* The intent is that this interface could as well be used to |
35 |
|
* save a version to a file; in that case, loading simply gets |
36 |
|
* the current version and saving writes a new one to the file, |
37 |
|
* overwriting the old one. This way, you could write an application |
38 |
|
* that is capable of storing data both in a file and in Storm. |
39 |
|
*/ |
40 |
public interface Filer { |
public interface Filer { |
41 |
|
/** A mapping from ids (opaque URIs) to <code>Filer</code>s. |
42 |
|
* This is the interface the Gzz client uses to communicate |
43 |
|
* with its backend; each slice is stored in a separate |
44 |
|
* <code>Filer</code> identified by the slice's id. |
45 |
|
* <p> |
46 |
|
* In a Storm implementation, this object represents a Storm pool; |
47 |
|
* pointer ids are mapped to <code>Filer</code>s for those |
48 |
|
* pointers. |
49 |
|
* <p> |
50 |
|
* In a file-based implementation, this would be something |
51 |
|
* like a directory, mapping file names to <code>Filer</code>s |
52 |
|
* for the respective files. <strong>However</strong>, |
53 |
|
* the abstraction currently breaks there: The opaque URIs |
54 |
|
* (e.g., <code>urn:urn-5:</code>s) are not usable as file names |
55 |
|
* (without breaking people's assumptions how files work, |
56 |
|
* and the point here is to provide an interface that can be |
57 |
|
* implemented in a way matching peoples' expectations). |
58 |
|
* This needs more thinking: how can this interface be made |
59 |
|
* so that it works with files <em>and</em> Storm as expected? |
60 |
|
*/ |
61 |
interface Group { |
interface Group { |
62 |
|
/** Get the <code>Filer</code> for the given id (opaque URI). |
63 |
|
*/ |
64 |
Filer getFiler(String id) throws IOException; |
Filer getFiler(String id) throws IOException; |
65 |
|
|
66 |
|
/** Take a <code>Map</code> from <code>Filer</code> ids |
67 |
|
* (<code>String</code>s representing opaque URIs) |
68 |
|
* to <code>Version</code>; for each entry |
69 |
|
* in the <code>Map</code>, get the appropriate |
70 |
|
* <code>Filer</code> and save the <code>Version</code> |
71 |
|
* to it. |
72 |
|
*/ |
73 |
void saveAll(Map versions) throws IOException; |
void saveAll(Map versions) throws IOException; |
74 |
} |
} |
75 |
|
|
76 |
|
/** Load the current version stored in this filer. */ |
77 |
Version load() throws IOException; |
Version load() throws IOException; |
78 |
|
|
79 |
|
/** Save a version into this filer. */ |
80 |
void save(Version v) throws IOException; |
void save(Version v) throws IOException; |
81 |
|
|
82 |
|
|
84 |
abstract protected Filer createFiler(String id) throws IOException; |
abstract protected Filer createFiler(String id) throws IOException; |
85 |
|
|
86 |
protected Map filers = new HashMap(); |
protected Map filers = new HashMap(); |
|
protected Version emptyVersion; |
|
87 |
|
|
|
public AbstractGroup(Version emptyVersion) { |
|
|
this.emptyVersion = emptyVersion; |
|
|
} |
|
88 |
public Filer getFiler(String id) throws IOException { |
public Filer getFiler(String id) throws IOException { |
89 |
Filer f = (Filer)filers.get(id); |
Filer f = (Filer)filers.get(id); |
90 |
if(f == null) { |
if(f == null) { |