blob: 12d7d39cec5318ba7e8215408544bc7bcdb41d96 [file] [log] [blame]
package org.apache.ldap.server.jndi;
import java.util.Map;
import java.util.Stack;
import java.util.Iterator;
import java.util.EmptyStackException;
import javax.naming.Name;
import javax.naming.Context;
import javax.naming.ldap.LdapContext;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.ModificationItem;
import org.apache.ldap.common.filter.ExprNode;
import org.apache.ldap.server.PartitionNexus;
import org.apache.ldap.server.db.Database;
import org.apache.ldap.server.ContextPartition;
import org.apache.ldap.server.invocation.Invocation;
/**
* Aspect coupling the JNDI provider with the nexus thereby facilitating the
* injection of interceptors between calls to the nexus from the JNDI.
*
* @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
* @author $Author$
* @version $Revision$
*/
public aspect ProviderNexusAspect
{
// ------------------------------------------------------------------------
// M E M B E R I N T R O D U C T I O N S
// ------------------------------------------------------------------------
/**
* Adds a static ThreadLocal for a Stack of LdapContexts representing nested
* backend nexus calls made by the DefaultContextFactoryContext's contexts within the same
* thread of execution.
*/
private static ThreadLocal DefaultContextFactoryContext.s_contextStacks = new ThreadLocal();
// ------------------------------------------------------------------------
// M E T H O D I N T R O D U C T I O N S
// ------------------------------------------------------------------------
/**
* Pushes a calling LdapContext onto the Thread's ThreadLocal Stack before
* calls are made on the nexus within the LdapContext code.
*
* @param context the caller or the current context for the nexus call
*/
private static void DefaultContextFactoryContext.push( LdapContext context )
{
Stack stack = ( Stack ) s_contextStacks.get();
if ( null == stack )
{
stack = new Stack();
s_contextStacks.set( stack );
}
stack.push( context );
}
/**
* Pops the head of the Thread's ThreadLocal Stack after calls complete on
* the nexus within the LdapContext code.
*
* @return the last LdapContext or caller
*/
private static LdapContext DefaultContextFactoryContext.pop()
{
Stack stack = ( Stack ) s_contextStacks.get();
if ( null == stack )
{
throw new EmptyStackException();
}
return ( LdapContext ) stack.pop();
}
/**
* Peeks at the head of the Thread's ThreadLocal Stack.
*
* @return the current LdapContext or caller
*/
static LdapContext DefaultContextFactoryContext.peek()
{
Stack stack = ( Stack ) s_contextStacks.get();
if ( null == stack )
{
throw new EmptyStackException();
}
return ( LdapContext ) stack.peek();
}
// ------------------------------------------------------------------------
// A S P E C T M E T H O D S
// ------------------------------------------------------------------------
/**
* Gets a shallow copy of the context stack.
*
* @return the context Stack.
*/
private static Stack getContextStack()
{
Stack stack = ( Stack ) DefaultContextFactoryContext.s_contextStacks.get();
if ( stack == null )
{
return null;
}
return ( Stack ) stack.clone();
}
// ------------------------------------------------------------------------
// P O I N T C U T S
// ------------------------------------------------------------------------
/**
* Selects join points on any public method calls made on the BackendNexus
* interface implementing proxy from code executing within an LdapContext
* caller. Makes sure that Proxy methods (static) and the
* getInvokationHandler() do not get selected.
*
* @param caller the calling LdapContext.
*/
pointcut jndiNexusCalls( Context caller ):
this( caller ) &&
! this( ContextPartition ) &&
target( PartitionNexus ) &&
! target( Database ) &&
(
// these are for the ContextPartition interface methods
// not used anymore since it was moved to RootNexus class
// call( public Attributes getRootDSE() ) ||
call( public Name getMatchedDn( Name, boolean ) ) ||
call( public Name getSuffix( Name, boolean ) ) ||
call( public Iterator listSuffixes( boolean ) ) ||
call( public Attributes lookup( Name, String [] ) ) ||
// these are for BackingStore interface methods
call( public void add( String, Name, Attributes ) ) ||
call( public void delete( Name ) ) ||
call( public boolean hasEntry( Name ) ) ||
call( public boolean isSuffix( Name ) ) ||
call( public NamingEnumeration list( Name ) ) ||
call( public Attributes lookup( Name ) ) ||
call( public void modify( Name, int, Attributes ) ) ||
call( public void modify( Name, ModificationItem [] ) ) ||
call( public void modifyRn( Name, String, boolean ) ) ||
call( public void move( Name, Name ) ) ||
call( public void move( Name, Name, String, boolean ) ) ||
call( public NamingEnumeration
search( Name, Map, ExprNode, SearchControls ) ) );
/**
* Selects join points where the Invokation default constructor executes.
*
* @param invocation the Invocation instantiated
*/
pointcut newInvocation( Invocation invocation ):
target( invocation ) &&
execution( Invocation.new(..) );
// ------------------------------------------------------------------------
// A D V I C E
// ------------------------------------------------------------------------
before( Context caller ):
jndiNexusCalls( caller )
{
DefaultContextFactoryContext.push( ( LdapContext ) caller );
//System.out.println( "\npushed " + caller + " for join point "
// + thisJoinPoint );
}
after( Context caller ):
jndiNexusCalls( caller )
{
LdapContext head = DefaultContextFactoryContext.pop();
//System.out.println( "\npopped " + caller + " for join point "
// + thisJoinPoint );
}
after( Invocation invocation ):
newInvocation( invocation )
{
invocation.setContextStack( getContextStack() );
//System.out.println(
// "\nJust set the context stack on a new Invocation: "
// + thisJoinPoint );
}
}