blob: 11f25edb50244ccb3bb4ed95534b466d23f5db1c [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.server.core.trigger;
import org.apache.directory.server.core.DirectoryService;
import org.apache.directory.server.core.entry.ServerEntry;
import org.apache.directory.server.core.interceptor.BaseInterceptor;
import org.apache.directory.server.core.interceptor.InterceptorChain;
import org.apache.directory.server.core.interceptor.NextInterceptor;
import org.apache.directory.server.core.interceptor.context.AddOperationContext;
import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
import org.apache.directory.server.core.interceptor.context.LookupOperationContext;
import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext;
import org.apache.directory.server.core.interceptor.context.MoveOperationContext;
import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
import org.apache.directory.server.core.invocation.Invocation;
import org.apache.directory.server.core.invocation.InvocationStack;
import org.apache.directory.server.core.jndi.ServerLdapContext;
import org.apache.directory.server.core.partition.PartitionNexusProxy;
import org.apache.directory.server.core.sp.StoredProcEngine;
import org.apache.directory.server.core.sp.StoredProcEngineConfig;
import org.apache.directory.server.core.sp.StoredProcExecutionManager;
import org.apache.directory.server.core.sp.java.JavaStoredProcEngineConfig;
import org.apache.directory.server.core.subtree.SubentryInterceptor;
import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
import org.apache.directory.server.schema.registries.Registries;
import org.apache.directory.shared.ldap.constants.SchemaConstants;
import org.apache.directory.shared.ldap.entry.EntryAttribute;
import org.apache.directory.shared.ldap.entry.Value;
import org.apache.directory.shared.ldap.exception.LdapNamingException;
import org.apache.directory.shared.ldap.message.ResultCodeEnum;
import org.apache.directory.shared.ldap.name.LdapDN;
import org.apache.directory.shared.ldap.name.Rdn;
import org.apache.directory.shared.ldap.schema.NormalizerMappingResolver;
import org.apache.directory.shared.ldap.schema.OidNormalizer;
import org.apache.directory.shared.ldap.trigger.ActionTime;
import org.apache.directory.shared.ldap.trigger.LdapOperation;
import org.apache.directory.shared.ldap.trigger.TriggerSpecification;
import org.apache.directory.shared.ldap.trigger.TriggerSpecification.SPSpec;
import org.apache.directory.shared.ldap.trigger.TriggerSpecificationParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.naming.NamingException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* The Trigger Service based on the Trigger Specification.
*
* @org.apache.xbean.XBean
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev:$
*/
public class TriggerInterceptor extends BaseInterceptor
{
/** the logger for this class */
private static final Logger LOG = LoggerFactory.getLogger( TriggerInterceptor.class );
/** the entry trigger attribute string: entryTrigger */
private static final String ENTRY_TRIGGER_ATTR = "entryTriggerSpecification";
/** a triggerSpecCache that responds to add, delete, and modify attempts */
private TriggerSpecCache triggerSpecCache;
/** a normalizing Trigger Specification parser */
private TriggerSpecificationParser triggerParser;
/** the global registries */
private Registries registries;
/** */
private InterceptorChain chain;
/** whether or not this interceptor is activated */
private boolean enabled = true;
/** a Trigger Execution Authorizer */
private TriggerExecutionAuthorizer triggerExecutionAuthorizer = new SimpleTriggerExecutionAuthorizer();
private StoredProcExecutionManager manager;
/**
* Adds prescriptiveTrigger TriggerSpecificaitons to a collection of
* TriggerSpeficaitions by accessing the triggerSpecCache. The trigger
* specification cache is accessed for each trigger subentry associated
* with the entry.
* Note that subentries are handled differently: their parent, the administrative
* entry is accessed to determine the perscriptiveTriggers effecting the AP
* and hence the subentry which is considered to be in the same context.
*
* @param triggerSpecs the collection of trigger specifications to add to
* @param dn the normalized distinguished name of the entry
* @param entry the target entry that is considered as the trigger source
* @throws NamingException if there are problems accessing attribute values
* @param proxy the partition nexus proxy
*/
private void addPrescriptiveTriggerSpecs( List<TriggerSpecification> triggerSpecs, PartitionNexusProxy proxy,
LdapDN dn, ServerEntry entry ) throws NamingException
{
/*
* If the protected entry is a subentry, then the entry being evaluated
* for perscriptiveTriggerss is in fact the administrative entry. By
* substituting the administrative entry for the actual subentry the
* code below this "if" statement correctly evaluates the effects of
* perscriptiveTrigger on the subentry. Basically subentries are considered
* to be in the same naming context as their access point so the subentries
* effecting their parent entry applies to them as well.
*/
if ( entry.contains( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC ) )
{
LdapDN parentDn = ( LdapDN ) dn.clone();
parentDn.remove( dn.size() - 1 );
entry = proxy.lookup( new LookupOperationContext( registries, parentDn ), PartitionNexusProxy.LOOKUP_BYPASS );
}
EntryAttribute subentries = entry.get( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT );
if ( subentries == null )
{
return;
}
for ( Value<?> value:subentries )
{
String subentryDn = ( String ) value.get();
triggerSpecs.addAll( triggerSpecCache.getSubentryTriggerSpecs( subentryDn ) );
}
}
/**
* Adds the set of entryTriggers to a collection of trigger specifications.
* The entryTrigger is parsed and tuples are generated on they fly then
* added to the collection.
*
* @param triggerSpecs the collection of trigger specifications to add to
* @param entry the target entry that is considered as the trigger source
* @throws NamingException if there are problems accessing attribute values
*/
private void addEntryTriggerSpecs( List<TriggerSpecification> triggerSpecs, ServerEntry entry ) throws NamingException
{
EntryAttribute entryTrigger = entry.get( ENTRY_TRIGGER_ATTR );
if ( entryTrigger == null )
{
return;
}
for ( Value<?> value:entryTrigger )
{
String triggerString = ( String ) value.get();
TriggerSpecification item;
try
{
item = triggerParser.parse( triggerString );
}
catch ( ParseException e )
{
String msg = "failed to parse entryTrigger: " + triggerString;
LOG.error( msg, e );
throw new LdapNamingException( msg, ResultCodeEnum.OPERATIONS_ERROR );
}
triggerSpecs.add( item );
}
}
/**
* Return a selection of trigger specifications for a certain type of trigger action time.
*
* @note This method serves as an extion point for new Action Time types.
*
* @param triggerSpecs the trigger specifications
* @param ldapOperation the ldap operation being performed
* @return the set of trigger specs for a trigger action
*/
public Map<ActionTime, List<TriggerSpecification>> getActionTimeMappedTriggerSpecsForOperation( List<TriggerSpecification> triggerSpecs, LdapOperation ldapOperation )
{
List<TriggerSpecification> afterTriggerSpecs = new ArrayList<TriggerSpecification>();
Map<ActionTime, List<TriggerSpecification>> triggerSpecMap = new HashMap<ActionTime, List<TriggerSpecification>>();
for ( TriggerSpecification triggerSpec : triggerSpecs )
{
if ( triggerSpec.getLdapOperation().equals( ldapOperation ) )
{
if ( triggerSpec.getActionTime().equals( ActionTime.AFTER ) )
{
afterTriggerSpecs.add( triggerSpec );
}
else
{
}
}
}
triggerSpecMap.put( ActionTime.AFTER, afterTriggerSpecs );
return triggerSpecMap;
}
////////////////////////////////////////////////////////////////////////////
// Interceptor Overrides
////////////////////////////////////////////////////////////////////////////
public void init( DirectoryService directoryService ) throws NamingException
{
super.init( directoryService );
registries = directoryService.getRegistries();
triggerSpecCache = new TriggerSpecCache( directoryService );
final AttributeTypeRegistry attrRegistry = directoryService.getRegistries().getAttributeTypeRegistry();
triggerParser = new TriggerSpecificationParser
( new NormalizerMappingResolver()
{
public Map<String, OidNormalizer> getNormalizerMapping() throws NamingException
{
return attrRegistry.getNormalizerMapping();
}
}
);
chain = directoryService.getInterceptorChain();
//StoredProcEngineConfig javaxScriptSPEngineConfig = new JavaxStoredProcEngineConfig();
StoredProcEngineConfig javaSPEngineConfig = new JavaStoredProcEngineConfig();
List<StoredProcEngineConfig> spEngineConfigs = new ArrayList<StoredProcEngineConfig>();
//spEngineConfigs.add( javaxScriptSPEngineConfig );
spEngineConfigs.add( javaSPEngineConfig );
String spContainer = "ou=Stored Procedures,ou=system";
manager = new StoredProcExecutionManager( spContainer, spEngineConfigs );
this.enabled = true; // TODO: Get this from the configuration if needed.
}
public void add( NextInterceptor next, AddOperationContext addContext ) throws NamingException
{
LdapDN name = addContext.getDn();
ServerEntry entry = addContext.getEntry();
// Bypass trigger handling if the service is disabled.
if ( !enabled )
{
next.add( addContext );
return;
}
// Gather supplementary data.
Invocation invocation = InvocationStack.getInstance().peek();
PartitionNexusProxy proxy = invocation.getProxy();
ServerLdapContext callerRootCtx = ( ServerLdapContext ) ( ( ServerLdapContext ) invocation.getCaller() ).getRootContext();
StoredProcedureParameterInjector injector = new AddStoredProcedureParameterInjector( invocation, name, entry );
// Gather Trigger Specifications which apply to the entry being added.
List<TriggerSpecification> triggerSpecs = new ArrayList<TriggerSpecification>();
addPrescriptiveTriggerSpecs( triggerSpecs, proxy, name, entry );
/**
* NOTE: We do not handle entryTriggerSpecs for ADD operation.
*/
Map<ActionTime, List<TriggerSpecification>> triggerMap = getActionTimeMappedTriggerSpecsForOperation( triggerSpecs, LdapOperation.ADD );
next.add( addContext );
triggerSpecCache.subentryAdded( name, entry );
// Fire AFTER Triggers.
List<TriggerSpecification> afterTriggerSpecs = triggerMap.get( ActionTime.AFTER );
executeTriggers( afterTriggerSpecs, injector, callerRootCtx );
}
public void delete( NextInterceptor next, DeleteOperationContext deleteContext ) throws NamingException
{
LdapDN name = deleteContext.getDn();
// Bypass trigger handling if the service is disabled.
if ( !enabled )
{
next.delete( deleteContext );
return;
}
// Gather supplementary data.
Invocation invocation = InvocationStack.getInstance().peek();
PartitionNexusProxy proxy = invocation.getProxy();
ServerEntry deletedEntry = proxy.lookup( new LookupOperationContext( registries, name ), PartitionNexusProxy.LOOKUP_BYPASS );
ServerLdapContext callerRootCtx = ( ServerLdapContext ) ( ( ServerLdapContext ) invocation.getCaller() ).getRootContext();
StoredProcedureParameterInjector injector = new DeleteStoredProcedureParameterInjector( registries, invocation, name );
// Gather Trigger Specifications which apply to the entry being deleted.
List<TriggerSpecification> triggerSpecs = new ArrayList<TriggerSpecification>();
addPrescriptiveTriggerSpecs( triggerSpecs, proxy, name, deletedEntry );
addEntryTriggerSpecs( triggerSpecs, deletedEntry );
Map<ActionTime, List<TriggerSpecification>> triggerMap = getActionTimeMappedTriggerSpecsForOperation( triggerSpecs, LdapOperation.DELETE );
next.delete( deleteContext );
triggerSpecCache.subentryDeleted( name, deletedEntry );
// Fire AFTER Triggers.
List<TriggerSpecification> afterTriggerSpecs = triggerMap.get( ActionTime.AFTER );
executeTriggers( afterTriggerSpecs, injector, callerRootCtx );
}
public void modify( NextInterceptor next, ModifyOperationContext opContext ) throws NamingException
{
// Bypass trigger handling if the service is disabled.
if ( !enabled )
{
next.modify( opContext );
return;
}
LdapDN normName = opContext.getDn();
// Gather supplementary data.
Invocation invocation = InvocationStack.getInstance().peek();
PartitionNexusProxy proxy = invocation.getProxy();
ServerEntry modifiedEntry = proxy.lookup( new LookupOperationContext( registries, normName ), PartitionNexusProxy.LOOKUP_BYPASS );
ServerLdapContext callerRootCtx = ( ServerLdapContext ) ( ( ServerLdapContext ) invocation.getCaller() ).getRootContext();
StoredProcedureParameterInjector injector = new ModifyStoredProcedureParameterInjector( invocation, opContext );
// Gather Trigger Specifications which apply to the entry being modified.
List<TriggerSpecification> triggerSpecs = new ArrayList<TriggerSpecification>();
addPrescriptiveTriggerSpecs( triggerSpecs, proxy, normName, modifiedEntry );
addEntryTriggerSpecs( triggerSpecs, modifiedEntry );
Map<ActionTime, List<TriggerSpecification>> triggerMap = getActionTimeMappedTriggerSpecsForOperation( triggerSpecs, LdapOperation.MODIFY );
next.modify( opContext );
triggerSpecCache.subentryModified( opContext, modifiedEntry );
// Fire AFTER Triggers.
List<TriggerSpecification> afterTriggerSpecs = triggerMap.get( ActionTime.AFTER );
executeTriggers( afterTriggerSpecs, injector, callerRootCtx );
}
public void rename( NextInterceptor next, RenameOperationContext renameContext ) throws NamingException
{
LdapDN name = renameContext.getDn();
Rdn newRdn = renameContext.getNewRdn();
boolean deleteOldRn = renameContext.getDelOldDn();
// Bypass trigger handling if the service is disabled.
if ( !enabled )
{
next.rename( renameContext );
return;
}
// Gather supplementary data.
Invocation invocation = InvocationStack.getInstance().peek();
PartitionNexusProxy proxy = invocation.getProxy();
ServerEntry renamedEntry = proxy.lookup( new LookupOperationContext( registries, name ), PartitionNexusProxy.LOOKUP_BYPASS );
ServerLdapContext callerRootCtx = ( ServerLdapContext ) ( ( ServerLdapContext ) invocation.getCaller() ).getRootContext();
LdapDN oldRDN = new LdapDN( name.getRdn().getUpName() );
LdapDN oldSuperiorDN = ( LdapDN ) name.clone();
oldSuperiorDN.remove( oldSuperiorDN.size() - 1 );
LdapDN newSuperiorDN = ( LdapDN ) oldSuperiorDN.clone();
LdapDN oldDN = ( LdapDN ) name.clone();
LdapDN newDN = ( LdapDN ) name.clone();
newDN.add( newRdn );
StoredProcedureParameterInjector injector = new ModifyDNStoredProcedureParameterInjector(
invocation, deleteOldRn, oldRDN, newRdn, oldSuperiorDN, newSuperiorDN, oldDN, newDN );
// Gather Trigger Specifications which apply to the entry being renamed.
List<TriggerSpecification> triggerSpecs = new ArrayList<TriggerSpecification>();
addPrescriptiveTriggerSpecs( triggerSpecs, proxy, name, renamedEntry );
addEntryTriggerSpecs( triggerSpecs, renamedEntry );
Map<ActionTime, List<TriggerSpecification>> triggerMap = getActionTimeMappedTriggerSpecsForOperation( triggerSpecs, LdapOperation.MODIFYDN_RENAME );
next.rename( renameContext );
triggerSpecCache.subentryRenamed( name, newDN );
// Fire AFTER Triggers.
List<TriggerSpecification> afterTriggerSpecs = triggerMap.get( ActionTime.AFTER );
executeTriggers( afterTriggerSpecs, injector, callerRootCtx );
}
public void moveAndRename( NextInterceptor next, MoveAndRenameOperationContext moveAndRenameContext ) throws NamingException
{
LdapDN oriChildName = moveAndRenameContext.getDn();
LdapDN parent = moveAndRenameContext.getParent();
Rdn newRdn = moveAndRenameContext.getNewRdn();
boolean deleteOldRn = moveAndRenameContext.getDelOldDn();
// Bypass trigger handling if the service is disabled.
if ( !enabled )
{
next.moveAndRename( moveAndRenameContext );
return;
}
// Gather supplementary data.
Invocation invocation = InvocationStack.getInstance().peek();
PartitionNexusProxy proxy = invocation.getProxy();
ServerEntry movedEntry = proxy.lookup( new LookupOperationContext( registries, oriChildName ), PartitionNexusProxy.LOOKUP_BYPASS );
ServerLdapContext callerRootCtx = ( ServerLdapContext ) ( ( ServerLdapContext ) invocation.getCaller() ).getRootContext();
LdapDN oldRDN = new LdapDN( oriChildName.getRdn().getUpName() );
LdapDN oldSuperiorDN = ( LdapDN ) oriChildName.clone();
oldSuperiorDN.remove( oldSuperiorDN.size() - 1 );
LdapDN newSuperiorDN = ( LdapDN ) parent.clone();
LdapDN oldDN = ( LdapDN ) oriChildName.clone();
LdapDN newDN = ( LdapDN ) parent.clone();
newDN.add( newRdn.getUpName() );
StoredProcedureParameterInjector injector = new ModifyDNStoredProcedureParameterInjector(
invocation, deleteOldRn, oldRDN, newRdn, oldSuperiorDN, newSuperiorDN, oldDN, newDN );
// Gather Trigger Specifications which apply to the entry being exported.
List<TriggerSpecification> exportTriggerSpecs = new ArrayList<TriggerSpecification>();
addPrescriptiveTriggerSpecs( exportTriggerSpecs, proxy, oriChildName, movedEntry );
addEntryTriggerSpecs( exportTriggerSpecs, movedEntry );
// Get the entry again without operational attributes
// because access control subentry operational attributes
// will not be valid at the new location.
// This will certainly be fixed by the SubentryInterceptor,
// but after this service.
ServerEntry importedEntry = proxy.lookup( new LookupOperationContext( registries, oriChildName ), PartitionNexusProxy.LOOKUP_EXCLUDING_OPR_ATTRS_BYPASS );
// As the target entry does not exist yet and so
// its subentry operational attributes are not there,
// we need to construct an entry to represent it
// at least with minimal requirements which are object class
// and access control subentry operational attributes.
SubentryInterceptor subentryInterceptor = ( SubentryInterceptor ) chain.get( SubentryInterceptor.class.getName() );
ServerEntry fakeImportedEntry = subentryInterceptor.getSubentryAttributes( newDN, importedEntry );
for ( EntryAttribute attribute:importedEntry )
{
fakeImportedEntry.put( attribute );
}
// Gather Trigger Specifications which apply to the entry being imported.
// Note: Entry Trigger Specifications are not valid for Import.
List<TriggerSpecification> importTriggerSpecs = new ArrayList<TriggerSpecification>();
addPrescriptiveTriggerSpecs( importTriggerSpecs, proxy, newDN, fakeImportedEntry );
Map<ActionTime, List<TriggerSpecification>> exportTriggerMap = getActionTimeMappedTriggerSpecsForOperation( exportTriggerSpecs, LdapOperation.MODIFYDN_EXPORT );
Map<ActionTime, List<TriggerSpecification>> importTriggerMap = getActionTimeMappedTriggerSpecsForOperation( importTriggerSpecs, LdapOperation.MODIFYDN_IMPORT );
next.moveAndRename( moveAndRenameContext );
triggerSpecCache.subentryRenamed( oldDN, newDN );
// Fire AFTER Triggers.
List<TriggerSpecification> afterExportTriggerSpecs = exportTriggerMap.get( ActionTime.AFTER );
List<TriggerSpecification> afterImportTriggerSpecs = importTriggerMap.get( ActionTime.AFTER );
executeTriggers( afterExportTriggerSpecs, injector, callerRootCtx );
executeTriggers( afterImportTriggerSpecs, injector, callerRootCtx );
}
public void move( NextInterceptor next, MoveOperationContext moveContext ) throws NamingException
{
// Bypass trigger handling if the service is disabled.
if ( !enabled )
{
next.move( moveContext );
return;
}
LdapDN oriChildName = moveContext.getDn();
LdapDN newParentName = moveContext.getParent();
// Gather supplementary data.
Invocation invocation = InvocationStack.getInstance().peek();
PartitionNexusProxy proxy = invocation.getProxy();
ServerEntry movedEntry = proxy.lookup( new LookupOperationContext( registries, oriChildName ), PartitionNexusProxy.LOOKUP_BYPASS );
ServerLdapContext callerRootCtx = ( ServerLdapContext ) ( ( ServerLdapContext ) invocation.getCaller() ).getRootContext();
LdapDN oldRDN = new LdapDN( oriChildName.getRdn().getUpName() );
Rdn newRDN = new Rdn( oriChildName.getRdn().getUpName() );
LdapDN oldSuperiorDN = ( LdapDN ) oriChildName.clone();
oldSuperiorDN.remove( oldSuperiorDN.size() - 1 );
LdapDN newSuperiorDN = ( LdapDN ) newParentName.clone();
LdapDN oldDN = ( LdapDN ) oriChildName.clone();
LdapDN newDN = ( LdapDN ) newParentName.clone();
newDN.add( newRDN.getUpName() );
StoredProcedureParameterInjector injector = new ModifyDNStoredProcedureParameterInjector(
invocation, false, oldRDN, newRDN, oldSuperiorDN, newSuperiorDN, oldDN, newDN );
// Gather Trigger Specifications which apply to the entry being exported.
List<TriggerSpecification> exportTriggerSpecs = new ArrayList<TriggerSpecification>();
addPrescriptiveTriggerSpecs( exportTriggerSpecs, proxy, oriChildName, movedEntry );
addEntryTriggerSpecs( exportTriggerSpecs, movedEntry );
// Get the entry again without operational attributes
// because access control subentry operational attributes
// will not be valid at the new location.
// This will certainly be fixed by the SubentryInterceptor,
// but after this service.
ServerEntry importedEntry = proxy.lookup( new LookupOperationContext( registries, oriChildName ), PartitionNexusProxy.LOOKUP_EXCLUDING_OPR_ATTRS_BYPASS );
// As the target entry does not exist yet and so
// its subentry operational attributes are not there,
// we need to construct an entry to represent it
// at least with minimal requirements which are object class
// and access control subentry operational attributes.
SubentryInterceptor subentryInterceptor = ( SubentryInterceptor ) chain.get( SubentryInterceptor.class.getName() );
ServerEntry fakeImportedEntry = subentryInterceptor.getSubentryAttributes( newDN, importedEntry );
for ( EntryAttribute attribute:importedEntry )
{
fakeImportedEntry.put( attribute );
}
// Gather Trigger Specifications which apply to the entry being imported.
// Note: Entry Trigger Specifications are not valid for Import.
List<TriggerSpecification> importTriggerSpecs = new ArrayList<TriggerSpecification>();
addPrescriptiveTriggerSpecs( importTriggerSpecs, proxy, newDN, fakeImportedEntry );
Map<ActionTime, List<TriggerSpecification>> exportTriggerMap = getActionTimeMappedTriggerSpecsForOperation( exportTriggerSpecs, LdapOperation.MODIFYDN_EXPORT );
Map<ActionTime, List<TriggerSpecification>> importTriggerMap = getActionTimeMappedTriggerSpecsForOperation( importTriggerSpecs, LdapOperation.MODIFYDN_IMPORT );
next.move( moveContext );
triggerSpecCache.subentryRenamed( oldDN, newDN );
// Fire AFTER Triggers.
List<TriggerSpecification> afterExportTriggerSpecs = exportTriggerMap.get( ActionTime.AFTER );
List<TriggerSpecification> afterImportTriggerSpecs = importTriggerMap.get( ActionTime.AFTER );
executeTriggers( afterExportTriggerSpecs, injector, callerRootCtx );
executeTriggers( afterImportTriggerSpecs, injector, callerRootCtx );
}
////////////////////////////////////////////////////////////////////////////
// Utility Methods
////////////////////////////////////////////////////////////////////////////
private Object executeTriggers( List<TriggerSpecification> triggerSpecs, StoredProcedureParameterInjector injector, ServerLdapContext callerRootCtx ) throws NamingException
{
Object result = null;
for ( TriggerSpecification triggerSpec : triggerSpecs )
{
// TODO: Replace the Authorization Code with a REAL one.
if ( triggerExecutionAuthorizer.hasPermission() )
{
/**
* If there is only one Trigger to be executed, this assignment
* will make sense (as in INSTEADOF search Triggers).
*/
result = executeTrigger( triggerSpec, injector, callerRootCtx );
}
}
/**
* If only one Trigger has been executed, returning its result
* can make sense (as in INSTEADOF Search Triggers).
*/
return result;
}
private Object executeTrigger( TriggerSpecification tsec, StoredProcedureParameterInjector injector, ServerLdapContext callerRootCtx ) throws NamingException
{
List<Object> returnValues = new ArrayList<Object>();
List<SPSpec> spSpecs = tsec.getSPSpecs();
for ( SPSpec spSpec : spSpecs )
{
List<Object> arguments = new ArrayList<Object>();
arguments.addAll( injector.getArgumentsToInject( registries, spSpec.getParameters() ) );
Object[] values = arguments.toArray();
Object returnValue = executeProcedure( callerRootCtx, spSpec.getName(), values );
returnValues.add( returnValue );
}
return returnValues;
}
private Object executeProcedure( ServerLdapContext ctx, String procedure, Object[] values ) throws NamingException
{
try
{
ServerEntry spUnit = manager.findStoredProcUnit( ctx, procedure, registries );
StoredProcEngine engine = manager.getStoredProcEngineInstance( spUnit );
return engine.invokeProcedure( ctx, procedure, values );
}
catch ( NamingException e )
{
LdapNamingException lne = new LdapNamingException( ResultCodeEnum.OTHER );
lne.setRootCause( e );
throw lne;
}
}
}