blob: ec9684e8d0b9be92735fb0e7a0b534a07f01467e [file] [log] [blame]
/*
* 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.common.wizards;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.directory.api.ldap.model.constants.SchemaConstants;
import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
import org.apache.directory.api.ldap.model.name.Ava;
import org.apache.directory.api.ldap.model.name.Dn;
import org.apache.directory.api.ldap.model.name.Rdn;
import org.apache.directory.api.ldap.model.schema.AttributeType;
import org.apache.directory.studio.common.ui.widgets.BaseWidgetUtils;
import org.apache.directory.studio.common.ui.widgets.WidgetModifyEvent;
import org.apache.directory.studio.common.ui.widgets.WidgetModifyListener;
import org.apache.directory.studio.connection.ui.RunnableContextRunner;
import org.apache.directory.studio.ldapbrowser.common.BrowserCommonActivator;
import org.apache.directory.studio.ldapbrowser.common.BrowserCommonConstants;
import org.apache.directory.studio.ldapbrowser.common.widgets.DnBuilderWidget;
import org.apache.directory.studio.ldapbrowser.common.widgets.ListContentProposalProvider;
import org.apache.directory.studio.ldapbrowser.core.events.EventRegistry;
import org.apache.directory.studio.ldapbrowser.core.jobs.ReadEntryRunnable;
import org.apache.directory.studio.ldapbrowser.core.model.IAttribute;
import org.apache.directory.studio.ldapbrowser.core.model.IEntry;
import org.apache.directory.studio.ldapbrowser.core.model.IValue;
import org.apache.directory.studio.ldapbrowser.core.model.impl.Attribute;
import org.apache.directory.studio.ldapbrowser.core.model.impl.DummyEntry;
import org.apache.directory.studio.ldapbrowser.core.model.impl.Value;
import org.apache.directory.studio.ldapbrowser.core.model.schema.SchemaUtils;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.fieldassist.ComboContentAdapter;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
/**
* The NewEntryDnWizardPage is used to compose the new entry's
* distinguished name.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class NewEntryDnWizardPage extends WizardPage implements WidgetModifyListener
{
/** The wizard. */
private NewEntryWizard wizard;
/** The Dn builder widget. */
private DnBuilderWidget dnBuilderWidget;
/** The context entry Dn combo. */
private Combo contextEntryDnCombo;
/** The content proposal adapter for the context entry Dn combo. */
private ContentProposalAdapter contextEntryDnComboCPA;
/**
* Creates a new instance of NewEntryDnWizardPage.
*
* @param pageName the page name
* @param wizard the wizard
*/
public NewEntryDnWizardPage( String pageName, NewEntryWizard wizard )
{
super( pageName );
setTitle( Messages.getString( "NewEntryDnWizardPage.DistinguishedName" ) ); //$NON-NLS-1$
if ( wizard.isNewContextEntry() )
{
setDescription( Messages.getString( "NewEntryDnWizardPage.EnterDN" ) ); //$NON-NLS-1$
}
else
{
setDescription( Messages.getString( "NewEntryDnWizardPage.SelectParent" ) ); //$NON-NLS-1$
}
setImageDescriptor( BrowserCommonActivator.getDefault().getImageDescriptor(
BrowserCommonConstants.IMG_ENTRY_WIZARD ) );
setPageComplete( false );
this.wizard = wizard;
}
/**
* {@inheritDoc}
*/
public void dispose()
{
if ( dnBuilderWidget != null )
{
dnBuilderWidget.removeWidgetModifyListener( this );
dnBuilderWidget.dispose();
dnBuilderWidget = null;
}
super.dispose();
}
/**
* Validates the input fields.
*/
private void validate()
{
if ( wizard.isNewContextEntry() && !"".equals( contextEntryDnCombo.getText() ) //$NON-NLS-1$
&& Dn.isValid( contextEntryDnCombo.getText() ) )
{
setPageComplete( true );
saveState();
}
else if ( !wizard.isNewContextEntry() && dnBuilderWidget.getRdn() != null
&& dnBuilderWidget.getParentDn() != null )
{
setPageComplete( true );
saveState();
}
else
{
setPageComplete( false );
}
}
/**
* Initializes the Dn builder widget with the Dn of
* the prototype entry. Called when this page becomes visible.
*/
private void loadState()
{
DummyEntry newEntry = wizard.getPrototypeEntry();
if ( wizard.isNewContextEntry() )
{
IAttribute attribute = wizard.getSelectedConnection().getRootDSE().getAttribute(
SchemaConstants.NAMING_CONTEXTS_AT );
if ( attribute != null )
{
String[] values = attribute.getStringValues();
// content proposals
contextEntryDnComboCPA.setContentProposalProvider( new ListContentProposalProvider( values ) );
// fill namingContext values into combo
contextEntryDnCombo.setItems( values );
// preset combo text
if ( Arrays.asList( values ).contains( newEntry.getDn().getName() ) )
{
contextEntryDnCombo.setText( newEntry.getDn().getName() );
}
}
}
else
{
Collection<AttributeType> atds = SchemaUtils.getAllAttributeTypeDescriptions( newEntry );
String[] attributeNames = SchemaUtils.getNames( atds ).toArray( ArrayUtils.EMPTY_STRING_ARRAY );
Dn parentDn = null;
boolean hasSelectedEntry = wizard.getSelectedEntry() != null;
boolean newEntryParentDnNotNullOrEmpty = !Dn.isNullOrEmpty( newEntry.getDn().getParent() );
if ( hasSelectedEntry )
{
boolean newEntryDnEqualsSelectedEntryDn = newEntry.getDn().equals( wizard.getSelectedEntry().getDn() );
if ( newEntryDnEqualsSelectedEntryDn && newEntryParentDnNotNullOrEmpty )
{
parentDn = newEntry.getDn().getParent();
}
else
{
parentDn = wizard.getSelectedEntry().getDn();
}
}
else if ( newEntryParentDnNotNullOrEmpty )
{
parentDn = newEntry.getDn().getParent();
}
Rdn rdn = newEntry.getRdn();
dnBuilderWidget.setInput( wizard.getSelectedConnection(), attributeNames, rdn, parentDn );
}
}
/**
* Saves the Dn of the Dn builder widget to the prototype entry.
*/
private void saveState()
{
DummyEntry newEntry = wizard.getPrototypeEntry();
try
{
EventRegistry.suspendEventFiringInCurrentThread();
// remove old Rdn
if ( newEntry.getRdn().size() > 0 )
{
Iterator<Ava> atavIterator = newEntry.getRdn().iterator();
while ( atavIterator.hasNext() )
{
Ava atav = atavIterator.next();
IAttribute attribute = newEntry.getAttribute( atav.getType() );
if ( attribute != null )
{
IValue[] values = attribute.getValues();
for ( int v = 0; v < values.length; v++ )
{
if ( values[v].getStringValue().equals( atav.getValue().getNormalized() ) )
{
attribute.deleteValue( values[v] );
}
}
// If we have removed all the values of the attribute,
// then we also need to remove this attribute from the
// entry.
// This test has been added to fix DIRSTUDIO-222
if ( attribute.getValueSize() == 0 )
{
newEntry.deleteAttribute( attribute );
}
}
}
}
// set new Dn
Dn dn;
if ( wizard.isNewContextEntry() )
{
try
{
dn = new Dn( contextEntryDnCombo.getText() );
}
catch ( LdapInvalidDnException e )
{
dn = Dn.EMPTY_DN;
}
}
else
{
try
{
dn = dnBuilderWidget.getParentDn().add( dnBuilderWidget.getRdn() );
}
catch ( LdapInvalidDnException lide )
{
// Do nothing
dn = Dn.EMPTY_DN;
}
}
newEntry.setDn( dn );
// add new Rdn
if ( dn.getRdn().size() > 0 )
{
Iterator<Ava> atavIterator = dn.getRdn().iterator();
while ( atavIterator.hasNext() )
{
Ava atav = atavIterator.next();
IAttribute rdnAttribute = newEntry.getAttribute( atav.getType() );
if ( rdnAttribute == null )
{
rdnAttribute = new Attribute( newEntry, atav.getType() );
newEntry.addAttribute( rdnAttribute );
}
Object rdnValue = atav.getValue().getNormalized();
String[] stringValues = rdnAttribute.getStringValues();
if ( !Arrays.asList( stringValues ).contains( rdnValue ) )
{
rdnAttribute.addValue( new Value( rdnAttribute, rdnValue ) );
}
}
}
}
finally
{
EventRegistry.resumeEventFiringInCurrentThread();
}
}
/**
* {@inheritDoc}
*
* This implementation initializes Dn builder widghet with the
* Dn of the protoype entry.
*/
public void setVisible( boolean visible )
{
super.setVisible( visible );
if ( visible )
{
loadState();
validate();
if ( wizard.isNewContextEntry() )
{
contextEntryDnCombo.setFocus();
}
}
}
/**
* {@inheritDoc}
*
* This implementation just checks if this page is complete. It
* doesn't call {@link #getNextPage()} to avoid unneeded
* invokings of {@link ReadEntryRunnable}s.
*/
@Override
public boolean canFlipToNextPage()
{
return isPageComplete();
}
/**
* {@inheritDoc}
*
* This implementation invokes a {@link ReadEntryRunnable} to check if an
* entry with the composed Dn already exists.
*/
@Override
public IWizardPage getNextPage()
{
if ( !wizard.isNewContextEntry() )
{
dnBuilderWidget.validate();
Rdn rdn = dnBuilderWidget.getRdn();
Dn parentDn = dnBuilderWidget.getParentDn();
try
{
final Dn dn = parentDn.add( rdn );
// check if parent exists
ReadEntryRunnable readEntryRunnable1 = new ReadEntryRunnable( wizard.getSelectedConnection(), parentDn );
RunnableContextRunner.execute( readEntryRunnable1, getContainer(), false );
IEntry parentEntry = readEntryRunnable1.getReadEntry();
if ( parentEntry == null )
{
getShell().getDisplay().syncExec( () ->
{
MessageDialog
.openError( getShell(),
Messages.getString( "NewEntryDnWizardPage.Error" ), //$NON-NLS-1$
NLS
.bind(
Messages.getString( "NewEntryDnWizardPage.ParentDoesNotExist" ), dnBuilderWidget.getParentDn().toString() ) ); //$NON-NLS-1$
}
);
return null;
}
// check that new entry does not exists yet
ReadEntryRunnable readEntryRunnable2 = new ReadEntryRunnable( wizard.getSelectedConnection(), dn );
RunnableContextRunner.execute( readEntryRunnable2, getContainer(), false );
IEntry entry = readEntryRunnable2.getReadEntry();
if ( entry != null )
{
getShell().getDisplay().syncExec( () ->
{
MessageDialog
.openError(
getShell(),
Messages.getString( "NewEntryDnWizardPage.Error" ), NLS.bind( Messages.getString( "NewEntryDnWizardPage.EntryAlreadyExists" ), dn.toString() ) ); //$NON-NLS-1$ //$NON-NLS-2$
}
);
return null;
}
}
catch ( LdapInvalidDnException lide )
{
return null;
}
}
else
{
try
{
final Dn dn = new Dn( contextEntryDnCombo.getText() );
// check that new entry does not exists yet
ReadEntryRunnable readEntryRunnable2 = new ReadEntryRunnable( wizard.getSelectedConnection(), dn );
RunnableContextRunner.execute( readEntryRunnable2, getContainer(), false );
IEntry entry = readEntryRunnable2.getReadEntry();
if ( entry != null )
{
getShell().getDisplay().syncExec( () ->
{
MessageDialog
.openError(
getShell(),
Messages.getString( "NewEntryDnWizardPage.Error" ), NLS.bind( Messages.getString( "NewEntryDnWizardPage.EntryAlreadyExists" ), dn.toString() ) ); //$NON-NLS-1$ //$NON-NLS-2$
}
);
return null;
}
}
catch ( LdapInvalidDnException e )
{
return null;
}
}
return super.getNextPage();
}
/**
* {@inheritDoc}
*/
public void createControl( Composite parent )
{
if ( wizard.isNewContextEntry() )
{
// the combo
Composite composite = BaseWidgetUtils.createColumnContainer( parent, 1, 1 );
contextEntryDnCombo = BaseWidgetUtils.createCombo( composite, ArrayUtils.EMPTY_STRING_ARRAY, 0, 1 );
contextEntryDnCombo.addModifyListener( event -> validate() );
// attach content proposal behavior
contextEntryDnComboCPA = new ContentProposalAdapter( contextEntryDnCombo, new ComboContentAdapter(), null,
null, null );
contextEntryDnComboCPA.setFilterStyle( ContentProposalAdapter.FILTER_NONE );
contextEntryDnComboCPA.setProposalAcceptanceStyle( ContentProposalAdapter.PROPOSAL_REPLACE );
setControl( composite );
}
else
{
dnBuilderWidget = new DnBuilderWidget( true, true );
dnBuilderWidget.addWidgetModifyListener( this );
Composite composite = dnBuilderWidget.createContents( parent );
setControl( composite );
}
}
/**
* {@inheritDoc}
*/
public void widgetModified( WidgetModifyEvent event )
{
validate();
}
/**
* Saves the dialogs settings.
*/
public void saveDialogSettings()
{
if ( !wizard.isNewContextEntry() )
{
dnBuilderWidget.saveDialogSettings();
}
}
}