001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 package org.apache.directory.server.core.journal; 020 021 022 import java.util.Set; 023 import java.util.concurrent.atomic.AtomicLong; 024 025 import org.apache.directory.server.core.DirectoryService; 026 import org.apache.directory.server.core.interceptor.BaseInterceptor; 027 import org.apache.directory.server.core.interceptor.NextInterceptor; 028 import org.apache.directory.server.core.interceptor.context.AddOperationContext; 029 import org.apache.directory.server.core.interceptor.context.DeleteOperationContext; 030 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext; 031 import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext; 032 import org.apache.directory.server.core.interceptor.context.MoveOperationContext; 033 import org.apache.directory.server.core.interceptor.context.RenameOperationContext; 034 import org.apache.directory.shared.ldap.entry.Modification; 035 import org.apache.directory.shared.ldap.entry.ServerEntry; 036 import org.apache.directory.shared.ldap.ldif.ChangeType; 037 import org.apache.directory.shared.ldap.ldif.LdifEntry; 038 import org.apache.directory.shared.ldap.schema.AttributeType; 039 import org.slf4j.Logger; 040 import org.slf4j.LoggerFactory; 041 042 043 /** 044 * An interceptor which intercepts write operations to the directory and 045 * logs them into a journal. 046 * 047 * @org.apache.xbean.XBean 048 */ 049 public class JournalInterceptor extends BaseInterceptor 050 { 051 /** for debugging */ 052 private static final Logger LOG = LoggerFactory.getLogger( JournalInterceptor.class ); 053 054 /** A flag set to true if the journal interceptor is enabled */ 055 private boolean journalEnabled; 056 057 /** A shared number stored within each change */ 058 private AtomicLong revision; 059 060 /** the Journal service to log changes to */ 061 private Journal journal; 062 063 064 // ----------------------------------------------------------------------- 065 // Overridden init() and destroy() methods 066 // ----------------------------------------------------------------------- 067 /** 068 * The init method will initialize the local variables and load the 069 * entryDeleted AttributeType. 070 */ 071 public void init( DirectoryService directoryService ) throws Exception 072 { 073 super.init( directoryService ); 074 075 if ( directoryService.getJournal().isEnabled() ) 076 { 077 journalEnabled = true; 078 journal = directoryService.getJournal(); 079 revision = new AtomicLong( System.currentTimeMillis() ); 080 } 081 082 LOG.debug( "JournalInterceptor has been initialized" ); 083 } 084 085 086 /** 087 * Log the operation, manage the logs rotations. 088 */ 089 private void log( long revision, LdifEntry ldif ) throws Exception 090 { 091 journal.log( getPrincipal(), revision, ldif ); 092 } 093 094 095 // ----------------------------------------------------------------------- 096 // Overridden (only change inducing) intercepted methods 097 // ----------------------------------------------------------------------- 098 /** 099 * {@inheritDoc} 100 */ 101 public void add( NextInterceptor next, AddOperationContext opContext ) throws Exception 102 { 103 long opRevision = 0; 104 105 if ( journalEnabled ) 106 { 107 opRevision = revision.incrementAndGet(); 108 109 // Store the added entry 110 ServerEntry addEntry = opContext.getEntry(); 111 112 LdifEntry ldif = new LdifEntry(); 113 ldif.setChangeType( ChangeType.Add ); 114 ldif.setDn( opContext.getDn() ); 115 116 Set<AttributeType> list = addEntry.getAttributeTypes(); 117 118 for ( AttributeType attributeType:list ) 119 { 120 ldif.addAttribute( addEntry.get( attributeType).toClientAttribute() ); 121 } 122 123 log( opRevision, ldif ); 124 } 125 126 try 127 { 128 next.add( opContext ); 129 130 if ( journalEnabled ) 131 { 132 // log the ACK 133 journal.ack( opRevision ); 134 } 135 } 136 catch( Exception e ) 137 { 138 if ( journalEnabled ) 139 { 140 // log the NACK 141 journal.nack( opRevision ); 142 } 143 throw e; 144 } 145 } 146 147 148 /** 149 * {@inheritDoc} 150 */ 151 public void delete( NextInterceptor next, DeleteOperationContext opContext ) throws Exception 152 { 153 long opRevision = 0; 154 155 if ( journalEnabled ) 156 { 157 opRevision = revision.incrementAndGet(); 158 159 // Store the deleted entry 160 LdifEntry ldif = new LdifEntry(); 161 ldif.setChangeType( ChangeType.Delete ); 162 ldif.setDn( opContext.getDn() ); 163 164 journal.log( getPrincipal(), opRevision, ldif ); 165 } 166 167 try 168 { 169 next.delete( opContext ); 170 171 if ( journalEnabled ) 172 { 173 // log the ACK 174 journal.ack( opRevision ); 175 } 176 } 177 catch( Exception e ) 178 { 179 if ( journalEnabled ) 180 { 181 // log the NACK 182 journal.nack( opRevision ); 183 } 184 throw e; 185 } 186 } 187 188 189 /** 190 * {@inheritDoc} 191 */ 192 public void modify( NextInterceptor next, ModifyOperationContext opContext ) throws Exception 193 { 194 long opRevision = 0; 195 196 if ( journalEnabled ) 197 { 198 opRevision = revision.incrementAndGet(); 199 200 // Store the modified entry 201 LdifEntry ldif = new LdifEntry(); 202 ldif.setChangeType( ChangeType.Modify ); 203 ldif.setDn( opContext.getDn() ); 204 205 // Store the modifications 206 for ( Modification modification:opContext.getModItems() ) 207 { 208 ldif.addModificationItem( modification ); 209 } 210 211 journal.log( getPrincipal(), opRevision, ldif ); 212 } 213 214 try 215 { 216 next.modify( opContext ); 217 218 if ( journalEnabled ) 219 { 220 // log the ACK 221 journal.ack( opRevision ); 222 } 223 } 224 catch( Exception e ) 225 { 226 if ( journalEnabled ) 227 { 228 // log the NACK 229 journal.nack( opRevision ); 230 } 231 throw e; 232 } 233 } 234 235 236 /** 237 * {@inheritDoc} 238 */ 239 public void rename ( NextInterceptor next, RenameOperationContext opContext ) throws Exception 240 { 241 long opRevision = 0; 242 243 if ( journalEnabled ) 244 { 245 opRevision = revision.incrementAndGet(); 246 247 // Store the renamed entry 248 LdifEntry ldif = new LdifEntry(); 249 ldif.setChangeType( ChangeType.ModRdn ); 250 ldif.setDn( opContext.getDn() ); 251 ldif.setNewRdn( opContext.getNewRdn().getNormName() ); 252 ldif.setDeleteOldRdn( opContext.getDelOldDn() ); 253 254 journal.log( getPrincipal(), opRevision, ldif ); 255 } 256 257 try 258 { 259 next.rename( opContext ); 260 261 if ( journalEnabled ) 262 { 263 // log the ACK 264 journal.ack( opRevision ); 265 } 266 } 267 catch( Exception e ) 268 { 269 if ( journalEnabled ) 270 { 271 // log the NACK 272 journal.nack( opRevision ); 273 } 274 throw e; 275 } 276 } 277 278 279 /** 280 * {@inheritDoc} 281 */ 282 public void moveAndRename( NextInterceptor next, MoveAndRenameOperationContext opContext ) 283 throws Exception 284 { 285 long opRevision = 0; 286 287 if ( journalEnabled ) 288 { 289 opRevision = revision.incrementAndGet(); 290 291 // Store the renamed entry 292 LdifEntry ldif = new LdifEntry(); 293 ldif.setChangeType( ChangeType.ModDn ); 294 ldif.setDn( opContext.getDn() ); 295 ldif.setNewRdn( opContext.getNewRdn().getNormName() ); 296 ldif.setDeleteOldRdn( opContext.getDelOldDn() ); 297 ldif.setNewSuperior( opContext.getNewDn().getNormName() ); 298 299 journal.log( getPrincipal(), opRevision, ldif ); 300 } 301 302 try 303 { 304 next.moveAndRename( opContext ); 305 306 if ( journalEnabled ) 307 { 308 // log the ACK 309 journal.ack( opRevision ); 310 } 311 } 312 catch( Exception e ) 313 { 314 if ( journalEnabled ) 315 { 316 // log the NACK 317 journal.nack( opRevision ); 318 } 319 throw e; 320 } 321 } 322 323 324 /** 325 * {@inheritDoc} 326 */ 327 public void move( NextInterceptor next, MoveOperationContext opContext ) throws Exception 328 { 329 long opRevision = 0; 330 331 if ( journalEnabled ) 332 { 333 opRevision = revision.incrementAndGet(); 334 335 // Store the moved entry 336 LdifEntry ldif = new LdifEntry(); 337 ldif.setChangeType( ChangeType.ModDn ); 338 ldif.setDn( opContext.getDn() ); 339 ldif.setNewSuperior( opContext.getParent().getNormName() ); 340 341 journal.log( getPrincipal(), opRevision, ldif ); 342 } 343 344 try 345 { 346 next.move( opContext ); 347 348 if ( journalEnabled ) 349 { 350 // log the ACK 351 journal.ack( opRevision ); 352 } 353 } 354 catch( Exception e ) 355 { 356 if ( journalEnabled ) 357 { 358 // log the NACK 359 journal.nack( opRevision ); 360 } 361 throw e; 362 } 363 } 364 }