I have recently asked a question here where I asked how to reference a String object in the mule registry from a Mule Flow. That has been successfully answered my current problem is that I cannot populate this in the registry before the flow is initialized.
Thus in the following segment (password="#app.registry['password']]) null is always used and my connection fails:
<sfdc:config name="ConfigurableSalesforceConnection"username="${sfdc.username}"password="#app.registry['password']]"securityToken="${sfdc.securityToken}"doc:name="Salesforce" url="${sfdc.url}" />
Amongst other things I have added a listener to my flow, but this adds the value too late and the flow has already been initialized.
<notifications>
<notification event="CONTEXT"/>
<notification-listener ref="Initializer"/>
</notifications>
<spring:beans>
<spring:bean id="Initializer" name="Initializer"
class="initializer.InitAccountSync" />
</spring:beans>
My question consists of two parts, firstly is there a way to fore the reinitialization of a flow after start-up, and/or how can I store a value in the mule-context registry before said initialization?
Thanks in advance.
The registry is shared with Spring, you can register some java.lang.String beans using SpEL or a MethodInvokingFactoryBean.
However, for this case, if you are not retrieving it outside mule, what I would recommend is leverage jasypt.
Related
Our application is deployed as a servlet war to multiple tomcat servers under multiple customer contexts:
customer#application.war
We're using log4j2 as our logging and alert email mechanism. So far, everything is working great and our fatal errors are being sent. However, as we deploy to new contexts, it's becoming less clear which customer is generating the error.
So far, it appears that the subject value is static and set in the config file and the system variables are loaded when the logger is built:
subject="[${applicationname}] Fatal Error ${hostname}:${sys:pwd}"
While it appears that there is a way to ascertain the name of our deployed context via the servlet API, we have yet to determine how to introduce this value in the email subject programmatically and dynamically at run time.
This would greatly reduce the time it takes to research an error. Any tips?
So far we've considered the following:
Custom war file with custom log4j2 config for each customer context (very hackish)
Update all log.fatal calls to include the context info from the servlet (horrid)
Custom SmtpAppender (final and protected so that's out)
Custom SmtpManager and override the subject in the MimeMessage object (seems workable but the documentation does not show how to implement)
TIA!!
Piko
This is actually a known issue in Log4j2 as of 2.9.1. The problem is that a MimeMessage is cached and the subject becomes a fixed value. A simple solution would be to stop caching.
There is an open ticket to address this: Log4j2-1450. (Related: Log4j2-1192, which implemented pattern lookups but didn’t fix that MimeMessages are cached.)
If you can provide a patch or a pull request it would greatly increase the chances of this being addressed speedily.
Update: looking my old comment in that ticket:
Looks like subject already supports $$ runtime lookups. The following
attributes are used for each email that is sent, and it should be
possible to support runtime lookups for these attributes:
* from
* replyto
* to
* cc
* bcc
* subject (already a runtime lookup)
It should be possible to configure the subject to be a system properties lookup like this:
subject = "$${sys:email.subject}"
Then you set system property email.subject to a different subject and send an email with a different subject. Can you try this?
Update 2:
If system properties are not suitable, you can also create a custom lookup, this is only a few lines of code.
Is it possible to re-read custom key/values from consul k/v store with spring-cloud-consul lib? Haven't found an answer in documentation.
Of course it can be accessed with http GET request, but the point is to change some key's value and to make spring application to handle this change immediately.
UPD: unfortunately we've migrated from Consul to config-server, but I guess #RefreshScope should do the magic.
spring-cloud-consul auto configures a ConsulClient into the application context. This if from the Ecwid/consul-api client. Usage is the same, but instead of calling new ConsulClient() you would inject one (ie #Autowired ConsulClient consulClient).
Expectation:
When i attempt booking, booking has been failed due to price change and throwing below price change exception.
Then i need to capture that errors in event and redirect the request to previous page and display the error message on top of the page.
As per my below logic i can able to redirect the request to previous page, while throwing price change exception but the issue is i can't able to
display my error message (Your booking price has been changed, please choose another) on previousPage.
Anybody can help me out. Thanks in advance.
BookAction.java
public class BookAction {
private static final String PRICE_CHANGED_ERROR = "Your booking price has been changed, please choose another";
public Event book(RequestContext context) {
try {
// Booking attempt
// Consider booking attempt failed and throwing price change exception
}catch (PriceChangeException priceChangeException) {
return handlePriceChange(context);
}
}
public Event handlePriceChange(RequestContext context) {
Errors pageErrors = getPageErrors(context);
if (true) { // Consider if its true and returning new Event "searchPage"
pageErrors.reject(PRICE_CHANGED_ERROR);
return new Event(this, "searchPage");
}
return error();
}
}
booking.xml
<webflow:flow>
<webflow:action-state id="book">
<webflow:evaluate expression="bookAction.book" />
<webflow:transition on="success" to="confirm" />
<webflow:transition on="error" to="handleFrd" />
<webflow:transition on="searchPage" to="searchPage" />
</webflow:action-state>
<webflow:end-state id="searchPage" view="externalRedirect:#{flowScope.bookState.searchResultURI}" />
</webflow:flow>
Unfortunately, this is a poorly documented part of SWF. What you are looking for is to use the flashScope. flashScope was specifically designed for this purpose after a variable in the flashScope is read once it is automatically deleted.
But... the design problem in SWF is that the flashScope only works between a Parent flow and an embedded child flow inside of it. It will not hold save your variables if you use an "externalRedirect" and try to access the error using "flashScope.error"... because technically the first flow ended and a new flow has begun. So how to solve this problem?
I was only able to solve it with 2 ways and both are hacks.
Option 1.
if the message is simple then in the 'externalRedirect:#{flowScope.bookState.searchResultURI}' append a HTTP GET param such as
?msg=An Error Occurred.
Although this will look ugly in the url bar, it is simpliest and the least painful solution.
Option 2.
is a bit more painful but provides the most flexibility if you want complex error msgs. Basically you have to merge the flashScope of Spring Web Flow and the flashMap of Spring MVC and send your externalRedirect to a spring mvc controller first.
You will need to create and register a FlowExecutionListenerAdapter
to merge (hack) the flashScope and the flashMap see the link directly below for step by step instructions (ignore the stuff about sessionMap)
Spring web flow how to add flash attribute when exiting from flow to external redirect
Then once you achieve that you can easily access your flash variable error msg using Spring MVC like so:
How to read flash attributes after redirection in Spring MVC 3.1?
Note: the variable will already be in the flashMap of spring mvc. So all you have to do is render a view in spring mvc and access the variable from the view.
My 2 cents: because of limitations like this I've personally stopped using webflow and only use Spring MVC exclusively now. I think Spring Web flow is still useful for very simple use cases (flow A -> flow B -> flow C) but if you're trying to to do something more complex or are trying to learn SWF from scratch right now... my advice to you is to just use Spring MVC... it will save you a lot of time in the long run. I think they are working on a major revision for SWF (3.0) maybe then all these limitations will get worked out
Indeed Spring Web Flow has a number of scopes where variables can be stored but when a flow ends all scopes end as well, unless the flow is a child flow delegating control back to the parent flow in which case you can use flash scope in addition to any parent flow scoped variables.
Spring Web Flow also knows how to interact with the Spring MVC flash scope. So when a top-level flow ends and the redirect is to a Spring MVC endpoint, there is a way to indicate that output variables should be put in Spring MVC flash scope, which would make them available after the redirect.
This is mentioned in the reference documentation http://docs.spring.io/autorepo/docs/webflow/current/reference/html/spring-mvc.html#spring-mvc-flash-output.
in booking.xml, add below changes
<webflow:transition on="searchPage" to="searchPage">
<set name="flowScope.error" value="'text u wanna show in next page'" type="string" />
</webflow:transition
And now in the redirected page try reading that text. hope it would work!
Use flash scope:
In xml
<set name="flashScope.flashScopeAttribute" value="'f'" />
In JSP
flash scope: #{flashScopeAttribute}
I currently need to utilize three vhosts for this application. I am only receiving messages over one as a consumer, and the others for RPC calls. Currently I am using CachingConnectionFactory that I have subclassed one for each virtual host. Then I am making each of those subclasses beans. I can then of course grab the connection factory to create the RabbitTemplate for the correct vhost instance.
I saw in the documentation about the AbstractRoutingConnectionFactory but wanted to know if there are any reasons I should refactor my currently working code. I want the most maintainable and perfomant solution, not the "easiest" one.
Thanks!
I am not sure why you felt it was necessary to subclass the CachingConnectionFactory you can simply declare multiple factories...
<rabbit:connection-factory id="default" host="localhost" />
<rabbit:connection-factory id="foo" host="localhost" virtual-host="/foo" />
<rabbit:connection-factory id="bar" host="localhost" virtual-host="/bar" />
Whether or not you using a routing connection factory (e.g. SimpleRoutingConnectionFactory) depends on your application needs. If you don't use it you would need 3 RabbitTemplates and decide which one to use at runtime.
With a routing connection factory, the RabbitTemplate can make the decision based on the message content with a send-connection-factory-selector-expression.
There's not really a lot of difference except the second decouples your application from the decision. For example, you can set a message header customerId before sending (or during message conversion if you're using a convertAndSend method) and use a selector expression such as #vhostFor.select(messageProperties.headers.customerId).
If you later add a new vhost you wouldn't have to change your main application, just your vhostFor lookup bean to pick the right vhost.
I would like to delete some temporal files when user session finishes. The information associated with the files is stored in an object annotated with #SessionAttributes.
The only way I've found to deal with this is creating an HttpSessionListener.
Is there a higher level, simplified, Springy way to listen to the session end event where I could easily get my annotated object?
You most likely will need to create a HttpSessionListener.
Another stackoverflow answer:
Detect session timeout in Spring 3/Spring Security 2.0.5
Also and example on how to load spring beans into it:
http://www.mkyong.com/spring/spring-how-to-do-dependency-injection-in-your-session-listener/
Two options to use HttpSessionListener with spring beans:
The first is to use WebApplicationContextUtils.getRequiredApplicationContext(servletContext) to obtain the servlet context. From there you have two sub-options:
use getBean(..)
If you want to use #Autowired / #Inject use getAutowireCapablyBeanFactory().autowireBean(this). You will have to do this only once (check if the fields are null), because the listener is singleton.
The second option is to use AspectJ and #Configurable on the listener.
Not directly related, but might be an interesting project to look at.
https://github.com/shawnmclean/Idle.js
Session deletion typically happens on the server side, when the session expires (usually 30mn). The project above allows to detect user behaviors in the front end.