Class FrankSender
- All Implemented Interfaces:
HasPhysicalDestination
,IConfigurable
,IConfigurationAware
,INamedObject
,IScopeProvider
,ISender
,ISenderWithParameters
,IWithParameters
,IThreadCreator
,org.springframework.beans.factory.Aware
,org.springframework.context.ApplicationContextAware
Sends a message to another Frank!Framework-adapter in the same Frank!Framework instance, or an external program running in
the same JVM as the Frank!Framework. If the callee exits with an <Exit/>
that has state PipeLine.ExitState.ERROR
,
an error is considered to happen in the caller which means that the exception
forward is followed if it is present.
Returns exit.code
as forward name to the SenderPipe
, provided that exit.code
can be parsed as integer.
For example, if the called adapter has an exit state with code
2
, then the SenderPipe
supports a forward with name 2
that is followed when the called adapter exits with the mentioned exit. This does not work if the code is for example c2
.
A FrankSender makes a call to either an Adapter
or an external program by setting the scope
. By default the scope is ADAPTER
.
Configuration of the Adapter to be called
A call to another Adapter in the same Frank!Framework instance is preferably made using the combination of a FrankSender configured with the name of the adapter.
Configuring FrankSender and Adapter
- Define a
SenderPipe
with a FrankSender - Set the attribute
target
to targetAdapterName - If the adapter is in another Configuration deployed in the same Frank!Framework instance, then set
target
totargetConfigurationName/targetAdapterName
(note the slash-separator between Configuration name and Adapter name).
- The adapter does not need to have a dedicated receiver configured to be called from a FrankSender.
- The adapter will run in the same transaction as the calling adapter.
- If the called adapter does not to run in its own transaction, set the transaction attributes on the
PipeLine
attribute of this adapter or on theSenderPipe
that contains thisFrankSender
.
Configuring FrankSender with FrankListener
- Define a
SenderPipe
with a FrankSender - In the target adapter, define a
Receiver
with aFrankListener
- Give a unique name to the listener:
FrankListener.setName(String)
. If the name is not set, the name of theAdapter
will be used. - Set the
setScope(Scope)
toLISTENER
and thesetTarget(String)
to the listener name as per previous point - If the listener is in a different configuration, prefix the listener name with the name of the configuration and a slash (
/
) as separator between configuration and listener name
Configuring FrankSender and Remote Application
NB: Please make sure that the IbisServiceDispatcher-1.4.jar or newer is present on the class path of the server. For more information, see:
- Define a
SenderPipe
with a FrankSender - Set the attribute
scope
to eitherJVM
for a Java application, or toDLL
for code loaded from a DLL - Set the attribute
target
to the service-name the other application used to register itself
In the other application:
- Implement the interface
nl.nn.adapterframework.dispatcher.RequestProcessor
from the IbisServiceDispatcher library - Register the instance with the
nl.nn.adapterframework.dispatcher.DispatcherManager
obtained via thenl.nn.adapterframework.dispatcher.DispatcherManagerFactory
- See the implementation code of the
JavaListener
in the Frank!Framework for an example
See also the repository of the IbisServiceDispatcher: https://github.com/frankframework/servicedispatcher
Using FrankSender to call an adapter from Larva tests
You can configure a FrankSender in Larva property files to use the FrankSender to invoke an adapter to test. When doing this, keep the following in mind:
- If you leave the default scope as
ADAPTER
, then thetarget
property needs to have both configuration name and adapter name, separated by a/
character - When scope is left as default, the receiver and JavaListener are skipped and no transaction is started unless it is set on the adapter's
PipeLine
- If you do need a transaction and the adapter has a JavaListener that has
JavaListener.setServiceName(String)
defined, you can use the FrankSender with scopeJVM
and set thetarget
attribute to theserviceName
attribute of theJavaListener
.
Migrating Existing Configurations
When one adapter (named A) needs to call another adapter (named B) like a subroutine, you will usually have an IbisLocalSender
or an IbisJavaSender
in adapter A, and a JavaListener
in adapter B.
NB: For the example it is assumed that all adapters are defined in the same configuration.
Example of Existing Configuration
The existing configuration might look like this in the calling adapter:
<module>
<adapter name="Adapter A">
<receiver name="Adapter A Receiver">
<listener name="Adapter A Listener"
className="org.frankframework..." etc/>
</receiver>
<pipeline firstPipe="...">
<pipe name="send" className="org.frankframework.pipes.SenderPipe">
<sender className="org.frankframework.senders.IbisJavaSender"
serviceName="service-Adapter-B" />
<forward name="success" path="..." />
</pipe>
</pipeline>
</adapter>
</module>
Or like using the modern XML XSD and an IbisLocalSender instead:
<Module>
<Adapter name="Adapter A">
<Receiver name="Adapter A Receiver">
... Listener setup and other configuration
</Receiver>
<Pipeline>
<SenderPipe name="send">
<IbisLocalSender name="call Adapter B"
javaListener="Adapter B Listener"/>
<Forward name="success" path="EXIT" />
</SenderPipe>
</Pipeline>
</Adapter>
</Module>
In the receiving adapter B the listener would have been configured like this:
<Module>
<Adapter name="adapter B">
<Receiver name="Receiver B">
<JavaListener name="Adapter B Listener" serviceName="service-Adapter-B"/>
</Receiver>
<Pipeline>
...
</Pipeline>
</Adapter>
</Module>
Rewritten Example Configuration With FrankSender
This example shows the most simple way of using the FrankSender to call another adapter with least amount of overhead.
<Module>
<Adapter name="Adapter A">
<Receiver name="Adapter A Receiver">
... Listener setup and other configuration
</Receiver>
<Pipeline>
<SenderPipe name="send">
<!-- when scope="ADAPTER", then target is directly the name of the adapter you want to call -->
<FrankSender name="call Adapter C"
scope="ADAPTER"
target="adapter B"
/>
<Forward name="success" path="EXIT" />
</SenderPipe>
</Pipeline>
</Adapter>
<Adapter name="adapter B">
<!-- No receiver needed for FrankSender in this scenario -->
<Pipeline>
... Exits, Pipes etc
</Pipeline>
</Adapter>
</Module>
Rewritten Example Configuration With FrankSender and FrankListener
This example shows why you might want to call the other adapter via the FrankListener. This adds a bit more overhead to the call of the sub-adapter for the extra error-handling done by the target receiver.
<Module>
<Adapter name="Adapter A">
<Receiver name="Adapter A Receiver">
... Listener setup and other configuration
</Receiver>
<Pipeline>
<SenderPipe name="send">
<!-- when scope="LISTENER", then target is directly the name of the FrankListener in the adapter you want to call -->
<FrankSender
scope="LISTENER"
target="Adapter B Listener"/>
<Forward name="success" path="EXIT" />
</SenderPipe>
</Pipeline>
</Adapter>
<Adapter name="adapter B">
<!-- Messages will only be sent to the error storage if:
- The target receiver is not transactional, and has maxTries="0", or
- The target receiver is transaction, and the Sender is set up to retry sending on error
For internal adapters, sending / receiving with retries might not make sense so the example does not show that.
-->
<Receiver name="Receiver B" maxRetries="0" transactionAttribute="NotSupported">
<!-- Listener name is optional, defaults to Adapter name -->
<FrankListener name="Adapter B Listener"/>
<!-- This adapter now has an error storage -- without Receiver and FrankListener the sub-adapter couldn't have that -->
<JdbcErrorStorage slotId="Adapter B - Errors" />
</Receiver>
<!-- If transactions are required, set transaction-attribute on the Pipeline -->
<Pipeline transactionAttribute="RequiresNew">
... Exits, Pipes etc
</Pipeline>
</Adapter>
</Module>
- Parameters
- All parameters except
scope
andtarget
are copied to thePipeLineSession
of the adapter called. - Specific parameters
- code Determine scope dynamically at runtime. If the parameter value is empty, fall back to the scope configured via the attribute, or the default scope
ADAPTER
., target Determine target dynamically at runtime. If the parameter value is empty, fall back to the target configured via the attribute.
-
Nested Class Summary
-
Field Summary
Fields inherited from class org.frankframework.senders.AbstractSenderWithParameters
parameterNamesMustBeUnique, paramList
Fields inherited from class org.frankframework.senders.AbstractSender
log
-
Constructor Summary
-
Method Summary
Modifier and TypeMethodDescriptionvoid
configure()
is called once at startup of the framework in the configure method of the owner of this sender.getScope()
boolean
Whentrue
, the result of sendMessage is the reply of the request.sendMessage
(Message message, PipeLineSession session) Send a message to some destination (as configured in the Sender object).void
setAdapterManager
(AdapterManager adapterManager) void
setIbisManager
(IbisManager ibisManager) void
setIsolatedServiceCaller
(IsolatedServiceCaller isolatedServiceCaller) void
setReturnedSessionKeys
(String string) Comma separated list of keys of session variables that will be returned to caller, for correct results as well as for erroneous results.void
setScope
(FrankSender.Scope scope) FrankSender.Scope
decides if the FrankSender calls another adapter, or another Java program running in the same JVM.void
setSynchronous
(boolean b) Synchronous or Asynchronous execution of the call to other adapter or system.void
Target: service-name of service in other application that should be called, or name of adapter to be called.void
setThreadLifeCycleEventListener
(ThreadLifeCycleEventListener<Object> threadLifeCycleEventListener) Methods inherited from class org.frankframework.senders.AbstractSenderWithParameters
addParameter, checkStringAttributeOrParameter, consumesSessionVariable, getParameterList, getParameterOverriddenAttributeValue, getParameterOverriddenAttributeValue, getParameterValueList
Methods inherited from class org.frankframework.senders.AbstractSender
createBean, getApplicationContext, getConfigurationClassLoader, getLogPrefix, getName, setApplicationContext, setName, start, stop
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
Methods inherited from interface org.springframework.context.ApplicationContextAware
setApplicationContext
Methods inherited from interface org.frankframework.core.IConfigurationAware
getApplicationContext, getName
Methods inherited from interface org.frankframework.core.INamedObject
getName, setName
Methods inherited from interface org.frankframework.core.IScopeProvider
getConfigurationClassLoader
Methods inherited from interface org.frankframework.core.ISender
sendMessageOrThrow, start, stop
-
Field Details
-
TARGET_PARAM_NAME
- See Also:
-
SCOPE_PARAM_NAME
- See Also:
-
-
Constructor Details
-
FrankSender
public FrankSender()
-
-
Method Details
-
configure
Description copied from interface:ISender
configure()
is called once at startup of the framework in the configure method of the owner of this sender. Purpose of this method is to check whether the static configuration of the sender is correct. As much as possible class-instantiating should take place in theconfigure()
oropen()
method, to improve performance.- Specified by:
configure
in interfaceIConfigurable
- Specified by:
configure
in interfaceISender
- Overrides:
configure
in classAbstractSenderWithParameters
- Throws:
ConfigurationException
-
getPhysicalDestinationName
- Specified by:
getPhysicalDestinationName
in interfaceHasPhysicalDestination
-
getDomain
- Specified by:
getDomain
in interfaceHasPhysicalDestination
-
sendMessage
@Nonnull public SenderResult sendMessage(@Nonnull Message message, @Nonnull PipeLineSession session) throws SenderException, TimeoutException Description copied from interface:ISender
Send a message to some destination (as configured in the Sender object). This method may only be called after theconfigure()
method is called.The following table shows the difference between synchronous and a-synchronous senders:
synchronous a-synchronous ISender.isSynchronous()
returnstrue
false
return value of sendMessage()
isthe reply-message the messageId of the message sent the correlationID specified with sendMessage()
may be ignored is sent with the message a {link TimeOutException} may be thrown if a timeout occurs waiting for a reply should not be expected Multiple objects may try to call this method at the same time, from different threads. Implementations of this method should therefore be thread-safe, or
synchronized
.- Specified by:
sendMessage
in interfaceISender
- Throws:
SenderException
TimeoutException
-
setSynchronous
public void setSynchronous(boolean b) Synchronous or Asynchronous execution of the call to other adapter or system.
Set tofalse
to make the call asynchronously. This means that the current adapter continues with the next pipeline and the result of the sub-adapter that was called, or other system that was called, is ignored. Instead, the input message will be returned as the result message.- Default value
- true
-
setScope
FrankSender.Scope
decides if the FrankSender calls another adapter, or another Java program running in the same JVM.
It is possible to set this via a parameter. If the parameter is defined but the value at runtime is empty, then the value set via this attribute will be used as default.- Parameters:
scope
- EitherADAPTER
,JVM
orDLL
.- Default value
- ADAPTER
-
setTarget
Target: service-name of service in other application that should be called, or name of adapter to be called. If the adapter is in another configuration, prefix the adapter name with the name of that configuration and a slash ("/
").
It is possible to set a target at runtime via a parameter.
If a parameter with name "target" exists but has no value, then the target configured via the attribute will be used as a default.- Parameters:
target
- Name of the target, adapter or registered service.
-
setReturnedSessionKeys
Comma separated list of keys of session variables that will be returned to caller, for correct results as well as for erroneous results. The set of available sessionKeys to be returned might be limited by the returnedSessionKeys attribute of the corresponding JavaListener. -
getScope
-
getTarget
-
getReturnedSessionKeys
-
isSynchronous
public boolean isSynchronous()Description copied from interface:ISender
Whentrue
, the result of sendMessage is the reply of the request.- Specified by:
isSynchronous
in interfaceISender
-
setIsolatedServiceCaller
-
setThreadLifeCycleEventListener
public void setThreadLifeCycleEventListener(ThreadLifeCycleEventListener<Object> threadLifeCycleEventListener) - Specified by:
setThreadLifeCycleEventListener
in interfaceIThreadCreator
-
setAdapterManager
-
setIbisManager
-