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.changelog;
20  
21  
22  import java.util.List;
23  
24  import org.apache.directory.api.ldap.model.exception.LdapException;
25  import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
26  import org.apache.directory.api.ldap.model.ldif.LdifEntry;
27  import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
28  import org.apache.directory.server.core.api.DirectoryService;
29  import org.apache.directory.server.core.api.LdapPrincipal;
30  import org.apache.directory.server.core.api.changelog.ChangeLog;
31  import org.apache.directory.server.core.api.changelog.ChangeLogEvent;
32  import org.apache.directory.server.core.api.changelog.ChangeLogSearchEngine;
33  import org.apache.directory.server.core.api.changelog.ChangeLogStore;
34  import org.apache.directory.server.core.api.changelog.SearchableChangeLogStore;
35  import org.apache.directory.server.core.api.changelog.Tag;
36  import org.apache.directory.server.core.api.changelog.TagSearchEngine;
37  import org.apache.directory.server.core.api.changelog.TaggableChangeLogStore;
38  import org.apache.directory.server.core.api.changelog.TaggableSearchableChangeLogStore;
39  import org.apache.directory.server.core.api.partition.Partition;
40  import org.apache.directory.server.i18n.I18n;
41  import org.slf4j.Logger;
42  import org.slf4j.LoggerFactory;
43  
44  
45  /**
46   * The default ChangeLog service implementation. It stores operations 
47   * in memory.
48   * 
49   * Entries are stored into a dedicated partition, named ou=changelog, under which
50   * we have two other sub-entries : ou=tags and ou= revisions :
51   * 
52   *  ou=changelog
53   *    |
54   *    +-- ou=revisions
55   *    |
56   *    +-- ou=tags
57   *
58   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
59   */
60  public class DefaultChangeLog implements ChangeLog
61  {
62      /** The class logger */
63      private static final Logger LOG = LoggerFactory.getLogger( DefaultChangeLog.class );
64  
65      /** Tells if the service is activated or not */
66      private boolean enabled;
67  
68      /** The latest tag set */
69      private Tag latest;
70  
71      /** 
72       * The default store is a InMemory store.
73       **/
74      private ChangeLogStore store;
75  
76      /** A volatile flag used to avoid store switching when in use */
77      private volatile boolean storeInitialized = false;
78  
79      /** A flag used to tell if the changeLog system is visible by the clients */
80      private boolean exposed;
81  
82      // default values for ChangeLogStorePartition containers
83      private static final String DEFAULT_PARTITION_SUFFIX = "ou=changelog";
84      private static final String DEFAULT_REV_CONTAINER_NAME = "ou=revisions";
85      private static final String DEFAULT_TAG_CONTAINER_NAME = "ou=tags";
86  
87      // default values for ChangeLogStorePartition containers
88      private String partitionSuffix = DEFAULT_PARTITION_SUFFIX;
89      private String revContainerName = DEFAULT_REV_CONTAINER_NAME;
90      private String tagContainerName = DEFAULT_TAG_CONTAINER_NAME;
91  
92  
93      /**
94       * {@inheritDoc}
95       */
96      @Override
97      public ChangeLogStore getChangeLogStore()
98      {
99          return store;
100     }
101 
102 
103     /**
104      * {@inheritDoc}
105      * 
106      * If there is an existing changeLog store, we don't switch it 
107      */
108     @Override
109     public void setChangeLogStore( ChangeLogStore store )
110     {
111         if ( storeInitialized )
112         {
113             LOG.error( I18n.err( I18n.ERR_29 ) );
114         }
115         else
116         {
117             this.store = store;
118         }
119     }
120 
121 
122     /**
123      * {@inheritDoc}
124      */
125     @Override
126 public long getCurrentRevision() throws LdapException
127     {
128         synchronized ( store )
129         {
130             return store.getCurrentRevision();
131         }
132     }
133 
134 
135     /**
136      * {@inheritDoc}
137      */
138     @Override
139     public ChangeLogEvent log( LdapPrincipal principal, LdifEntry forward, LdifEntry reverse ) throws LdapException
140     {
141         if ( !enabled )
142         {
143             throw new IllegalStateException( I18n.err( I18n.ERR_236 ) );
144         }
145 
146         try
147         {
148             return store.log( principal, forward, reverse );
149         }
150         catch ( Exception e )
151         {
152             throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getMessage(), e );
153         }
154     }
155 
156 
157     /**
158      * {@inheritDoc}
159      */
160     @Override
161     public ChangeLogEvent log( LdapPrincipal principal, LdifEntry forward, List<LdifEntry> reverses )
162         throws LdapException
163     {
164         if ( !enabled )
165         {
166             throw new IllegalStateException( I18n.err( I18n.ERR_236 ) );
167         }
168 
169         try
170         {
171             return store.log( principal, forward, reverses );
172         }
173         catch ( Exception e )
174         {
175             throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getMessage(), e );
176         }
177     }
178 
179 
180     /**
181      * {@inheritDoc}
182      */
183     @Override
184     public boolean isLogSearchSupported()
185     {
186         return store instanceof SearchableChangeLogStore;
187     }
188 
189 
190     /**
191      * {@inheritDoc}
192      */
193     @Override
194     public boolean isTagSearchSupported()
195     {
196         return store instanceof TaggableSearchableChangeLogStore;
197     }
198 
199 
200     /**
201      * {@inheritDoc}
202      */
203     @Override
204     public boolean isTagStorageSupported()
205     {
206         return store instanceof TaggableChangeLogStore;
207     }
208 
209 
210     /**
211      * {@inheritDoc}
212      */
213     @Override
214     public ChangeLogSearchEngine getChangeLogSearchEngine()
215     {
216         if ( isLogSearchSupported() )
217         {
218             return ( ( SearchableChangeLogStore ) store ).getChangeLogSearchEngine();
219         }
220 
221         throw new UnsupportedOperationException( I18n.err( I18n.ERR_237 ) );
222     }
223 
224 
225     /**
226      * {@inheritDoc}
227      */
228     @Override
229     public TagSearchEngine getTagSearchEngine()
230     {
231         if ( isTagSearchSupported() )
232         {
233             return ( ( TaggableSearchableChangeLogStore ) store ).getTagSearchEngine();
234         }
235 
236         throw new UnsupportedOperationException( I18n.err( I18n.ERR_238 ) );
237     }
238 
239 
240     /**
241      * {@inheritDoc}
242      */
243     @Override
244     public Tag tag( long revision, String description ) throws Exception
245     {
246         if ( revision < 0 )
247         {
248             throw new IllegalArgumentException( I18n.err( I18n.ERR_239 ) );
249         }
250 
251         if ( revision > store.getCurrentRevision() )
252         {
253             throw new IllegalArgumentException( I18n.err( I18n.ERR_240 ) );
254         }
255 
256         if ( store instanceof TaggableChangeLogStore )
257         {
258             latest = ( ( TaggableChangeLogStore ) store ).tag( revision );
259             return latest;
260         }
261 
262         latest = new Tag( revision, description );
263         return latest;
264     }
265 
266 
267     /**
268      * {@inheritDoc}
269      */
270     @Override
271     public Tag tag( long revision ) throws Exception
272     {
273         return tag( revision, null );
274     }
275 
276 
277     /**
278      * {@inheritDoc}
279      */
280     @Override
281     public Tag tag( String description ) throws Exception
282     {
283         return tag( store.getCurrentRevision(), description );
284     }
285 
286 
287     /**
288      * {@inheritDoc}
289      */
290     @Override
291     public Tag tag() throws Exception
292     {
293         return tag( store.getCurrentRevision(), null );
294     }
295 
296 
297     /**
298      * {@inheritDoc}
299      */
300     @Override
301     public void setEnabled( boolean enabled )
302     {
303         this.enabled = enabled;
304     }
305 
306 
307     /**
308      * {@inheritDoc}
309      */
310     @Override
311     public boolean isEnabled()
312     {
313         return enabled;
314     }
315 
316 
317     /**
318      * {@inheritDoc}
319      */
320     @Override
321     public Tag getLatest() throws LdapException
322     {
323         if ( latest != null )
324         {
325             return latest;
326         }
327 
328         if ( store instanceof TaggableChangeLogStore )
329         {
330             latest = ( ( TaggableChangeLogStore ) store ).getLatest();
331             return latest;
332         }
333 
334         return null;
335     }
336 
337 
338     /**
339      * Initialize the ChangeLog system. We will initialize the associated store.
340      */
341     @Override
342     public void init( DirectoryService service ) throws LdapException
343     {
344         if ( enabled )
345         {
346             if ( store == null )
347             {
348                 // If no store has been defined, create an In Memory store
349                 store = new MemoryChangeLogStore();
350             }
351 
352             store.init( service );
353 
354             if ( exposed && isTagSearchSupported() )
355             {
356                 TaggableSearchableChangeLogStoreache/directory/server/core/api/changelog/TaggableSearchableChangeLogStore.html#TaggableSearchableChangeLogStore">TaggableSearchableChangeLogStore tmp = ( TaggableSearchableChangeLogStore ) store;
357 
358                 tmp.createPartition( partitionSuffix, revContainerName, tagContainerName );
359 
360                 Partition partition = tmp.getPartition();
361                 partition.initialize();
362 
363                 service.addPartition( partition );
364             }
365         }
366 
367         // Flip the protection flag
368         storeInitialized = true;
369     }
370 
371 
372     /**
373      * {@inheritDoc}
374      */
375     @Override
376     public void sync() throws LdapException
377     {
378         if ( enabled )
379         {
380             store.sync();
381         }
382     }
383 
384 
385     /**
386      * {@inheritDoc}
387      */
388     @Override
389     public void destroy() throws LdapException
390     {
391         if ( enabled )
392         {
393             store.destroy();
394         }
395 
396         storeInitialized = false;
397     }
398 
399 
400     /**
401      * {@inheritDoc}
402      */
403     @Override
404     public boolean isExposed()
405     {
406         return exposed;
407     }
408 
409 
410     /**
411      * {@inheritDoc}
412      */
413     @Override
414     public void setExposed( boolean exposed )
415     {
416         this.exposed = exposed;
417     }
418 
419 
420     /**
421      * {@inheritDoc}
422      */
423     @Override
424     public void setPartitionSuffix( String suffix )
425     {
426         this.partitionSuffix = suffix;
427     }
428 
429 
430     /**
431      * {@inheritDoc}
432      */
433     @Override
434     public void setRevisionsContainerName( String revContainerName )
435     {
436         this.revContainerName = revContainerName;
437     }
438 
439 
440     /**
441      * {@inheritDoc}
442      */
443     @Override
444     public void setTagsContainerName( String tagContainerName )
445     {
446         this.tagContainerName = tagContainerName;
447     }
448 
449 
450     /**
451      * @see Object#toString()
452      */
453     @Override
454     public String toString()
455     {
456         StringBuilder sb = new StringBuilder();
457 
458         sb.append( "ChangeLog tag[" ).append( latest ).append( "]\n" );
459         sb.append( "    store : \n" ).append( store );
460 
461         return sb.toString();
462     }
463 }