[jira] [Comment Edited] (AXIS2-5721) Module engaged at the service level is used globally

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[jira] [Comment Edited] (AXIS2-5721) Module engaged at the service level is used globally

Adam Fordham (Jira)

    [ https://issues.apache.org/jira/browse/AXIS2-5721?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17015209#comment-17015209 ]

Jeff Thomas edited comment on AXIS2-5721 at 1/14/20 5:03 PM:
-------------------------------------------------------------

This issues is pretty old (2015) but is exactly the behavior we are encountering now - applies to current trunk version as well.  It appears to be a design 'feature' :)

Engaging a module from any service-operation adds it to the corresponding flow-phase.  All calls run through all phases for the relevant flow (ie. InFlow) .

So we have two scenarios.. assume a Module 'foobar' is defined with a handler associated to phase _Security_.
 * If module 'foobar' is engaged for _ServiceA_ its handler will be added to the _Security_ phase and will _*always*_ be invoked for _ServiceA_ but also for _ServiceB, ServiceC,_ etc.
 * If module 'foobar' is disengaged at runtime on _ServiceA_ its handler will be removed from the _Security_ phase and will _*never*_ be invoked... even if it is still engaged for _ServiceB, ServiceC_ etc.

*_NOTE: Based on the two points above I would encourage you *NOT_* _to use axis2-admin tools to engage/disengage modules at runtime - if two or more services/operations engage the same module then the 'engaged' status and the handlers that are *really* defined for a phase will not match._*

One workaround on a handler-by-handler basis is to check if a handler is _really_ engaged in the _doInvoke(..._) method of the handler and return false if not.  (see note about the AxisDescription _engagedModules_ lookup below).

The workaround I am testing at the moment I have added to _Phase.java_ to test if the handler belongs to a parent module and if so check if the module is enaged relative to the message-context (service-group, service, operation, etc.).

