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.changelog; 020 021 022 import java.util.List; 023 024 import org.apache.directory.server.core.DirectoryService; 025 import org.apache.directory.server.core.LdapPrincipal; 026 import org.apache.directory.server.core.partition.Partition; 027 import org.apache.directory.server.i18n.I18n; 028 import org.apache.directory.shared.ldap.ldif.LdifEntry; 029 import org.slf4j.Logger; 030 import org.slf4j.LoggerFactory; 031 032 033 /** 034 * The default ChangeLog service implementation. It stores operations 035 * in memory. 036 * 037 * Entries are stored into a dedicated partition, named ou=changelog, under which 038 * we have two other sub-entries : ou=tags and ou= revisions : 039 * 040 * ou=changelog 041 * | 042 * +-- ou=revisions 043 * | 044 * +-- ou=tags 045 * 046 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 047 * @version $Rev$, $Date$ 048 */ 049 public class DefaultChangeLog implements ChangeLog 050 { 051 /** The class logger */ 052 private static final Logger LOG = LoggerFactory.getLogger( DefaultChangeLog.class ); 053 054 /** Tells if the service is activated or not */ 055 private boolean enabled; 056 057 /** The latest tag set */ 058 private Tag latest; 059 060 /** 061 * The default store is a InMemory store. 062 **/ 063 private ChangeLogStore store; 064 065 /** A volatile flag used to avoid store switching when in use */ 066 private volatile boolean storeInitialized = false; 067 068 /** A flag used to tell if the changeLog system is vivible by the clients */ 069 private boolean exposed; 070 071 // default values for ChangeLogStorePartition containers 072 private static final String DEFAULT_PARTITION_SUFFIX = "ou=changelog"; 073 private static final String DEFAULT_REV_CONTAINER_NAME = "ou=revisions"; 074 private static final String DEFAULT_TAG_CONTAINER_NAME = "ou=tags"; 075 076 // default values for ChangeLogStorePartition containers 077 private String partitionSuffix = DEFAULT_PARTITION_SUFFIX; 078 private String revContainerName = DEFAULT_REV_CONTAINER_NAME; 079 private String tagContainerName = DEFAULT_TAG_CONTAINER_NAME; 080 081 082 /** 083 * {@inheritDoc} 084 */ 085 public ChangeLogStore getChangeLogStore() 086 { 087 return store; 088 } 089 090 091 /** 092 * {@inheritDoc} 093 * 094 * If there is an existing changeLog store, we don't switch it 095 */ 096 public void setChangeLogStore( ChangeLogStore store ) 097 { 098 if ( storeInitialized ) 099 { 100 LOG.error( I18n.err( I18n.ERR_29 ) ); 101 } 102 else 103 { 104 this.store = store; 105 } 106 } 107 108 109 /** 110 * {@inheritDoc} 111 */ 112 public long getCurrentRevision() throws Exception 113 { 114 synchronized( store ) 115 { 116 return store.getCurrentRevision(); 117 } 118 } 119 120 121 /** 122 * {@inheritDoc} 123 */ 124 public ChangeLogEvent log( LdapPrincipal principal, LdifEntry forward, LdifEntry reverse ) throws Exception 125 { 126 if ( !enabled ) 127 { 128 throw new IllegalStateException( I18n.err( I18n.ERR_236 ) ); 129 } 130 131 return store.log( principal, forward, reverse ); 132 } 133 134 135 /** 136 * {@inheritDoc} 137 */ 138 public ChangeLogEvent log( LdapPrincipal principal, LdifEntry forward, List<LdifEntry> reverses ) throws Exception 139 { 140 if ( !enabled ) 141 { 142 throw new IllegalStateException( I18n.err( I18n.ERR_236 ) ); 143 } 144 145 return store.log( principal, forward, reverses ); 146 } 147 148 149 /** 150 * {@inheritDoc} 151 */ 152 public boolean isLogSearchSupported() 153 { 154 return store instanceof SearchableChangeLogStore; 155 } 156 157 158 /** 159 * {@inheritDoc} 160 */ 161 public boolean isTagSearchSupported() 162 { 163 return store instanceof TaggableSearchableChangeLogStore; 164 } 165 166 167 /** 168 * {@inheritDoc} 169 */ 170 public boolean isTagStorageSupported() 171 { 172 return store instanceof TaggableChangeLogStore; 173 } 174 175 176 /** 177 * {@inheritDoc} 178 */ 179 public ChangeLogSearchEngine getChangeLogSearchEngine() 180 { 181 if ( isLogSearchSupported() ) 182 { 183 return ( ( SearchableChangeLogStore ) store ).getChangeLogSearchEngine(); 184 } 185 186 throw new UnsupportedOperationException( I18n.err( I18n.ERR_237 ) ); 187 } 188 189 190 /** 191 * {@inheritDoc} 192 */ 193 public TagSearchEngine getTagSearchEngine() 194 { 195 if ( isTagSearchSupported() ) 196 { 197 return ( ( TaggableSearchableChangeLogStore ) store ).getTagSearchEngine(); 198 } 199 200 throw new UnsupportedOperationException( I18n.err( I18n.ERR_238 ) ); 201 } 202 203 204 /** 205 * {@inheritDoc} 206 */ 207 public Tag tag( long revision, String description ) throws Exception 208 { 209 if ( revision < 0 ) 210 { 211 throw new IllegalArgumentException( I18n.err( I18n.ERR_239 ) ); 212 } 213 214 if ( revision > store.getCurrentRevision() ) 215 { 216 throw new IllegalArgumentException( I18n.err( I18n.ERR_240 ) ); 217 } 218 219 if ( store instanceof TaggableChangeLogStore ) 220 { 221 return latest = ( ( TaggableChangeLogStore ) store ).tag( revision ); 222 } 223 224 return latest = new Tag( revision, description ); 225 } 226 227 228 /** 229 * {@inheritDoc} 230 */ 231 public Tag tag( long revision ) throws Exception 232 { 233 return tag( revision, null ); 234 } 235 236 237 /** 238 * {@inheritDoc} 239 */ 240 public Tag tag( String description ) throws Exception 241 { 242 return tag( store.getCurrentRevision(), description ); 243 } 244 245 246 /** 247 * {@inheritDoc} 248 */ 249 public Tag tag() throws Exception 250 { 251 return tag( store.getCurrentRevision(), null ); 252 } 253 254 255 /** 256 * {@inheritDoc} 257 */ 258 public void setEnabled( boolean enabled ) 259 { 260 this.enabled = enabled; 261 } 262 263 264 /** 265 * {@inheritDoc} 266 */ 267 public boolean isEnabled() 268 { 269 return enabled; 270 } 271 272 273 /** 274 * {@inheritDoc} 275 */ 276 public Tag getLatest() throws Exception 277 { 278 if ( latest != null ) 279 { 280 return latest; 281 } 282 283 if ( store instanceof TaggableChangeLogStore ) 284 { 285 return latest = ( ( TaggableChangeLogStore ) store ).getLatest(); 286 } 287 288 return null; 289 } 290 291 292 /** 293 * Initialize the ChangeLog system. We will initialize the associated store. 294 */ 295 public void init( DirectoryService service ) throws Exception 296 { 297 if ( enabled ) 298 { 299 if ( store == null ) 300 { 301 // If no store has been defined, create an In Memory store 302 store = new MemoryChangeLogStore(); 303 } 304 305 store.init( service ); 306 307 if ( exposed && isTagSearchSupported() ) 308 { 309 TaggableSearchableChangeLogStore tmp = ( TaggableSearchableChangeLogStore ) store; 310 311 tmp.createPartition( partitionSuffix, revContainerName, tagContainerName ); 312 313 Partition partition = tmp.getPartition(); 314 partition.initialize( ); 315 316 service.addPartition( partition ); 317 } 318 } 319 320 // Flip the protection flag 321 storeInitialized = true; 322 } 323 324 325 /** 326 * {@inheritDoc} 327 */ 328 public void sync() throws Exception 329 { 330 if ( enabled ) 331 { 332 store.sync(); 333 } 334 } 335 336 337 /** 338 * {@inheritDoc} 339 */ 340 public void destroy() throws Exception 341 { 342 if ( enabled ) 343 { 344 store.destroy(); 345 } 346 347 storeInitialized = false; 348 } 349 350 351 /** 352 * {@inheritDoc} 353 */ 354 public boolean isExposed() 355 { 356 return exposed; 357 } 358 359 360 /** 361 * {@inheritDoc} 362 */ 363 public void setExposed( boolean exposed ) 364 { 365 this.exposed = exposed; 366 } 367 368 369 /** 370 * {@inheritDoc} 371 */ 372 public void setPartitionSuffix( String suffix ) 373 { 374 this.partitionSuffix = suffix; 375 } 376 377 378 /** 379 * {@inheritDoc} 380 */ 381 public void setRevisionsContainerName( String revContainerName ) 382 { 383 this.revContainerName = revContainerName; 384 } 385 386 387 /** 388 * {@inheritDoc} 389 */ 390 public void setTagsContainerName( String tagContainerName ) 391 { 392 this.tagContainerName = tagContainerName; 393 } 394 395 396 /** 397 * @see Object#toString() 398 */ 399 public String toString() 400 { 401 StringBuilder sb = new StringBuilder(); 402 403 sb.append( "ChangeLog tag[" ).append( latest ).append( "]\n" ); 404 sb.append( " store : \n" ).append( store ); 405 406 return sb.toString(); 407 } 408 }