A flow can be a fairly complex thing that interacts with many backend systems, and so it is likely that different users
of a specific CordApp will require differences in how flows interact with their specific infrastructure.

Corda supports this functionality by providing two mechanisms to modify the behaviour of apps in your node.

If you have a workflow which is mostly common, but also requires slight alterations in specific situations, most developers would be familiar
with refactoring into Base and Sub classes. A simple example is shown below.

@InitiatedBy(Initiator::class)openclassBaseResponder(internalvalotherSideSession:FlowSession):FlowLogic<Unit>(){@Suspendableoverridefuncall(){otherSideSession.send(getMessage())}protectedopenfungetMessage()="This Is the Legacy Responder"}@InitiatedBy(Initiator::class)classSubResponder(otherSideSession:FlowSession):BaseResponder(otherSideSession){overridefungetMessage():String{return"This is the sub responder"}}

@InitiatingFlowpublicclassInitiatorextendsFlowLogic<String>{privatefinalPartyotherSide;publicInitiator(PartyotherSide){this.otherSide=otherSide;}@OverridepublicStringcall()throwsFlowException{returninitiateFlow(otherSide).receive(String.class).unwrap((it)->it);}}@InitiatedBy(Initiator.class)publicclassBaseResponderextendsFlowLogic<Void>{privateFlowSessioncounterpartySession;publicBaseResponder(FlowSessioncounterpartySession){super();this.counterpartySession=counterpartySession;}@OverridepublicVoidcall()throwsFlowException{counterpartySession.send(getMessage());returnVoid;}protectedStringgetMessage(){return"This Is the Legacy Responder";}}@InitiatedBy(Initiator.class)publicclassSubResponderextendsBaseResponder{publicSubResponder(FlowSessioncounterpartySession){super(counterpartySession);}@OverrideprotectedStringgetMessage(){return"This is the sub responder";}}

Corda would detect that both BaseResponder and SubResponder are configured for responding to Initiator.
Corda will then calculate the hops to FlowLogic and select the implementation which is furthest distance, ie: the most subclassed implementation.
In the above example, SubResponder would be selected as the default responder for Initiator

Note

The flows do not need to be within the same CordApp, or package, therefore to customise a shared app you obtained from a third party, you’d write your own CorDapp that subclasses the first.

Whilst the subclassing approach is likely to be useful for most applications, there is another mechanism to override this behaviour.
This would be useful if for example, a specific CordApp user requires such a different responder that subclassing an existing flow
would not be a good solution. In this case, it’s possible to specify a hardcoded flow via the node configuration.

Note

A new responder written to override an existing responder must still be annotated with @InitiatedBy referencing the base initiator.

The configuration section is named flowOverrides and it accepts an array of overrides

It is likely that initiating flows will also require changes to reflect the different systems that are likely to be encountered.
At the moment, corda provides the ability to subclass an Initiator, and ensures that the correct responder will be invoked.
In the below example, we will change the behaviour of an Initiator from filtering Notaries out from comms, to only communicating with Notaries

@InitiatingFlow@StartableByRPC@StartableByServiceopenclassBaseInitiator:FlowLogic<String>(){@Suspendableoverridefuncall():String{valpartiesToTalkTo=serviceHub.networkMapCache.allNodes.filterNot{it.legalIdentities.first()inserviceHub.networkMapCache.notaryIdentities}.filterNot{it.legalIdentities.first().name==ourIdentity.name}.map{it.legalIdentities.first()}valresponses=ArrayList<String>()for(partyinpartiesToTalkTo){valsession=initiateFlow(party)valreceived=session.receive<String>().unwrap{it}responses.add(party.name.toString()+" responded with backend: "+received)}return"${getFLowName()} received the following \n"+responses.joinToString("\n"){it}}openfungetFLowName():String{return"Normal Computer"}}@StartableByRPC@StartableByServiceclassNotaryOnlyInitiator:BaseInitiator(){@Suspendableoverridefuncall():String{return"Notary Communicator received:\n"+serviceHub.networkMapCache.notaryIdentities.map{"Notary: ${it.name.organisation} is using a "+initiateFlow(it).receive<String>().unwrap{it}}.joinToString("\n"){it}}

Warning

The subclass must not have the @InitiatingFlow annotation.

Corda will use the first annotation detected in the class hierarchy to determine which responder should be invoked. So for a Responder similar to