1
2
3
4
5
6 package org.openrdf.repository.memento;
7
8 import java.util.ArrayList;
9 import java.util.List;
10
11 import org.openrdf.model.Resource;
12 import org.openrdf.model.URI;
13 import org.openrdf.model.Value;
14 import org.openrdf.repository.DelegatingRepositoryConnection;
15 import org.openrdf.repository.RepositoryConnection;
16 import org.openrdf.repository.RepositoryException;
17 import org.openrdf.repository.event.NotifyingRepository;
18 import org.openrdf.repository.event.NotifyingRepositoryConnection;
19 import org.openrdf.repository.event.RepositoryConnectionListener;
20 import org.openrdf.repository.event.base.NotifyingRepositoryConnectionWrapper;
21
22
23
24
25
26
27
28
29
30
31
32
33 public class RepositoryMemento implements RepositoryConnectionListener {
34
35 private NotifyingRepositoryConnection conn;
36
37 private List<Command> committed;
38
39 private List<Command> active;
40
41 private RepositoryException exc;
42
43 public RepositoryMemento(RepositoryConnection conn)
44 throws RepositoryException {
45 this(findNotifier(conn));
46 }
47
48 public RepositoryMemento(NotifyingRepositoryConnection conn) {
49 this.conn = conn;
50 this.active = new ArrayList<Command>();
51 this.conn.addRepositoryConnectionListener(this);
52 if (conn instanceof NotifyingRepositoryConnectionWrapper) {
53 NotifyingRepositoryConnectionWrapper w;
54 w = (NotifyingRepositoryConnectionWrapper) conn;
55 w.setReportDeltas(true);
56 }
57 }
58
59 public void close(RepositoryConnection conn) {
60 stopListening();
61 }
62
63 public void setAutoCommit(RepositoryConnection conn, boolean autoCommit) {
64 synchronized (active) {
65 if (committed == null) {
66 committed = new ArrayList<Command>(active);
67 } else {
68 committed.addAll(active);
69 }
70 active.clear();
71 }
72 }
73
74 public void commit(RepositoryConnection conn) {
75 setAutoCommit(conn, true);
76 }
77
78 public void rollback(RepositoryConnection conn) {
79 synchronized (active) {
80 active.clear();
81 }
82 }
83
84 public void add(RepositoryConnection conn, Resource subj, URI pred,
85 Value obj, Resource... contexts) {
86 addCommand(new AddCommand(subj, pred, obj, contexts));
87 }
88
89 public void remove(RepositoryConnection conn, Resource subj, URI pred,
90 Value obj, Resource... contexts) {
91 if (subj == null || pred == null || obj == null || contexts == null || contexts.length == 0)
92 throw new UnsupportedOperationException("RepositoryMemento is only supported when reporting deltas is enabled");
93 addCommand(new RemoveCommand(subj, pred, obj, contexts));
94 }
95
96 public void clear(RepositoryConnection conn, Resource... contexts) {
97 throw new UnsupportedOperationException("RepositoryMemento is only supported when reporting deltas is enabled");
98 }
99
100 public void setNamespace(RepositoryConnection conn, String prefix,
101 String name) {
102 try {
103 String namespace = conn.getNamespace(prefix);
104 Command command = new OverrideNamespaceCommand(prefix, namespace,
105 name);
106 addCommand(command);
107 } catch (RepositoryException e) {
108 handleException(e);
109 }
110 }
111
112 public void removeNamespace(RepositoryConnection conn, String prefix) {
113 try {
114 String namespace = conn.getNamespace(prefix);
115 Command command = new OverrideNamespaceCommand(prefix, namespace,
116 null);
117 addCommand(command);
118 } catch (RepositoryException e) {
119 handleException(e);
120 }
121 }
122
123 public void clearNamespaces(RepositoryConnection conn) {
124 throw new UnsupportedOperationException("RepositoryMemento is only supported when reporting deltas is enabled");
125 }
126
127
128
129
130
131
132
133
134
135 public void undo(RepositoryConnection conn) throws RepositoryException {
136 if (exc != null)
137 throw exc;
138 stopListening();
139 synchronized (active) {
140 boolean autoCommit = conn.isAutoCommit();
141 conn.setAutoCommit(false);
142 undo(active, conn);
143 if (committed != null)
144 undo(committed, conn);
145 conn.setAutoCommit(autoCommit);
146 }
147 }
148
149
150
151
152
153
154
155
156
157 public void redo(RepositoryConnection conn) throws RepositoryException {
158 if (exc != null)
159 throw exc;
160 stopListening();
161 synchronized (active) {
162 boolean autoCommit = conn.isAutoCommit();
163 conn.setAutoCommit(false);
164 if (committed != null)
165 redo(committed, conn);
166 redo(active, conn);
167 conn.setAutoCommit(autoCommit);
168 }
169 }
170
171 private void undo(List<Command> commands, RepositoryConnection conn)
172 throws RepositoryException {
173 for (int i = commands.size() - 1; i >= 0; i--) {
174 Command command = commands.get(i);
175 command.undo(conn);
176 }
177 }
178
179 private void redo(List<Command> commands, RepositoryConnection conn)
180 throws RepositoryException {
181 for (Command command : commands) {
182 command.redo(conn);
183 }
184 }
185
186 private void addCommand(Command command) {
187 synchronized (active) {
188 active.add(command);
189 }
190 }
191
192 private void handleException(Exception e) {
193 if (e instanceof RepositoryException) {
194 exc = (RepositoryException) e;
195 } else if (e.getCause() instanceof RepositoryException) {
196 exc = (RepositoryException) e.getCause();
197 } else {
198 throw new AssertionError(e);
199 }
200 stopListening();
201 }
202
203 private static NotifyingRepositoryConnection findNotifier(
204 RepositoryConnection conn) throws RepositoryException {
205 if (conn instanceof NotifyingRepositoryConnectionWrapper) {
206 return (NotifyingRepositoryConnection) conn;
207 }
208 if (conn instanceof DelegatingRepositoryConnection) {
209 DelegatingRepositoryConnection dconn = (DelegatingRepositoryConnection) conn;
210 return findNotifier(dconn.getDelegate());
211 }
212 throw new IllegalArgumentException(
213 "Repository stack does not contain notification support");
214 }
215
216 private void stopListening() {
217 conn.removeRepositoryConnectionListener(this);
218 conn = null;
219 }
220 }