Package org.apache.directory.studio.ldapbrowser.core.jobs

Source Code of org.apache.directory.studio.ldapbrowser.core.jobs.CopyEntriesJob

/*
*  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.ldapbrowser.core.jobs;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import javax.naming.NameAlreadyBoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control;
import javax.naming.ldap.ManageReferralControl;

import org.apache.directory.shared.ldap.constants.SchemaConstants;
import org.apache.directory.shared.ldap.name.AttributeTypeAndValue;
import org.apache.directory.shared.ldap.name.LdapDN;
import org.apache.directory.shared.ldap.name.Rdn;
import org.apache.directory.studio.connection.core.Connection;
import org.apache.directory.studio.connection.core.DnUtils;
import org.apache.directory.studio.connection.core.Connection.AliasDereferencingMethod;
import org.apache.directory.studio.connection.core.Connection.ReferralHandlingMethod;
import org.apache.directory.studio.connection.core.jobs.StudioProgressMonitor;
import org.apache.directory.studio.ldapbrowser.core.BrowserCoreMessages;
import org.apache.directory.studio.ldapbrowser.core.events.BulkModificationEvent;
import org.apache.directory.studio.ldapbrowser.core.events.EventRegistry;
import org.apache.directory.studio.ldapbrowser.core.jobs.EntryExistsCopyStrategyDialog.EntryExistsCopyStrategy;
import org.apache.directory.studio.ldapbrowser.core.model.IBrowserConnection;
import org.apache.directory.studio.ldapbrowser.core.model.IEntry;
import org.apache.directory.studio.ldapbrowser.core.model.ISearch;
import org.apache.directory.studio.ldapbrowser.core.model.ISearch.SearchScope;
import org.apache.directory.studio.ldapbrowser.core.utils.JNDIUtils;


/**
* Job to copy entries asynchronously.
*
* TODO: implement overwrite strategy
* TODO: implement remember selection
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev$, $Date$
*/
public class CopyEntriesJob extends AbstractNotificationJob
{

    /** The parent entry. */
    private IEntry parent;

    /** The entries to copy. */
    private IEntry[] entriesToCopy;

    /** The copy scope */
    private SearchScope scope;

    /** The dialog to ask for the strategy */
    private EntryExistsCopyStrategyDialog dialog;


    /**
     * Creates a new instance of CopyEntriesJob.
     *
     * @param parent the parent entry
     * @param entriesToCopy the entries to copy
     * @param scope the copy scope
     * @param dialog the dialog
     */
    public CopyEntriesJob( final IEntry parent, final IEntry[] entriesToCopy, SearchScope scope,
        EntryExistsCopyStrategyDialog dialog )
    {
        this.parent = parent;
        this.entriesToCopy = entriesToCopy;
        this.scope = scope;
        this.dialog = dialog;
        setName( entriesToCopy.length == 1 ? BrowserCoreMessages.jobs__copy_entries_name_1
            : BrowserCoreMessages.jobs__copy_entries_name_n );
    }


    /**
     * @see org.apache.directory.studio.ldapbrowser.core.jobs.AbstractEclipseJob#getConnections()
     */
    protected Connection[] getConnections()
    {
        return new Connection[]
            { parent.getBrowserConnection().getConnection() };
    }


    /**
     * @see org.apache.directory.studio.ldapbrowser.core.jobs.AbstractEclipseJob#getLockedObjects()
     */
    protected Object[] getLockedObjects()
    {
        List<IEntry> l = new ArrayList<IEntry>();
        l.add( parent );
        l.addAll( Arrays.asList( entriesToCopy ) );
        return l.toArray();
    }


