/*
* 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.connection.core.io.api;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.naming.NamingException;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.BasicControl;
import javax.naming.ldap.Control;
import javax.naming.ldap.PagedResultsResponseControl;
import org.apache.directory.api.ldap.codec.api.CodecControl;
import org.apache.directory.api.ldap.codec.api.LdapApiService;
import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
import org.apache.directory.api.ldap.model.cursor.CursorException;
import org.apache.directory.api.ldap.model.cursor.SearchCursor;
import org.apache.directory.api.ldap.model.entry.AttributeUtils;
import org.apache.directory.api.ldap.model.exception.LdapException;
import org.apache.directory.api.ldap.model.message.Referral;
import org.apache.directory.api.ldap.model.message.Response;
import org.apache.directory.api.ldap.model.message.SearchResultDone;
import org.apache.directory.api.ldap.model.message.SearchResultEntry;
import org.apache.directory.api.ldap.model.message.SearchResultReference;
import org.apache.directory.api.ldap.model.url.LdapUrl;
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.IJndiLogger;
import org.apache.directory.studio.connection.core.io.AbstractStudioNamingEnumeration;
import org.apache.directory.studio.connection.core.io.ConnectionWrapperUtils;
import org.apache.directory.studio.connection.core.io.StudioNamingEnumeration;
import org.apache.directory.studio.connection.core.io.jndi.ReferralsInfo;
import org.apache.directory.studio.connection.core.io.jndi.StudioSearchResult;
/**
* A naming enumeration that handles referrals itself.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class CursorStudioNamingEnumeration extends AbstractStudioNamingEnumeration
{
private SearchCursor cursor;
private SearchResultEntry currentSearchResultEntry;
private List<String> currentReferralUrlsList;
private StudioNamingEnumeration cursorNamingEnumeration;
private SearchResultDone searchResultDone;
// @TODO: By Alex: temporary fix until things are in order (needs to be fixed)
private LdapApiService codec = LdapApiServiceFactory.getSingleton();
/**
* Creates a new instance of ReferralNamingEnumeration.
*
* @param connection the connection
* @param cursor the search cursor
* @param searchBase the search base
* @param filter the filter
* @param searchControls the search controls
* @param aliasesDereferencingMethod the aliases dereferencing method
* @param referralsHandlingMethod the referrals handling method
* @param controls the LDAP controls
* @param monitor the progress monitor
* @param referralsInfo the referrals info
*/
public CursorStudioNamingEnumeration( Connection connection, SearchCursor cursor, String searchBase, String filter,
SearchControls searchControls, AliasDereferencingMethod aliasesDereferencingMethod,
ReferralHandlingMethod referralsHandlingMethod, Control[] controls, long requestNum,
StudioProgressMonitor monitor, ReferralsInfo referralsInfo )
{
super( connection, searchBase, filter, searchControls, aliasesDereferencingMethod, referralsHandlingMethod,
controls, requestNum, monitor, referralsInfo );
this.connection = connection;
this.cursor = cursor;
this.searchBase = searchBase;
this.filter = filter;
this.searchControls = searchControls;
this.aliasesDereferencingMethod = aliasesDereferencingMethod;
this.referralsHandlingMethod = referralsHandlingMethod;
this.controls = controls;
this.monitor = monitor;
if ( super.referralsInfo == null )
{
super.referralsInfo = new ReferralsInfo( false );
}
}
/**
* @see javax.naming.NamingEnumeration#close()
*/
public void close() throws NamingException
{
try
{
cursor.close();
}
catch ( Exception e )
{
throw new NamingException( e.getMessage() );
}
}
/**
* @see javax.naming.NamingEnumeration#hasMore()
*/
public boolean hasMore() throws NamingException
{
try
{
// Nulling the current search result entry
currentSearchResultEntry = null;
// Do we have another response in the cursor?
while ( cursor.next() )
{
Response currentResponse = cursor.get();
// Is it a search result entry?
if ( currentResponse instanceof SearchResultEntry )
{
currentSearchResultEntry = ( SearchResultEntry ) currentResponse;
// return true if the current response is a search result entry
return true;
}
// Is it a search result reference (ie. a referral)?
else if ( currentResponse instanceof SearchResultReference )
{
// Are we ignoring referrals?
if ( referralsHandlingMethod != ReferralHandlingMethod.IGNORE )
{
// Storing the referral for later use
referralsInfo.addReferral( ( ( SearchResultReference ) currentResponse ).getReferral() );
}
}
}
// Storing the search result done (if needed)
if ( searchResultDone == null )
{
searchResultDone = ( ( SearchCursor ) cursor ).getSearchResultDone();
Referral referral = searchResultDone.getLdapResult().getReferral();
if ( referralsHandlingMethod != ReferralHandlingMethod.IGNORE && referral != null )
{
// Storing the referral for later use
referralsInfo.addReferral( referral );
}
}
// Are we following referrals manually?
if ( referralsHandlingMethod == ReferralHandlingMethod.FOLLOW_MANUALLY )
{
// Checking the current referral's URLs list
if ( ( currentReferralUrlsList != null ) && ( currentReferralUrlsList.size() > 0 ) )
{
// return true if there's at least one referral LDAP URL to handle
return true;
}
// Checking the referrals list
if ( referralsInfo.hasMoreReferrals() )
{
// Getting the list of the next referral
currentReferralUrlsList = new ArrayList<String>( referralsInfo.getNextReferral().getLdapUrls() );
// return true if there's at least one referral LDAP URL to handle
return currentReferralUrlsList.size() > 0;
}
}
// Are we following referrals automatically?
else if ( referralsHandlingMethod == ReferralHandlingMethod.FOLLOW )
{
if ( ( cursorNamingEnumeration != null ) && ( cursorNamingEnumeration.hasMore() ) )
{
// return true if there's at least one more entry in the current cursor naming enumeration
return true;
}
if ( referralsInfo.hasMoreReferrals() )
{
Referral referral = referralsInfo.getNextReferral();
List<String> referralUrls = new ArrayList<String>( referral.getLdapUrls() );
LdapUrl url = new LdapUrl( referralUrls.get( 0 ) );
Connection referralConnection = ConnectionWrapperUtils.getReferralConnection( referral, monitor,
this );
if ( referralConnection != null )
{
String referralSearchBase = url.getDn() != null && !url.getDn().isEmpty()
? url.getDn().getName() : searchBase;
String referralFilter = url.getFilter() != null && url.getFilter().length() == 0
? url.getFilter() : filter;
SearchControls referralSearchControls = new SearchControls();
referralSearchControls.setSearchScope( url.getScope().getScope() > -1
? url.getScope().getScope() : searchControls.getSearchScope() );
referralSearchControls
.setReturningAttributes( url.getAttributes() != null && url.getAttributes().size() > 0
? url.getAttributes().toArray( new String[url.getAttributes().size()] )
: searchControls.getReturningAttributes() );
referralSearchControls.setCountLimit( searchControls.getCountLimit() );
referralSearchControls.setTimeLimit( searchControls.getTimeLimit() );
referralSearchControls.setDerefLinkFlag( searchControls.getDerefLinkFlag() );
referralSearchControls.setReturningObjFlag( searchControls.getReturningObjFlag() );
cursorNamingEnumeration = referralConnection.getConnectionWrapper().search( referralSearchBase,
referralFilter, referralSearchControls, aliasesDereferencingMethod, referralsHandlingMethod,
controls, monitor, referralsInfo );
return cursorNamingEnumeration.hasMore();
}
}
}
for ( IJndiLogger logger : ConnectionCorePlugin.getDefault().getJndiLoggers() )
{
logger.logSearchResultDone( connection, resultEntryCounter, requestNum, null );
}
return false;
}
catch ( CursorException | LdapException e )
{
throw new NamingException( e.getMessage() );
}
}
/**
* @see java.util.Enumeration#hasMoreElements()
*/
public boolean hasMoreElements()
{
throw new UnsupportedOperationException( "Call hasMore() instead of hasMoreElements() !" ); //$NON-NLS-1$
}
/**
* @see javax.naming.NamingEnumeration#next()
*/
public StudioSearchResult next() throws NamingException
{
try
{
if ( currentSearchResultEntry != null )
{
resultEntryCounter++;
SearchResult sr = new SearchResult( currentSearchResultEntry.getObjectName().toString(), null,
AttributeUtils.toAttributes( currentSearchResultEntry.getEntry() ) );
sr.setNameInNamespace( currentSearchResultEntry.getObjectName().toString() );
// Converting the SearchResult to a StudioSearchResult
StudioSearchResult ssr = new StudioSearchResult( sr, connection, false, null );
return ssr;
}
// Are we following referrals manually?
if ( referralsHandlingMethod == ReferralHandlingMethod.FOLLOW_MANUALLY )
{
// Checking the current referral's URLs list
if ( ( currentReferralUrlsList != null ) && ( currentReferralUrlsList.size() > 0 ) )
{
resultEntryCounter++;
// Building an LDAP URL from the the url
LdapUrl url = new LdapUrl( currentReferralUrlsList.remove( 0 ) );
// Building the search result
SearchResult searchResult = new SearchResult( url.getDn().getName(), null, new BasicAttributes(),
false );
searchResult.setNameInNamespace( url.getDn().getName() );
return new StudioSearchResult( searchResult, null, false, url );
}
}
// Are we following referrals automatically?
else if ( referralsHandlingMethod == ReferralHandlingMethod.FOLLOW )
{
resultEntryCounter++;
return new StudioSearchResult( cursorNamingEnumeration.next(), connection, true, null );
}
return null;
}
catch ( Exception e )
{
throw new NamingException( e.getMessage() );
}
}
/**
* @see java.util.Enumeration#nextElement()
*/
public StudioSearchResult nextElement()
{
throw new UnsupportedOperationException( "Call next() instead of nextElement() !" ); //$NON-NLS-1$
}
/**
* Gets the connection.
*
* @return the connection
*/
public Connection getConnection()
{
return connection;
}
/**
* Gets the response controls.
*
* @return the response controls, may be null
*
* @throws NamingException the naming exception
*/
public Control[] getResponseControls() throws NamingException
{
if ( searchResultDone != null )
{
Map<String, org.apache.directory.api.ldap.model.message.Control> controlsMap = searchResultDone
.getControls();
if ( ( controlsMap != null ) && ( controlsMap.size() > 0 ) )
{
return convertControls( controlsMap.values() );
}
}
return new Control[0];
}
/**
* Converts the controls.
*
* @param controls
* an array of controls
* @return
* an array of converted controls
*/
private Control[] convertControls( Collection<org.apache.directory.api.ldap.model.message.Control> controls )
{
if ( controls != null )
{
List<Control> convertedControls = new ArrayList<Control>();
for ( org.apache.directory.api.ldap.model.message.Control control : controls )
{
Control convertedControl = null;
CodecControl<? extends org.apache.directory.api.ldap.model.message.Control> wrapped = null;
if ( control instanceof CodecControl )
{
wrapped = ( org.apache.directory.api.ldap.codec.api.CodecControl<?> ) control;
}
else
{
wrapped = codec.newControl( control );
}
if ( PagedResultsResponseControl.OID.equals( control.getOid() ) )
{
// Special case for the PagedResultsResponseControl
try
{
convertedControl = new PagedResultsResponseControl( wrapped.getOid(), wrapped.isCritical(),
wrapped.getValue() );
}
catch ( IOException e )
{
convertedControl = new BasicControl( wrapped.getOid(), wrapped.isCritical(),
wrapped.getValue() );
}
}
else
{
// Default case
convertedControl = new BasicControl( wrapped.getOid(), wrapped.isCritical(), wrapped.getValue() );
}
convertedControls.add( convertedControl );
}
return convertedControls.toArray( new Control[0] );
}
else
{
return new Control[0];
}
}
}