You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@directory.apache.org by Ersin Er <er...@gmail.com> on 2007/09/19 09:42:15 UTC

Re: svn commit: r577181 - in /directory/apacheds/trunk: core-unit/src/main/java/org/apache/directory/server/core/unit/ core/src/main/java/org/apache/directory/server/core/changelog/ server-tools/src/main/java/org/apache/directory/server/tools/command

The Studio also has a similar capability. So I think some common code might
be reused. WDYT?

On 9/19/07, akarasulu@apache.org <ak...@apache.org> wrote:
>
> Author: akarasulu
> Date: Wed Sep 19 00:19:21 2007
> New Revision: 577181
>
> URL: http://svn.apache.org/viewvc?rev=577181&view=rev
> Log:
> adding initial change log interceptor and various interfaces
>
> Added:
>
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogEvent.java
> (with props)
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogInterceptor.java
> (with props)
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogSearchEngine.java
> (with props)
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogService.java
> (with props)
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogStore.java
> (with props)
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/RevisionOrder.java
> (with props)
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/Scope.java
> (with props)
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/SearchableChangeLogStore.java
> (with props)
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/Tag.java
> (with props)
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TagSearchEngine.java
> (with props)
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TaggableChangeLogStore.java
> (with props)
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TaggableSearchableChangeLogStore.java
> (with props)
>     directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/package.html
> (with props)
> Modified:
>
>     directory/apacheds/trunk/core-unit/src/main/java/org/apache/directory/server/core/unit/AbstractPerformanceTest.java
>
>     directory/apacheds/trunk/server-tools/src/main/java/org/apache/directory/server/tools/commands/importcmd/ImportCommandExecutor.java
>
> Modified:
> directory/apacheds/trunk/core-unit/src/main/java/org/apache/directory/server/core/unit/AbstractPerformanceTest.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core-unit/src/main/java/org/apache/directory/server/core/unit/AbstractPerformanceTest.java?rev=577181&r1=577180&r2=577181&view=diff
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core-unit/src/main/java/org/apache/directory/server/core/unit/AbstractPerformanceTest.java
> (original)
> +++
> directory/apacheds/trunk/core-unit/src/main/java/org/apache/directory/server/core/unit/AbstractPerformanceTest.java
> Wed Sep 19 00:19:21 2007
> @@ -40,6 +40,7 @@
> import org.apache.directory.server.core.partition.PartitionNexus;
> import org.apache.directory.shared.ldap.constants.SchemaConstants;
> import org.apache.directory.shared.ldap.ldif.Entry;
> +import org.apache.directory.shared.ldap.ldif.ChangeType;
> import org.apache.directory.shared.ldap.ldif.LdifReader;
> import org.apache.directory.shared.ldap.message.AttributesImpl;
> import org.apache.directory.shared.ldap.name.LdapDN;
> @@ -99,7 +100,7 @@
>   */
> public class AbstractPerformanceTest extends AbstractTestCase
> {
> -    private final Class subclass;
> +    private final Class<?> subclass;
>      private boolean isExternal = false;
>      private String prepareCommand = null;
>      private File outputDirectory = null;
> @@ -113,7 +114,7 @@
>       *
>       * @param subclass
>       */
> -    protected AbstractPerformanceTest( Class subclass ) throws
> IOException
> +    protected AbstractPerformanceTest( Class<?> subclass ) throws
> IOException
>      {
>          super( PartitionNexus.ADMIN_PRINCIPAL, "secret" );
>          this.subclass = subclass;
> @@ -225,9 +226,9 @@
>       */
>      protected boolean applyEntry( Entry entry ) throws Exception
>      {
> -        switch ( entry.getChangeType() )
> +        switch ( entry.getChangeType().getChangeType() )
>          {
> -            case( Entry.ADD ):
> +            case( ChangeType.ADD_ORDINAL ):
>                  LdapDN ancestor = new LdapDN( testRoot.getNameInNamespace()
> );
>                  LdapDN descendant = new LdapDN( entry.getDn() );
>                  LdapDN relative = ( LdapDN )
> NamespaceTools.getRelativeName( ancestor, descendant );
> @@ -250,7 +251,7 @@
>              LdifReader reader = new LdifReader( in );
>              start = System.currentTimeMillis();
>              log( "Started LDIF Import: " + ldifResource  );
> -            for ( Iterator ii = reader.iterator(); ii.hasNext(); /**/ )
> +            for ( Iterator<Entry> ii = reader.iterator(); ii.hasNext();
> /**/ )
>              {
>                  long startEntry = System.currentTimeMillis();
>                  if ( applyEntry( ( Entry ) ii.next() ) )
>
> Added:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogEvent.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogEvent.java?rev=577181&view=auto
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogEvent.java
> (added)
> +++
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogEvent.java
> Wed Sep 19 00:19:21 2007
> @@ -0,0 +1,107 @@
> +/*
> + *   Licensed to the Apache Software Foundation (ASF) under one
> + *   or more contributor license agreements.  See the NOTICE file
> + *   distributed with this work for additional information
> + *   regarding copyright ownership.  The ASF licenses this file
> + *   to you under the Apache License, Version 2.0 (the
> + *   "License"); you may not use this file except in compliance
> + *   with the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + *   Unless required by applicable law or agreed to in writing,
> + *   software distributed under the License is distributed on an
> + *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + *   KIND, either express or implied.  See the License for the
> + *   specific language governing permissions and limitations
> + *   under the License.
> + *
> + */
> +package org.apache.directory.server.core.changelog;
> +
> +
> +import java.io.Serializable;
> +
> +import org.apache.directory.server.core.authn.LdapPrincipal;
> +import org.apache.directory.shared.ldap.ldif.Entry;
> +
> +
> +/**
> + * A loggable directory change event.
> + *
> + * @author <a href="mailto:dev@directory.apache.org">Apache Directory
> Project</a>
> + * @version $Rev$, $Date$
> + */
> +public class ChangeLogEvent implements Serializable
> +{
> +    private static final long serialVersionUID = 1L;
> +    private final String zuluTime;
> +    private final long revision;
> +    private final Entry forwardLdif;
> +    private final Entry reverseLdif;
> +    private final LdapPrincipal committer;
> +
> +
> +    /**
> +     * Creates a new instance of ChangeLogEvent.
> +     *
> +     * @param the revision for the change
> +     * @param committer the authorized user which triggered the change
> +     * @param forwardLdif the LDIF representing the change forward in
> time
> +     * @param reverseLdif an LDIF which reverts the change going reverse
> in time to an earlier revision
> +     */
> +    public ChangeLogEvent( long commitId, String zuluTime, LdapPrincipal
> committer,
> +        Entry forwardLdif, Entry reverseLdif )
> +    {
> +        this.zuluTime = zuluTime;
> +        this.revision = commitId;
> +        this.forwardLdif = forwardLdif;
> +        this.reverseLdif = reverseLdif;
> +        this.committer = committer;
> +    }
> +
> +
> +    /**
> +     * @return the forwardLdif
> +     */
> +    public Entry getForwardLdif()
> +    {
> +        return forwardLdif;
> +    }
> +
> +
> +    /**
> +     * @return the reverseLdif
> +     */
> +    public Entry getReverseLdif()
> +    {
> +        return reverseLdif;
> +    }
> +
> +
> +    /**
> +     * @return the committer
> +     */
> +    public LdapPrincipal getCommitter()
> +    {
> +        return committer;
> +    }
> +
> +
> +    /**
> +     * @return the revision
> +     */
> +    public long getRevision()
> +    {
> +        return revision;
> +    }
> +
> +
> +    /**
> +     * @return the zuluTime
> +     */
> +    public String getZuluTime()
> +    {
> +        return zuluTime;
> +    }
> +}
>
> Propchange:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogEvent.java
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogInterceptor.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogInterceptor.java?rev=577181&view=auto
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogInterceptor.java
> (added)
> +++
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogInterceptor.java
> Wed Sep 19 00:19:21 2007
> @@ -0,0 +1,568 @@
> +package org.apache.directory.server.core.changelog;
> +
> +
> +import java.io.File;
> +import java.io.FileWriter;
> +import java.io.PrintWriter;
> +import java.io.UnsupportedEncodingException;
> +import java.util.LinkedList;
> +import java.util.Queue;
> +
> +import javax.naming.NamingEnumeration;
> +import javax.naming.NamingException;
> +import javax.naming.directory.Attribute;
> +import javax.naming.directory.Attributes;
> +import javax.naming.directory.DirContext;
> +import javax.naming.directory.ModificationItem;
> +
> +import org.apache.directory.server.core.DirectoryServiceConfiguration;
> +import
> org.apache.directory.server.core.configuration.InterceptorConfiguration;
> +import org.apache.directory.server.core.interceptor.BaseInterceptor;
> +import org.apache.directory.server.core.interceptor.NextInterceptor;
> +import
> org.apache.directory.server.core.interceptor.context.AddOperationContext;
> +import
> org.apache.directory.server.core.interceptor.context.DeleteOperationContext
> ;
> +import
> org.apache.directory.server.core.interceptor.context.ModifyOperationContext
> ;
> +import
> org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext
> ;
> +import
> org.apache.directory.server.core.interceptor.context.MoveOperationContext;
> +import
> org.apache.directory.server.core.interceptor.context.RenameOperationContext
> ;
> +import org.apache.directory.server.core.invocation.InvocationStack;
> +import org.apache.directory.server.core.jndi.ServerContext;
> +import
> org.apache.directory.server.schema.registries.AttributeTypeRegistry;
> +
> +import org.apache.directory.shared.ldap.util.Base64;
> +import org.apache.directory.shared.ldap.util.DateUtils;
> +
> +import org.slf4j.Logger;
> +import org.slf4j.LoggerFactory;
> +
> +
> +/**
> + * An interceptor which maintains a change log as it intercepts changes
> to the
> + * directory.  It mainains a changes.log file using the LDIF format for
> changes.
> + * It appends changes to this file so the entire LDIF file can be loaded
> to
> + * replicate the state of the server.
> + *
> + */
> +public class ChangeLogInterceptor extends BaseInterceptor implements
> Runnable
> +{
> +    /** time to wait before automatically waking up the writer thread */
> +    private static final long WAIT_TIMEOUT_MILLIS = 1000;
> +    private static final Logger log = LoggerFactory.getLogger(
> ChangeLogInterceptor.class );
> +
> +    /** the changes.log file's stream which we append change log messages
> to */
> +    PrintWriter out = null;
> +    /** queue of string buffers awaiting serialization to the log file */
> +    Queue<StringBuffer> queue = new LinkedList<StringBuffer>();
> +    /** a handle on the attributeType registry to determine the binary
> nature of attributes */
> +    AttributeTypeRegistry registry = null;
> +    /** determines if this service has been activated */
> +    boolean isActive = false;
> +    /** thread used to asynchronously write change logs to disk */
> +    Thread writer = null;
> +
> +
> +    //
> -----------------------------------------------------------------------
> +    // Overridden init() and destroy() methods
> +    //
> -----------------------------------------------------------------------
> +
> +
> +    public void init( DirectoryServiceConfiguration dsConfig,
> InterceptorConfiguration iConfig ) throws NamingException
> +    {
> +        super.init( dsConfig, iConfig );
> +
> +        // Get a handle on the attribute registry to check if attributes
> are binary
> +        registry = dsConfig.getRegistries().getAttributeTypeRegistry();
> +
> +        // Open a print stream to use for flushing LDIFs into
> +        File changes = new File( dsConfig.getStartupConfiguration().getWorkingDirectory(),
> "changes.log" );
> +        try
> +        {
> +            if ( changes.exists() )
> +            {
> +                out = new PrintWriter( new FileWriter( changes, true ) );
> +            }
> +            else
> +            {
> +                out = new PrintWriter( new FileWriter( changes ) );
> +            }
> +        }
> +        catch( Exception e )
> +        {
> +            log.error( "Failed to open the change log file: " + changes,
> e );
> +        }
> +
> +        out.println( "#
> -----------------------------------------------------------------------------"
> );
> +        out.println( "# Initializing changelog service: " +
> DateUtils.getGeneralizedTime() );
> +        out.println( "#
> -----------------------------------------------------------------------------"
> );
> +        out.flush();
> +
> +        writer = new Thread( this );
> +        isActive = true;
> +        writer.start();
> +    }
> +
> +
> +    public void destroy()
> +    {
> +        // Gracefully stop writer thread and push remaining enqueued
> buffers ourselves
> +        isActive = false;
> +        do
> +        {
> +            // Let's notify the writer thread to make it die faster
> +            synchronized( queue )
> +            {
> +                queue.notifyAll();
> +            }
> +
> +            // Sleep tiny bit waiting for the writer to die
> +            try
> +            {
> +                Thread.sleep( 50 );
> +            }
> +            catch ( InterruptedException e )
> +            {
> +                log.error( "Failed to sleep while waiting for writer to
> die", e );
> +            }
> +        } while ( writer.isAlive() );
> +
> +        // Ok lock down queue and start draining it
> +        synchronized( queue )
> +        {
> +            while ( ! queue.isEmpty() )
> +            {
> +                StringBuffer buf = queue.poll();
> +                if ( buf != null )
> +                {
> +                    out.println( buf );
> +                }
> +            }
> +        }
> +
> +        // Print message that we're stopping log service, flush and close
> +        out.println( "#
> -----------------------------------------------------------------------------"
> );
> +        out.println( "# Deactivating changelog service: " +
> DateUtils.getGeneralizedTime() );
> +        out.println( "#
> -----------------------------------------------------------------------------"
> );
> +        out.flush();
> +        out.close();
> +
> +        super.destroy();
> +    }
> +
> +
> +    //
> -----------------------------------------------------------------------
> +    // Implementation for Runnable.run() for writer Thread
> +    //
> -----------------------------------------------------------------------
> +
> +
> +    public void run()
> +    {
> +        while ( isActive )
> +        {
> +            StringBuffer buf = null;
> +
> +            // Grab semphore to queue and dequeue from it
> +            synchronized( queue )
> +            {
> +                try
> +                {
> +                    queue.wait( WAIT_TIMEOUT_MILLIS );
> +                }
> +                catch ( InterruptedException e )
> +                {
> +                    log.error( "Failed to to wait() on queue", e );
> +                }
> +
> +                buf = queue.poll();
> +                queue.notifyAll();
> +            }
> +
> +            // Do writing outside of synch block to allow other threads
> to enqueue
> +            if ( buf != null )
> +            {
> +                out.println( buf );
> +                out.flush();
> +            }
> +        }
> +    }
> +
> +
> +    //
> -----------------------------------------------------------------------
> +    // Overridden (only change inducing) intercepted methods
> +    //
> -----------------------------------------------------------------------
> +
> +
> +    public void add( NextInterceptor next, AddOperationContext opContext
> ) throws NamingException
> +    {
> +        StringBuffer buf;
> +        next.add( opContext );
> +
> +        if ( ! isActive )
> +        {
> +            return;
> +        }
> +
> +        // Append comments that can be used to track the user and time
> this operation occurred
> +        buf = new StringBuffer();
> +        buf.append( "\n#! creatorsName: " );
> +        buf.append( getPrincipalName() );
> +        buf.append( "\n#! createTimestamp: " );
> +        buf.append( DateUtils.getGeneralizedTime() );
> +
> +        // Append the LDIF entry now
> +        buf.append( "\ndn: " );
> +        buf.append( opContext.getDn().getUpName() );
> +        buf.append( "\nchangetype: add" );
> +        append( buf, opContext.getEntry() );
> +        buf.append( "\n" );
> +
> +        // Enqueue the buffer onto a queue that is emptied by another
> thread asynchronously.
> +        synchronized ( queue )
> +        {
> +            queue.offer( buf );
> +            queue.notifyAll();
> +        }
> +    }
> +
> +
> +    public void delete( NextInterceptor next, DeleteOperationContext
> opContext ) throws NamingException
> +    {
> +        StringBuffer buf;
> +        next.delete( opContext );
> +
> +        if ( ! isActive )
> +        {
> +            return;
> +        }
> +
> +        // Append comments that can be used to track the user and time
> this operation occurred
> +        buf = new StringBuffer();
> +        buf.append( "\n#! deletorsName: " );
> +        buf.append( getPrincipalName() );
> +        buf.append( "\n#! deleteTimestamp: " );
> +        buf.append( DateUtils.getGeneralizedTime() );
> +
> +        // Append the LDIF record now
> +        buf.append( "\ndn: " );
> +        buf.append( opContext.getDn() );
> +        buf.append( "\nchangetype: delete\n" );
> +
> +        // Enqueue the buffer onto a queue that is emptied by another
> thread asynchronously.
> +        synchronized ( queue )
> +        {
> +            queue.offer( buf );
> +            queue.notifyAll();
> +        }
> +    }
> +
> +
> +    public void modify( NextInterceptor next, ModifyOperationContext
> opContext ) throws NamingException
> +    {
> +        StringBuffer buf;
> +        next.modify( opContext );
> +
> +        if ( ! isActive )
> +        {
> +            return;
> +        }
> +
> +        // Append comments that can be used to track the user and time
> this operation occurred
> +        buf = new StringBuffer();
> +        buf.append( "\n#! modifiersName: " );
> +        buf.append( getPrincipalName() );
> +        buf.append( "\n#! modifyTimestamp: " );
> +        buf.append( DateUtils.getGeneralizedTime() );
> +
> +        // Append the LDIF record now
> +        buf.append( "\ndn: " );
> +        buf.append( opContext.getDn() );
> +        buf.append( "\nchangetype: modify" );
> +
> +        ModificationItem[] mods = opContext.getModItems();
> +        for ( int ii = 0; ii < mods.length; ii++ )
> +        {
> +            append( buf, mods[ii].getAttribute(), getModOpStr(
> mods[ii].getModificationOp() ) );
> +        }
> +        buf.append( "\n" );
> +
> +        // Enqueue the buffer onto a queue that is emptied by another
> thread asynchronously.
> +        synchronized ( queue )
> +        {
> +            queue.offer( buf );
> +            queue.notifyAll();
> +        }
> +    }
> +
> +
> +    //
> -----------------------------------------------------------------------
> +    // Though part left as an exercise (Not Any More!)
> +    //
> -----------------------------------------------------------------------
> +
> +
> +    public void rename ( NextInterceptor next, RenameOperationContext
> renameContext ) throws NamingException
> +    {
> +        next.rename( renameContext );
> +
> +        if ( ! isActive )
> +        {
> +            return;
> +        }
> +
> +        StringBuffer buf;
> +
> +        // Append comments that can be used to track the user and time
> this operation occurred
> +        buf = new StringBuffer();
> +        buf.append( "\n#! principleName: " );
> +        buf.append( getPrincipalName() );
> +        buf.append( "\n#! operationTimestamp: " );
> +        buf.append( DateUtils.getGeneralizedTime() );
> +
> +        // Append the LDIF record now
> +        buf.append( "\ndn: " );
> +        buf.append( renameContext.getDn() );
> +        buf.append( "\nchangetype: modrdn" );
> +        buf.append( "\nnewrdn: " + renameContext.getNewRdn() );
> +        buf.append( "\ndeleteoldrdn: " + ( renameContext.getDelOldDn() ?
> "1" : "0" ) );
> +
> +        buf.append( "\n" );
> +
> +        // Enqueue the buffer onto a queue that is emptied by another
> thread asynchronously.
> +        synchronized ( queue )
> +        {
> +            queue.offer( buf );
> +            queue.notifyAll();
> +        }
> +    }
> +
> +
> +    public void moveAndRename( NextInterceptor next,
> MoveAndRenameOperationContext moveAndRenameOperationContext )
> +        throws NamingException
> +    {
> +        next.moveAndRename( moveAndRenameOperationContext );
> +
> +        if ( ! isActive )
> +        {
> +            return;
> +        }
> +
> +        StringBuffer buf;
> +
> +        // Append comments that can be used to track the user and time
> this operation occurred
> +        buf = new StringBuffer();
> +        buf.append( "\n#! principleName: " );
> +        buf.append( getPrincipalName() );
> +        buf.append( "\n#! operationTimestamp: " );
> +        buf.append( DateUtils.getGeneralizedTime() );
> +
> +        // Append the LDIF record now
> +        buf.append( "\ndn: " );
> +        buf.append( moveAndRenameOperationContext.getDn() );
> +        buf.append( "\nchangetype: modrdn" ); // FIXME: modrdn --> moddn
> ?
> +        buf.append( "\nnewrdn: " +
> moveAndRenameOperationContext.getNewRdn() );
> +        buf.append( "\ndeleteoldrdn: " + (
> moveAndRenameOperationContext.getDelOldDn() ? "1" : "0" ) );
> +        buf.append( "\nnewsperior: " +
> moveAndRenameOperationContext.getParent() );
> +
> +        buf.append( "\n" );
> +
> +        // Enqueue the buffer onto a queue that is emptied by another
> thread asynchronously.
> +        synchronized ( queue )
> +        {
> +            queue.offer( buf );
> +            queue.notifyAll();
> +        }
> +    }
> +
> +
> +    public void move ( NextInterceptor next, MoveOperationContext
> moveOperationContext ) throws NamingException
> +    {
> +        next.move( moveOperationContext );
> +
> +        if ( ! isActive )
> +        {
> +            return;
> +        }
> +
> +        StringBuffer buf;
> +
> +        // Append comments that can be used to track the user and time
> this operation occurred
> +        buf = new StringBuffer();
> +        buf.append( "\n#! principleName: " );
> +        buf.append( getPrincipalName() );
> +        buf.append( "\n#! operationTimestamp: " );
> +        buf.append( DateUtils.getGeneralizedTime() );
> +
> +        // Append the LDIF record now
> +        buf.append( "\ndn: " );
> +        buf.append( moveOperationContext.getDn() );
> +        buf.append( "\nchangetype: moddn" );
> +        buf.append( "\nnewsperior: " + moveOperationContext.getParent()
> );
> +
> +        buf.append( "\n" );
> +
> +        // Enqueue the buffer onto a queue that is emptied by another
> thread asynchronously.
> +        synchronized ( queue )
> +        {
> +            queue.offer( buf );
> +            queue.notifyAll();
> +        }
> +    }
> +
> +
> +    //
> -----------------------------------------------------------------------
> +    // Private utility methods used by interceptor methods
> +    //
> -----------------------------------------------------------------------
> +
> +
> +    /**
> +     * Appends an Attribute and its values to a buffer containing an LDIF
> entry taking
> +     * into account whether or not the attribute's syntax is binary or
> not.
> +     *
> +     * @param buf the buffer written to and returned (for chaining)
> +     * @param attr the attribute written to the buffer
> +     * @return the buffer argument to allow for call chaining.
> +     * @throws NamingException if the attribute is not identified by the
> registry
> +     */
> +    private StringBuffer append( StringBuffer buf, Attribute attr )
> throws NamingException
> +    {
> +        String id = ( String ) attr.getID();
> +        int sz = attr.size();
> +        boolean isBinary = ! registry.lookup( id
> ).getSyntax().isHumanReadable();
> +
> +        if ( isBinary )
> +        {
> +            for ( int ii = 0; ii < sz; ii++  )
> +            {
> +                buf.append( "\n" );
> +                buf.append( id );
> +                buf.append( ":: " );
> +                Object value = attr.get( ii );
> +                String encoded;
> +                if ( value instanceof String )
> +                {
> +                    encoded = ( String ) value;
> +                    try
> +                    {
> +                        encoded = new String( Base64.encode(
> encoded.getBytes( "UTF-8" ) ) );
> +                    }
> +                    catch ( UnsupportedEncodingException e )
> +                    {
> +                        log.error( "can't convert to UTF-8: " + encoded,
> e );
> +                    }
> +                }
> +                else
> +                {
> +                    encoded = new String( Base64.encode( ( byte[] )
> attr.get( ii ) ) );
> +                }
> +                buf.append( encoded );
> +            }
> +        }
> +        else
> +        {
> +            for ( int ii = 0; ii < sz; ii++  )
> +            {
> +                buf.append( "\n" );
> +                buf.append( id );
> +                buf.append( ": " );
> +                buf.append( attr.get( ii ) );
> +            }
> +        }
> +
> +        return buf;
> +    }
> +
> +
> +    /**
> +     * Appends a set of attributes to a buffer for an LDIF record.  The
> Dn is presumed
> +     * to be added some time before.
> +     *
> +     * @param buf the buffer to add the attributes to
> +     * @param attrs the attributes to append to the buffer
> +     * @return the buffer argument passed in for chaining
> +     * @throws NamingException if some attribute identifiers are not
> defined
> +     */
> +    private StringBuffer append( StringBuffer buf, Attributes attrs )
> throws NamingException
> +    {
> +        NamingEnumeration<String> ids = attrs.getIDs();
> +        while ( ids.hasMore() )
> +        {
> +            String id = ids.next();
> +            append( buf, attrs.get( id ) );
> +        }
> +        return buf;
> +    }
> +
> +
> +    /**
> +     * Gets the DN of the user currently bound to the server executing
> this operation.  If
> +     * the user is anonymous "" is returned.
> +     *
> +     * @return the DN of the user executing the current intercepted
> operation
> +     * @throws NamingException if we cannot access the interceptor stack
> +     */
> +    private String getPrincipalName() throws NamingException
> +    {
> +        ServerContext ctx = ( ServerContext ) InvocationStack.getInstance
> ().peek().getCaller();
> +        return ctx.getPrincipal().getName();
> +    }
> +
> +
> +    /**
> +     * Gets a String representation of the JNDI attribute modificaion
> flag.  Here are the mappings:
> +     * <table>
> +     *   <tr><th>JNDI Constant</th><th>Returned String</th></tr>
> +     *   <tr><td>DirContext.ADD_ATTRIBUTE</td><td>'add: '</td></tr>
> +     *   <tr><td>DirContext.REMOVE_ATTRIBUTE</td><td>'delete: '</td></tr>
> +     *   <tr><td>DirContext.REPLACE_ATTRIBUTE</td><td>'replace:
> '</td></tr>
> +     * </table>
> +     * <ul><li>
> +     * Note that the String in right hand column is quoted to show
> trailing space.
> +     * </li></ul>
> +     *
> +     * @param modOp the int value of the JNDI modification operation
> +     * @return the string representation of the JNDI Modification
> operation
> +     */
> +    private String getModOpStr( int modOp )
> +    {
> +        String opStr;
> +        switch( modOp )
> +        {
> +            case( DirContext.ADD_ATTRIBUTE ):
> +                opStr = "add: ";
> +                break;
> +            case( DirContext.REMOVE_ATTRIBUTE ):
> +                opStr = "delete: ";
> +                break;
> +            case( DirContext.REPLACE_ATTRIBUTE ):
> +                opStr = "replace: ";
> +                break;
> +            default:
> +                throw new IllegalArgumentException( "Undefined attribute
> modify operation: " + modOp );
> +        }
> +        return opStr;
> +    }
> +
> +
> +    /**
> +     * Appends a modification delta instruction to an LDIF: i.e.
> +     * <pre>
> +     * add: telephoneNumber
> +     * telephoneNumber: +1 408 555 1234
> +     * telephoneNumber: +1 408 444 9999
> +     * -
> +     * </pre>
> +     *
> +     * @param buf the buffer to append the attribute delta to
> +     * @param mod the modified values if any for that attribute
> +     * @param modOp the modification operation as a string followd by ":
> "
> +     * @return the buffer argument provided for chaining
> +     * @throws NamingException if the modification attribute id is
> undefined
> +     */
> +    private StringBuffer append( StringBuffer buf, Attribute mod, String
> modOp ) throws NamingException
> +    {
> +        buf.append( "\n" );
> +        buf.append( modOp );
> +        buf.append( mod.getID() );
> +        append( buf, mod );
> +        buf.append( "\n-" );
> +        return buf;
> +    }
> +}
>
> Propchange:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogInterceptor.java
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogSearchEngine.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogSearchEngine.java?rev=577181&view=auto
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogSearchEngine.java
> (added)
> +++
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogSearchEngine.java
> Wed Sep 19 00:19:21 2007
> @@ -0,0 +1,227 @@
> +/*
> + *   Licensed to the Apache Software Foundation (ASF) under one
> + *   or more contributor license agreements.  See the NOTICE file
> + *   distributed with this work for additional information
> + *   regarding copyright ownership.  The ASF licenses this file
> + *   to you under the Apache License, Version 2.0 (the
> + *   "License"); you may not use this file except in compliance
> + *   with the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + *   Unless required by applicable law or agreed to in writing,
> + *   software distributed under the License is distributed on an
> + *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + *   KIND, either express or implied.  See the License for the
> + *   specific language governing permissions and limitations
> + *   under the License.
> + *
> + */
> +package org.apache.directory.server.core.changelog;
> +
> +
> +import javax.naming.NamingEnumeration;
> +import javax.naming.NamingException;
> +
> +import org.apache.directory.server.core.authn.LdapPrincipal;
> +import org.apache.directory.shared.ldap.filter.ExprNode;
> +import org.apache.directory.shared.ldap.ldif.ChangeType;
> +import org.apache.directory.shared.ldap.name.LdapDN;
> +import org.apache.directory.shared.ldap.schema.AttributeType;
> +import org.apache.directory.shared.ldap.schema.ObjectClass;
> +
> +
> +/**
> + * A custom search engine designed for optimized searching across
> ChangeLogEvents
> + * within the ChangeLogStore.  The following lookup and search operations
> are
> + * provided:
> + *
> + * <ul>
> + *   <li>lookup change by revision</li>
> + *   <li>lookup change by date</li>
> + *   <li>find all changes</li>
> + *   <li>find all changes before or after a revision</li>
> + *   <li>find all changes in a revision range</li>
> + *   <li>find changes by LDAP namespace scope on DN</li>
> + *   <li>find changes by DN</li>
> + *   <li>find changes by principal</li>
> + *   <li>find changes by change type</li>
> + *   <li>find changes by attribute</li>
> + *   <li>find changes using a restricted LDAP filter on all of the above
> factors</li>
> + * </ul>
> + *
> + * Note change lookups by date can be conducted by first looking up a
> revision
> + * using a generalizedTime descriptor to find a revision.  Then these
> revisions
> + * can be plugged into the revision based find and lookup methods.
> + *
> + * @author <a href="mailto:dev@directory.apache.org">Apache Directory
> Project</a>
> + * @version $Rev$, $Date$
> + */
> +public interface ChangeLogSearchEngine
> +{
> +    /**
> +     * Looks up the revision in effect at some time specified by a
> generalized
> +     * time descriptor.
> +     *
> +     * @param generalizedTime the generalized time descriptor to find the
> effective revision for
> +     * @return the revision that was in effect at a certain time
> +     * @throws NamingException if there are failures accessing the store
> +     */
> +    long lookup( String generalizedTime ) throws NamingException;
> +
> +
> +    /**
> +     * Looks up the ChangeLogEvent for a revision.
> +     *
> +     * @param revision to get a ChangeLogEvent for
> +     * @return the ChangeLogEvent associated with the revision
> +     * @throws NamingException if there are failures accessing the store
> +     */
> +    ChangeLogEvent lookup( long revision ) throws NamingException;
> +
> +
> +    /**
> +     * Finds all the ChangeLogEvents within the system since revision 0.
> +     *
> +     * @param order the order in which to return ChangeLogEvents (ordered
> by revision number)
> +     * @return an enumeration of all the ChangeLogEvents
> +     * @throws NamingException if there are failures accessing the store
> +     */
> +    NamingEnumeration<ChangeLogEvent> find( RevisionOrder order ) throws
> NamingException;
> +
> +
> +    /**
> +     * Finds the ChangeLogEvents that occurred before a revision
> inclusive.
> +     *
> +     * @param revision the revision number to get the ChangeLogEvents
> before
> +     * @param order the order in which to return ChangeLogEvents (ordered
> by revision number)
> +     * @return an enumeration of all the ChangeLogEvents before and
> including some revision
> +     * @throws NamingException if there are failures accessing the store
> +     */
> +    NamingEnumeration<ChangeLogEvent> findBefore( long revision,
> RevisionOrder order ) throws NamingException;
> +
> +
> +    /**
> +     * Finds the ChangeLogEvents that occurred after a revision
> inclusive.
> +     *
> +     * @param revision the revision number to get the ChangeLogEvents
> after
> +     * @param order the order in which to return ChangeLogEvents (ordered
> by revision number)
> +     * @return an enumeration of all the ChangeLogEvents after and
> including the revision
> +     * @throws NamingException if there are failures accessing the store
> +     */
> +    NamingEnumeration<ChangeLogEvent> findAfter( long revision,
> RevisionOrder order ) throws NamingException;
> +
> +
> +    /**
> +     * Finds the ChangeLogEvents that occurred between a revision range
> inclusive.
> +     *
> +     * @param startRevision the revision number to start getting the
> ChangeLogEvents above
> +     * @param endRevision the revision number to start getting the
> ChangeLogEvents below
> +     * @param order the order in which to return ChangeLogEvents (ordered
> by revision number)
> +     * @return an enumeration of all the ChangeLogEvents within some
> revision range inclusive
> +     * @throws NamingException if there are failures accessing the store
> +     */
> +    NamingEnumeration<ChangeLogEvent> find( long startRevision, long
> endRevision, RevisionOrder order )
> +        throws NamingException;
> +
> +
> +    /**
> +     * Finds all the ChangeLogEvents on an entry.
> +     *
> +     * @param dn the normalized DN of the entry to get ChangeLogEvents
> for
> +     * @param order the order in which to return ChangeLogEvents (ordered
> by revision number)
> +     * @return the set of changes that occurred on an entry
> +     * @throws NamingException if there are failures accessing the store
> +     */
> +    NamingEnumeration<ChangeLogEvent> find( LdapDN dn, RevisionOrder
> order ) throws NamingException;
> +
> +
> +    /**
> +     * Finds all the ChangeLogEvents on an entry base and/or it's
> children/descendants.
> +     *
> +     * @param base the normalized DN of the entry base to get
> ChangeLogEvents for
> +     * @param scope the scope of the search under the base similar to
> LDAP search scope
> +     * @param order the order in which to return ChangeLogEvents (ordered
> by revision number)
> +     * @return the set of changes that occurred on an entry and/or it's
> descendants depending on the scope
> +     * @throws NamingException if there are failures accessing the store
> +     */
> +    NamingEnumeration<ChangeLogEvent> find( LdapDN base, Scope scope,
> RevisionOrder order ) throws NamingException;
> +
> +
> +    /**
> +     * Finds all the ChangeLogEvents triggered by a principal in the
> system.
> +     *
> +     * @param principal the LDAP principal who triggered the events
> +     * @param order the order in which to return ChangeLogEvents (ordered
> by revision number)
> +     * @return the set of changes that were triggered by a specific LDAP
> user
> +     * @throws NamingException if there are failures accessing the store
> +     */
> +    NamingEnumeration<ChangeLogEvent> find( LdapPrincipal principal,
> RevisionOrder order ) throws NamingException;
> +
> +
> +    /**
> +     * Finds all the ChangeLogEvents of a particular change type.
> +     *
> +     * @param changeType the change type of the ChangeLogEvents to search
> for
> +     * @param order the order in which to return ChangeLogEvents (ordered
> by revision number)
> +     * @return the set of ChangeLogEvents of a particular ChangeType
> +     * @throws NamingException if there are failures accessing the store
> +     */
> +    NamingEnumeration<ChangeLogEvent> find( ChangeType changeType,
> RevisionOrder order ) throws NamingException;
> +
> +
> +    /**
> +     * Finds all the ChangeLogEvents altering a particular attributeType.
> +     *
> +     * @param attributeType the attributeType definition for the changed
> attribute to search changes for
> +     * @param order the order in which to return ChangeLogEvents (ordered
> by revision number)
> +     * @return the set of ChangeLogEvents on a particular attributeType
> +     * @throws NamingException if there are failures accessing the store
> +     */
> +    NamingEnumeration<ChangeLogEvent> find( AttributeType attributeType,
> RevisionOrder order ) throws NamingException;
> +
> +
> +    /**
> +     * Finds all the ChangeLogEvents altering a particular objectClass.
> +     *
> +     * @param objectClass the objectClass definition for the entries to
> search changes for
> +     * @param order the order in which to return ChangeLogEvents (ordered
> by revision number)
> +     * @return the set of ChangeLogEvents on a particular attributeType
> +     * @throws NamingException if there are failures accessing the store
> +     */
> +    NamingEnumeration<ChangeLogEvent> find( ObjectClass objectClass,
> RevisionOrder order ) throws NamingException;
> +
> +
> +    /**
> +     * Finds all the ChangeLogEvents matched by the filter expression
> tree parameter.
> +     *
> +     * The following attributes can be used in the constrained LDAP
> filter expression
> +     * tree.  The expression must be normalized and can contain only ATA
> pairs with the
> +     * following set of attributes:
> +     *
> +     * <ul>
> +     *   <li>ndn: normalized distinguishedName syntax (defaults to
> matching a string)</li>
> +     *   <li>date: generalizedTime syntax</li>
> +     *   <li>revision: integer syntax</li>
> +     *   <li>attributeType: numeric OID</li>
> +     *   <li>objectClass: numeric OID</li>
> +     *   <li>changeType: new changeType syntax</li>
> +     *   <li>principal: normalized distinguishedName syntax (defaults to
> matching a string)</li>
> +     * </ul>
> +     *
> +     * The following are the only kinds of AVA node types allowed:
> +     *
> +     * <ul>
> +     *   <li>equality (=) </li>
> +     *   <li>greaterThanEq (>=) </li>
> +     *   <li>lessThanEq (<=) </li>
> +     *   <li>scope (specialized) </li>
> +     * </ul>
> +     *
> +     * @param objectClass the objectClass definition for the entries to
> search changes for
> +     * @param order the order in which to return ChangeLogEvents (ordered
> by revision number)
> +     * @return the set of ChangeLogEvents on entries of a particular
> objectClass
> +     * @throws NamingException if there are failures accessing the store
> +     */
> +    NamingEnumeration<ChangeLogEvent> find( ExprNode filter,
> RevisionOrder order ) throws NamingException;
> +}
>
> Propchange:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogSearchEngine.java
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogService.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogService.java?rev=577181&view=auto
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogService.java
> (added)
> +++
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogService.java
> Wed Sep 19 00:19:21 2007
> @@ -0,0 +1,32 @@
> +/*
> + *   Licensed to the Apache Software Foundation (ASF) under one
> + *   or more contributor license agreements.  See the NOTICE file
> + *   distributed with this work for additional information
> + *   regarding copyright ownership.  The ASF licenses this file
> + *   to you under the Apache License, Version 2.0 (the
> + *   "License"); you may not use this file except in compliance
> + *   with the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + *   Unless required by applicable law or agreed to in writing,
> + *   software distributed under the License is distributed on an
> + *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + *   KIND, either express or implied.  See the License for the
> + *   specific language governing permissions and limitations
> + *   under the License.
> + *
> + */
> +package org.apache.directory.server.core.changelog;
> +
> +
> +/**
> + * TODO ChangeLogService.
> + *
> + * @author <a href="mailto:dev@directory.apache.org">Apache Directory
> Project</a>
> + * @version $Rev$, $Date$
> + */
> +public interface ChangeLogService
> +{
> +
> +}
>
> Propchange:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogService.java
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogStore.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogStore.java?rev=577181&view=auto
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogStore.java
> (added)
> +++
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogStore.java
> Wed Sep 19 00:19:21 2007
> @@ -0,0 +1,55 @@
> +/*
> + *   Licensed to the Apache Software Foundation (ASF) under one
> + *   or more contributor license agreements.  See the NOTICE file
> + *   distributed with this work for additional information
> + *   regarding copyright ownership.  The ASF licenses this file
> + *   to you under the Apache License, Version 2.0 (the
> + *   "License"); you may not use this file except in compliance
> + *   with the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + *   Unless required by applicable law or agreed to in writing,
> + *   software distributed under the License is distributed on an
> + *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + *   KIND, either express or implied.  See the License for the
> + *   specific language governing permissions and limitations
> + *   under the License.
> + *
> + */
> +package org.apache.directory.server.core.changelog;
> +
> +import javax.naming.NamingException;
> +
> +import org.apache.directory.server.core.authn.LdapPrincipal;
> +import org.apache.directory.shared.ldap.ldif.Entry;
> +
> +
> +/**
> + * A store for change events on the directory which exposes methods for
> + * managing, querying and in general performing legal operations on the
> log.
> + *
> + * @author <a href="mailto:dev@directory.apache.org">Apache Directory
> Project</a>
> + * @version $Rev$, $Date$
> + */
> +public interface ChangeLogStore
> +{
> +    /**
> +     * Get's the current revision of the server (a.k.a. the HEAD
> revision).
> +     *
> +     * @return the current revision of the server
> +     */
> +    long getCurrentRevision();
> +
> +    /**
> +     * Records a change as a forward LDIF, a reverse change to revert the
> change and
> +     * the authorized principal triggering the revertable change event.
> +     *
> +     * @param principal the authorized LDAP principal triggering the
> change
> +     * @param forward LDIF of the change going to the next state
> +     * @param reverse LDIF (anti-operation): the change required to
> revert this change
> +     * @return the commit id or revision representing the change within
> the log
> +     * @throws NamingException
> +     */
> +    long log( LdapPrincipal principal, Entry forward, Entry reverse )
> throws NamingException;
> +}
>
> Propchange:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogStore.java
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/RevisionOrder.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/RevisionOrder.java?rev=577181&view=auto
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/RevisionOrder.java
> (added)
> +++
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/RevisionOrder.java
> Wed Sep 19 00:19:21 2007
> @@ -0,0 +1,52 @@
> +/*
> + *   Licensed to the Apache Software Foundation (ASF) under one
> + *   or more contributor license agreements.  See the NOTICE file
> + *   distributed with this work for additional information
> + *   regarding copyright ownership.  The ASF licenses this file
> + *   to you under the Apache License, Version 2.0 (the
> + *   "License"); you may not use this file except in compliance
> + *   with the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + *   Unless required by applicable law or agreed to in writing,
> + *   software distributed under the License is distributed on an
> + *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + *   KIND, either express or implied.  See the License for the
> + *   specific language governing permissions and limitations
> + *   under the License.
> + *
> + */
> +package org.apache.directory.server.core.changelog;
> +
> +
> +/**
> + * The order, based on revision numbers, in which to return log changes
> or
> + * tags.
> + *
> + * @author <a href="mailto:dev@directory.apache.org">Apache Directory
> Project</a>
> + * @version $Rev$, $Date$
> + */
> +public enum RevisionOrder
> +{
> +    AscendingOrder( true ),
> +    DescendingOrder( false );
> +
> +
> +    private final boolean ascending;
> +
> +
> +    private RevisionOrder( boolean ascending )
> +    {
> +        this.ascending = ascending;
> +    }
> +
> +
> +    /**
> +     * @return the ascending
> +     */
> +    public boolean isAscending()
> +    {
> +        return ascending;
> +    }
> +}
>
> Propchange:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/RevisionOrder.java
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/Scope.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/Scope.java?rev=577181&view=auto
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/Scope.java
> (added)
> +++
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/Scope.java
> Wed Sep 19 00:19:21 2007
> @@ -0,0 +1,55 @@
> +/*
> + *   Licensed to the Apache Software Foundation (ASF) under one
> + *   or more contributor license agreements.  See the NOTICE file
> + *   distributed with this work for additional information
> + *   regarding copyright ownership.  The ASF licenses this file
> + *   to you under the Apache License, Version 2.0 (the
> + *   "License"); you may not use this file except in compliance
> + *   with the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + *   Unless required by applicable law or agreed to in writing,
> + *   software distributed under the License is distributed on an
> + *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + *   KIND, either express or implied.  See the License for the
> + *   specific language governing permissions and limitations
> + *   under the License.
> + *
> + */
> +package org.apache.directory.server.core.changelog;
> +
> +
> +import javax.naming.directory.SearchControls;
> +
> +
> +/**
> + * TODO Scope.
> + *
> + * @author <a href="mailto:dev@directory.apache.org">Apache Directory
> Project</a>
> + * @version $Rev$, $Date$
> + */
> +public enum Scope
> +{
> +    Subtree( SearchControls.SUBTREE_SCOPE ),
> +    OneLevel( SearchControls.ONELEVEL_SCOPE ),
> +    Object( SearchControls.OBJECT_SCOPE );
> +
> +
> +    private final int scope;
> +
> +
> +    private Scope( int scope )
> +    {
> +        this.scope = scope;
> +    }
> +
> +
> +    /**
> +     * @return the scope
> +     */
> +    public int getScope()
> +    {
> +        return scope;
> +    }
> +}
>
> Propchange:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/Scope.java
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/SearchableChangeLogStore.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/SearchableChangeLogStore.java?rev=577181&view=auto
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/SearchableChangeLogStore.java
> (added)
> +++
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/SearchableChangeLogStore.java
> Wed Sep 19 00:19:21 2007
> @@ -0,0 +1,37 @@
> +/*
> + *   Licensed to the Apache Software Foundation (ASF) under one
> + *   or more contributor license agreements.  See the NOTICE file
> + *   distributed with this work for additional information
> + *   regarding copyright ownership.  The ASF licenses this file
> + *   to you under the Apache License, Version 2.0 (the
> + *   "License"); you may not use this file except in compliance
> + *   with the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + *   Unless required by applicable law or agreed to in writing,
> + *   software distributed under the License is distributed on an
> + *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + *   KIND, either express or implied.  See the License for the
> + *   specific language governing permissions and limitations
> + *   under the License.
> + *
> + */
> +package org.apache.directory.server.core.changelog;
> +
> +
> +/**
> + * TODO SearchableChangeLogStore.
> + *
> + * @author <a href="mailto:dev@directory.apache.org">Apache Directory
> Project</a>
> + * @version $Rev$, $Date$
> + */
> +public interface SearchableChangeLogStore extends ChangeLogStore
> +{
> +    /**
> +     * Get's the search engine for this SearchableChangeLogStore.
> +     *
> +     * @return the search engine for this SearchableChangeLogStore
> +     */
> +    ChangeLogSearchEngine getChangeLogSearchEngine();
> +}
>
> Propchange:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/SearchableChangeLogStore.java
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/Tag.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/Tag.java?rev=577181&view=auto
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/Tag.java
> (added)
> +++
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/Tag.java
> Wed Sep 19 00:19:21 2007
> @@ -0,0 +1,63 @@
> +/*
> + *   Licensed to the Apache Software Foundation (ASF) under one
> + *   or more contributor license agreements.  See the NOTICE file
> + *   distributed with this work for additional information
> + *   regarding copyright ownership.  The ASF licenses this file
> + *   to you under the Apache License, Version 2.0 (the
> + *   "License"); you may not use this file except in compliance
> + *   with the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + *   Unless required by applicable law or agreed to in writing,
> + *   software distributed under the License is distributed on an
> + *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + *   KIND, either express or implied.  See the License for the
> + *   specific language governing permissions and limitations
> + *   under the License.
> + *
> + */
> +package org.apache.directory.server.core.changelog;
> +
> +
> +/**
> + * A tag on a revision representing a snapshot of the directory server's
> + * state.
> + *
> + * @author <a href="mailto:dev@directory.apache.org">Apache Directory
> Project</a>
> + * @version $Rev$, $Date$
> + */
> +public class Tag
> +{
> +    /*
> +     * TODO should we have date in which tag was taken
> +     * TODO should we have the date of the revision
> +     */
> +    private final long revision;
> +    private final String description;
> +
> +
> +    public Tag( long revision, String description )
> +    {
> +        this.revision = revision;
> +        this.description = description;
> +    }
> +
> +
> +    /**
> +     * @return the revision
> +     */
> +    public long getRevision()
> +    {
> +        return revision;
> +    }
> +
> +
> +    /**
> +     * @return the description
> +     */
> +    public String getDescription()
> +    {
> +        return description;
> +    }
> +}
>
> Propchange:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/Tag.java
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TagSearchEngine.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TagSearchEngine.java?rev=577181&view=auto
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TagSearchEngine.java
> (added)
> +++
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TagSearchEngine.java
> Wed Sep 19 00:19:21 2007
> @@ -0,0 +1,129 @@
> +/*
> + *   Licensed to the Apache Software Foundation (ASF) under one
> + *   or more contributor license agreements.  See the NOTICE file
> + *   distributed with this work for additional information
> + *   regarding copyright ownership.  The ASF licenses this file
> + *   to you under the Apache License, Version 2.0 (the
> + *   "License"); you may not use this file except in compliance
> + *   with the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + *   Unless required by applicable law or agreed to in writing,
> + *   software distributed under the License is distributed on an
> + *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + *   KIND, either express or implied.  See the License for the
> + *   specific language governing permissions and limitations
> + *   under the License.
> + *
> + */
> +package org.apache.directory.server.core.changelog;
> +
> +
> +import javax.naming.NamingEnumeration;
> +import javax.naming.NamingException;
> +
> +
> +/**
> + * An optional search interface supported by
> TaggableChangeLogStores.  This
> + * interface enables the:
> + *
> + * <ul>
> + *   <li>lookup of tags by revision</li>
> + *   <li>finding all tags</li>
> + *   <li>finding tags before or after a revision</li>
> + *   <li>finding tags in some revision range</li>
> + * </ul>
> + *
> + * While investigating these interface methods keep in mind that only one
> + * tag can exist on a revision.  Unlike subversion which allows multiple
> + * tags on a revision we only allow at most one: more than one is
> pointless.
> + *
> + * Date wise searches for tags are not present within this interface
> since
> + * they should be used in conjunction with the ChangeLogSearchEngine
> which
> + * is by default supported by TaggableSearchableChangeLogStores.  The
> + * ChangeLogSearchEngine can find revisions based on time descriptors and
> + * returned revisions can be checked for the presence of tags using this
> + * interface.  The whole point to enabling both search engines in a
> single
> + * interfaces is because if you can search for tags you should be able to
> + * search for revisions: however the converse may not be the case.
> + *
> + * @author <a href="mailto:dev@directory.apache.org">Apache Directory
> Project</a>
> + * @version $Rev$, $Date$
> + */
> +public interface TagSearchEngine
> +{
> +
> +    //
> -----------------------------------------------------------------------
> +    // Tag Lookup Operations
> +    //
> -----------------------------------------------------------------------
> +
> +
> +    /**
> +     * Gets the tag for a specific snapshot if that snapshot exists.
> +     *
> +     * @param revision the revision number to use to check for a snapshot
> +     * @return the snapshot at the revision if one exists, otherwise null
> +     * @throws NamingException if there is a problem accessing the store
> +     */
> +    Tag lookup( long revision ) throws NamingException;
> +
> +    /**
> +     * Checks to see if a snapshot exists for a specific revision.
> +     *
> +     * @param revision the revision number to use to check for a snapshot
> +     * @return true if a snapshot exists at the revision, false otherwise
> +     * @throws NamingException if there is a problem accessing the store
> +     */
> +    boolean has( long revision ) throws NamingException;
> +
> +
> +    //
> -----------------------------------------------------------------------
> +    // Tag Search Operations
> +    //
> -----------------------------------------------------------------------
> +
> +
> +    /**
> +     * Finds all the snapshot tags taken since revision 0 until the
> current
> +     * revision.
> +     *
> +     * @param order the revision order in which to return snapshot tags
> +     * @return an enumeration over the tags of all snapshots taken since
> revision 0
> +     * @throws NamingException if there is a problem accessing the store
> +     */
> +    NamingEnumeration<Tag> find( RevisionOrder order ) throws
> NamingException;
> +
> +    /**
> +     * Finds all the snapshot tags taken before a specific revision.  If
> a tag
> +     * exists at the revision parameter it will be returned as well.
> +     *
> +     * @param revision the revision number to get snapshots before
> +     * @param order the revision order in which to return snapshot tags
> +     * @return an enumeration over the tags of all snapshots taken before
> a revision inclusive
> +     * @throws NamingException if there is a problem accessing the store
> +     */
> +    NamingEnumeration<Tag> findBefore( long revision, RevisionOrder order
> ) throws NamingException;
> +
> +    /**
> +     * Finds all the snapshot tags taken after a specific revision.  If a
> tag
> +     * exists at the revision parameter it will be returned as well.
> +     *
> +     * @param revision the revision number to get snapshots after
> +     * @param order the revision order in which to return snapshot tags
> +     * @return an enumeration over the tags of all snapshots taken after
> a revision inclusive
> +     * @throws NamingException if there is a problem accessing the store
> +     */
> +    NamingEnumeration<Tag> findAfter( long revision, RevisionOrder order
> ) throws NamingException;
> +
> +    /**
> +     * Enumerates over the tags of all snapshots taken between a specific
> revision
> +     * range inclusive.  The first revision parameter should be less than
> or equal
> +     * to the second revision parameter.
> +     *
> +     * @param order the revision order in which to return snapshot tags
> +     * @return enumeration over all the snapshots taken in a revision
> range inclusive
> +     * @throws NamingException if there is a problem accessing the store
> +     */
> +    NamingEnumeration<Tag> find( long startRevision, long endRevision,
> RevisionOrder order )
> +        throws NamingException;
> +}
>
> Propchange:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TagSearchEngine.java
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TaggableChangeLogStore.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TaggableChangeLogStore.java?rev=577181&view=auto
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TaggableChangeLogStore.java
> (added)
> +++
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TaggableChangeLogStore.java
> Wed Sep 19 00:19:21 2007
> @@ -0,0 +1,50 @@
> +/*
> + *   Licensed to the Apache Software Foundation (ASF) under one
> + *   or more contributor license agreements.  See the NOTICE file
> + *   distributed with this work for additional information
> + *   regarding copyright ownership.  The ASF licenses this file
> + *   to you under the Apache License, Version 2.0 (the
> + *   "License"); you may not use this file except in compliance
> + *   with the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + *   Unless required by applicable law or agreed to in writing,
> + *   software distributed under the License is distributed on an
> + *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + *   KIND, either express or implied.  See the License for the
> + *   specific language governing permissions and limitations
> + *   under the License.
> + *
> + */
> +package org.apache.directory.server.core.changelog;
> +
> +import javax.naming.NamingException;
> +
> +
> +/**
> + * A ChangeLogStore which allows tagging for tracking server state
> snapshots.
> + * At most one tag per revision can be created.  There is no point to
> creating
> + * more than one tag on a revision in our case for snapshotting server
> state.
> + *
> + * @author <a href="mailto:dev@directory.apache.org">Apache Directory
> Project</a>
> + * @version $Rev$, $Date$
> + */
> +public interface TaggableChangeLogStore extends ChangeLogStore
> +{
> +    /**
> +     * Creates a tag for a snapshot of the server in a specific state at
> a revision.
> +     *
> +     * @param the revision to tag the snapshot
> +     * @throws NamingException
> +     */
> +    Tag tag( long revision ) throws NamingException;
> +
> +    /**
> +     * Creates a snapshot of the server at the current revision.
> +     *
> +     * @return the revision at which the tag is created
> +     * @throws NamingException
> +     */
> +    Tag tag() throws NamingException;
> +}
>
> Propchange:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TaggableChangeLogStore.java
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TaggableSearchableChangeLogStore.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TaggableSearchableChangeLogStore.java?rev=577181&view=auto
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TaggableSearchableChangeLogStore.java
> (added)
> +++
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TaggableSearchableChangeLogStore.java
> Wed Sep 19 00:19:21 2007
> @@ -0,0 +1,37 @@
> +/*
> + *   Licensed to the Apache Software Foundation (ASF) under one
> + *   or more contributor license agreements.  See the NOTICE file
> + *   distributed with this work for additional information
> + *   regarding copyright ownership.  The ASF licenses this file
> + *   to you under the Apache License, Version 2.0 (the
> + *   "License"); you may not use this file except in compliance
> + *   with the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + *   Unless required by applicable law or agreed to in writing,
> + *   software distributed under the License is distributed on an
> + *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + *   KIND, either express or implied.  See the License for the
> + *   specific language governing permissions and limitations
> + *   under the License.
> + *
> + */
> +package org.apache.directory.server.core.changelog;
> +
> +
> +/**
> + * TODO TaggableSearchableChangeLogStore.
> + *
> + * @author <a href="mailto:dev@directory.apache.org">Apache Directory
> Project</a>
> + * @version $Rev$, $Date$
> + */
> +public interface TaggableSearchableChangeLogStore extends
> TaggableChangeLogStore, SearchableChangeLogStore
> +{
> +    /**
> +     * Get's the tag search engine for this
> TaggableSearchableChangeLogStore.
> +     *
> +     * @return the snapshot query engine for this store.
> +     */
> +    TagSearchEngine getTagSearchEngine();
> +}
>
> Propchange:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/TaggableSearchableChangeLogStore.java
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/package.html
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/package.html?rev=577181&view=auto
>
> ==============================================================================
> ---
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/package.html
> (added)
> +++
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/package.html
> Wed Sep 19 00:19:21 2007
> @@ -0,0 +1,28 @@
> +
> +
> +<h1>Ideas</h1>
> +
> +Use AdminModel to control what goes into the changelog ?  Or use admin
> model to identify
> +scopes/concerns which are put into different channels in the
> changelog?  Cool idea perhaps,
> +perhaps not.  To some degree the DN does the scope thingy for us.  There
> really is no point
> +to having an additional scope parameter.
> +
> +Perhaps we can also inject a new revisions (multi-valued) operational
> attribute into
> +entries to track the revisions of changes in the changeLog to that
> entry.  This can
> +be used to ask the server for a log of changes that have been performed
> on a specific
> +entry.  Whoa that's really hot for auditing!
> +
> +We could try to do the same thing (meaning having a tags operational
> attribute) with revisions.
> +However this is pointless since the tag revision would already be in the
> revisions attribute.  Also
> +a tag would select entries dynamically: all entries with revisions below
> the tag revision would be
> +selected in the tag.  This leads to a neat idea: you can easily
> regenerate not only the revision
> +history of an entry, you can do it for an entire subtree, and furthermore
> you might even be able
> +to conduct search operations based on a tag and the state of the server
> in the past.  This would be
> +pretty wild.
> +
> +Another neat thing that could be done is to request an attribute by
> revision using the protocol
> +based tagging mechanism in LDAP.  For example we have language based tags
> like cn;lang-en so why
> +not have version based tags like cn;revision-23.  When requested in this
> mannar the server can
> +reconstruct the state of the attribute at a specific revision and return
> it to the user.  This is
> +an incredible capability when storing the configurations of systems in
> LDAP.  Being able to rollback
> +to a previous configuration or just inquire about a previous state is a
> powerful feature to have.
>
> Propchange:
> directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/changelog/package.html
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Modified:
> directory/apacheds/trunk/server-tools/src/main/java/org/apache/directory/server/tools/commands/importcmd/ImportCommandExecutor.java
> URL:
> http://svn.apache.org/viewvc/directory/apacheds/trunk/server-tools/src/main/java/org/apache/directory/server/tools/commands/importcmd/ImportCommandExecutor.java?rev=577181&r1=577180&r2=577181&view=diff
>
> ==============================================================================
> ---
> directory/apacheds/trunk/server-tools/src/main/java/org/apache/directory/server/tools/commands/importcmd/ImportCommandExecutor.java
> (original)
> +++
> directory/apacheds/trunk/server-tools/src/main/java/org/apache/directory/server/tools/commands/importcmd/ImportCommandExecutor.java
> Wed Sep 19 00:19:21 2007
> @@ -67,6 +67,7 @@
> import org.apache.directory.shared.ldap.codec.modify.ModifyRequest;
> import org.apache.directory.shared.ldap.codec.modifyDn.ModifyDNRequest;
> import org.apache.directory.shared.ldap.codec.unbind.UnBindRequest;
> +import org.apache.directory.shared.ldap.ldif.ChangeType;
> import org.apache.directory.shared.ldap.ldif.Entry;
> import org.apache.directory.shared.ldap.ldif.LdifReader;
> import org.apache.directory.shared.ldap.message.ModificationItemImpl;
> @@ -516,20 +517,20 @@
>      private int changeEntry( Entry entry, int messageId ) throws
> IOException, DecoderException, InvalidNameException,
>          NamingException, EncoderException
>      {
> -        switch ( entry.getChangeType() )
> +        switch ( entry.getChangeType().getChangeType() )
>          {
> -            case Entry.ADD:
> +            case ChangeType.ADD_ORDINAL:
>                  // No difference with the injection of new entries
>                  return addEntry( entry, messageId );
>
> -            case Entry.DELETE:
> +            case ChangeType.DELETE_ORDINAL:
>                  return deleteEntry( entry, messageId );
>
> -            case Entry.MODIFY:
> +            case ChangeType.MODIFY_ORDINAL:
>                  return changeModifyEntry( entry, messageId );
>
> -            case Entry.MODDN:
> -            case Entry.MODRDN:
> +            case ChangeType.MODDN_ORDINAL:
> +            case ChangeType.MODRDN_ORDINAL:
>                  return changeModRDNEntry( entry, messageId );
>
>              default:
>
>
>


-- 
Ersin Er
http://www.ersin-er.name