{{{{public final InvocationResponse invoke(MessageContext msgctx) throws AxisFault {}}}}
{{ {{  ...}}}}
{{ {{  int handlersSize = handlers.size();}}}}
{{ {{ {color:#172b4d} for (int i= currentIndex; i < handlersSize; i++) {{color}}}}}
{{{color:#172b4d}{{ {{    Handler handler = (Handler) handlers.get(i);}}}}{color}}}
{{{color:#172b4d}{{ {{    *ParameterInclude handlerParent = handler.getHandlerDesc().getParent();*}}}}{color}}}
{{{color:#172b4d}{{ {{    *if (handlerParent instanceof AxisModule) {*}}}}{color}}}
{{{color:#172b4d}{{ {{      *AxisModule module = (AxisModule) handlerParent;*}}}}{color}}}
{{{color:#172b4d}{{ {{      *if (msgctx.isEngaged(module.getName())) {*}}}}{color}}}
{{{color:#172b4d}{{ {{       }}InvocationResponse pi = invokeHandler(handler, msgctx);}}{color}}}
{{{color:#172b4d}{{       if (!pi.equals(InvocationResponse.CONTINUE)) {}}{color}}}
{{{color:#172b4d}{{         return pi;}}{color}}}
{{{color:#172b4d}{{       }}}{color}}}
{{{color:#172b4d}{{    }}}
    // Set phase index to the next handler{color}}}
{{{color:#172b4d}    msgctx.setCurrentPhaseIndex(i+1);{color}}}
{{{color:#172b4d}{{  }}}{color}}}
{{ {{  ...}}}}
{{ }}}

IMPORTANT: A parallel change has to be made to AxisDescription.java.  The default implementation maps the modules in the _engagedModules<String, AxisModule>_ map using the module archive name as a key (ie. '_addressing-1.7.4_'). 

This means you have to know the name of the archive to call '_isEnaged("addressing-1.7.4_").  Nobody is ever going to know the name of the archive at runtime and if you code to this key your code will break as soon as the module version changes.   So I changed the code to key by the generic module name - this also makes sense because you configure and engage modules by this common name (ie. '_addressing_').

{{public void engageModule(AxisModule axisModule, AxisDescription source) throws AxisFault {}}
 {{  ...}}
 {{  // removed - engagedModules.put(axisModule.getArchiveName(), axisModule) and replaced with:}}
 {{  engagedModules.put(*{color:#de350b}axisModule.getName(){color}*, axisModule);}}
 {{}}}

{{public boolean isEngaged(AxisModule axisModule) {}}
 {{  String id = {color:#de350b}*axisModule.getName()*{color};  // changed from axisModule.getArchiveName()}}
 {{  return engagedModules != null && engagedModules.keySet().contains(id);}}
 {{}}}

I am still testing the above but I am pretty confident it will work :)


was (Author: jwt007):
This issues is pretty old (2015) but is exactly the behavior we are encountering now - applies to current trunk version as well.  It appears to be a design 'feature' :)

Engaging a module from any service-operation adds it to the corresponding flow-phase.  All calls run through all phases for the relevant flow (ie. InFlow) .

So we have two scenarios.. assume a Module 'foobar' is defined with a handler associated to phase _Security_.
 * If module 'foobar' is engaged for _ServiceA_ its handler will be added to the _Security_ phase and will _*always*_ be invoked for _ServiceA_ but also for _ServiceB, ServiceC,_ etc.
 * If module 'foobar' is disengaged at runtime on _ServiceA_ its handler will be removed from the _Security_ phase and will _*never*_ be invoked... even if it is still engaged for _ServiceB, ServiceC_ etc.

*_NOTE: Based on the two points above I would encourage you *NOT_* _to use axis2-admin tools to engage/disengage modules at runtime - if two or more services/operations engage the same module then the 'engaged' status and the handlers that are *really* defined for a phase will not match._*

One workaround on a handler-by-handler basis is to check if a handler is _really_ engaged in the _doInvoke(..._) method of the handler and return false if not.  (see note about the AxisDescription _engagedModules_ lookup below).

The workaround I am testing at the moment I have added to _Phase.java_ to test if the handler belongs to a parent module and if so check if the module is enaged relative to the message-context (service-group, service, operation, etc.).

{{public final InvocationResponse invoke(MessageContext msgctx) throws AxisFault {}}
 {{  ...}}
 {{  int handlersSize = handlers.size();}}
 {{  for (int i= currentIndex; i < handlersSize; i++) {}}
 {{    Handler handler = (Handler) handlers.get(i);}}
 {{    *{color:#de350b}ParameterInclude handlerParent = handler.getHandlerDesc().getParent();{color}*}}
 {{    *{color:#de350b}if (handlerParent instanceof AxisModule) {{color}*}}
 {{      *{color:#de350b}AxisModule module = (AxisModule) handlerParent;{color}*}}
 {{      *{color:#de350b}if (!msgctx.isEngaged(module.getName())) {{color}*}}
 {{        *{color:#de350b}continue;
{color}*}}{{      }}}
        }
{{  ...}}
}

IMPORTANT: A parallel change has to be made to AxisDescription.java.  The default implementation maps the modules in the _engagedModules<String, AxisModule>_ map using the module archive name as a key (ie. '_addressing-1.7.4_'). 

This means you have to know the name of the archive to call '_isEnaged("addressing-1.7.4_").  Nobody is ever going to know the name of the archive at runtime and if you code to this key your code will break as soon as the module version changes.   So I changed the code to key by the generic module name - this also makes sense because you configure and engage modules by this common name (ie. '_addressing_').

{{public void engageModule(AxisModule axisModule, AxisDescription source) throws AxisFault {}}
 {{  ...}}
 {{  // removed - engagedModules.put(axisModule.getArchiveName(), axisModule) and replaced with:}}
 {{  engagedModules.put(*{color:#de350b}axisModule.getName(){color}*, axisModule);}}
 {{}}}

{{public boolean isEngaged(AxisModule axisModule) {}}
 {{  String id = {color:#de350b}*axisModule.getName()*{color};  // changed from axisModule.getArchiveName()}}
 {{  return engagedModules != null && engagedModules.keySet().contains(id);}}
 {{}}}

I am still testing the above but I am pretty confident it will work :)

> Module engaged at the service level is used globally
> ----------------------------------------------------
>
>                 Key: AXIS2-5721
>                 URL: https://issues.apache.org/jira/browse/AXIS2-5721
>             Project: Axis2
>          Issue Type: Bug
>          Components: modules
>    Affects Versions: 1.6.3
>            Reporter: Victor
>            Priority: Major
>
> Hi,
> Maybe I misunderstood how Axis2 was meant to work, but I have addressing and rampart present in my modules directory, they are made available in the AxisConfiguration object, then addressing is globally engaged because it is present in the axis2.xml file.
> Later I engage rampart manually on a specific service (by calling engageModule() on the AxisService object) and then the rampart handlers are executed for every request, even not those of the aforementioned service.
> I looked at the code and apparently, engageModule() goes down to call PhaseResolver.engageModuleToOperation(AxisOperation, AxisModule, int) on all the operations of the AxisService, gather all the phases from the global AxisConfiguration object and then add the Handler to the needed phases (Security in this case) within the method PhaseHolder.addHandler(HandlerDescription).
> Obviously, being in an Object-Oriented language, modifying the Phase without cloning it first will impact also the global AxisConfiguration that have references to them as well as all the other PhaseHolder for all the operations that have references to them…
> Is that meant to be? I don't think so but I may be mistaken :)
> Thank you



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]