/*
* 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.jndi;
import java.util.ArrayList;
import java.util.List;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.PartialResultException;
import javax.naming.ReferralException;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control;
import javax.naming.ldap.LdapContext;
import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
import org.apache.directory.api.ldap.model.message.Referral;
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;
/**
* A naming enumeration that handles referrals itself.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class JndiStudioNamingEnumeration extends AbstractStudioNamingEnumeration
{
private final LdapContext ctx;
private NamingEnumeration<SearchResult> initialNamingEnumeration;
private NamingEnumeration<SearchResult> delegate;
private NamingException initialReferralException;
/**
* Creates a new instance of ReferralNamingEnumeration.
*
* @param connection the connection
* @param ctx the JNDI context
* @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 JndiStudioNamingEnumeration( Connection connection, LdapContext ctx,
NamingEnumeration<SearchResult> delegate,
NamingException initialReferralException, 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.ctx = ctx;
this.initialNamingEnumeration = delegate;
this.delegate = delegate;
this.initialReferralException = initialReferralException;
this.requestNum = requestNum;
}
/**
* @see javax.naming.NamingEnumeration#close()
*/
public void close() throws NamingException
{
delegate.close();
}
/**
* @see javax.naming.NamingEnumeration#hasMore()
*/
public boolean hasMore() throws NamingException
{
NamingException logResultDoneException = null;
boolean done = false;
while ( true )
{
try
{
if ( initialReferralException != null )
{
NamingException referralException = initialReferralException;
initialReferralException = null;
throw referralException;
}
boolean hasMore = delegate != null && delegate.hasMore();
if ( !hasMore && !done && referralsInfo != null && referralsInfo.hasMoreReferrals() )
{
done = checkReferral();
}
else
{
done = !hasMore;
return hasMore;
}
}
catch ( PartialResultException pre )
{
done = true;
logResultDoneException = pre;
// ignore exception if referrals handling method is IGNORE
// report exception if referrals handling method is FOLLOW or MANGAGE
if ( referralsHandlingMethod == ReferralHandlingMethod.IGNORE )
{
return false;
}
else
{
throw pre;
}
}
catch ( ReferralException re )
{
done = true;
logResultDoneException = re;
if ( referralsInfo == null )
{
referralsInfo = new ReferralsInfo( false );
}
referralsInfo = JNDIConnectionWrapper.handleReferralException( re, referralsInfo );
if ( referralsInfo.hasMoreReferrals() )
{
logResultDoneException = null;
done = checkReferral();
}
}
catch ( NamingException ne )
{
done = true;
logResultDoneException = ne;
throw ne;
}
finally
{
if ( done )
{
for ( IJndiLogger logger : ConnectionCorePlugin.getDefault().getJndiLoggers() )
{
logger.logSearchResultDone( connection, resultEntryCounter, requestNum, logResultDoneException );
}
}
}
}
}
/**
* @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
{
StudioSearchResult studioSearchResult = null;
NamingException namingException = null;
try
{
SearchResult searchResult = delegate.next();
resultEntryCounter++;
if ( searchResult instanceof StudioSearchResult )
{
studioSearchResult = ( StudioSearchResult ) searchResult;
}
else
{
studioSearchResult = new StudioSearchResult( searchResult, getConnection(), referralsInfo != null, null );
}
return studioSearchResult;
}
catch ( NamingException ne )
{
namingException = ne;
throw ne;
}
finally
{
if ( delegate == initialNamingEnumeration )
{
for ( IJndiLogger logger : ConnectionCorePlugin.getDefault().getJndiLoggers() )
{
logger.logSearchResultEntry( connection, studioSearchResult, requestNum, namingException );
}
}
}
}
/**
* @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()
{
if ( delegate instanceof JndiStudioNamingEnumeration )
{
return ( ( JndiStudioNamingEnumeration ) delegate ).getConnection();
}
else
{
return connection;
}
}
/**
* Gets the response controls.
*
* @return the response controls, may be null
*
* @throws NamingException the naming exception
*/
public Control[] getResponseControls() throws NamingException
{
return ctx != null ? ctx.getResponseControls() : null;
}
private boolean checkReferral() throws NamingException
{
try
{
boolean done = false;
// ignore exception if referrals handling method is IGNORE
// follow referral if referrals handling method is FOLLOW
// follow manually if referrals handling method is FOLLOW_MANUALLY
if ( referralsHandlingMethod == ReferralHandlingMethod.IGNORE )
{
done = true;
delegate = null;
}
else if ( referralsHandlingMethod == ReferralHandlingMethod.FOLLOW_MANUALLY )
{
delegate = new NamingEnumeration<SearchResult>()
{
List<String> urls;
private NamingEnumeration<SearchResult> init() throws NamingException
{
urls = new ArrayList<String>();
{
while ( referralsInfo.hasMoreReferrals() )
{
Referral referral = referralsInfo.getNextReferral();
for ( IJndiLogger logger : ConnectionCorePlugin.getDefault().getJndiLoggers() )
{
logger.logSearchResultReference( connection, referral, referralsInfo, requestNum,
null );
}
urls.addAll( referral.getLdapUrls() );
}
}
return this;
}
public SearchResult nextElement()
{
throw new UnsupportedOperationException( "Call next() instead of nextElement() !" ); //$NON-NLS-1$
}
public boolean hasMoreElements()
{
throw new UnsupportedOperationException( "Call hasMore() instead of hasMoreElements() !" ); //$NON-NLS-1$
}
public SearchResult next() throws NamingException
{
try
{
LdapUrl url = new LdapUrl( urls.remove( 0 ) );
SearchResult searchResult = new SearchResult( url.getDn().getName(), null,
new BasicAttributes(),
false );
searchResult.setNameInNamespace( url.getDn().getName() );
StudioSearchResult ssr = new StudioSearchResult( searchResult, null, false, url );
return ssr;
}
catch ( LdapURLEncodingException e )
{
throw new NamingException( e.getMessage() );
}
}
public boolean hasMore() throws NamingException
{
return !urls.isEmpty();
}
public void close() throws NamingException
{
urls.clear();
referralsInfo = null;
}
}.init();
}
else if ( referralsHandlingMethod == ReferralHandlingMethod.FOLLOW )
{
Referral referral = referralsInfo.getNextReferral();
for ( IJndiLogger logger : ConnectionCorePlugin.getDefault().getJndiLoggers() )
{
logger.logSearchResultReference( connection, referral, referralsInfo, requestNum, null );
}
List<String> urls = new ArrayList<String>( referral.getLdapUrls() );
LdapUrl url = new LdapUrl( urls.get( 0 ) );
Connection referralConnection = ConnectionWrapperUtils.getReferralConnection( referral, monitor, this );
if ( referralConnection != null )
{
done = false;
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() );
delegate = referralConnection.getConnectionWrapper().search( referralSearchBase, referralFilter,
referralSearchControls, aliasesDereferencingMethod, referralsHandlingMethod, controls, monitor,
referralsInfo );
}
else
{
done = true;
delegate = null;
}
}
return done;
}
catch ( LdapURLEncodingException e )
{
return false;
}
}
}