Just for the record, which ApacheDS version is this based on ?

On 23/07/2019 18:00, Philipp Grigoryev wrote:
Hi Emmanuel,

Thank you for replying to my question and providing a thorough explanation. I 
tried some recipes based on your response (with partial success) and that’s my 
observations.

1) I have to deal with some legacy code developed by a guy who left our 
company, so I’m trying not to break things and introduce very granular changes 
for the same purpose

2) Directory Server created explicitly with the following code as an example:

DefaultDirectoryServiceFactory factory = new DefaultDirectoryServiceFactory()
factory.init(“xxx.ldapgw")

cs = new CacheService()
cs.initialize( null)

directoryService = factory.getDirectoryService()
directoryService.setShutdownHookEnabled(true)
directoryService.setAllowAnonymousAccess(ldapSettings.allowAnonymousAccess)

if ( ldapSettings.schemaLdif.length() > 0 ) {
     def fSchema = new File(ldapSettings.schemaLdif)
     if ( !fSchema.exists()) {
         throw new Exception("LDIF file does not exist:" + 
ldapSettings.schemaLdif)
     }
     auditLog.info "Loading Schemas${new 
LdifFileLoader(directoryService.getAdminSession(), fSchema, null).execute()}"
}


             directoryService.dnFactory = new DefaultDnFactory( 
directoryService.schemaManager, cs.getCache("dnCache"))

             // add our bind interceptor to the front of the list
             def interceptors = directoryService.getInterceptors()
             interceptors.add(0, bindInterceptor)

//            
interceptors.add(findNormalizationInterceptorPosition(interceptors) + 1, 
crudInterceptor)

             bindInterceptor.init(directoryService)

             directoryService.setInterceptors(interceptors)
             directoryService.addFirst(crudInterceptor)

             def adminSession = directoryService.getAdminSession()

             ldapServer = new LdapServer()
             ldapServer.directoryService = directoryService

...

So it’s not declarative like it’s shown in the online documentation, which I 
have to admit is quite outdated. Maybe there is a place where it’s in the most 
recent state?

As you can see from the file, there is a section related to interceptors, and 
while setting server up, I see that my interceptors is in the middle of the 
pack. I can also see that while doing “modify(opContext)” in my custom 
interceptor, where opContext would reflect total number of interceptors and 
current number (though still throwing NPE at next(opContext)). Nevertheless, I 
tried to grab the default config.ldif from downloaded DS archive and inserted a 
section related to interceptors into schemaLdif file. That didn’t really change 
anything for me. I think it might be related to the fact that I can’t see 
anything with Directory Browser under ou=config, after server is up. So would 
be really nice if you can direct me to how I can use config.ldif while setting 
the server up programmatically.

2) As you can see from the snippet, I tried to do .addFirst(crudInterceptor) 
and from a first glance it worked for me, no more NPE, my custom code works 
fine, but as you said, I’m not sure if that’s a right way or any complications 
can be right around the corner.

Please let me know your thoughts on those two topics.

Thank you,
Philipp

===================

Accordingly to what you posted on stackoverflow, the NPE is due to the
fact your interceptor does not know what is the next one to call:


      protected Interceptor getNextInterceptor( OperationContext
operationContext )
      {
          String currentInterceptor = operationContext.getNextInterceptor();

          if ( currentInterceptor.equals( "FINAL" ) )

Here, currentInterceptor is most certainly null.


Why is that ?

The operationContext (here, it's an instance of ModifyOperationContext)
contains a list of interceptors to call, and this list is computed when
the server is started by the DefaultDirectoryServer.gatherInterceptors()
private method. This method gets all the interceptors  that are
configured, and for each operation context, search for the associated
method using reflection (here, it willl search for the 'modify' method).
At the end, each OperationContext instance is stored in a Map associated
with the list of interceptors it may call ( this map is named
operationInterceptors). When a new operation starts (ie when a user send
a request to the server), it will get the list of interceptors to
process from this map (which can be modified dynamically, but that's
another story).

Anyway, the problem here is to be able to inject another interceptor and
to have it properly 'linked' so that when the operation fetch the next
interceptor, it finds it. This is all about registering the interceptor.
Currently, this is done by this method:

      private void addInterceptor( Interceptor interceptor, int position )

It adds an interceptor at a given position. The thing is that this
method is private, so it can't be called outside the
DefaultDirectoryServer class.

It's called at two other places:

- addFirst

- addLast

which are public methods. That means the only way to inject an
interceptor into the chain is to call one of those two methods (and as
it only add an interceptor at the end or at the beginning of the list,
it must be called  exactly at the right moment accordingly to the
expected position of the new interceptor in the chain. It also means you
don't really have a way to inject your interceptor in the middle of the
chain, because you don't have a way to control how this chain is created
(at least programatically).

The key here is to play with the server configuration. When the server
starts, it reads the config from a set of LDIF files and extract the
list of intercpeots - and the order in which they will be loaded - from
this configuration. It then creates a list of those interceptors, pass
it to the DefaultDirectoryServer instance using the setInterceptors()
method, then the initOperationsList() method is called, which create the
Map we mention before, with the proper intercaptor lists for each operation.

So you have to configure your system with a new LDIF like this one :


dn:
ads-interceptorId=|MyCRUDInterceptor|,ou=interceptors,ads-directoryServiceId=default,ou=config
objectclass: top
objectclass: ads-base
objectclass: ads-interceptor
ads-interceptororder: <NNN>
ads-interceptorclassname: xxx.company.ldapbridge.impl.MyCRUDInterceptor
ads-interceptorid: |MyCRUDInterceptor|
ads-enabled: TRUE

Note that the ads-interceptororder value (here, <NNN>) must be
consistent with the other interceptors' position, which means you will
have to change all the other orders if you inject your interceptor in
the middle.


Ok, this is how it works. It's not simple, and I hope I have been clear
enough... Please ask if you have any issue with what I explained !


I posted a question on StackOverflow with details of my implementation and a 
stack trace.
Not sure if I need to duplicate everything here, but will do if required. It’s 
my first
time posting into this mail list.
Here is the URL for my question on SO -> 
https://stackoverflow.com/questions/57150901/calling-nextmodifycontext-from-a-custom-interceptor-leads-to-nullpointerexcept
<https://stackoverflow.com/questions/57150901/calling-nextmodifycontext-from-a-custom-interceptor-leads-to-nullpointerexcept>
I’d appreciate any help or thoughts.



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@directory.apache.org
For additional commands, e-mail: users-h...@directory.apache.org

Reply via email to