I enable publish confirm, and call RabbitTemplate send method with CorrelationData. But when i get CorrelationData in ConfirmCallback, sometimes CorrelationData is null and ack is true. I must add judgement Correlation!=null.
Is it a normal behavior in spring amqp?
If you configure the RabbitTemplate to support confirms you have to provide correlation data.
If you invoke a send method with no correlation data parameter or with a null argument, you will get null in the callback.
The intention is that, if you want confirmations, you need to provide correlation data for every send (so you can determine which send the confirmation is for).
Related
I have two fields in SAP Fiori App: Template_ID and Offer_ID.
I want to choose value in Offer_ID depending on Template_ID field value.
For solving this problem I've tried to do this steps:
When the user click on Template_ID field in Back-End runs the method:
CL_CUAN_CAMPAIGN_DPC->contentset_get_entityset().
This method has returning paramater et_result. In et_result I have the necessary field temp_id.
For saving temp_id value I created a global attribute in class ZCL_CUAN_CLASS.
ZCL_CUAN_CLASS=>GV_CONTENT = VALUE #( et_result[ 1 ]-temp_ID OPTIONAL ).
I'll use this global attribute as an input parameter for my second method:
CL_CUAN_CAMPAIGN_DPC->GET_OFFER_BY_TEMPLATE().
This method returns to me the internal table with the offer_id, which belongs to my choosen temp_id.
But when the user click on Offer_ID field on Web UI, in debugging I see that my global attribute is blank.
May be it's because of session or something else, but it's blank.
OData is a stateless protocol, meaning the server responds your query, then forgets you were ever there. By definition, this does not allow you to transport main memory content from one request to the next.
User interfaces on the other hand usually require state. It can be gained through one of the following options:
Stateful user interface
As Haojie points out, one solution is to store the data that was selected in the user interface and submit it as a filter criterion back to the server with the next request. Having a stateful user interface is the standard solution for stateless server apps.
Stateful persistence
Another option is to store the data permanently in the server's database, in ABAP preferredly in a business object. This object has a unique identifier, probably a GUID, that you can reference in your requests to identify the process you are working on.
Draft persistence
If not all information is available in one step, such as in a multi-step wizard, should not become "active" right away, or you want to be able to switch devices while working on a multi-step process, drafts are an option. Drafts are regular business objects, with the one specialty that they remain inert until the user triggers a final activation step.
Soft state
For performance optimizations, you can have a look at SAP Gateway's soft state mode, which allows you to buffer some data to be able to respond to related requests more quickly. This is generally discouraged though, as it contradicts the stateless paradigm of OData.
Stateful protocol
In some cases, stateless protocols like OData are not the right way to go. For example, banking apps still prefer to pertain state to avoid that users remain logged in infinitely, and thus becoming vulnerable to attacks like CSRF. If this is the case for you, you should have a look at ABAP WebDynpro for your user interface. Generally, stateful server protocols are considered inferior because they bind lots of server resources for long times and thus cannot handle larger user numbers.
When ther user click on OfferId field, it will start a NEW session and of course what you store as GV_CONTENT in class ZCL_CUAN_CLASS is lost.
What you should do is that for the second request you should send to backend with filter Template_ID so in your CL_CUAN_CAMPAIGN_DPC->GET_OFFER_BY_TEMPLATE() method, you can further process the result by Template_ID.
Or SET/GET Parameter.
Based on the information here http://docs.valence.desire2learn.com/res/course.html#actions I would expect that to 'update' a courseOffering I would specify a PUT with a CourseOfferingInfo block, which only contains a few attributes. Every time I try this, I get a 404, not found - even using the same route for a successful GET (404 says org doesn't exist OR org is not an offering - neither is true). However, if I specify a CreateCourseOffering block (directly from a previous GET), the PUT works fine. Is this correct and the documentation not? Or are there other things I should look for in this scenario? The documentation says use CreateCourseOffering for the POST to create an offering… I simply want to update one attribute of that offering and as such thought the PUT was the way to go.
If you use the "create" POST route with a CreateCourseOffering block, this will create a new course offering, and send back the CourseOffering block for the newly created course offering (this will include the org unit ID value for the new org unit you've built).
If you want to update an existing course offering, you should, as you suspected, use the "update" PUT route with a CourseOfferingInfo block. Note that you must provide valid information for all the fields in this block, since when used successfully, the LMS will use all the properties you specify in that block for new values for the org unit. The StartDate and EndDate fields are particularly finicky: you must provide either a valid UTCDateTime value (notice that the three-digit millisecond specifier in these values is mandatory) or a JSON null value if the field is not applicable.
Why a 404? What you're seeing with the 404s and the data you're passing is likely down to the way the back-end service is doing data binding. It tries to de-serialize your provided JSON data (and query parameters) into data objects it can read/manipulate -- if you provide a JSON block that contains a superset of the properties it's expecting, then this may work (for example, if you provide a CourseOffering block when you're expected to provide a CourseOfferingInfo) as the binding layer may ignore fields it doesn't need. If the binding process fails, because you provide a value for a property that can't be bound to the data type expected, or because you fail to provide a JSON property field it expects, then this can cause the service to return a 404 (because binding/de-serializing incoming parameterized data happens at the same time as matching the URL route to an underlying service handler).
If you provide a JSON structure (and query parameters) that the web-service can bind to its expected data objects, but the values you provide are invalid or nonsensical, then this can cause the underlying service handler to respond with a 400 (signalling an Invalid Request). But in order to get this far, your parameterized data still needs to get properly deserialized and bound into data objects for the underlying service to examine.
We'll be updating the documentation to more explicitly draw out this fact. The safest policy from the calling client perspective is to pass valid JSON structures that are exactly what's expected by the individual routes, especially since the underlying back-end service implementation might change how it handles incoming requests.
It seems that there is no around interceptor for the filter in grails.We have the same in case of Spring.If we want to implement it as per grails format what will be the best way to do it.
You could mimic that somewhat. In the before closure you can check the request, session, etc. and determine whether to proceed with the regular call. If you want you can redirect, or render a response in the filter, and return false to indicate that the controller shouldn't be called.
If you want to allow the controller to proceed, you can then do work in the after closure. You can store information in request scope in the before closure (e.g. request.currentRequestNumber = counter.incrementAndGet()) and retrieve it in the after closure (e.g. int currentRequestNumber = request.currentRequestNumber) taking advantage of using property access to store and retrieve request attributes.
You cannot however "call" the controller and inspect its result, and choose whether to send that response, or modify it, or send a different response. You could probably do that with a response wrapper though, where you have a custom writer that captures the rendered response.
Note that you have more flexibility (but less Grails/Groovy help) with a regular servlet filter, i.e. a class that implements javax.servlet.Filter and is registered in web.xml.
I have an application that shows many charts and tables using JQuery. Some of these charts are based on variables that are saved in the session (E.g. user added a value in another page and in the next page I am generating a chart, so the user request doesn't send any parameters)
I was looking around on the net and most of the solutions are based on
[OutputCache(Duration=60, VaryByParam="someParm")]
The problem is most of my request don't send parameters, they just use values that are in the session.
Is there any way to enable cache for these kinds of requests?
Edit: We have a complex security requirement that we couldn't use the default authorization attribute of MVC. We had to write logics based on the current user + the parameters sent to the action, so a method inside the action decides either to go ahead with the request or returns nothing. This makes caching very difficult because at the time OutputCache is executed we just have parameters, but identity object in the context is empty. As a result, if a user with admin privilege send a request for a and b and after him someone with minimum privilege send request for a and b, the second person will see the result because the action didn't run, but the value from the cache is used!
To solve this problem I used the getvarybyCustome. All this function does is to return user's group name which helps to create a more complex key. The person with minimum privilege in the last example will have different cache key (a,b,group_less) than the admin's request cache key (a,b,group_admin). However, getting's group name for each request is expensive as well, so I use Cache object to cache user's group, so at the beginning of the session the user's group is queried from AD and saved to cache, so for his/her later requests, his group name is retrieved from cache.
If something you can't achieve by VaryByParam then you can try VaryByCustom. See an example here
You could make a redirect of this request and send it to a new controller method sending the session parameters, by this way in a future implementation may be you use query string parameters instead of session and your code will work too.
You could make a method for conversion of this session parameters on a base class of all your controllers, to write the conversion once.
Working in JBoss AS7, using Conversation Scope to manage the user's interactions within a browser tab.
I note that my pages get ?cid parameters appended. This is great - until the user bookmarks the page then tries to return to it! The Conversation Filter gives a "No such conversation" message.
Is there a better way of managing conversations? Perhaps an implementation or a switch to make it use hidden fields (with appropriate care in AJAX)? Alternatively I'll have to start trying to intercept the Conversation Exception or modify the filter!
Thanks
- Richard
Further:
I'm intercepting the BeforeRestoreView event for other purpose (login handling mainly). You'd think this would work:
/**
* #return true if there is no valid Conversation context.
*/
private boolean conversationNotActive()
{
Context conversationContext = m_beanManager.getContext(ConversationScoped.class);
return !conversationContext.isActive();
}
But I can't get the context to ask if if it's active! Will just throw a Try-Catch in for now.
We now take a two pronged approach.
A quite complex conversation manager detects a bad conversation Id and takes appropriate action. It responds currently to the After Restore View event. I'd like to move it earlier but am having problems deriving the view ID at this stage. I've written a JSF to CDI bridge to pass the events to CDI. SeamFaces would do the same, but proved too heavyweight for us.
For a normal GET the Conversation Manager redirects to self without the cid parameter in order to cause a new conversation to be started. For a postback it returns an HTTP 410 error. The detection of dead conversation is as above. We could use a more random conversation Id when we create conversations to try to prevent collision if an ID is reused.
The Conversation Manager will also start a conversation depending on metadata it holds about the pages. (All pages under /forms/ require a conversation in our application). It uses redirect when it does this to ensure that the CID parameter is everywhere it needs to be. This may become unnecessary if I can solve the problem of getting the form ID before RestoreView phase.
We use the browser history API to remove the cid from the user's browser URL window.