I have a flow that makes two calls to a database to insert data, and one call to a stored procedure on another database. I would like the two insert calls to be processed as a transaction, i.e. either they both insert or neither does. I would also like the call to the stored procedure to be asynchronous, as I don't need to wait for a response and any errors during the stored procedure call should not impact the main message processing. Here's how I configured my flow:
<flow name="saveBrowser" doc:name="saveBrowser" >
<http:inbound-endpoint exchange-pattern="request-response" host="${my.host}" port="${my.port}" path="Browser/Save" doc:name="/Browser/Save" />
...assorted transformations...
<json:json-to-object-transformer doc:name="JSON to BrowserData" returnClass="com.mycompany.BrowserData"/>
<transactional action="ALWAYS_BEGIN" doc:name="Transactional">
<jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="saveBrowser" queryTimeout="-1" connector-ref="firstJdbcConnector" doc:name="INSERT Browser"/>
<jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="saveBrowserExtended" queryTimeout="-1" connector-ref="firstJdbcConnector" doc:name="INSERT BrowserExtended"/>
</transactional>
<async doc:name="Async">
<jdbc:outbound-endpoint exchange-pattern="one-way" queryKey="storedProcedureBrowser" queryTimeout="-1" connector-ref="secondJdbcConnector" doc:name="Stored Proc">
<jdbc:transaction action="NONE"/>
</jdbc:outbound-endpoint>
</async>
<json:object-to-json-transformer doc:name="BrowserData to JSON" sourceClass="com.mycompany.BrowserData" />
<catch-exception-strategy doc:name="Catch Exception Strategy">
...
</catch-exception-strategy>
</flow>
The error I get when I send a request to this flow, however, is that async scope can't be used with transactions. The documentation for transactional scope says, "You cannot build an asynchronous flow inside a transaction." However, the async scope is not within the transactional scope. It's adjacent but not within its scope. Why is this a problem?
I worked around this by passing the message to a separate flow containing the async scope and stored procedure call, via VM endpoints. If there's a better way to do this, I'd love to know.
I'm in community edition, FYI.
Related
I have an action state in a Spring Web Flow that take in parameters from a submitted form:
<action-state id="newToken">
<set name="requestScope.timestamp" value="requestParameters.timestamp" type="java.lang.String"/>
<set name="requestScope.origin" value="requestParameters.origin" type="java.lang.String"/>
<set name="requestScope.tokenHmacToValidate" value="requestParameters.tokenHmacToValidate" type="java.lang.String"/>
<transition to="validateToken"/>
</action-state>
However, only the first requestParameters value gets set (i.e. if timestamp is first, then only it gets set. If origin is first, then only it gets set). When I access the second and third values, they have a value of null instead of the value that is passed into it. Here is an example of form data that is passed on form submission:
_eventId=tokenValidationEvent
origin=https%3A%2F%2Flocalhost%3A8443
timestamp=20200218171041
tokenHmacToValidate=**REDACTED**
All the information is getting passed when the form is submitted, but only the first <set> tag is actually setting data. Am I receiveing the request wrong? Is there something I need to register somewhere that I'm not doing
This is the way <action-state> works. Only the first expression is evaluated.
If you want all three to be evaluated, you could use <on-entry> to evaluate the other 2:
<action-state id="newToken">
<on-entry>
<set name="requestScope.timestamp" value="requestParameters.timestamp" type="java.lang.String"/>
<set name="requestScope.origin" value="requestParameters.origin" type="java.lang.String"/>
</on-entry>
<set name="requestScope.tokenHmacToValidate" value="requestParameters.tokenHmacToValidate" type="java.lang.String"/>
<transition to="validateToken"/>
</action-state>
From https://docs.spring.io/spring-webflow/docs/current/reference/html/actions.html#action-state
After the execution of each action, the action-state checks the result to see if matches a declared transition to another state. That means if more than one action is configured they are executed in an ordered chain until one returns a result event that matches a state transition out of the action-state while the rest are ignored. This is a form of the Chain of Responsibility (CoR) pattern.
The result of an action's execution is typically the criteria for a transition out of this state. Additional information in the current RequestContext may also be tested as part of custom transitional criteria allowing for sophisticated transition expressions that reason on contextual state.
Note also that an action-state just like any other state can have one more on-entry actions that are executed as a list from start to end.
I have a little problem I can't solve so far. In BPEL I want to create an onAlarm eventHandler which fires immediatly (i.e. the "for" element is set to 'PT0S') and repeats every 2 seconds. This eventHandler shall contain a counter which increments every time the alarm fires.
The question is: How to initialize the counter? If the variable will be initialized within the onAlarm scope the value would not increment anymore. In the "normal" control flow the value also cannot be initialized, because it is not defined if the process or the onAlarm scope runs first. So I would get every now and then an uninitializedVariable exception.
My solution would be to not initialize the variable neither in the process scope nor in the onAlarm scope, but create a faultHandler wherein the variable will be initialized and afterwards the onAlarm flow will be executed. Problem is every uninitializedVariable execution will be caught now by this faultHandler and there may be another too.
So is there another possibility to deal with this problem or can I somehow find out which variable wasn't initialized properly so the faultHandler can get two control flows?
The solution should work on every BPEL engine.
Thanks, Michael
You can initialize a variable with a default value on its definition using a from-spec just like in an assignment. See section 8.4.1 of the spec for the details.
A default initialization can look like this:
<variables>
<variable name="Default" type="xsd:int" >
<from>5</from>
</variable>
</variables>
This should work as eventHandlers are installed after the start activity of a process has completed. By then, the variables defined in the root scope have already been initialized. To quote the spec, section 12.1:
Scope initialization consists of instantiating and initializing the
scope's variables and partner links; ... If a scope contains an
initial start activity then the start activity MUST complete before
the event handlers are installed.
So much for spec. I think nobody can tell whether this "works on every BPEL engine". As far as I know, it works on bpel-g, Orchestra and EasyBPEL, but not on Apache ODE or OpenESB.
What is the best place to call the business logic in? I have the following requirements.
1). Get the search criteria from user
2). If the current user is trying search for unauthorized results throw business exception
3). Retrieve results
4). If number of results==0, go to search page again and put a message.
5). If number of results>limit, go to search page again and put a message.
6). Go to showresults page.
This is what I have so far...
<flow....>
<on-start>
<evaluate expression="appConfig.setUpSupportData()" result="flowScope.supportData"/>
</on-start>
<view-state id="searchHome" view="searchHome" model="searchCriteria">
<transition on="search" to="doSearch"/>
</view-state>
<action-state id="doSearch">
<evaluate expression="searchUtil.getSearchResults(flowScope.searchCriteria)" result="flowScope.personList"/>
<evaluate expression="searchUtil.showSearchResults(flowScope.personList, flowRequestContext)" >
<attribute name="name" value="expression2"/>
</evaluate>
<transition on="expression2.yes" to="showSearchResults"/>
<transition on="expression2.no" to="searchHome"/>
</action-state>
<view-state id="showSearchResults"></view-state>
</flow>
My question is, should I be calling the getSearchResults() method in action-stae or in view-state="showSearchResults"? If I call the method in action-stae, I have to put the search results in flowscope so that second view can get the results - I am worried about memory in this scenario. If I call the method in second view- on-entry, I can put the personList in viewscope but how do I handle cases 2,4 and 5?
Thanks in advance!
You've answered part of your own question already:
Using an action-state to invoke business logic gives you a bit more control on how you react to different outcomes: go here on-exception, go somewhere else if everything is fine, and so on. The downside being that you need to put data in a longer lived scope (flow scope) to make it available to the view-state.
Using a view-state allows you to use a short lived scope (view scope or request scope) by retrieving the data using a render-action or entry-action, but doesn't give you much control when it comes to processing action outcomes.
Selecting between the two is a bit of a trade-of. If the search results can get very big, using a short lived scope to reduce memory load as much as possible is probably an important concern, so you would use a view-state. In other scenarios an action-state might be more appropriate.
One alternative approach is to introduce an application controller (invoked from the flow) that calls the business logic and returns an object that contains several things:
the search results
a potential info/warning message to display
You could then use a view-state and the view would be able to simply pick up the search results and info/warning message from the result object and display it.
while trying to solve my problems in serializing the execution of cairngorm commands, I tried to bypass completely the event dispatching and simply instantiated the command I wanted to execute, then called it's execute method. In this method there's a call to a delegate that calls ServiceUtils that performs the HTTPService.send thing...
Now, those commands should be run in the exact order I call them.
And, since the server (RAILS) is only one, all requests should return in the same order.
This isn't so.. the order varies upon different executions.. why?!?
Just because you send requests in a certain order doesn't mean the responses will return in that order. HTTPService calls are asynchronous. For example, assume the following three requests are sent at the same time:
Request 1 (takes 4 seconds on the server to process)
Request 2 (takes 0.5 seconds to process)
Request 3 (takes 2 seconds to process)
Assuming network speed is constant (and a lot of other environment issues being constant), you will get the response for Request 2 back first, then Request 3, then Request 1.
If you need to call them in serial, you should do something like this:
protected function doWork():void {
request1.send();
}
protected function onRequest1Complete(e:ResultEvent):void {
request2.send();
}
protected function onRequest2Complete(e:ResultEvent):void {
request3.send();
}
protected function onRequest3Complete(e:ResultEvent):void {
// you are done at this point
}
...
<mx:HTTPService id="request1" url="http://example.com/service1" result="onRequest1Complete(event)" />
<mx:HTTPService id="request2" url="http://example.com/service2" result="onRequest2Complete(event)" />
<mx:HTTPService id="request3" url="http://example.com/service3" result="onRequest3Complete(event)" />
Hope that helps.
RJ's answer covers it very well. Just to add to it:
Your commands will create asynchronous requests via the services you use. If you want to "simulate" synchronous execution of commands, the subsequent command will have to be executed in the resultHandler of the previous commands request.
Although this may not always be the cleanest way of doing things, it may be suitable for your scenario. I'll need more information about the nature of service calls and the app in general to make a call whether this is the best method for you or not.
HTH,
Sri
Can one declare multiple beans in the ejb-jar.xml (in EJB 1.1) deployment descriptor with different names but the same classes behind?
For example:
<session>
<ejb-name>AccountFacade</ejb-name>
<home>com.something.ejb.AccountFacadeHome</home>
<remote>com.something.ejb.AccountFacadeRemote</remote>
<ejb-class>com.something.ejb.AccountFacadeBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Bean</transaction-type>
</session>
<session>
<ejb-name>RestrictiveAccountFacade</ejb-name>
<home>com.something.ejb.AccountFacadeHome</home>
<remote>com.something.ejb.AccountFacadeRemote</remote>
<ejb-class>com.something.ejb.AccountFacadeBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Bean</transaction-type>
</session>
For RestrictiveAccountFacade I want to set a higher isolation level in the orion-ejb-jar.xml file, something like:
<entity-deployment name="AccountFacade" location="AccountFacade">
<resource-ref-mapping location="..." name="jdbc/..."/>
</entity-deployment>
<entity-deployment name="RestrictiveAccountFacade" location="RestrictiveAccountFacade" isolation="serializable">
<resource-ref-mapping location="..." name="jdbc/..."/>
</entity-deployment>
Is there a risk involved in doing this, any side effects or unspecified behavior?
This is totally OK to have it as you mentioned above. One should note that as per container is concerned AccountFacade and RestrictiveAccountFacade will be two totally unrelated session beans.
However RestrictiveAccountFacade has transaction serializable access to same jdbc resource as AccountFacade so they will interfere with each other only at transaction isolation level.
Hence AccountFacade may be blocked if it needs access to same record as that is participated in transaction of RestrictiveAccountFacade.
Similarly RestrictiveAccountFacade transaction will be blocked on same record as that is being used by AccountFacade in it's transaction.