Package org.apache.directory.studio.apacheds.configuration.v2.jobs

Source Code of org.apache.directory.studio.apacheds.configuration.v2.jobs.PartitionsDiffComputer

/*
*  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.studio.apacheds.configuration.v2.jobs;


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.directory.api.ldap.model.entry.Attribute;
import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
import org.apache.directory.api.ldap.model.entry.DefaultModification;
import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.entry.Modification;
import org.apache.directory.api.ldap.model.entry.ModificationOperation;
import org.apache.directory.api.ldap.model.entry.Value;
import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
import org.apache.directory.api.ldap.model.filter.FilterParser;
import org.apache.directory.api.ldap.model.ldif.ChangeType;
import org.apache.directory.api.ldap.model.ldif.LdifEntry;
import org.apache.directory.api.ldap.model.message.AliasDerefMode;
import org.apache.directory.api.ldap.model.message.SearchScope;
import org.apache.directory.api.ldap.model.name.Dn;
import org.apache.directory.api.ldap.model.schema.AttributeType;
import org.apache.directory.api.ldap.model.schema.UsageEnum;
import org.apache.directory.server.core.api.entry.ClonedServerEntry;
import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
import org.apache.directory.server.core.api.partition.Partition;


public class PartitionsDiffComputer
{
    /** The original partition */
    private Partition originalPartition;

    /** The destination partition */
    private Partition destinationPartition;


    public PartitionsDiffComputer()
    {
    }


    public PartitionsDiffComputer( Partition originalPartition, Partition destinationPartition )
    {
        this.originalPartition = originalPartition;
        this.destinationPartition = destinationPartition;
    }


    public List<LdifEntry> computeModifications() throws Exception
    {
        // Using the original partition suffix as base
        // '*' for all user attributes, '+' for all operational attributes
        return computeModifications( originalPartition.getSuffixDn(), new String[]
            { "*", "+" } ); //$NON-NLS-1$ //$NON-NLS-2$
    }


    public List<LdifEntry> computeModifications( String[] attributeIds ) throws Exception
    {
        return computeModifications( originalPartition.getSuffixDn(), attributeIds );
    }


    public List<LdifEntry> computeModifications( Dn baseDn, String[] attributeIds ) throws Exception
    {
        // Checking partitions
        checkPartitions();

        return comparePartitions( baseDn, attributeIds );
    }


    /**
     * Checks the partitions.
     *
     * @throws PartitionsDiffException
     */
    private void checkPartitions() throws PartitionsDiffException
    {
        // Checking the original partition
        if ( originalPartition == null )
        {
            throw new PartitionsDiffException( "The original partition must not be 'null'." ); //$NON-NLS-1$
        }
        else
        {
            if ( !originalPartition.isInitialized() )
            {
                throw new PartitionsDiffException( "The original partition must be intialized." ); //$NON-NLS-1$
            }
            else if ( originalPartition.getSuffixDn() == null )
            {
                throw new PartitionsDiffException( "The original suffix is null." ); //$NON-NLS-1$
            }
        }

        // Checking the destination partition
        if ( destinationPartition == null )
        {
            throw new PartitionsDiffException( "The destination partition must not be 'null'." ); //$NON-NLS-1$
        }
        else
        {
            if ( !destinationPartition.isInitialized() )
            {
                throw new PartitionsDiffException( "The destination partition must be intialized." ); //$NON-NLS-1$
            }
            else if ( destinationPartition.getSuffixDn() == null )
            {
                throw new PartitionsDiffException( "The destination suffix is null." ); //$NON-NLS-1$
            }
        }
    }


    /**
     * Compare the two partitions.
     *
     * @param baseDn
     *      the base Dn
     * @param attributeIds
     *      the IDs of the attributes
     * @return
     *      a list containing LDIF entries with all modifications
     * @throws Exception
     */
    public List<LdifEntry> comparePartitions( Dn baseDn, String[] attributeIds ) throws PartitionsDiffException
    {
        // Creating the list containing all modifications
        List<LdifEntry> modifications = new ArrayList<LdifEntry>();

        try
        {
            // Looking up the original base entry
            Entry originalBaseEntry = originalPartition
                .lookup( new LookupOperationContext( null, baseDn, attributeIds ) );
            if ( originalBaseEntry == null )
            {
                throw new PartitionsDiffException( "Unable to find the base entry in the original partition." ); //$NON-NLS-1$
            }

            // Creating the list containing all the original entries to be processed
            // and adding it the original base entry
            List<Entry> originalEntries = new ArrayList<Entry>();
            originalEntries.add( originalBaseEntry );

            // Looping until all original entries are being processed
            while ( originalEntries.size() > 0 )
            {
                // Getting the first original entry from the list
                Entry originalEntry = originalEntries.remove( 0 );

                // Creating a modification entry to hold all modifications
                LdifEntry modificationEntry = new LdifEntry();
                modificationEntry.setDn( originalEntry.getDn() );

                // Looking for the equivalent entry in the destination partition
                Entry destinationEntry = destinationPartition.lookup( new LookupOperationContext( null, originalEntry
                    .getDn(), attributeIds ) );
                if ( destinationEntry != null )
                {
                    // Setting the changetype to delete
                    modificationEntry.setChangeType( ChangeType.Modify );

                    // Comparing both entries
                    compareEntries( originalEntry, destinationEntry, modificationEntry );
                }
                else
                {
                    // The original entry is no longer present in the destination partition

                    // Setting the changetype to delete
                    modificationEntry.setChangeType( ChangeType.Delete );
                }

                // Checking if modifications occurred on the original entry
                ChangeType modificationEntryChangeType = modificationEntry.getChangeType();
                if ( modificationEntryChangeType != ChangeType.None )
                {
                    if ( modificationEntryChangeType == ChangeType.Delete
                        || ( modificationEntryChangeType == ChangeType.Modify && modificationEntry
                            .getModifications().size() > 0 ) )
                    {
                        // Adding the modification entry to the list
                        modifications.add( modificationEntry );
                    }
                }

                // Creating a search operation context to get the children of the current entry
                SearchOperationContext soc = new SearchOperationContext( null, originalEntry.getDn(),
                    SearchScope.ONELEVEL,
                    FilterParser.parse( originalPartition.getSchemaManager(), "(objectClass=*)" ), attributeIds ); //$NON-NLS-1$
                soc.setAliasDerefMode( AliasDerefMode.DEREF_ALWAYS );

                // Looking for the children of the current entry
                EntryFilteringCursor cursor = originalPartition.search( soc );

                while ( cursor.next() )
                {
                    originalEntries.add( ( ( ClonedServerEntry ) cursor.get() ).getClonedEntry() );
                }
            }

            // Reversing the list to allow deletion of leafs first (otherwise we would be deleting
            // higher nodes with children first).
            // Order for modified entries does not matter.
            Collections.reverse( modifications );

            // Looking up the destination base entry
            Entry destinationBaseEntry = destinationPartition
                .lookup( new LookupOperationContext( null, baseDn, attributeIds ) );
            if ( destinationBaseEntry == null )
            {
                throw new PartitionsDiffException( "Unable to find the base entry in the destination partition." ); //$NON-NLS-1$
            }

            // Creating the list containing all the destination entries to be processed
            // and adding it the destination base entry
            List<Entry> destinationEntries = new ArrayList<Entry>();
            destinationEntries.add( originalBaseEntry );

            // Looping until all destination entries are being processed
            while ( destinationEntries.size() > 0 )
            {
                // Getting the first destination entry from the list
                Entry destinationEntry = destinationEntries.remove( 0 );

                // Looking for the equivalent entry in the destination partition
                Entry originalEntry = originalPartition.lookup( new LookupOperationContext( null, destinationEntry
                    .getDn(), attributeIds ) );
                // We're only looking for new entries, modified or removed
                // entries have already been computed
                if ( originalEntry == null )
                {
                    // Creating a modification entry to hold all modifications
                    LdifEntry modificationEntry = new LdifEntry();
                    modificationEntry.setDn( destinationEntry.getDn() );

                    // Setting the changetype to addition
                    modificationEntry.setChangeType( ChangeType.Add );

                    // Copying attributes
                    for ( Attribute attribute : destinationEntry )
                    {
                        modificationEntry.addAttribute( attribute );
                    }

                    // Adding the modification entry to the list
                    modifications.add( modificationEntry );
                }

                // Creating a search operation context to get the children of the current entry
                SearchOperationContext soc = new SearchOperationContext( null, destinationEntry.getDn(),
                    SearchScope.ONELEVEL,
                    FilterParser.parse( originalPartition.getSchemaManager(), "(objectClass=*)" ), attributeIds ); //$NON-NLS-1$
                soc.setAliasDerefMode( AliasDerefMode.DEREF_ALWAYS );

                // Looking for the children of the current entry
                EntryFilteringCursor cursor = destinationPartition.search( soc );

                while ( cursor.next() )
                {
                    destinationEntries.add( ( ( ClonedServerEntry ) cursor.get() ).getClonedEntry() );
                }
            }
        }
        catch ( Exception e )
        {
            // e.printStackTrace();
            throw new PartitionsDiffException( e );
        }

        return modifications;
    }


    /**
     * Compares the two given entries.
     *
     * @param originalEntry
     *      the original entry
     * @param destinationEntry
     *      the destination entry
     * @param modificationEntry
     *      the modification LDIF entry holding the modifications
     *      between both entries
     */
    private void compareEntries( Entry originalEntry, Entry destinationEntry, LdifEntry modificationEntry )
    {
        // Creating a list to store the already evaluated attribute type
        List<AttributeType> evaluatedATs = new ArrayList<AttributeType>();

        // Checking attributes of the original entry
        for ( Attribute originalAttribute : originalEntry )
        {
            AttributeType originalAttributeType = originalAttribute.getAttributeType();

            // We're only working on 'userApplications' attributes
            if ( originalAttributeType.getUsage() == UsageEnum.USER_APPLICATIONS )
            {
                Attribute destinationAttribute = destinationEntry.get( originalAttributeType );
                if ( destinationAttribute == null )
                {
                    // Creating a modification for the removed AT
                    Modification modification = new DefaultModification();
                    modification.setOperation( ModificationOperation.REMOVE_ATTRIBUTE );
                    modification.setAttribute( new DefaultAttribute( originalAttribute.getAttributeType() ) );

                    modificationEntry.addModification( modification );
                }
                else
                {
                    // Comparing both attributes
                    compareAttributes( originalAttribute, destinationAttribute, modificationEntry );
                }

                evaluatedATs.add( originalAttributeType );
            }
        }

        // Checking attributes of the destination entry
        for ( Attribute destinationAttribute : destinationEntry )
        {
            AttributeType destinationAttributeType = destinationAttribute.getAttributeType();

            // We're only working on 'userApplications' attributes
            if ( destinationAttributeType.getUsage() == UsageEnum.USER_APPLICATIONS )
            {
                // Checking if the current AT has already been evaluated
                if ( !evaluatedATs.contains( destinationAttributeType ) )
                {
                    // Creating a modification for the added AT
                    Modification modification = new DefaultModification();
                    modification.setOperation( ModificationOperation.ADD_ATTRIBUTE );
                    Attribute attribute = new DefaultAttribute( destinationAttributeType );
                    modification.setAttribute( attribute );

                    for ( Value<?> value : destinationAttribute )
                    {
                        try
                        {
                            attribute.add( value );
                        }
                        catch ( LdapInvalidAttributeValueException liave )
                        {
                            // TODO : handle the exception
                        }
                    }

                    modificationEntry.addModification( modification );
                }
            }
        }
    }


    /**
     * Compares the two given attributes.
     *
     * @param originalAttribute
     *      the original attribute
     * @param destinationAttribute
     *      the destination attribute
     * @param modificationEntry
     *      the modification LDIF entry holding the modifications
     *      between both attributes
     */
    private void compareAttributes( Attribute originalAttribute, Attribute destinationAttribute,
        LdifEntry modificationEntry )
    {
        // Creating a list to store the already evaluated values
        List<Value<?>> evaluatedValues = new ArrayList<Value<?>>();

        // Checking values of the original attribute
        for ( Value<?> originalValue : originalAttribute )
        {
            if ( !destinationAttribute.contains( originalValue ) )
            {
                // Creating a modification for the removed AT value
                Modification modification = new DefaultModification();
                modification.setOperation( ModificationOperation.REMOVE_ATTRIBUTE );
                Attribute attribute = new DefaultAttribute( originalAttribute.getAttributeType() );
                modification.setAttribute( attribute );

                try
                {
                    attribute.add( originalValue );
                }
                catch ( LdapInvalidAttributeValueException liave )
                {
                    // TODO : handle the exception
                }

                modificationEntry.addModification( modification );
            }

            evaluatedValues.add( originalValue );
        }

        // Checking values of the destination attribute
        for ( Value<?> destinationValue : destinationAttribute )
        {
            if ( !evaluatedValues.contains( destinationValue ) )
            {
                // Creating a modification for the added AT value
                Modification modification = new DefaultModification();
                modification.setOperation( ModificationOperation.ADD_ATTRIBUTE );
                Attribute attribute = new DefaultAttribute( originalAttribute.getAttributeType() );
                modification.setAttribute( attribute );

                try
                {
                    attribute.add( destinationValue );
                }
                catch ( LdapInvalidAttributeValueException liave )
                {
                    // TODO : handle the exception
                }

                modificationEntry.addModification( modification );
            }
        }
    }


    /**
     * Gets the original partition.
     *
     * @return
     *      the original partition
     */
    public Partition getOriginalPartition()
    {
        return originalPartition;
    }


    /**
     * Sets the original partition.
     *
     * @param originalPartition
     *      the original partition
     */
    public void setOriginalPartition( Partition originalPartition )
    {
        this.originalPartition = originalPartition;
    }


    /**
     * Gets the destination partition.
     *
     * @return
     *      the destination partition
     */
    public Partition getDestinationPartition()
    {
        return destinationPartition;
    }


    /**
     * Sets the destination partition.
     *
     * @param destinationPartition
     *      the destination partition
     */
    public void setDestinationPartition( Partition destinationPartition )
    {
        this.destinationPartition = destinationPartition;
    }
}
TOP

Related Classes of org.apache.directory.studio.apacheds.configuration.v2.jobs.PartitionsDiffComputer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.