All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.directory.studio.schemaeditor.view.wizards.MergeSchemasWizard Maven / Gradle / Ivy

There is a newer version: 2.0.0.v20130628
Show newest version
/*
 *  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.schemaeditor.view.wizards;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.directory.shared.ldap.schema.AbstractSchemaObject;
import org.apache.directory.studio.schemaeditor.Activator;
import org.apache.directory.studio.schemaeditor.model.AttributeTypeImpl;
import org.apache.directory.studio.schemaeditor.model.ObjectClassImpl;
import org.apache.directory.studio.schemaeditor.model.Project;
import org.apache.directory.studio.schemaeditor.model.Schema;
import org.apache.directory.studio.schemaeditor.model.SchemaImpl;
import org.apache.directory.studio.schemaeditor.view.dialogs.MessageDialogWithTextarea;
import org.apache.directory.studio.schemaeditor.view.wizards.MergeSchemasSelectionWizardPage.AttributeTypeFolder;
import org.apache.directory.studio.schemaeditor.view.wizards.MergeSchemasSelectionWizardPage.ObjectClassFolder;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.IImportWizard;
import org.eclipse.ui.IWorkbench;


/**
 * This class represents the wizard to merge schema projects.
 *
 * @author Apache Directory Project
 * @version $Rev$, $Date$
 */
public class MergeSchemasWizard extends Wizard implements IImportWizard
{
    // The pages of the wizard
    private MergeSchemasSelectionWizardPage selectionPage;
    private MergeSchemasOptionsWizardPage optionsPage;


    /* (non-Javadoc)
     * @see org.eclipse.jface.wizard.Wizard#addPages()
     */
    public void addPages()
    {
        // Creating pages
        selectionPage = new MergeSchemasSelectionWizardPage();
        optionsPage = new MergeSchemasOptionsWizardPage();

        // Adding pages
        addPage( selectionPage );
        addPage( optionsPage );
    }


    /* (non-Javadoc)
     * @see org.eclipse.jface.wizard.Wizard#performFinish()
     */
    public boolean performFinish()
    {
        Object[] sourceObjects = selectionPage.getSelectedObjects();

        boolean replaceUnknownSyntax = optionsPage.isReplaceUnknownSyntax();
        boolean mergeDependencies = optionsPage.isMergeDependencies();
        boolean pullUpAttributes = optionsPage.isPullUpAttributes();

        List errorMessages = new ArrayList();
        mergeObjects( sourceObjects, errorMessages, replaceUnknownSyntax, mergeDependencies, pullUpAttributes );
        if ( !errorMessages.isEmpty() )
        {
            StringBuilder sb = new StringBuilder();
            for ( String errorMessage : errorMessages )
            {
                sb.append( errorMessage );
                sb.append( '\n' );
            }
            new MessageDialogWithTextarea( getShell(), Messages.getString( "MergeSchemasWizard.MergeResultTitle" ), //$NON-NLS-1$
                Messages.getString( "MergeSchemasWizard.MergeResultMessage" ), sb.toString() ).open(); //$NON-NLS-1$
        }

        return true;
    }


