Freemarker Templates Caching Shared Variable after refresh - java

I have a Spring MVC web app which uses FreeMarker for rendering the views and have come up with the following issue.
Within my FreeMarker config I declare a Singleton Spring bean as a FreeMarker variable and within my application I have provided the mechanism for the Singleton Bean to be dynamically refreshed (the bean contains the application config retrieved from the DB).
Now the problem is that when it is refreshed the previously rendered FreeMarker templates use the values within the older version yet if I navigate to a page not rendered since the container started it uses the new values.
The following is a snippet of my FreeMarker config:
<!-- FreeMarker config -->
<bean id="freemarkerViewConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPaths">
<array>
<value>/WEB-INF/freemarker</value>
<value>classpath:/WEB-INF/freemarker</value>
</array>
</property>
<property name="freemarkerSettings">
<props>
<prop key="datetime_format">dd/MM/yyyy</prop>
<prop key="number_format">#</prop>
<prop key="whitespace_stripping">true</prop>
<prop key="auto_import">
spring.ftl as spring,
custom-macros.ftl as custom,
</prop>
</props>
</property>
<property name="freemarkerVariables">
<map>
<entry key="xml_escape" value-ref="fmXmlEscape"/>
<entry key="html_escape" value-ref="fmHtmlEscape"/>
<entry key="config" value-ref="config"/>
</map>
</property>
</bean>
To refresh the config model I execute the following within my Controller class:
((XmlWebApplicationContext)applicationContext).refresh();
Having this configuration picks up the refreshed config model when accessing a page which hasn't been already rendered but won't recognise the change on pages already visited.
I have tried the following to enforce the 'refresh' of the variable with no luck:
In the controller after the context is refresh I clear the templateCache within the FreeMarker Config which has been autowired:
freeMarkerConfig.getConfiguration().clearTemplateCache();
I have also tried disabling the caching of templates within the FreeMarker config using the following property within freeMarkerSettings:
freemarker.cache.NullCacheStorage
Finally, its worth pointing out that when in debug and looking through the cache and configuration the Shared Variable does indeed reference the most up to date config model yet the page renders using the older version.
Any advice / guidance on how to resolve this?
ps I am using Spring v3.1.1.RELEASE and FreeMarker v2.3.19

Not quite a solution but I have fixed my issue but it is more a hack to be honest.
I changed the code to refresh my config by using the following command so only the config bean was recreated:
((DefaultListableBeanFactory) beanFactory).destroySingleton("config");
And then modified the freemarker config by removing the reference to the config model as regardless what I tried I could not get this to be refreshed. So the solution to my issues was then to modify the BaseController which every controller within the application extends exposing the config model available as a #ModelAttribute so it was available to all the views.
As I said doesn't really solve the underlying issue but I have solved my problem albeit in a unorthodox fashion.

Related

Spring Integration and UriEndpointMapping

I've managed to setup a web service using Spring Integration that goes through a ws inbound gateway and then on to a service activator. Now I want to change the setup so that the inbound gateway is no longer the default endpoint mapping because there are other existing services that need to be available. When I change the UriEndpointMapping so that the gateway is no longer the default endpoint, I get this message: org.springframework.ws.server.EndpointNotFound - No endpoint mapping found for [SaajSoapMessage ....
I've tried changing the UriEndpointMapping to set the mappings property where I set the url to the gateway reference, and I've tried setting the endpointMap property and used a number of different keys, all without success. The Spring Integration documentation doesn't indicate how to set the UriEndpointMapping for multiple endpoints that are mapped to gateways, and the examples I've found on the web don't work for me either. I'm at a loss on how to proceed.
FYI, this configuration needs to be done in a spring xml file if at all possible.
This works:
<bean class="org.springframework.ws.server.endpoint.mapping.UriEndpointMapping">
<property name="defaultEndpoint" ref="reconGateway"/>
</bean>
This is my latest try, but it fails.
<bean class="org.springframework.ws.server.endpoint.mapping.UriEndpointMapping">
<property name="usePath" value="true"/>
<property name="mappings">
<props>
<prop key="http://localhost:8081/intfacade-web/reconService">reconGateway</prop>
</props>
</property>
</bean>
Any help would be greatly appreciated. Oh, I have tried with just the path and that didn't work either.
Thanks!
Anyone?

Spring-Boot: Jmx annotation not working in library

