Mercurial > hg > blitz_condensed
comparison src/org/prevayler/implementation/SnapshotPrevaylerImpl.java @ 0:3dc0c5604566
Initial checkin of blitz 2.0 fcs - no installer yet.
author | Dan Creswell <dan.creswell@gmail.com> |
---|---|
date | Sat, 21 Mar 2009 11:00:06 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:3dc0c5604566 |
---|---|
1 /* | |
2 The copyright of all source code included in this Prevayler distribution is | |
3 held by Klaus Wuestefeld, except the files that specifically state otherwise. | |
4 All rights are reserved. "PREVAYLER" is a trademark of Klaus Wuestefeld. | |
5 | |
6 | |
7 BSD License: | |
8 | |
9 Redistribution and use in source and binary forms, with or without | |
10 modification, are permitted provided that the following conditions are met: | |
11 | |
12 - Redistributions of source code must retain the above copyright notice, this | |
13 list of conditions and the following disclaimer. | |
14 | |
15 - Redistributions in binary form must reproduce the above copyright notice, | |
16 this list of conditions and the following disclaimer in the documentation | |
17 and/or other materials provided with the distribution. | |
18 | |
19 - Neither the name of Prevayler nor the names of its contributors may be used | |
20 to endorse or promote products derived from this software without specific | |
21 prior written permission. | |
22 | |
23 | |
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
25 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
26 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
27 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
28 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
29 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
30 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
31 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
32 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
33 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
34 POSSIBILITY OF SUCH DAMAGE. | |
35 */ | |
36 | |
37 package org.prevayler.implementation; | |
38 | |
39 import java.util.Date; | |
40 import java.io.*; | |
41 | |
42 import java.rmi.RMISecurityManager; | |
43 | |
44 import org.prevayler.*; | |
45 | |
46 /** Provides transparent persistence for business objects. | |
47 * This applies to any deterministic system implementing the PrevalentSystem interface. | |
48 * All commands to the system must be represented as objects implementing the Command interface and must be executed using Prevayler.executeCommand(Command). | |
49 * Take a look at the demo application included with the Prevayler distribution for examples. | |
50 */ | |
51 public class SnapshotPrevaylerImpl implements SnapshotPrevayler { | |
52 | |
53 private final PrevalentSystem system; | |
54 private final SystemClock clock; | |
55 private final CommandOutputStream output; | |
56 | |
57 | |
58 /** Returns a new Prevayler for the given PrevalentSystem. | |
59 * "PrevalenceBase" shall be the directory where the snapshot and log files shall be created and read. | |
60 * @param newSystem The newly started, "empty" PrevalentSystem that will be used as a starting point for every system startup, until the first snapshot is taken. | |
61 * @param shouldReset Whether to issue resets in the underlying OOS | |
62 */ | |
63 public SnapshotPrevaylerImpl(PrevalentSystem newSystem, | |
64 boolean shouldReset, boolean shouldClean, | |
65 int aBufferSize) | |
66 throws IOException, ClassNotFoundException { | |
67 | |
68 this(newSystem, "PrevalenceBase", shouldReset, shouldClean, | |
69 aBufferSize); | |
70 } | |
71 | |
72 | |
73 /** Returns a new Prevayler for the given PrevalentSystem. | |
74 * @param newSystem The newly started, "empty" PrevalentSystem that will be used as a starting point for every system startup, until the first snapshot is taken. | |
75 * @param directory The full path of the directory where the snapshot and log files shall be created and read. | |
76 * @param shouldReset Whether to issue resets in the underlying OOS | |
77 */ | |
78 public SnapshotPrevaylerImpl(PrevalentSystem newSystem, String directory, | |
79 boolean shouldReset, boolean shouldClean, | |
80 int aBufferSize) | |
81 throws IOException, ClassNotFoundException { | |
82 | |
83 newSystem.clock(new SystemClock()); | |
84 CommandInputStream input = new CommandInputStream(directory); | |
85 | |
86 PrevalentSystem savedSystem = input.readLastSnapshot(); | |
87 system = (savedSystem == null) | |
88 ? newSystem | |
89 : savedSystem; | |
90 | |
91 recoverCommands(input); | |
92 | |
93 output = input.commandOutputStream(shouldReset, shouldClean, | |
94 aBufferSize); | |
95 clock = (SystemClock)system.clock(); | |
96 clock.resume(); | |
97 } | |
98 | |
99 public SnapshotPrevaylerImpl(PrevalentSystem newSystem, String directory) | |
100 throws IOException, ClassNotFoundException { | |
101 | |
102 clock = null; | |
103 output = null; | |
104 | |
105 newSystem.clock(new SystemClock()); | |
106 CommandInputStream input = new CommandInputStream(directory); | |
107 | |
108 PrevalentSystem savedSystem = input.readLastSnapshot(); | |
109 | |
110 if (savedSystem != null) | |
111 system = savedSystem; | |
112 else | |
113 system = newSystem; | |
114 | |
115 System.out.println("System base clock: " + system.clock().time().getTime()); | |
116 Serializable[] myUserData = system.getSnapshotContributions(); | |
117 | |
118 for (int i = 0; i < myUserData.length; i++) { | |
119 System.out.println(myUserData[i].toString()); | |
120 } | |
121 | |
122 debugCommands(input); | |
123 } | |
124 | |
125 /** | |
126 Returns the underlying PrevalentSystem. | |
127 */ | |
128 public PrevalentSystem system() { | |
129 return system; | |
130 } | |
131 | |
132 /** Logs the received command for crash or shutdown recovery and executes it on the underlying PrevalentSystem. | |
133 * @see system() | |
134 * @return The serializable object that was returned by the execution of command. | |
135 * @throws IOException if there is trouble writing the command to the log. | |
136 * @throws Exception if command.execute() throws an exception. | |
137 */ | |
138 public Serializable executeCommand(Command command) throws Exception { | |
139 | |
140 synchronized(this) { | |
141 try { | |
142 clock.pause(); //To be deterministic, the system must know exactly at what time the command is being executed. | |
143 output.writeCommand(new ClockRecoveryCommand(command, clock.time())); | |
144 } finally { | |
145 clock.resume(); | |
146 } | |
147 } | |
148 | |
149 return command.execute(system); | |
150 } | |
151 | |
152 public Serializable executeCommand(Command command, | |
153 boolean doSync) | |
154 throws Exception { | |
155 | |
156 synchronized(this) { | |
157 try { | |
158 clock.pause(); | |
159 output.writeCommand(new ClockRecoveryCommand(command, | |
160 clock.time()), | |
161 doSync); | |
162 } finally { | |
163 clock.resume(); | |
164 } | |
165 } | |
166 | |
167 return command.execute(system); | |
168 } | |
169 | |
170 /** | |
171 * This method prepares a snapshot of the system and returns it in a | |
172 * Snapshotter instance which can be used to save the snapshot to disk | |
173 * once dirty state has been sync'd to disk. If your application has no | |
174 * additional state, you can simply invoke on the Snapshotter immediately. | |
175 * @return Snapshotter to be used to save an appropriate snapshot post | |
176 * sync'ing of dirty state to disk. | |
177 * @see system() | |
178 * @throws IOException if there is trouble preparing the snapshot file. | |
179 */ | |
180 public synchronized Snapshotter takeSnapshot() throws IOException { | |
181 clock.pause(); | |
182 try { | |
183 return output.writeSnapshot(system); | |
184 } finally { | |
185 clock.resume(); | |
186 } | |
187 } | |
188 | |
189 private void debugCommands(CommandInputStream input) throws IOException, ClassNotFoundException { | |
190 Command command; | |
191 while(true) { | |
192 try { | |
193 command = input.readCommand(); | |
194 } catch (EOFException eof) { | |
195 break; | |
196 } | |
197 | |
198 try { | |
199 System.out.println(command); | |
200 System.out.println(); | |
201 // command.execute(system); | |
202 } catch (Exception e) { | |
203 //Don't do anything at all. Commands may throw exceptions normally. | |
204 System.err.println("Command threw exception"); | |
205 e.printStackTrace(System.err); | |
206 } | |
207 } | |
208 } | |
209 | |
210 private void recoverCommands(CommandInputStream input) throws IOException, ClassNotFoundException { | |
211 Command command; | |
212 while(true) { | |
213 try { | |
214 command = input.readCommand(); | |
215 } catch (EOFException eof) { | |
216 break; | |
217 } | |
218 | |
219 try { | |
220 command.execute(system); | |
221 } catch (Exception e) { | |
222 //Don't do anything at all. Commands may throw exceptions normally. | |
223 System.err.println("Command threw exception"); | |
224 e.printStackTrace(System.err); | |
225 } | |
226 } | |
227 } | |
228 | |
229 public static void main(String anArgs[]) { | |
230 try { | |
231 System.setSecurityManager(new RMISecurityManager()); | |
232 | |
233 new SnapshotPrevaylerImpl(new DebugSystem(), anArgs[0]); | |
234 } catch (Exception anE) { | |
235 System.err.println("Whoops"); | |
236 anE.printStackTrace(System.err); | |
237 } | |
238 } | |
239 | |
240 static class DebugSystem implements org.prevayler.PrevalentSystem { | |
241 private org.prevayler.AlarmClock theClock; | |
242 | |
243 public void clock(org.prevayler.AlarmClock clock) { | |
244 theClock = clock; | |
245 } | |
246 | |
247 public org.prevayler.AlarmClock clock() { | |
248 return theClock; | |
249 } | |
250 | |
251 public void add(SnapshotContributor aContributor) { | |
252 } | |
253 | |
254 public void remove(SnapshotContributor aContributor) { | |
255 } | |
256 | |
257 public Serializable[] getSnapshotContributions() { | |
258 return new Serializable[0]; | |
259 } | |
260 } | |
261 } |