    private void mergeObjects( Object[] sourceObjects, List errorMessages, boolean replaceUnknownSyntax,
        boolean mergeDependencies, boolean pullUpAttributes )
    {
        /* 
         * List of already processed schema objects. Used to avoid that schema objects are process multiple time.
         */
        Set processedObjects = new HashSet();

        /*
         * List of created target schemas. 
         */
        Map targetSchemas = new HashMap();

        Project targetProject = Activator.getDefault().getProjectsHandler().getOpenProject();

        // merge all source objects to the target project
        for ( Object sourceObject : sourceObjects )
        {
            if ( sourceObject instanceof Project )
            {
                Project sourceProject = ( Project ) sourceObject;
                for ( Schema sourceSchema : sourceProject.getSchemaHandler().getSchemas() )
                {
                    Schema targetSchema = getTargetSchema( sourceSchema.getProject(), targetProject, targetSchemas );
                    mergeSchema( sourceSchema, targetProject, targetSchema, processedObjects, errorMessages,
                        replaceUnknownSyntax, mergeDependencies, pullUpAttributes );
                }
            }
            if ( sourceObject instanceof Schema )
            {
                Schema sourceSchema = ( Schema ) sourceObject;
                Schema targetSchema = getTargetSchema( sourceSchema.getProject(), targetProject, targetSchemas );
                mergeSchema( sourceSchema, targetProject, targetSchema, processedObjects, errorMessages,
                    replaceUnknownSyntax, mergeDependencies, pullUpAttributes );
            }
            if ( sourceObject instanceof AttributeTypeFolder )
            {
                AttributeTypeFolder atf = ( AttributeTypeFolder ) sourceObject;
                Schema targetSchema = getTargetSchema( atf.schema.getProject(), targetProject, targetSchemas );
                List sourceAttributeTypes = atf.schema.getAttributeTypes();
                for ( AttributeTypeImpl sourceAttributeType : sourceAttributeTypes )
                {
                    mergeAttributeType( sourceAttributeType, targetProject, targetSchema, processedObjects,
                        errorMessages, replaceUnknownSyntax, mergeDependencies, pullUpAttributes );
                }
            }
            if ( sourceObject instanceof ObjectClassFolder )
            {
                ObjectClassFolder ocf = ( ObjectClassFolder ) sourceObject;
                Schema targetSchema = getTargetSchema( ocf.schema.getProject(), targetProject, targetSchemas );
                List sourceObjectClasses = ocf.schema.getObjectClasses();
                for ( ObjectClassImpl sourceObjectClass : sourceObjectClasses )
                {
                    mergeObjectClass( sourceObjectClass, targetProject, targetSchema, processedObjects, errorMessages,
                        replaceUnknownSyntax, mergeDependencies, pullUpAttributes );
                }
            }
            if ( sourceObject instanceof AttributeTypeImpl )
            {
                AttributeTypeImpl at = ( AttributeTypeImpl ) sourceObject;
                Schema targetSchema = getTargetSchema( at.getSchemaObject().getProject(), targetProject, targetSchemas );
                mergeAttributeType( at, targetProject, targetSchema, processedObjects, errorMessages,
                    replaceUnknownSyntax, mergeDependencies, pullUpAttributes );
            }
            if ( sourceObject instanceof ObjectClassImpl )
            {
                ObjectClassImpl oc = ( ObjectClassImpl ) sourceObject;
                Schema targetSchema = getTargetSchema( oc.getSchemaObject().getProject(), targetProject, targetSchemas );
                mergeObjectClass( oc, targetProject, targetSchema, processedObjects, errorMessages,
                    replaceUnknownSyntax, mergeDependencies, pullUpAttributes );
            }
        }

        //add created target schemas to project
        for ( Schema targetSchema : targetSchemas.values() )
        {
            if ( !targetProject.getSchemaHandler().getSchemas().contains( targetSchema ) )
            {
                targetProject.getSchemaHandler().addSchema( targetSchema );
            }
        }
    }


    private Schema getTargetSchema( Project sourceProject, Project targetProject, Map targetSchemas )
    {
        String targetSchemaName = "merge-from-" + sourceProject.getName(); //$NON-NLS-1$
        Schema targetSchema = targetProject.getSchemaHandler().getSchema( targetSchemaName );
        if ( targetSchema != null )
        {
            targetProject.getSchemaHandler().removeSchema( targetSchema );
        }
        else if ( targetSchemas.containsKey( targetSchemaName ) )
        {
            targetSchema = targetSchemas.get( targetSchemaName );
        }
        else
        {
            targetSchema = new SchemaImpl( targetSchemaName );
            targetSchema.setProject( targetProject );
        }
        targetSchemas.put( targetSchemaName, targetSchema );
        return targetSchema;
    }


    /**
     * Merges all attribute types and object classes and form the given sourceSchema to the targetSchema. 
     */
    private void mergeSchema( Schema sourceSchema, Project targetProject, Schema targetSchema,
        Set processedObjects, List errorMessages, boolean replaceUnknownSyntax,
        boolean mergeDependencies, boolean pullUpAttributes )
    {
        List sourceAttributeTypes = sourceSchema.getAttributeTypes();
        for ( AttributeTypeImpl sourceAttributeType : sourceAttributeTypes )
        {
            mergeAttributeType( sourceAttributeType, targetProject, targetSchema, processedObjects, errorMessages,
                replaceUnknownSyntax, mergeDependencies, pullUpAttributes );
        }

        List sourceObjectClasses = sourceSchema.getObjectClasses();
        for ( ObjectClassImpl sourceObjectClass : sourceObjectClasses )
        {
            mergeObjectClass( sourceObjectClass, targetProject, targetSchema, processedObjects, errorMessages,
                replaceUnknownSyntax, mergeDependencies, pullUpAttributes );
        }
    }