    /**
     * @see org.apache.directory.studio.ldapbrowser.core.jobs.AbstractNotificationJob#executeNotificationJob(org.apache.directory.studio.connection.core.jobs.StudioProgressMonitor)
     */
    protected void executeNotificationJob( StudioProgressMonitor monitor )
    {
        monitor.beginTask( entriesToCopy.length == 1 ? BrowserCoreMessages.bind(
            BrowserCoreMessages.jobs__copy_entries_task_1, new String[]
                { entriesToCopy[0].getDn().getUpName(), parent.getDn().getUpName() } ) : BrowserCoreMessages.bind(
            BrowserCoreMessages.jobs__copy_entries_task_n, new String[]
                { Integer.toString( entriesToCopy.length ), parent.getDn().getUpName() } ), 2 + entriesToCopy.length );

        monitor.reportProgress( " " ); //$NON-NLS-1$
        monitor.worked( 1 );

        if ( scope == SearchScope.OBJECT || scope == SearchScope.ONELEVEL || scope == SearchScope.SUBTREE )
        {
            StudioProgressMonitor dummyMonitor = new StudioProgressMonitor( monitor );
            int copyScope = scope == SearchScope.SUBTREE ? SearchControls.SUBTREE_SCOPE
                : scope == SearchScope.ONELEVEL ? SearchControls.ONELEVEL_SCOPE : SearchControls.OBJECT_SCOPE;

            int num = 0;
            for ( int i = 0; !monitor.isCanceled() && i < entriesToCopy.length; i++ )
            {
                IEntry entryToCopy = entriesToCopy[i];

                if ( scope == SearchScope.OBJECT
                    || !parent.getDn().getNormName().endsWith( entryToCopy.getDn().getNormName() ) )
                {
                    dummyMonitor.reset();
                    num = copyEntry( entryToCopy, parent, null, copyScope, num, dialog, dummyMonitor, monitor );
                }
                else
                {
                    monitor.reportError( BrowserCoreMessages.jobs__copy_entries_source_and_target_are_equal );
                }
            }

            parent.setChildrenInitialized( false );
            parent.setHasChildrenHint( true );
        }
    }


    /**
     * @see org.apache.directory.studio.ldapbrowser.core.jobs.AbstractNotificationJob#runNotification()
     */
    protected void runNotification()
    {
        // don't fire an EntryCreatedEvent for each created entry
        // that would cause massive UI updates
        // instead we fire a BulkModificationEvent
        EventRegistry.fireEntryUpdated( new BulkModificationEvent( parent.getBrowserConnection() ), this );
    }


    /**
     * @see org.apache.directory.studio.ldapbrowser.core.jobs.AbstractEclipseJob#getErrorMessage()
     */
    protected String getErrorMessage()
    {
        return entriesToCopy.length == 1 ? BrowserCoreMessages.jobs__copy_entries_error_1
            : BrowserCoreMessages.jobs__copy_entries_error_n;
    }


    /**
     * Copy entry. If scope is SearchControls.SUBTREE_SCOPE the entry is copied
     * recursively.
     *
     * @param browserConnection the browser connection
     * @param dnToCopy the DN to copy
     * @param parentDn the parent DN
     * @param newRdn the new RDN, if null the RDN of dnToCopy is used
     * @param scope the copy scope
     * @param numberOfCopiedEntries the number of copied entries
     * @param dialog the dialog to ask for the copy strategy, if null the user won't be
     *        asked instead the NameAlreadyBoundException it reported to the monitor
     * @param dummyMonitor the dummy monitor, used for I/O that causes exceptions that
     *        should be handled
     * @param monitor the real monitor
     *
     * @return the number of copied entries
     */
    static int copyEntry( IEntry entryToCopy, IEntry parent, Rdn newRdn, int scope, int numberOfCopiedEntries,
        EntryExistsCopyStrategyDialog dialog, StudioProgressMonitor dummyMonitor, StudioProgressMonitor monitor )
    {
        SearchControls searchControls = new SearchControls();
        searchControls.setCountLimit( 1 );
        searchControls.setReturningAttributes( new String[]
            { SchemaConstants.ALL_USER_ATTRIBUTES, SchemaConstants.REF_AT } );
        searchControls.setSearchScope( SearchControls.OBJECT_SCOPE );

        // ManageDsaIT control
        Control[] controls = null;
        if ( entryToCopy.isReferral() )
        {
            controls = new Control[]
                { new ManageReferralControl( false ) };
        }

        NamingEnumeration<SearchResult> result = entryToCopy.getBrowserConnection().getConnection()
            .getJNDIConnectionWrapper().search( entryToCopy.getDn().getUpName(), ISearch.FILTER_TRUE, searchControls,
                AliasDereferencingMethod.NEVER, ReferralHandlingMethod.IGNORE, controls, monitor, null );

        // In case the parent is the RootDSE: use the parent DN of the old entry
        LdapDN parentDn = parent.getDn();
        if ( parentDn.isEmpty() )
        {
            parentDn = DnUtils.getParent( entryToCopy.getDn() );
        }
        numberOfCopiedEntries = copyEntryRecursive( entryToCopy.getBrowserConnection(), result, parent
            .getBrowserConnection(), parentDn, newRdn, scope, numberOfCopiedEntries, dialog, dummyMonitor, monitor );

        return numberOfCopiedEntries;
    }


