| /* |
| * 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.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| 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.message.SearchScope; |
| import org.apache.directory.api.ldap.model.name.Dn; |
| import org.apache.directory.studio.common.core.jobs.StudioProgressMonitor; |
| import org.apache.directory.studio.connection.core.Connection; |
| 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.ConnectionCorePlugin; |
| import org.apache.directory.studio.connection.core.DetectedConnectionProperties; |
| import org.apache.directory.studio.connection.core.jobs.StudioConnectionBulkRunnableWithProgress; |
| import org.apache.directory.studio.ldapbrowser.core.BrowserCoreMessages; |
| import org.apache.directory.studio.ldapbrowser.core.events.AttributesInitializedEvent; |
| import org.apache.directory.studio.ldapbrowser.core.events.EventRegistry; |
| import org.apache.directory.studio.ldapbrowser.core.model.IAttribute; |
| 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.IRootDSE; |
| import org.apache.directory.studio.ldapbrowser.core.model.ISearch; |
| import org.apache.directory.studio.ldapbrowser.core.model.ISearchResult; |
| import org.apache.directory.studio.ldapbrowser.core.model.impl.BaseDNEntry; |
| import org.apache.directory.studio.ldapbrowser.core.model.impl.DirectoryMetadataEntry; |
| import org.apache.directory.studio.ldapbrowser.core.model.impl.Search; |
| |
| |
| /** |
| * Runnable to initialize the Root DSE. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| public class InitializeRootDSERunnable implements StudioConnectionBulkRunnableWithProgress |
| { |
| /** The requested attributes when reading the Root DSE. */ |
| public static final String[] ROOT_DSE_ATTRIBUTES = |
| { |
| SchemaConstants.NAMING_CONTEXTS_AT, |
| SchemaConstants.SUBSCHEMA_SUBENTRY_AT, |
| SchemaConstants.SUPPORTED_LDAP_VERSION_AT, |
| SchemaConstants.SUPPORTED_SASL_MECHANISMS_AT, |
| SchemaConstants.SUPPORTED_EXTENSION_AT, |
| SchemaConstants.SUPPORTED_CONTROL_AT, |
| SchemaConstants.SUPPORTED_FEATURES_AT, |
| SchemaConstants.VENDOR_NAME_AT, |
| SchemaConstants.VENDOR_VERSION_AT, |
| SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES }; |
| |
| private IRootDSE rootDSE; |
| |
| |
| /** |
| * Creates a new instance of InitializeRootDSERunnable. |
| * |
| * @param rootDSE the root DSE |
| */ |
| private InitializeRootDSERunnable( IRootDSE rootDSE ) |
| { |
| this.rootDSE = rootDSE; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Connection[] getConnections() |
| { |
| return new Connection[] |
| { rootDSE.getBrowserConnection().getConnection() }; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public String getName() |
| { |
| return BrowserCoreMessages.jobs__init_entries_title_attonly; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Object[] getLockedObjects() |
| { |
| return new IEntry[] |
| { rootDSE }; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public String getErrorMessage() |
| { |
| return BrowserCoreMessages.jobs__init_entries_error_1; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void run( StudioProgressMonitor monitor ) |
| { |
| monitor.beginTask( " ", 3 ); //$NON-NLS-1$ |
| monitor.reportProgress( " " ); //$NON-NLS-1$ |
| |
| monitor.setTaskName( BrowserCoreMessages.bind( BrowserCoreMessages.jobs__init_entries_task, new String[] |
| { rootDSE.getDn().getName() } ) ); |
| monitor.worked( 1 ); |
| |
| monitor.reportProgress( BrowserCoreMessages.bind( BrowserCoreMessages.jobs__init_entries_progress_att, |
| new String[] |
| { rootDSE.getDn().getName() } ) ); |
| |
| loadRootDSE( rootDSE.getBrowserConnection(), monitor ); |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void runNotification( StudioProgressMonitor monitor ) |
| { |
| EventRegistry.fireEntryUpdated( new AttributesInitializedEvent( rootDSE ), this ); |
| } |
| |
| |
| /** |
| * Loads the Root DSE. |
| * |
| * @param browserConnection the browser connection |
| * @param monitor the progress monitor |
| * |
| * @throws Exception the exception |
| */ |
| public static synchronized void loadRootDSE( IBrowserConnection browserConnection, StudioProgressMonitor monitor ) |
| { |
| // clear old children |
| InitializeChildrenRunnable.clearCaches( browserConnection.getRootDSE(), true ); |
| |
| // delete old attributes |
| IAttribute[] oldAttributes = browserConnection.getRootDSE().getAttributes(); |
| |
| if ( oldAttributes != null ) |
| { |
| for ( IAttribute oldAttribute : oldAttributes ) |
| { |
| browserConnection.getRootDSE().deleteAttribute( oldAttribute ); |
| } |
| } |
| |
| // load well-known Root DSE attributes and operational attributes |
| ISearch search = new Search( null, browserConnection, Dn.EMPTY_DN, ISearch.FILTER_TRUE, |
| ROOT_DSE_ATTRIBUTES, SearchScope.OBJECT, 0, 0, Connection.AliasDereferencingMethod.NEVER, |
| Connection.ReferralHandlingMethod.IGNORE, false, null, false ); |
| SearchRunnable.searchAndUpdateModel( browserConnection, search, monitor ); |
| |
| // Load all user attributes. This is done because the BEA "LDAP server" (so called) is stupid |
| // enough not to accept searches where "+" and "*" are provided on the list of parameters. |
| // We have to do two searches... |
| search = new Search( null, browserConnection, Dn.EMPTY_DN, ISearch.FILTER_TRUE, new String[] |
| { SchemaConstants.ALL_USER_ATTRIBUTES }, SearchScope.OBJECT, 0, 0, |
| Connection.AliasDereferencingMethod.NEVER, Connection.ReferralHandlingMethod.IGNORE, false, null, false ); |
| SearchRunnable.searchAndUpdateModel( browserConnection, search, monitor ); |
| |
| // the list of entries under the Root DSE |
| Map<Dn, IEntry> rootDseEntries = new HashMap<Dn, IEntry>(); |
| |
| // 1st: add base DNs, either the specified or from the namingContexts attribute |
| if ( !browserConnection.isFetchBaseDNs() && browserConnection.getBaseDN() != null |
| && !"".equals( browserConnection.getBaseDN().toString() ) ) //$NON-NLS-1$ |
| { |
| // only add the specified base Dn |
| Dn dn = browserConnection.getBaseDN(); |
| IEntry entry = browserConnection.getEntryFromCache( dn ); |
| |
| if ( entry == null ) |
| { |
| entry = new BaseDNEntry( dn, browserConnection ); |
| browserConnection.cacheEntry( entry ); |
| } |
| rootDseEntries.put( dn, entry ); |
| } |
| else |
| { |
| // get base DNs from namingContexts attribute |
| Set<String> namingContextSet = new HashSet<String>(); |
| IAttribute attribute = browserConnection.getRootDSE().getAttribute( SchemaConstants.NAMING_CONTEXTS_AT ); |
| |
| if ( attribute != null ) |
| { |
| String[] values = attribute.getStringValues(); |
| |
| for ( int i = 0; i < values.length; i++ ) |
| { |
| namingContextSet.add( values[i] ); |
| } |
| } |
| |
| if ( !namingContextSet.isEmpty() ) |
| { |
| for ( String namingContext : namingContextSet ) |
| { |
| if ( namingContext.length() > 0 && namingContext.charAt( namingContext.length() - 1 ) == '\u0000' ) |
| { |
| namingContext = namingContext.substring( 0, namingContext.length() - 1 ); |
| } |
| |
| if ( !"".equals( namingContext ) ) //$NON-NLS-1$ |
| { |
| try |
| { |
| Dn dn = new Dn( namingContext ); |
| IEntry entry = browserConnection.getEntryFromCache( dn ); |
| |
| if ( entry == null ) |
| { |
| entry = new BaseDNEntry( dn, browserConnection ); |
| browserConnection.cacheEntry( entry ); |
| } |
| |
| rootDseEntries.put( dn, entry ); |
| } |
| catch ( LdapInvalidDnException e ) |
| { |
| monitor.reportError( BrowserCoreMessages.model__error_setting_base_dn, e ); |
| } |
| } |
| else |
| { |
| // special handling of empty namingContext (Novell eDirectory): |
| // perform a one-level search and add all result DNs to the set |
| searchRootDseEntries( browserConnection, rootDseEntries, monitor ); |
| } |
| } |
| } |
| else |
| { |
| // special handling of non-existing namingContexts attribute (Oracle Internet Directory) |
| // perform a one-level search and add all result DNs to the set |
| searchRootDseEntries( browserConnection, rootDseEntries, monitor ); |
| } |
| } |
| |
| // 2nd: add schema sub-entry |
| IEntry[] schemaEntries = getDirectoryMetadataEntries( browserConnection, SchemaConstants.SUBSCHEMA_SUBENTRY_AT ); |
| |
| for ( IEntry entry : schemaEntries ) |
| { |
| if ( entry instanceof DirectoryMetadataEntry ) |
| { |
| ( ( DirectoryMetadataEntry ) entry ).setSchemaEntry( true ); |
| } |
| |
| rootDseEntries.put( entry.getDn(), entry ); |
| } |
| |
| // get other meta data entries |
| IAttribute[] rootDseAttributes = browserConnection.getRootDSE().getAttributes(); |
| |
| if ( rootDseAttributes != null ) |
| { |
| for ( IAttribute attribute : rootDseAttributes ) |
| { |
| IEntry[] metadataEntries = getDirectoryMetadataEntries( browserConnection, attribute.getDescription() ); |
| |
| for ( IEntry entry : metadataEntries ) |
| { |
| rootDseEntries.put( entry.getDn(), entry ); |
| } |
| } |
| } |
| |
| // try to init entries |
| StudioProgressMonitor dummyMonitor = new StudioProgressMonitor( monitor ); |
| |
| for ( IEntry entry : rootDseEntries.values() ) |
| { |
| initBaseEntry( entry, dummyMonitor ); |
| } |
| |
| // set flags |
| browserConnection.getRootDSE().setHasMoreChildren( false ); |
| browserConnection.getRootDSE().setAttributesInitialized( true ); |
| browserConnection.getRootDSE().setInitOperationalAttributes( true ); |
| browserConnection.getRootDSE().setChildrenInitialized( true ); |
| browserConnection.getRootDSE().setHasChildrenHint( true ); |
| browserConnection.getRootDSE().setDirectoryEntry( true ); |
| |
| // Set detected connection properties |
| DetectedConnectionProperties detectedConnectionProperties = browserConnection.getConnection() |
| .getDetectedConnectionProperties(); |
| IAttribute vendorNameAttribute = browserConnection.getRootDSE().getAttribute( "vendorName" ); //$NON-NLS-1$ |
| |
| if ( ( vendorNameAttribute != null ) && ( vendorNameAttribute.getValueSize() > 0 ) ) |
| { |
| detectedConnectionProperties.setVendorName( vendorNameAttribute.getStringValue() ); |
| } |
| |
| IAttribute vendorVersionAttribute = browserConnection.getRootDSE().getAttribute( "vendorVersion" ); //$NON-NLS-1$ |
| |
| if ( ( vendorVersionAttribute != null ) && ( vendorVersionAttribute.getValueSize() > 0 ) ) |
| { |
| detectedConnectionProperties.setVendorVersion( vendorVersionAttribute.getStringValue() ); |
| } |
| |
| IAttribute supportedControlAttribute = browserConnection.getRootDSE().getAttribute( "supportedControl" ); //$NON-NLS-1$ |
| |
| if ( ( supportedControlAttribute != null ) && ( supportedControlAttribute.getValueSize() > 0 ) ) |
| { |
| detectedConnectionProperties.setSupportedControls( Arrays.asList( supportedControlAttribute |
| .getStringValues() ) ); |
| } |
| |
| IAttribute supportedExtensionAttribute = browserConnection.getRootDSE().getAttribute( "supportedExtension" ); //$NON-NLS-1$ |
| |
| if ( ( supportedExtensionAttribute != null ) && ( supportedExtensionAttribute.getValueSize() > 0 ) ) |
| { |
| detectedConnectionProperties.setSupportedExtensions( Arrays.asList( supportedExtensionAttribute |
| .getStringValues() ) ); |
| } |
| |
| IAttribute supportedFeaturesAttribute = browserConnection.getRootDSE().getAttribute( "supportedFeatures" ); //$NON-NLS-1$ |
| |
| if ( ( supportedFeaturesAttribute != null ) && ( supportedFeaturesAttribute.getValueSize() > 0 ) ) |
| { |
| detectedConnectionProperties.setSupportedFeatures( Arrays.asList( supportedFeaturesAttribute |
| .getStringValues() ) ); |
| } |
| |
| detectedConnectionProperties |
| .setServerType( ServerTypeDetector.detectServerType( browserConnection.getRootDSE() ) ); |
| |
| ConnectionCorePlugin.getDefault().getConnectionManager() |
| .connectionUpdated( browserConnection.getConnection() ); |
| } |
| |
| |
| private static void initBaseEntry( IEntry entry, StudioProgressMonitor monitor ) |
| { |
| IBrowserConnection browserConnection = entry.getBrowserConnection(); |
| Dn dn = entry.getDn(); |
| |
| // search the entry |
| AliasDereferencingMethod derefAliasMethod = browserConnection.getAliasesDereferencingMethod(); |
| ReferralHandlingMethod handleReferralsMethod = browserConnection.getReferralsHandlingMethod(); |
| ISearch search = new Search( null, browserConnection, dn, ISearch.FILTER_TRUE, ISearch.NO_ATTRIBUTES, |
| SearchScope.OBJECT, 1, 0, derefAliasMethod, handleReferralsMethod, true, null, false ); |
| SearchRunnable.searchAndUpdateModel( browserConnection, search, monitor ); |
| |
| ISearchResult[] results = search.getSearchResults(); |
| |
| if ( results != null && results.length == 1 ) |
| { |
| // add entry to Root DSE |
| ISearchResult result = results[0]; |
| entry = result.getEntry(); |
| browserConnection.getRootDSE().addChild( entry ); |
| } |
| else |
| { |
| // Dn exists in the Root DSE, but doesn't exist in directory |
| browserConnection.uncacheEntryRecursive( entry ); |
| } |
| } |
| |
| |
| private static IEntry[] getDirectoryMetadataEntries( IBrowserConnection browserConnection, |
| String metadataAttributeName ) |
| { |
| List<Dn> metadataEntryDnList = new ArrayList<Dn>(); |
| IAttribute attribute = browserConnection.getRootDSE().getAttribute( metadataAttributeName ); |
| |
| if ( attribute != null ) |
| { |
| String[] values = attribute.getStringValues(); |
| |
| for ( String dn : values ) |
| { |
| if ( dn != null && !"".equals( dn ) ) //$NON-NLS-1$ |
| { |
| try |
| { |
| metadataEntryDnList.add( new Dn( dn ) ); |
| } |
| catch ( LdapInvalidDnException e ) |
| { |
| } |
| } |
| } |
| } |
| |
| IEntry[] metadataEntries = new IEntry[metadataEntryDnList.size()]; |
| |
| for ( int i = 0; i < metadataEntryDnList.size(); i++ ) |
| { |
| Dn dn = metadataEntryDnList.get( i ); |
| metadataEntries[i] = browserConnection.getEntryFromCache( dn ); |
| |
| if ( metadataEntries[i] == null ) |
| { |
| metadataEntries[i] = new DirectoryMetadataEntry( dn, browserConnection ); |
| metadataEntries[i].setDirectoryEntry( true ); |
| browserConnection.cacheEntry( metadataEntries[i] ); |
| } |
| } |
| |
| return metadataEntries; |
| } |
| |
| |
| private static void searchRootDseEntries( IBrowserConnection browserConnection, Map<Dn, IEntry> rootDseEntries, |
| StudioProgressMonitor monitor ) |
| { |
| ISearch search = new Search( null, browserConnection, Dn.EMPTY_DN, ISearch.FILTER_TRUE, |
| ISearch.NO_ATTRIBUTES, SearchScope.ONELEVEL, 0, 0, Connection.AliasDereferencingMethod.NEVER, |
| Connection.ReferralHandlingMethod.IGNORE, false, null, false ); |
| SearchRunnable.searchAndUpdateModel( browserConnection, search, monitor ); |
| |
| ISearchResult[] results = search.getSearchResults(); |
| |
| if ( results != null ) |
| { |
| for ( ISearchResult searchResult : results ) |
| { |
| IEntry entry = searchResult.getEntry(); |
| rootDseEntries.put( entry.getDn(), entry ); |
| } |
| } |
| } |
| } |