    /**
     * Merges the given attribute type to the targetSchema. 
     */
    private void mergeAttributeType( AttributeTypeImpl sourceAttributeType, Project targetProject, Schema targetSchema,
        Set processedObjects, List errorMessages, boolean replaceUnknownSyntax,
        boolean mergeDependencies, boolean pullUpAttributes )
    {
        if ( processedObjects.contains( sourceAttributeType ) )
        {
            return;
        }
        processedObjects.add( sourceAttributeType );

        // check if attribute (identified by OID or name) already exists in the project
        AttributeTypeImpl targetAttributeType = targetProject.getSchemaHandler().getAttributeType(
            sourceAttributeType.getOid() );
        if ( targetAttributeType == null )
        {
            for ( String name : sourceAttributeType.getNamesRef() )
            {
                targetAttributeType = targetProject.getSchemaHandler().getAttributeType( name );
                if ( targetAttributeType != null )
                {
                    break;
                }
            }
        }

        // check if OID or alias name already exist in target project
        boolean oidOrAliasAlreadyTaken = targetProject.getSchemaHandler().isAliasOrOidAlreadyTaken(
            sourceAttributeType.getOid() );
        if ( !oidOrAliasAlreadyTaken )
        {
            for ( String name : sourceAttributeType.getNamesRef() )
            {
                oidOrAliasAlreadyTaken = targetProject.getSchemaHandler().isAliasOrOidAlreadyTaken( name );
                if ( oidOrAliasAlreadyTaken )
                {
                    break;
                }
            }
        }

        if ( targetAttributeType != null )
        {
            errorMessages.add( NLS.bind( Messages.getString( "MergeSchemasWizard.AttributeTypeExistsInTargetProject" ), //$NON-NLS-1$
                getIdString( sourceAttributeType ) ) );
        }
        else
        {
            if ( oidOrAliasAlreadyTaken )
            {
                errorMessages.add( NLS.bind( Messages.getString( "MergeSchemasWizard.OidOrAliasAlreadyTaken" ), //$NON-NLS-1$
                    getIdString( sourceAttributeType ) ) );
            }
            else
            {
                // remove attribute type if already there from previous merge
                AttributeTypeImpl at = targetSchema.getAttributeType( sourceAttributeType.getOid() );
                if ( at != null )
                {
                    targetSchema.removeAttributeType( at );
                }

                // clone attribute type
                AttributeTypeImpl clonedAttributeType = new AttributeTypeImpl( sourceAttributeType.getOid() );
                clonedAttributeType.setOid( sourceAttributeType.getOid() );
                clonedAttributeType.setNames( sourceAttributeType.getNamesRef() );
                clonedAttributeType.setDescription( sourceAttributeType.getDescription() );
                clonedAttributeType.setSuperiorName( sourceAttributeType.getSuperiorName() );
                clonedAttributeType.setUsage( sourceAttributeType.getUsage() );
                clonedAttributeType.setSyntaxOid( sourceAttributeType.getSyntaxOid() );
                clonedAttributeType.setLength( sourceAttributeType.getLength() );
                clonedAttributeType.setObsolete( sourceAttributeType.isObsolete() );
                clonedAttributeType.setCollective( sourceAttributeType.isCollective() );
                clonedAttributeType.setSingleValue( sourceAttributeType.isSingleValue() );
                clonedAttributeType.setCanUserModify( sourceAttributeType.isCanUserModify() );
                clonedAttributeType.setEqualityName( sourceAttributeType.getEqualityName() );
                clonedAttributeType.setOrderingName( sourceAttributeType.getOrderingName() );
                clonedAttributeType.setSubstrName( sourceAttributeType.getSubstrName() );
                clonedAttributeType.setSchema( targetSchema.getName() );
                clonedAttributeType.setSchemaObject( targetSchema );

                // if no/unknown syntax: set "Directory String" syntax and appropriate matching rules
                if ( replaceUnknownSyntax )
                {
                    if ( clonedAttributeType.getSyntaxOid() == null
                        || targetProject.getSchemaHandler().getSyntax( clonedAttributeType.getSyntaxOid() ) == null )
                    {
                        errorMessages.add( NLS.bind( Messages.getString( "MergeSchemasWizard.ReplacedSyntax" ), //$NON-NLS-1$
                            new String[]
                                { getIdString( sourceAttributeType ), clonedAttributeType.getSyntaxOid(),
                                    "1.3.6.1.4.1.1466.115.121.1.15 (Directory String)" } ) ); //$NON-NLS-1$
                        clonedAttributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.15" );
                        clonedAttributeType.setEqualityName( "caseIgnoreMatch" );
                        clonedAttributeType.setOrderingName( null );
                        clonedAttributeType.setSubstrName( "caseIgnoreSubstringsMatch" );
                    }
                }
                // TODO: if unknown (single) matching rule: set appropriate matching rule according to syntax
                // TODO: if no (all) matching rules: set appropriate matching rules according to syntax

                // merge dependencies: super attribute type
                if ( mergeDependencies )
                {
                    String superiorName = clonedAttributeType.getSuperiorName();
                    if ( superiorName != null )
                    {
                        AttributeTypeImpl superiorAttributeType = sourceAttributeType.getSchemaObject().getProject()
                            .getSchemaHandler().getAttributeType( superiorName );
                        if ( superiorAttributeType != null )
                        {
                            mergeAttributeType( superiorAttributeType, targetProject, targetSchema, processedObjects,
                                errorMessages, replaceUnknownSyntax, mergeDependencies, pullUpAttributes );
                        }
                    }
                }

                targetSchema.addAttributeType( clonedAttributeType );
            }
        }
    }