I have a Spring-Boot application that just have a simple rest controller. On this controller, I added the jmx annotations #ManagedResource and #ManagedOperation and it is working fine. It is correctly exposed in Jmx.
This application depends on a "global-commons" library to share many basic functionality to all of our modules.
But if I add the same annotations to a class in this library, it is ignored!
And before you ask, yes the library is imported with the latest change.
There is no error or warning message in the logs.
I am configuring all my beans using an xml file. Both classes are beans defined in the same file.
One is a #RestController. The other one is a simple utility class.
Any idea?
Make sure the classes from the global-commons library as managed by Spring. As long as none of the classes in the library are managed by Spring, the annotions don't have any effect.
I found the problems:
The bean that was not working was defined as an "inner" bean:
<bean id="imMetrics" class="com.imetrik.global.common.metrics.ImGlobalMetrics" init-method="init">
...
<property name="reporterList">
<util:list>
<bean id="jmxReporter" class="com.imetrik.global.common.metrics.reporters.ImJmxReporter">
<property name="registryId" value="metricRegistry1"/>
<property name="durationUnit" value="SECONDS"/>
<property name="rateUnit" value="SECONDS"/>
<property name="domain" value="com.imetrik.global.metric"/>
</bean>
</util:list>
</property>
</bean>
The annotated beans is "jmxReporter".
But if I put it outside as a normal "first level" bean and use a reference instead, it is working.
But it is annoying! Is there a way to make it work even as a inner beans?

metrics-spring configuration via .properties file

I'm trying to configure metrics-spring via configuration file
In my spring.xml I've added
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>
classpath:metrics.properties
</value>
</list>
</property>
<property name="systemPropertiesModeName"
value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="searchSystemEnvironment" value="true"/>
</bean>
filled with something like
metrics.reporter.type=console
and then I'm setting it in the spring config accessing that property via ${metrics.reporter.type}
<metrics:reporter metric-registry="metrics" type="${metrics.reporter.type}" period="1m"/>
During the startup of the web application, spring throws a BeanDefinitionParsingException due to the unresolved variable above
Configuration problem: No ReporterElementParser found for reporter type '${metrics.reporter.type}'
I'm using this configuration method (via properties file) for mongo host and port and it works like a charm.
I'm running in Tomcat7, Spring 4.0.5.RELEASE, metrics framework 3.1.0-SNAPSHOT (I need jersey 2 support) and metrics-spring 3.0.1. I also tried with a self-compiled metrics-spring 3.1.0-SNAPSHOT but doesn't solve my problem.
[EDIT]
Found this issue which explain that SpEL is not supported by the ElementParser.
I'm afraid it isn't possible to use a property placeholder in the type attribute. Spring does not resolve property placeholders or SpEL until the phase after metrics-spring reads the type attribute and parses the reporter element (which is necessary to allow placeholders and bean references to be used in all the other attributes).
A possible solution would be to configure all the reporters you might want to use, and use a placeholder in the enabled attribute:
<metrics:reporter metric-registry="metrics" type="console" period="1m"
enabled="${metrics.reporter.console.enabled}" />
<metrics:reporter metric-registry="metrics" type="slf4j" period="1m"
enabled="${metrics.reporter.slf4j.enabled}" />
And the properties file:
metrics.reporter.console.enabled=true
metrics.reporter.slf4j.enabled=false
I hope this makes sense, I've had a very long week!

Using spring as configurator

I have a server application. Now I'm using Spring not only to inject dependencies, but also to config my application. Something like this:
<bean id="server" class="foo.bar.Server">
<property name="host" value="${config.host}"/>
<property name="someBean">
<ref bean="someBean"/>
</property>
</bean>
My colleague sad that configuring application in Spring is not obvious and we should avoid this. I see logic in his words, because Spring is for dependence injection and server port is not dependency, isn't it? But for me configuring application is Spring is very convenient and obvious. Is my colleague right?
Configuring in Spring is simple, clear and maintainable.
This way you can easily create several instances with different properties.

Correct usage Of LOG4J in Spring Framework Via DI

I am trying to use Log4j as part of the Spring Framework,
as far as i understand through the use of a an appropriate bean
the system is supposed to map a singleton instance accessible in the code
while mapping the logging depth automatically to the class
Similar to the normal use of Log4J as in
Logger log = Logger.getLogger(getClass());
i have been using the following Spring bean definition
<bean id="log4jInitialization"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass"
value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>conf\log4j.xml</value>
</list>
</property>
</bean>
But i am unable to map this bean to a specific member in a given class
nor am i able to use it through #autowired
Please let me know if there are any better ways to integrate Log4j and Spring
Best Regards
Mark
The short answer to your question is that log4j is not DI friendly.
The Log4jConfigurer.initLogging() method has a void return value, so there's nothing to inject. The idea is that you call that method, which bootstraps log4j, and then you use the Log4j API as usual (using Logger.getLogger(getClass())).
You generally wouldn't configure Log4jConfigurer as a Spring bean, though, but more usually you'd invoke it directly from your own code during application startup.
If this is a webapp, then Spring provides alternatives to Log4jConfigurer that are better suited to that environment (Log4jWebConfigurer, Log4jConfigListener).
Incidentally, 2 years ago I filed a feature request to allow loggers to be autowired, and it's finally been marked as fix for Spring 3.1. Horray.

Categories

Resources