Mercurial > dive4elements > framework
comparison artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java @ 32:c2d53bd30ab8
Re-factored artifact API for better integration of background processing.
artifacts/trunk@78 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Sun, 13 Sep 2009 14:50:53 +0000 |
parents | c4d85a8532d1 |
children | 9935e1c928de |
comparison
equal
deleted
inserted
replaced
31:c4d85a8532d1 | 32:c2d53bd30ab8 |
---|---|
1 package de.intevation.artifactdatabase; | 1 package de.intevation.artifactdatabase; |
2 | |
3 import org.w3c.dom.Document; | |
4 | 2 |
5 import java.util.UUID; | 3 import java.util.UUID; |
6 | 4 |
7 import java.sql.Connection; | 5 import java.sql.Connection; |
8 import java.sql.SQLException; | 6 import java.sql.SQLException; |
15 import java.io.IOException; | 13 import java.io.IOException; |
16 import java.io.ByteArrayInputStream; | 14 import java.io.ByteArrayInputStream; |
17 import java.io.ByteArrayOutputStream; | 15 import java.io.ByteArrayOutputStream; |
18 import java.io.ObjectOutputStream; | 16 import java.io.ObjectOutputStream; |
19 import java.io.ObjectInputStream; | 17 import java.io.ObjectInputStream; |
20 import java.io.OutputStream; | |
21 | 18 |
22 import java.util.zip.GZIPOutputStream; | 19 import java.util.zip.GZIPOutputStream; |
23 import java.util.zip.GZIPInputStream; | 20 import java.util.zip.GZIPInputStream; |
24 | 21 |
25 import de.intevation.artifacts.ArtifactFactory; | |
26 import de.intevation.artifacts.Artifact; | 22 import de.intevation.artifacts.Artifact; |
27 | 23 |
28 import org.apache.log4j.Logger; | 24 import org.apache.log4j.Logger; |
29 | 25 |
30 /** | 26 /** |
49 public static final String SQL_LOAD_BY_GID = | 45 public static final String SQL_LOAD_BY_GID = |
50 SQL.get("artifacts.select.gid"); | 46 SQL.get("artifacts.select.gid"); |
51 | 47 |
52 protected DatabaseCleaner cleaner; | 48 protected DatabaseCleaner cleaner; |
53 | 49 |
54 /** | 50 public final class PersistentArtifact |
55 * Used to wrap the calls to invole database actions. | 51 extends Id |
56 */ | |
57 public class ArtifactProxy | |
58 implements Artifact | |
59 { | 52 { |
60 protected Artifact original; | 53 private Artifact artifact; |
61 protected int id; | 54 |
62 protected boolean unwritten; | 55 public PersistentArtifact(Artifact artifact, int id) { |
63 | 56 super(id); |
64 public ArtifactProxy() { | 57 this.artifact = artifact; |
65 } | 58 } |
66 | 59 |
67 public ArtifactProxy(Artifact original, int id, boolean unwritten) { | 60 public Artifact getArtifact() { |
68 this.original = original; | 61 return artifact; |
69 this.id = id; | 62 } |
70 this.unwritten = unwritten; | 63 |
71 } | 64 public void store() { |
72 | 65 Backend.this.store(this); |
73 public Artifact getOriginal() { | 66 } |
74 return original; | 67 |
75 } | 68 public void touch() { |
76 | 69 Backend.this.touch(this); |
77 public int getId() { | 70 } |
78 return id; | 71 } // class ArtifactWithId |
79 } | |
80 | |
81 public boolean isUnwritten() { | |
82 return unwritten; | |
83 } | |
84 | |
85 public String identifier() { | |
86 return original.identifier(); | |
87 } | |
88 | |
89 public String hash() { | |
90 return original.hash(); | |
91 } | |
92 | |
93 public Document describe(Object context) { | |
94 try { | |
95 return original.describe(context); | |
96 } | |
97 finally { | |
98 touch(this); | |
99 } | |
100 } | |
101 | |
102 public Document advance(Document target, Object context) { | |
103 try { | |
104 return original.advance(target, context); | |
105 } | |
106 finally { | |
107 store(this); | |
108 } | |
109 } | |
110 | |
111 public Document feed(Document data, Object context) { | |
112 try { | |
113 return original.feed(data, context); | |
114 } | |
115 finally { | |
116 store(this); | |
117 } | |
118 } | |
119 | |
120 public void out( | |
121 Document format, | |
122 OutputStream output, | |
123 Object context | |
124 ) | |
125 throws IOException | |
126 { | |
127 try { | |
128 original.out(format, output, context); | |
129 } | |
130 finally { | |
131 touch(this); | |
132 } | |
133 } | |
134 | |
135 public void setup(String identifier, ArtifactFactory factory, Object context) { | |
136 original.setup(identifier, factory, context); | |
137 } | |
138 | |
139 public void endOfLife(Object context) { | |
140 original.endOfLife(context); | |
141 } | |
142 | |
143 public byte [] toBytes() { | |
144 try { | |
145 ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
146 GZIPOutputStream gos = new GZIPOutputStream(bos); | |
147 ObjectOutputStream oos = new ObjectOutputStream(gos); | |
148 | |
149 oos.writeObject(original); | |
150 oos.flush(); | |
151 oos.close(); | |
152 | |
153 return bos.toByteArray(); | |
154 } | |
155 catch (IOException ioe) { | |
156 logger.error(ioe.getLocalizedMessage(), ioe); | |
157 throw new RuntimeException(ioe); | |
158 } | |
159 } | |
160 } // class ArtifactProxy | |
161 | 72 |
162 public Backend() { | 73 public Backend() { |
163 } | 74 } |
164 | 75 |
165 public Backend(DatabaseCleaner cleaner) { | 76 public Backend(DatabaseCleaner cleaner) { |
166 this.cleaner = cleaner; | 77 this.cleaner = cleaner; |
167 } | 78 } |
168 | 79 |
169 public Artifact getArtifact(String idenitfier) { | 80 public void setCleaner(DatabaseCleaner cleaner) { |
170 UUID uuid; | 81 this.cleaner = cleaner; |
171 | 82 } |
172 try { | 83 |
173 uuid = UUID.fromString(idenitfier); | 84 public String newIdentifier() { |
85 UUID uuid = UUID.randomUUID(); | |
86 // TODO: check database for collisions. | |
87 return uuid.toString(); | |
88 } | |
89 | |
90 public PersistentArtifact storeInitially( | |
91 Artifact artifact, | |
92 Long ttl | |
93 ) | |
94 throws Exception | |
95 { | |
96 return new PersistentArtifact( | |
97 artifact, | |
98 insertDatabase(artifact, ttl)); | |
99 } | |
100 | |
101 public PersistentArtifact getArtifact(String identifer) { | |
102 | |
103 try { | |
104 UUID.fromString(identifer); | |
174 } | 105 } |
175 catch (IllegalArgumentException iae) { | 106 catch (IllegalArgumentException iae) { |
176 logger.warn(iae.getLocalizedMessage()); | 107 logger.warn(iae.getLocalizedMessage()); |
177 return null; | 108 return null; |
178 } | 109 } |
179 | 110 |
180 return getArtifactByUUID(uuid); | |
181 } | |
182 | |
183 public Artifact createArtifactWithFactory( | |
184 ArtifactFactory factory, Object context | |
185 ) { | |
186 UUID uuid = UUID.randomUUID(); | |
187 Artifact artifact = factory.createArtifact( | |
188 uuid.toString(), context); | |
189 | |
190 Long ttl = factory.timeToLiveUntouched( | |
191 artifact, context); | |
192 | |
193 try { | |
194 int id = insertDatabase(uuid, ttl); | |
195 return new ArtifactProxy(artifact, id, true); | |
196 } | |
197 catch (Exception e) { | |
198 logger.error(e.getLocalizedMessage(), e); | |
199 } | |
200 return null; | |
201 } | |
202 | |
203 protected Artifact getArtifactByUUID(UUID uuid) { | |
204 | |
205 Connection connection = null; | 111 Connection connection = null; |
206 PreparedStatement stmnt_load = null; | 112 PreparedStatement stmnt_load = null; |
207 ResultSet load_result = null; | 113 ResultSet load_result = null; |
208 | 114 |
209 DataSource dataSource = DBConnection.getDataSource(); | 115 DataSource dataSource = DBConnection.getDataSource(); |
210 try { | 116 try { |
211 connection = dataSource.getConnection(); | 117 connection = dataSource.getConnection(); |
212 stmnt_load = connection.prepareStatement(SQL_LOAD_BY_GID); | 118 stmnt_load = connection.prepareStatement(SQL_LOAD_BY_GID); |
213 stmnt_load.setString(1, uuid.toString()); | 119 stmnt_load.setString(1, identifer); |
214 | 120 |
215 load_result = stmnt_load.executeQuery(); | 121 load_result = stmnt_load.executeQuery(); |
216 | 122 |
217 if (!load_result.next()) { | 123 if (!load_result.next()) { |
218 return null; | 124 return null; |
229 } | 135 } |
230 } | 136 } |
231 | 137 |
232 byte [] bytes = load_result.getBytes(4); | 138 byte [] bytes = load_result.getBytes(4); |
233 | 139 |
234 if (bytes == null) { | 140 Artifact artifact = restoreArtifact(bytes); |
235 return null; | 141 |
236 } | 142 return artifact == null |
237 | 143 ? null |
238 Artifact original = restoreArtifact(bytes); | 144 : new PersistentArtifact(artifact, id); |
239 if (original == null) { | |
240 return null; | |
241 } | |
242 | |
243 return new ArtifactProxy(original, id, false); | |
244 } | 145 } |
245 catch (SQLException sqle) { | 146 catch (SQLException sqle) { |
246 logger.error(sqle.getLocalizedMessage(), sqle); | 147 logger.error(sqle.getLocalizedMessage(), sqle); |
247 } | 148 } |
248 finally { | 149 finally { |
258 try { connection.close(); } | 159 try { connection.close(); } |
259 catch (SQLException sqle) {} | 160 catch (SQLException sqle) {} |
260 } | 161 } |
261 } | 162 } |
262 return null; | 163 return null; |
164 } | |
165 | |
166 public static byte [] toBytes(Artifact artifact) { | |
167 try { | |
168 ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
169 GZIPOutputStream gos = new GZIPOutputStream(bos); | |
170 ObjectOutputStream oos = new ObjectOutputStream(gos); | |
171 | |
172 oos.writeObject(artifact); | |
173 oos.flush(); | |
174 oos.close(); | |
175 | |
176 return bos.toByteArray(); | |
177 } | |
178 catch (IOException ioe) { | |
179 logger.error(ioe.getLocalizedMessage(), ioe); | |
180 throw new RuntimeException(ioe); | |
181 } | |
263 } | 182 } |
264 | 183 |
265 public static Artifact restoreArtifact(byte [] bytes) { | 184 public static Artifact restoreArtifact(byte [] bytes) { |
266 | 185 |
267 if (bytes == null) { | 186 if (bytes == null) { |
301 if (cleaner != null) { | 220 if (cleaner != null) { |
302 cleaner.wakeup(); | 221 cleaner.wakeup(); |
303 } | 222 } |
304 } | 223 } |
305 | 224 |
306 protected int insertDatabase(UUID uuid, Long ttl) { | 225 protected int insertDatabase(Artifact artifact, Long ttl) { |
226 | |
227 String uuid = artifact.identifier(); | |
228 | |
307 Connection connection = null; | 229 Connection connection = null; |
308 PreparedStatement stmnt_next_id = null; | 230 PreparedStatement stmnt_next_id = null; |
309 PreparedStatement stmnt_insert = null; | 231 PreparedStatement stmnt_insert = null; |
310 ResultSet res_id = null; | 232 ResultSet res_id = null; |
311 | 233 |
325 } | 247 } |
326 | 248 |
327 int id = res_id.getInt(1); | 249 int id = res_id.getInt(1); |
328 | 250 |
329 stmnt_insert.setInt(1, id); | 251 stmnt_insert.setInt(1, id); |
330 stmnt_insert.setString(2, uuid.toString()); | 252 stmnt_insert.setString(2, uuid); |
331 if (ttl == null) { | 253 if (ttl == null) { |
332 stmnt_insert.setNull(3, Types.BIGINT); | 254 stmnt_insert.setNull(3, Types.BIGINT); |
333 } | 255 } |
334 else { | 256 else { |
335 stmnt_insert.setLong(3, ttl.longValue()); | 257 stmnt_insert.setLong(3, ttl.longValue()); |
336 } | 258 } |
259 | |
260 stmnt_insert.setBytes(4, toBytes(artifact)); | |
337 | 261 |
338 stmnt_insert.execute(); | 262 stmnt_insert.execute(); |
339 | 263 |
340 connection.commit(); | 264 connection.commit(); |
341 | 265 |
368 } | 292 } |
369 } | 293 } |
370 throw new RuntimeException("failed insert artifact into database"); | 294 throw new RuntimeException("failed insert artifact into database"); |
371 } | 295 } |
372 | 296 |
373 public void touch(ArtifactProxy proxy) { | 297 public void touch(PersistentArtifact artifact) { |
374 | |
375 if (proxy.isUnwritten()) { | |
376 store(proxy); | |
377 return; | |
378 } | |
379 | 298 |
380 try { | 299 try { |
381 Connection connection = null; | 300 Connection connection = null; |
382 PreparedStatement stmnt_touch = null; | 301 PreparedStatement stmnt_touch = null; |
383 DataSource dataSource = DBConnection.getDataSource(); | 302 DataSource dataSource = DBConnection.getDataSource(); |
384 try { | 303 try { |
385 connection = dataSource.getConnection(); | 304 connection = dataSource.getConnection(); |
386 try { | 305 try { |
387 connection.setAutoCommit(false); | 306 connection.setAutoCommit(false); |
388 stmnt_touch = connection.prepareStatement(SQL_UPDATE); | 307 stmnt_touch = connection.prepareStatement(SQL_UPDATE); |
389 stmnt_touch.setInt(1, proxy.getId()); | 308 stmnt_touch.setInt(1, artifact.getId()); |
390 stmnt_touch.execute(); | 309 stmnt_touch.execute(); |
391 connection.commit(); | 310 connection.commit(); |
392 } | 311 } |
393 catch (SQLException sqle) { | 312 catch (SQLException sqle) { |
394 connection.rollback(); | 313 connection.rollback(); |
411 catch (Exception e) { | 330 catch (Exception e) { |
412 logger.error(e.getLocalizedMessage(), e); | 331 logger.error(e.getLocalizedMessage(), e); |
413 } | 332 } |
414 } | 333 } |
415 | 334 |
416 public void store(ArtifactProxy proxy) { | 335 public void store(PersistentArtifact artifact) { |
417 | 336 |
418 try { | 337 try { |
419 Connection connection = null; | 338 Connection connection = null; |
420 PreparedStatement stmnt_update = null; | 339 PreparedStatement stmnt_update = null; |
421 DataSource dataSource = DBConnection.getDataSource(); | 340 DataSource dataSource = DBConnection.getDataSource(); |
422 try { | 341 try { |
423 connection = dataSource.getConnection(); | 342 connection = dataSource.getConnection(); |
424 try { | 343 try { |
425 connection.setAutoCommit(false); | 344 connection.setAutoCommit(false); |
426 stmnt_update = connection.prepareStatement(SQL_UPDATE); | 345 stmnt_update = connection.prepareStatement(SQL_UPDATE); |
427 stmnt_update.setInt(2, proxy.getId()); | 346 stmnt_update.setInt(2, artifact.getId()); |
428 | 347 |
429 byte [] bytes = proxy.toBytes(); | 348 byte [] bytes = toBytes(artifact.getArtifact()); |
430 | 349 |
431 stmnt_update.setBytes(1, bytes); | 350 stmnt_update.setBytes(1, bytes); |
432 stmnt_update.execute(); | 351 stmnt_update.execute(); |
433 connection.commit(); | 352 connection.commit(); |
434 } | 353 } |
452 } | 371 } |
453 catch (Exception e) { | 372 catch (Exception e) { |
454 logger.error(e.getLocalizedMessage(), e); | 373 logger.error(e.getLocalizedMessage(), e); |
455 } | 374 } |
456 } | 375 } |
457 | |
458 } | 376 } |
459 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: | 377 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: |