    /**
     * Merges the given object class to the targetSchema. 
     */
    private void mergeObjectClass( ObjectClassImpl sourceObjectClass, Project targetProject, Schema targetSchema,
        Set processedObjects, List errorMessages, boolean replaceUnknownSyntax,
        boolean mergeDependencies, boolean pullUpAttributes )
    {
        if ( processedObjects.contains( sourceObjectClass ) )
        {
            return;
        }
        processedObjects.add( sourceObjectClass );

        // check if object class (identified by OID or alias name) already exists in the target project
        ObjectClassImpl targetObjectClass = targetProject.getSchemaHandler()
            .getObjectClass( sourceObjectClass.getOid() );
        if ( targetObjectClass == null )
        {
            for ( String name : sourceObjectClass.getNamesRef() )
            {
                targetObjectClass = targetProject.getSchemaHandler().getObjectClass( name );
                if ( targetObjectClass != null )
                {
                    break;
                }
            }
        }

        // check if OID or alias name already exist in target project
        boolean oidOrAliasAlreadyTaken = targetProject.getSchemaHandler().isAliasOrOidAlreadyTaken(
            sourceObjectClass.getOid() );
        if ( !oidOrAliasAlreadyTaken )
        {
            for ( String name : sourceObjectClass.getNamesRef() )
            {
                oidOrAliasAlreadyTaken = targetProject.getSchemaHandler().isAliasOrOidAlreadyTaken( name );
                if ( oidOrAliasAlreadyTaken )
                {
                    break;
                }
            }
        }

        if ( targetObjectClass != null )
        {
            errorMessages.add( NLS.bind( Messages.getString( "MergeSchemasWizard.ObjectClassExistsInTargetProject" ), //$NON-NLS-1$
                getIdString( sourceObjectClass ) ) );
        }
        else
        {
            if ( oidOrAliasAlreadyTaken )
            {
                errorMessages.add( NLS.bind( Messages.getString( "MergeSchemasWizard.OidOrAliasAlreadyTaken" ), //$NON-NLS-1$
                    getIdString( sourceObjectClass ) ) );
            }
            else
            {
                // remove object class if already there from previous merge
                ObjectClassImpl oc = targetSchema.getObjectClass( sourceObjectClass.getOid() );
                if ( oc != null )
                {
                    targetSchema.removeObjectClass( oc );
                }

                // create object class
                ObjectClassImpl clonedObjectClass = new ObjectClassImpl( sourceObjectClass.getOid() );
                clonedObjectClass.setOid( sourceObjectClass.getOid() );
                clonedObjectClass.setNames( sourceObjectClass.getNamesRef() );
                clonedObjectClass.setDescription( sourceObjectClass.getDescription() );
                clonedObjectClass.setSuperClassesNames( sourceObjectClass.getSuperClassesNames() );
                clonedObjectClass.setType( sourceObjectClass.getType() );
                clonedObjectClass.setObsolete( sourceObjectClass.isObsolete() );
                clonedObjectClass.setMustNamesList( sourceObjectClass.getMustNamesList() );
                clonedObjectClass.setMayNamesList( sourceObjectClass.getMayNamesList() );
                clonedObjectClass.setSchema( targetSchema.getName() );
                clonedObjectClass.setSchemaObject( targetSchema );

                // merge dependencies: super object classes and must/may attributes
                if ( mergeDependencies )
                {
                    String[] superClassesNames = clonedObjectClass.getSuperClassesNames();
                    if ( superClassesNames != null )
                    {
                        for ( String superClassName : superClassesNames )
                        {
                            if ( superClassName != null )
                            {
                                ObjectClassImpl superSourceObjectClass = sourceObjectClass.getSchemaObject()
                                    .getProject().getSchemaHandler().getObjectClass( superClassName );
                                ObjectClassImpl superTargetObjectClass = targetProject.getSchemaHandler()
                                    .getObjectClass( superClassName );
                                if ( superSourceObjectClass != null )
                                {
                                    if ( superTargetObjectClass == null )
                                    {
                                        mergeObjectClass( superSourceObjectClass, targetProject, targetSchema,
                                            processedObjects, errorMessages, replaceUnknownSyntax, mergeDependencies,
                                            pullUpAttributes );
                                    }
                                    else
                                    {
                                        // pull-up may and must attributes to this OC if super already exists in target
                                        if ( pullUpAttributes )
                                        {
                                            pullUpAttributes( clonedObjectClass, superSourceObjectClass,
                                                superTargetObjectClass );
                                        }
                                    }
                                }
                            }
                        }
                    }

                    String[] mustNamesList = clonedObjectClass.getMustNamesList();
                    String[] mayNamesList = clonedObjectClass.getMayNamesList();
                    List attributeNames = new ArrayList();
                    if ( mustNamesList != null )
                    {
                        attributeNames.addAll( Arrays.asList( mustNamesList ) );
                    }
                    if ( mayNamesList != null )
                    {
                        attributeNames.addAll( Arrays.asList( mayNamesList ) );
                    }
                    for ( String attributeName : attributeNames )
                    {
                        if ( attributeName != null )
                        {
                            AttributeTypeImpl attributeType = sourceObjectClass.getSchemaObject().getProject()
                                .getSchemaHandler().getAttributeType( attributeName );
                            if ( attributeType != null )
                            {
                                mergeAttributeType( attributeType, targetProject, targetSchema, processedObjects,
                                    errorMessages, replaceUnknownSyntax, mergeDependencies, pullUpAttributes );
                            }
                        }
                    }
                }

                targetSchema.addObjectClass( clonedObjectClass );
            }
        }
    }


