1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.directory.server.core.changelog;
20
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileOutputStream;
25 import java.io.FileReader;
26 import java.io.FileWriter;
27 import java.io.IOException;
28 import java.io.ObjectInputStream;
29 import java.io.ObjectOutputStream;
30 import java.io.PrintWriter;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Properties;
37
38 import org.apache.directory.server.core.DirectoryService;
39 import org.apache.directory.server.core.authn.LdapPrincipal;
40 import org.apache.directory.server.core.cursor.Cursor;
41 import org.apache.directory.server.core.cursor.ListCursor;
42 import org.apache.directory.shared.ldap.ldif.LdifEntry;
43 import org.apache.directory.shared.ldap.util.DateUtils;
44
45
46
47
48
49
50
51
52
53
54
55 public class MemoryChangeLogStore implements TaggableChangeLogStore
56 {
57 private static final String REV_FILE = "revision";
58 private static final String TAG_FILE = "tags";
59 private static final String CHANGELOG_FILE = "changelog.dat";
60
61 private long currentRevision;
62 private Tag latest;
63 private final Map<Long,Tag> tags = new HashMap<Long,Tag>( 100 );
64 private final List<ChangeLogEvent> events = new ArrayList<ChangeLogEvent>();
65 private File workingDirectory;
66
67
68 public Tag tag( long revision ) throws Exception
69 {
70 if ( tags.containsKey( revision ) )
71 {
72 return tags.get( revision );
73 }
74
75 latest = new Tag( revision, null );
76 tags.put( revision, latest );
77 return latest;
78 }
79
80
81 public Tag tag() throws Exception
82 {
83 if ( latest != null && latest.getRevision() == currentRevision )
84 {
85 return latest;
86 }
87
88 latest = new Tag( currentRevision, null );
89 tags.put( currentRevision, latest );
90 return latest;
91 }
92
93
94 public Tag tag( String description ) throws Exception
95 {
96 if ( latest != null && latest.getRevision() == currentRevision )
97 {
98 return latest;
99 }
100
101 latest = new Tag( currentRevision, description );
102 tags.put( currentRevision, latest );
103 return latest;
104 }
105
106
107 public void init( DirectoryService service ) throws Exception
108 {
109 workingDirectory = service.getWorkingDirectory();
110 loadRevision();
111 loadTags();
112 loadChangeLog();
113 }
114
115
116 private void loadRevision() throws Exception
117 {
118 File revFile = new File( workingDirectory, REV_FILE );
119 if ( revFile.exists() )
120 {
121 BufferedReader reader = null;
122 try
123 {
124 reader = new BufferedReader( new FileReader( revFile ) );
125 String line = reader.readLine();
126 currentRevision = Long.valueOf( line );
127 }
128 catch ( IOException e )
129 {
130 throw e;
131 }
132 finally
133 {
134 if ( reader != null )
135 {
136
137 try
138 {
139 reader.close();
140 }
141 catch ( IOException e )
142 {
143 }
144 }
145 }
146 }
147 }
148
149
150 private void saveRevision() throws Exception
151 {
152 File revFile = new File( workingDirectory, REV_FILE );
153 if ( revFile.exists() )
154 {
155 revFile.delete();
156 }
157
158 PrintWriter out = null;
159 try
160 {
161 out = new PrintWriter( new FileWriter( revFile ) );
162 out.println( currentRevision );
163 out.flush();
164 }
165 catch ( IOException e )
166 {
167 throw e;
168 }
169 finally
170 {
171 if ( out != null )
172 {
173 out.close();
174 }
175 }
176 }
177
178
179 private void saveTags() throws Exception
180 {
181 File tagFile = new File( workingDirectory, TAG_FILE );
182 if ( tagFile.exists() )
183 {
184 tagFile.delete();
185 }
186
187 FileOutputStream out = null;
188 try
189 {
190 out = new FileOutputStream( tagFile );
191
192 Properties props = new Properties();
193 for ( Tag tag : tags.values() )
194 {
195 String key = String.valueOf( tag.getRevision() );
196 if ( tag.getDescription() == null )
197 {
198 props.setProperty( key, "null" );
199 }
200 else
201 {
202 props.setProperty( key, tag.getDescription() );
203 }
204 }
205
206 props.store( out, null );
207 out.flush();
208 }
209 catch ( IOException e )
210 {
211 throw e;
212 }
213 finally
214 {
215 if ( out != null )
216 {
217
218 try
219 {
220 out.close();
221 }
222 catch ( IOException e )
223 {
224 }
225 }
226 }
227 }
228
229
230 private void loadTags() throws Exception
231 {
232 File revFile = new File( workingDirectory, REV_FILE );
233 if ( revFile.exists() )
234 {
235 Properties props = new Properties();
236 FileInputStream in = null;
237 try
238 {
239 in = new FileInputStream( revFile );
240 props.load( in );
241 ArrayList<Long> revList = new ArrayList<Long>();
242 for ( Object key : props.keySet() )
243 {
244 revList.add( Long.valueOf( ( String ) key ) );
245 }
246
247 Collections.sort( revList );
248 Tag tag = null;
249
250
251 tags.clear();
252 for ( Long lkey : revList )
253 {
254 String rev = String.valueOf( lkey );
255 String desc = props.getProperty( rev );
256
257 if ( desc != null && desc.equals( "null" ) )
258 {
259 tag = new Tag( lkey, null );
260 }
261 else
262 {
263 tag = new Tag( lkey, desc );
264 }
265
266 tags.put( lkey, tag );
267 }
268
269 latest = tag;
270 }
271 catch ( IOException e )
272 {
273 throw e;
274 }
275 finally
276 {
277 if ( in != null )
278 {
279
280 try
281 {
282 in.close();
283 }
284 catch ( IOException e )
285 {
286 }
287 }
288 }
289 }
290 }
291
292
293 private void loadChangeLog() throws Exception
294 {
295 File file = new File( workingDirectory, CHANGELOG_FILE );
296
297 if ( file.exists() )
298 {
299 ObjectInputStream in = null;
300
301 try
302 {
303 in = new ObjectInputStream( new FileInputStream( file ) );
304 int size = in.readInt();
305
306 ArrayList<ChangeLogEvent> changeLogEvents = new ArrayList<ChangeLogEvent>( size );
307
308 for ( int i = 0; i < size; i++ )
309 {
310 ChangeLogEvent event = ( ChangeLogEvent ) in.readObject();
311 changeLogEvents.add( event );
312 }
313
314
315 this.events.clear();
316 this.events.addAll( changeLogEvents );
317 }
318 catch ( Exception e )
319 {
320 throw e;
321 }
322 finally
323 {
324 if ( in != null )
325 {
326
327 try
328 {
329 in.close();
330 }
331 catch ( IOException e )
332 {
333 }
334 }
335 }
336 }
337 }
338
339
340 private void saveChangeLog() throws Exception
341 {
342 File file = new File( workingDirectory, CHANGELOG_FILE );
343 if ( file.exists() )
344 {
345 file.delete();
346 }
347
348 try
349 {
350 file.createNewFile();
351 }
352 catch ( IOException e )
353 {
354 throw e;
355 }
356
357 ObjectOutputStream out = null;
358
359 try
360 {
361 out = new ObjectOutputStream( new FileOutputStream( file ) );
362
363 out.writeInt( events.size() );
364
365 for ( ChangeLogEvent event : events )
366 {
367 out.writeObject( event );
368 }
369
370 out.flush();
371 }
372 catch ( Exception e )
373 {
374 throw e;
375 }
376 finally
377 {
378 if ( out != null )
379 {
380
381 try
382 {
383 out.close();
384 }
385 catch ( IOException e )
386 {
387 }
388 }
389 }
390 }
391
392
393 public void sync() throws Exception
394 {
395 saveRevision();
396 saveTags();
397 saveChangeLog();
398 }
399
400
401 public void destroy() throws Exception
402 {
403 saveRevision();
404 saveTags();
405 saveChangeLog();
406 }
407
408
409 public long getCurrentRevision()
410 {
411 return currentRevision;
412 }
413
414
415
416
417
418 public ChangeLogEvent log( LdapPrincipal principal, LdifEntry forward, LdifEntry reverse ) throws Exception
419 {
420 currentRevision++;
421 ChangeLogEvent event = new ChangeLogEvent( currentRevision, DateUtils.getGeneralizedTime(),
422 principal, forward, reverse );
423 events.add( event );
424 return event;
425 }
426
427
428
429
430
431 public ChangeLogEvent log( LdapPrincipal principal, LdifEntry forward, List<LdifEntry> reverses ) throws Exception
432 {
433 currentRevision++;
434 ChangeLogEvent event = new ChangeLogEvent( currentRevision, DateUtils.getGeneralizedTime(),
435 principal, forward, reverses );
436 events.add( event );
437 return event;
438 }
439
440
441 public ChangeLogEvent lookup( long revision ) throws Exception
442 {
443 if ( revision < 0 )
444 {
445 throw new IllegalArgumentException( "revision must be greater than or equal to 0" );
446 }
447
448 if ( revision > getCurrentRevision() )
449 {
450 throw new IllegalArgumentException( "The revision must not be greater than the current revision" );
451 }
452
453 return events.get( ( int ) revision );
454 }
455
456
457 public Cursor<ChangeLogEvent> find() throws Exception
458 {
459 return new ListCursor<ChangeLogEvent>( events );
460 }
461
462
463 public Cursor<ChangeLogEvent> findBefore( long revision ) throws Exception
464 {
465 return new ListCursor<ChangeLogEvent>( events, ( int ) revision );
466 }
467
468
469 public Cursor<ChangeLogEvent> findAfter( long revision ) throws Exception
470 {
471 return new ListCursor<ChangeLogEvent>( ( int ) revision, events );
472 }
473
474
475 public Cursor<ChangeLogEvent> find( long startRevision, long endRevision ) throws Exception
476 {
477 return new ListCursor<ChangeLogEvent>( ( int ) startRevision, events, ( int ) ( endRevision + 1 ) );
478 }
479
480
481 public Tag getLatest() throws Exception
482 {
483 return latest;
484 }
485
486
487
488
489
490 public Tag removeTag( long revision ) throws Exception
491 {
492 return tags.remove( revision );
493 }
494
495
496
497
498
499 public Tag tag( long revision, String descrition ) throws Exception
500 {
501 if ( tags.containsKey( revision ) )
502 {
503 return tags.get( revision );
504 }
505
506 latest = new Tag( revision, descrition );
507 tags.put( revision, latest );
508 return latest;
509 }
510
511
512
513
514
515 public String toString()
516 {
517 StringBuilder sb = new StringBuilder();
518
519 sb.append( "MemoryChangeLog\n" );
520 sb.append( "latest tag : " ).append( latest ).append( '\n' );
521
522 if ( events != null )
523 {
524 sb.append( "Nb of events : " ).append( events.size() ).append( '\n' );
525
526 int i = 0;
527
528 for ( ChangeLogEvent event:events )
529 {
530 sb.append( "event[" ).append( i++ ).append( "] : " );
531 sb.append( "\n---------------------------------------\n" );
532 sb.append( event );
533 sb.append( "\n---------------------------------------\n" );
534 }
535 }
536
537
538 return sb.toString();
539 }
540 }