View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.directory.server.core.journal;
20  
21  
22  import java.util.concurrent.atomic.AtomicLong;
23  
24  import org.apache.directory.api.ldap.model.entry.Attribute;
25  import org.apache.directory.api.ldap.model.entry.Entry;
26  import org.apache.directory.api.ldap.model.entry.Modification;
27  import org.apache.directory.api.ldap.model.exception.LdapException;
28  import org.apache.directory.api.ldap.model.ldif.ChangeType;
29  import org.apache.directory.api.ldap.model.ldif.LdifEntry;
30  import org.apache.directory.api.ldap.model.schema.AttributeType;
31  import org.apache.directory.server.core.api.DirectoryService;
32  import org.apache.directory.server.core.api.InterceptorEnum;
33  import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
34  import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
35  import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
36  import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
37  import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
38  import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
39  import org.apache.directory.server.core.api.interceptor.context.OperationContext;
40  import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
41  import org.apache.directory.server.core.api.journal.Journal;
42  import org.slf4j.Logger;
43  import org.slf4j.LoggerFactory;
44  
45  
46  /**
47   * An interceptor which intercepts write operations to the directory and
48   * logs them into a journal.
49   * 
50   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
51   */
52  public class JournalInterceptor extends BaseInterceptor
53  {
54      /** for debugging */
55      private static final Logger LOG = LoggerFactory.getLogger( JournalInterceptor.class );
56  
57      /** A flag set to true if the journal interceptor is enabled */
58      private boolean journalEnabled;
59  
60      /** A shared number stored within each change */
61      private AtomicLong revision;
62  
63      /** the Journal service to log changes to */
64      private Journal journal;
65  
66  
67      /**
68       * Creates a new instance of a JournalInterceptor.
69       */
70      public JournalInterceptor()
71      {
72          super( InterceptorEnum.JOURNAL_INTERCEPTOR );
73      }
74  
75  
76      // -----------------------------------------------------------------------
77      // Overridden init() and destroy() methods
78      // -----------------------------------------------------------------------
79      /**
80       * The init method will initialize the local variables and load the
81       * entryDeleted AttributeType.
82       */
83      @Override
84      public void init( DirectoryService directoryService ) throws LdapException
85      {
86          super.init( directoryService );
87  
88          if ( directoryService.getJournal().isEnabled() )
89          {
90              journalEnabled = true;
91              journal = directoryService.getJournal();
92              revision = new AtomicLong( System.currentTimeMillis() );
93          }
94  
95          LOG.debug( "JournalInterceptor has been initialized" );
96      }
97  
98  
99      /**
100      * Log the operation, manage the logs rotations.
101      */
102     private void log( OperationContext opCtx, long revision, LdifEntry ldif ) throws LdapException
103     {
104         journal.log( getPrincipal( opCtx ), revision, ldif );
105     }
106 
107 
108     // -----------------------------------------------------------------------
109     // Overridden (only change inducing) intercepted methods
110     // -----------------------------------------------------------------------
111     /**
112      * {@inheritDoc}
113      */
114     @Override
115     public void add( AddOperationContext addContext ) throws LdapException
116     {
117         long opRevision = 0;
118 
119         if ( journalEnabled )
120         {
121             opRevision = revision.incrementAndGet();
122 
123             // Store the added entry
124             Entry addEntry = addContext.getEntry();
125 
126             LdifEntry ldif = new LdifEntry();
127             ldif.setChangeType( ChangeType.Add );
128             ldif.setDn( addContext.getDn() );
129 
130             for ( Attribute attribute : addEntry.getAttributes() )
131             {
132                 AttributeType attributeType = attribute.getAttributeType();
133                 ldif.addAttribute( addEntry.get( attributeType ).clone() );
134             }
135 
136             log( addContext, opRevision, ldif );
137         }
138 
139         try
140         {
141             next( addContext );
142 
143             if ( journalEnabled )
144             {
145                 // log the ACK
146                 journal.ack( opRevision );
147             }
148         }
149         catch ( LdapException le )
150         {
151             if ( journalEnabled )
152             {
153                 // log the NACK
154                 journal.nack( opRevision );
155             }
156 
157             throw le;
158         }
159     }
160 
161 
162     /**
163      * {@inheritDoc}
164      */
165     @Override
166     public void delete( DeleteOperationContext deleteContext ) throws LdapException
167     {
168         long opRevision = 0;
169 
170         if ( journalEnabled )
171         {
172             opRevision = revision.incrementAndGet();
173 
174             // Store the deleted entry
175             LdifEntry ldif = new LdifEntry();
176             ldif.setChangeType( ChangeType.Delete );
177             ldif.setDn( deleteContext.getDn() );
178 
179             journal.log( getPrincipal( deleteContext ), opRevision, ldif );
180         }
181 
182         try
183         {
184             next( deleteContext );
185 
186             if ( journalEnabled )
187             {
188                 // log the ACK
189                 journal.ack( opRevision );
190             }
191         }
192         catch ( LdapException e )
193         {
194             if ( journalEnabled )
195             {
196                 // log the NACK
197                 journal.nack( opRevision );
198             }
199 
200             throw e;
201         }
202     }
203 
204 
205     /**
206      * {@inheritDoc}
207      */
208     @Override
209     public void modify( ModifyOperationContext modifyContext ) throws LdapException
210     {
211         long opRevision = 0;
212 
213         if ( journalEnabled )
214         {
215             opRevision = revision.incrementAndGet();
216 
217             // Store the modified entry
218             LdifEntry ldif = new LdifEntry();
219             ldif.setChangeType( ChangeType.Modify );
220             ldif.setDn( modifyContext.getDn() );
221 
222             // Store the modifications
223             for ( Modification modification : modifyContext.getModItems() )
224             {
225                 ldif.addModification( modification );
226             }
227 
228             journal.log( getPrincipal( modifyContext ), opRevision, ldif );
229         }
230 
231         try
232         {
233             next( modifyContext );
234 
235             if ( journalEnabled )
236             {
237                 // log the ACK
238                 journal.ack( opRevision );
239             }
240         }
241         catch ( LdapException e )
242         {
243             if ( journalEnabled )
244             {
245                 // log the NACK
246                 journal.nack( opRevision );
247             }
248             throw e;
249         }
250     }
251 
252 
253     /**
254      * {@inheritDoc}
255      */
256     @Override
257     public void move( MoveOperationContext moveContext ) throws LdapException
258     {
259         long opRevision = 0;
260 
261         if ( journalEnabled )
262         {
263             opRevision = revision.incrementAndGet();
264 
265             // Store the moved entry
266             LdifEntry ldif = new LdifEntry();
267             ldif.setChangeType( ChangeType.ModDn );
268             ldif.setDn( moveContext.getDn() );
269             ldif.setNewSuperior( moveContext.getNewSuperior().getName() );
270 
271             journal.log( getPrincipal( moveContext ), opRevision, ldif );
272         }
273 
274         try
275         {
276             next( moveContext );
277 
278             if ( journalEnabled )
279             {
280                 // log the ACK
281                 journal.ack( opRevision );
282             }
283         }
284         catch ( LdapException e )
285         {
286             if ( journalEnabled )
287             {
288                 // log the NACK
289                 journal.nack( opRevision );
290             }
291 
292             throw e;
293         }
294     }
295 
296 
297     /**
298      * {@inheritDoc}
299      */
300     @Override
301     public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
302     {
303         long opRevision = 0;
304 
305         if ( journalEnabled )
306         {
307             opRevision = revision.incrementAndGet();
308 
309             // Store the renamed entry
310             LdifEntry ldif = new LdifEntry();
311             ldif.setChangeType( ChangeType.ModDn );
312             ldif.setDn( moveAndRenameContext.getDn() );
313             ldif.setNewRdn( moveAndRenameContext.getNewRdn().getName() );
314             ldif.setDeleteOldRdn( moveAndRenameContext.getDeleteOldRdn() );
315             ldif.setNewSuperior( moveAndRenameContext.getNewDn().getName() );
316 
317             journal.log( getPrincipal( moveAndRenameContext ), opRevision, ldif );
318         }
319 
320         try
321         {
322             next( moveAndRenameContext );
323 
324             if ( journalEnabled )
325             {
326                 // log the ACK
327                 journal.ack( opRevision );
328             }
329         }
330         catch ( LdapException e )
331         {
332             if ( journalEnabled )
333             {
334                 // log the NACK
335                 journal.nack( opRevision );
336             }
337 
338             throw e;
339         }
340     }
341 
342 
343     /**
344      * {@inheritDoc}
345      */
346     @Override
347     public void rename( RenameOperationContext renameContext ) throws LdapException
348     {
349         long opRevision = 0;
350 
351         if ( journalEnabled )
352         {
353             opRevision = revision.incrementAndGet();
354 
355             // Store the renamed entry
356             LdifEntry ldif = new LdifEntry();
357             ldif.setChangeType( ChangeType.ModRdn );
358             ldif.setDn( renameContext.getDn() );
359             ldif.setNewRdn( renameContext.getNewRdn().getName() );
360             ldif.setDeleteOldRdn( renameContext.getDeleteOldRdn() );
361 
362             journal.log( getPrincipal( renameContext ), opRevision, ldif );
363         }
364 
365         try
366         {
367             next( renameContext );
368 
369             if ( journalEnabled )
370             {
371                 // log the ACK
372                 journal.ack( opRevision );
373             }
374         }
375         catch ( LdapException e )
376         {
377             if ( journalEnabled )
378             {
379                 // log the NACK
380                 journal.nack( opRevision );
381             }
382 
383             throw e;
384         }
385     }
386 }