    private void pullUpAttributes( ObjectClassImpl targetObjectClass, ObjectClassImpl sourceSuperObjectClass,
        ObjectClassImpl targetSuperObjectClass )
    {
        // must
        Set sourceMustAttributeNames = new HashSet();
        fetchAttributes( sourceMustAttributeNames, sourceSuperObjectClass, true );
        Set targetMustAttributeNames = new HashSet();
        fetchAttributes( targetMustAttributeNames, targetSuperObjectClass, true );
        sourceMustAttributeNames.removeAll( targetMustAttributeNames );
        if ( !sourceMustAttributeNames.isEmpty() )
        {
            sourceMustAttributeNames.addAll( Arrays.asList( targetObjectClass.getMustNamesList() ) );
            targetObjectClass.setMustNamesList( sourceMustAttributeNames.toArray( new String[0] ) );
        }

        // may
        Set sourceMayAttributeNames = new HashSet();
        fetchAttributes( sourceMayAttributeNames, sourceSuperObjectClass, false );
        Set targetMayAttributeNames = new HashSet();
        fetchAttributes( targetMayAttributeNames, targetSuperObjectClass, false );
        sourceMayAttributeNames.removeAll( targetMayAttributeNames );
        if ( !sourceMayAttributeNames.isEmpty() )
        {
            sourceMayAttributeNames.addAll( Arrays.asList( targetObjectClass.getMayNamesList() ) );
            targetObjectClass.setMayNamesList( sourceMayAttributeNames.toArray( new String[0] ) );
        }
    }


    private void fetchAttributes( Set attributeNameList, ObjectClassImpl oc, boolean must )
    {
        String[] attributeNames = must ? oc.getMustNamesList() : oc.getMayNamesList();
        attributeNameList.addAll( Arrays.asList( attributeNames ) );

        for ( String superClassName : oc.getSuperClassesNames() )
        {
            ObjectClassImpl superObjectClass = oc.getSchemaObject().getProject().getSchemaHandler().getObjectClass(
                superClassName );
            fetchAttributes( attributeNameList, superObjectClass, must );
        }
    }


    private String getIdString( AbstractSchemaObject schemaObject )
    {
        StringBuilder sb = new StringBuilder();
        sb.append( '[' );
        if ( schemaObject.getNamesRef() != null )
        {
            for ( String name : schemaObject.getNamesRef() )
            {
                sb.append( name );
                sb.append( ',' );
            }
        }
        sb.append( schemaObject.getOid() );
        sb.append( ']' );
        return sb.toString();
    }


    /* (non-Javadoc)
     * @see org.eclipse.ui.IWorkbenchWizard#init(org.eclipse.ui.IWorkbench, org.eclipse.jface.viewers.IStructuredSelection)
     */
    public void init( IWorkbench workbench, IStructuredSelection selection )
    {
    }
}