    /**
     * Copy the entries. If scope is SearchControls.SUBTREE_SCOPE the entries are copied
     * recursively.
     *
     * @param sourceBrowserConnection the source browser connection
     * @param entries the source entries to copy
     * @param targetBrowserConnection the target browser connection
     * @param parentDn the target parent DN
     * @param newRdn the new RDN, if null the original RDN of each entry is used
     * @param scope the copy scope
     * @param numberOfCopiedEntries the number of copied entries
     * @param dialog the dialog to ask for the copy strategy, if null the user won't be
     *        asked instead the NameAlreadyBoundException it reported to the monitor
     * @param dummyMonitor the dummy monitor, used for I/O that causes exceptions that
     *        should be handled
     * @param monitor the real monitor
     *
     * @return the number of copied entries
     */
    static int copyEntryRecursive( IBrowserConnection sourceBrowserConnection, NamingEnumeration<SearchResult> entries,
        IBrowserConnection targetBrowserConnection, LdapDN parentDn, Rdn forceNewRdn, int scope,
        int numberOfCopiedEntries, EntryExistsCopyStrategyDialog dialog, StudioProgressMonitor dummyMonitor,
        StudioProgressMonitor monitor )
    {
        try
        {
            while ( !monitor.isCanceled() && entries.hasMore() )
            {
                // get next entry to copy
                SearchResult sr = entries.next();
                LdapDN oldLdapDn = JNDIUtils.getDn( sr );
                Rdn oldRdn = oldLdapDn.getRdn();

                // reuse attributes of the entry to copy
                Attributes newAttributes = sr.getAttributes();

                // compose new DN
                Rdn newRdn = oldLdapDn.getRdn();
                if ( forceNewRdn != null )
                {
                    newRdn = forceNewRdn;
                }
                LdapDN newLdapDn = DnUtils.composeDn( newRdn, parentDn );

                // apply new RDN to the attributes
                applyNewRdn( newAttributes, oldRdn, newRdn );

                // ManageDsaIT control
                Control[] controls = null;
                if ( newAttributes.get( SchemaConstants.OBJECT_CLASS_AT ) != null
                    && newAttributes.get( SchemaConstants.OBJECT_CLASS_AT ).contains( SchemaConstants.REFERRAL_OC ) )
                {
                    controls = new Control[]
                        { new ManageReferralControl( false ) };
                }

                // create entry
                targetBrowserConnection.getConnection().getJNDIConnectionWrapper().createEntry( newLdapDn.getUpName(),
                    newAttributes, controls, dummyMonitor, null );

                while ( dummyMonitor.errorsReported() )
                {
                    if ( dialog != null && dummyMonitor.getException() instanceof NameAlreadyBoundException )
                    {
                        // open dialog
                        dialog.setExistingEntry( targetBrowserConnection, newLdapDn );
                        dialog.open();
                        EntryExistsCopyStrategy strategy = dialog.getStrategy();
                        //                        boolean rememberSelection = dialog.isRememberSelection();
                        if ( strategy != null )
                        {
                            dummyMonitor.reset();

                            switch ( strategy )
                            {
                                case BREAK:
                                    monitor.setCanceled( true );
                                    break;

                                case IGNORE_AND_CONTINUE:
                                    break;

                                case OVERWRITE_AND_CONTINUE:
                                    // create modification items
                                    List<ModificationItem> mis = new ArrayList<ModificationItem>();
                                    NamingEnumeration<? extends Attribute> all = newAttributes.getAll();
                                    while ( all.hasMore() )
                                    {
                                        Attribute attribute = all.next();
                                        ModificationItem mi = new ModificationItem( DirContext.REPLACE_ATTRIBUTE,
                                            attribute );
                                        mis.add( mi );
                                    }

                                    // modify entry
                                    targetBrowserConnection.getConnection().getJNDIConnectionWrapper().modifyEntry(
                                        newLdapDn.getUpName(), mis.toArray( new ModificationItem[mis.size()] ), null,
                                        dummyMonitor, null );

                                    // force reloading of attributes
                                    IEntry newEntry = targetBrowserConnection.getEntryFromCache( newLdapDn );
                                    if ( newEntry != null )
                                    {
                                        newEntry.setAttributesInitialized( false );
                                    }

                                    break;

                                case RENAME_AND_CONTINUE:
                                    Rdn renamedRdn = dialog.getRdn();

                                    // apply renamed RDN to the attributes
                                    applyNewRdn( newAttributes, newRdn, renamedRdn );

                                    // compose new DN
                                    newLdapDn = DnUtils.composeDn( renamedRdn, parentDn );

                                    // create entry
                                    targetBrowserConnection.getConnection().getJNDIConnectionWrapper().createEntry(
                                        newLdapDn.getUpName(), newAttributes, null, dummyMonitor, null );

                                    break;
                            }
                        }
                        else
                        {
                            monitor.reportError( dummyMonitor.getException() );
                            break;
                        }
                    }
                    else
                    {
                        monitor.reportError( dummyMonitor.getException() );
                        break;
                    }
                }

                if ( !monitor.isCanceled() && !monitor.errorsReported() )
                {
                    numberOfCopiedEntries++;

                    monitor.reportProgress( BrowserCoreMessages.bind( BrowserCoreMessages.model__copied_n_entries,
                        new String[]
                            { "" + numberOfCopiedEntries } ) ); //$NON-NLS-1$

                    // copy recursively
                    if ( scope == SearchControls.ONELEVEL_SCOPE || scope == SearchControls.SUBTREE_SCOPE )
                    {
                        SearchControls searchControls = new SearchControls();
                        searchControls.setCountLimit( 0 );
                        searchControls.setReturningAttributes( new String[]
                            { SchemaConstants.ALL_USER_ATTRIBUTES, SchemaConstants.REF_AT } );
                        searchControls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
                        NamingEnumeration<SearchResult> childEntries = sourceBrowserConnection.getConnection()
                            .getJNDIConnectionWrapper().search( oldLdapDn.getUpName(), ISearch.FILTER_TRUE,
                                searchControls, AliasDereferencingMethod.NEVER, ReferralHandlingMethod.IGNORE, null,
                                monitor, null );

                        if ( scope == SearchControls.ONELEVEL_SCOPE )
                        {
                            scope = SearchControls.OBJECT_SCOPE;
                        }

                        numberOfCopiedEntries = copyEntryRecursive( sourceBrowserConnection, childEntries,
                            targetBrowserConnection, newLdapDn, null, scope, numberOfCopiedEntries, dialog,
                            dummyMonitor, monitor );
                    }
                }
            }
        }
        catch ( NamingException e )
        {
            monitor.reportError( e );
        }

        return numberOfCopiedEntries;
    }


    private static void applyNewRdn( Attributes attributes, Rdn oldRdn, Rdn newRdn )
    {
        // remove old RDN attributes and values
        for ( Iterator<AttributeTypeAndValue> it = oldRdn.iterator(); it.hasNext(); )
        {
            AttributeTypeAndValue atav = it.next();
            Attribute attribute = attributes.get( atav.getUpType() );
            if ( attribute != null )
            {
                attribute.remove( atav.getNormValue().getString() );
                if ( attribute.size() == 0 )
                {
                    attributes.remove( atav.getUpType() );
                }
            }
        }

        // add new RDN attributes and values
        for ( Iterator<AttributeTypeAndValue> it = newRdn.iterator(); it.hasNext(); )
        {
            AttributeTypeAndValue atav = it.next();
            Attribute attribute = attributes.get( atav.getUpType() );
            if ( attribute == null )
            {
                attribute = new BasicAttribute( atav.getUpType() );
                attributes.put( attribute );
            }
            if ( !attribute.contains( atav.getNormValue().getString() ) )
            {
                attribute.add( atav.getNormValue().getString() );
            }
        }
    }
}
TOP

Related Classes of org.apache.directory.studio.ldapbrowser.core.jobs.CopyEntriesJob

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.