Products | Versions |
---|---|
TIBCO EBX | All supported versions. |
In EBX5, a Procedure is the way to implement a transaction.
https://docs.tibco.com/pub/ebx/5.9.7/doc/html/en/Java_API/com/orchestranetworks/service/Procedure.html
There are several places where updates can be performed in EBX through a procedure.
Ex :
A procedure can only perform CUD (Create, Update, Delete) on the dataspace on which it is executed.
This is due to EBX transaction management and usage contraints.
The following constraints apply:
Let's use an example here. I have 2 tables "Person" and "Address" that are in 2 different dataspaces "PersonDataSpace" and "LocationDataSpace". "Person" has a field "FKAddress" which is a foreign key to the "Address" table.
When a user creates a record in the "Person" table, we want EBX to automatically create a record in "Address" table and also automatically fill the foreign key field in "Person".
Such operations are performed in a TableTrigger declared on the "Person" table.
public class CreatAddressTrigger extends TableTrigger{ ... } |
In the method "handleAfterCreate", I am able to retrieve the ProcedureContext of the current procedure but it will not allow to write in "LocationDataSpace" due to the constraint we mentioned above.
public void handleAfterCreate(AfterCreateOccurrenceContext aContext) throws OperationException { ProcedureContext procContext = aContext.getProcedureContext(); } |
In order to write in "LocationDataSpace", we will implement a new procedure that implements "Procedure" Interface. The method execute of this class will then contain the code which performs the CUD on the "LocationDataSpace".
private class CreateAddressProc implements Procedure { private Adaptation addressRecord; public void execute(ProcedureContext aContext) throws Exception { AdaptationHome locationDataSpace = aContext.getAdaptationHome(); Adaptation locationDataSet = locationDataSpace.findAdaptationOrNull(AdaptationName.forName( "Location" )); AdaptationTable addressTable = locationDataSet.getTable(Path.parse( "/root/address" )); ValueContextForUpdate vcfu = aContext.getContextForNewOccurrence(addressTable); vcfu.setValue( "France" , Path.parse( "./country" )); vcfu.setValue( "Paris" , Path.parse( "./city" )); vcfu.setValue( "Avenue des Champs Elysées" , Path.parse( "./Street" )); this .addressRecord = aContext.doCreateOccurrence(vcfu, addressTable); } public Adaptation getAddressRecord() { return addressRecord; } } |
Once the procedure is implemented, we still need to execute it on the appropriate dataspace.
In the method handleAfterCreate of the TableTrigger, we will retrieve a ProgrammaticService.
handleAfterCreatepublic void handleAfterCreate(AfterCreateOccurrenceContext aContext) throws OperationException { Repository repository = aContext.getAdaptationHome().getRepository(); AdaptationHome addressDataSpace = repository.lookupHome(HomeKey.forBranchName( "LocationDataSpace" )); ProgrammaticService service = ProgrammaticService.createForSession(aContext.getSession(), addressDataSpace); ... } |
With this ProgrammaticService instanciated on the "LocationDataSpace" it is now possible to execute the procedure.
public void handleAfterCreate(AfterCreateOccurrenceContext aContext) throws OperationException { Repository repository = aContext.getAdaptationHome().getRepository(); AdaptationHome addressDataSpace = repository.lookupHome(HomeKey.forBranchName( "LocationDataSpace" )); ProgrammaticService service = ProgrammaticService.createForSession(aContext.getSession(), addressDataSpace); CreateAddressProc createAdressProc = new CreateAddressProc(); service.execute(createAdressProc); } |
At this step, we are able to create a new record in "Address" table. What we want to do now is to update the foreign key field in the "Person" table.
We will use the getter on the "CreateAddressProcedure" to retrieve the "Address" record Adaptation.
Then, we will need to retrieve the ProcedureContext that will allow to write in "PersonDataSpace".
Finally, we will update the foreign key field using the method "ProcedureContext.doModifyContent(...)".
handleAfterCreatepublic void handleAfterCreate(AfterCreateOccurrenceContext aContext) throws OperationException { Repository repository = aContext.getAdaptationHome().getRepository(); AdaptationHome addressDataSpace = repository.lookupHome(HomeKey.forBranchName( "LocationDataSpace" )); ProgrammaticService service = ProgrammaticService.createForSession(aContext.getSession(), addressDataSpace); CreateAddressProc createAdressProc = new CreateAddressProc(); service.execute(createAdressProc); Adaptation addressRecord = createAdressProc.getAddressRecord(); ProcedureContext procContext = aContext.getProcedureContext(); Adaptation personRecord = aContext.getAdaptationOccurrence(); ValueContextForUpdate vcfu = procContext.getContext(aContext.getAdaptationOccurrence().getAdaptationName()); vcfu.setValue(addressRecord.getOccurrencePrimaryKey().format(), Path.parse( "./FKAddress" )); procContext.doModifyContent(personRecord, vcfu); } |
We were able to create a record in the "address" table and to fill the foreign key field automatically.
There is still something important we need to remember : In EBX5, a procedure is the way to implement a transaction.
In this use case we executed 2 different procedures, which means that the updates that are performed on the "LocationDataSpace" are not rolled back if an exception occurs while executing the procedure on "PersonDataSpace".