How to disable freemarker caching in Spring MVC - caching

I'm using spring mvc v3 with freemarker views and cannot disable caching.
I tried by setting cache to false in viewResolver element in (spring-servlet.xml) but didn't work.
Basically what I'd like to the do some changes in freemarker and see these changes in the browser with refresh only (w/o restarting the application)
Any hints how to do that?

In my XML the following was successful:
<bean id="freemarkerMailConfiguration" class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
<property name="templateLoaderPaths" value="classpath:emailtemplates/task,classpath:emailtemplates/user"/>
<!-- Activate the following to disable template caching -->
<property name="freemarkerSettings" value="cache_storage=freemarker.cache.NullCacheStorage" />
</bean>
This is my mail config, but the freemarkerConfig should be interesting four you, too.

I dont use to configure freemarker with xml configurations but with #Configuration annotated classes; cause i rather the Spring-Boot´ style. So you can disable the freemarker´s cache like this:
#Bean
public FreeMarkerConfigurer freeMarkerConfigurer() throws IOException, TemplateException
{
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer()
{
#Override
protected void postProcessConfiguration(freemarker.template.Configuration config) throws IOException, TemplateException
{
ClassTemplateLoader classTplLoader = new ClassTemplateLoader(context.getClassLoader(), "/templates");
ClassTemplateLoader baseMvcTplLoader = new ClassTemplateLoader(FreeMarkerConfigurer.class, ""); //TODO tratar de acceder a spring.ftl de forma directa
MultiTemplateLoader mtl = new MultiTemplateLoader(new TemplateLoader[]
{
classTplLoader,
baseMvcTplLoader
});
config.setTemplateLoader(mtl);
config.setCacheStorage(new NullCacheStorage());
}
};
configurer.setDefaultEncoding("UTF-8");
configurer.setPreferFileSystemAccess(false);
return configurer;
}
The key is in:
config.setCacheStorage(new NullCacheStorage());
But you can also use this instruction instead:
config.setTemplateUpdateDelayMilliseconds(0);
It should work for you.

In application.properties:
spring.freemarker.cache=false

As defined by the manual :
If you change the template file, then FreeMarker will re-load and
re-parse the template automatically when you get the template next
time. However, since checking if the file has been changed can be time
consuming, there is a Configuration level setting called ``update
delay''. This is the time that must elapse since the last checking for
a newer version of a certain template before FreeMarker will check
that again. This is set to 5 seconds by default. If you want to see
the changes of templates immediately, set it to 0.
After searching around, the configuration key was in the freemarker.template.Configuration javadocs, at the setSetting(key, value) method.
So, in short, just set the config template_update_delay to 0 for immediate change detection.
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/ftl/"/>
<property name="freemarkerSettings">
<props>
<prop key="template_update_delay">0</prop>
<prop key="default_encoding">UTF-8</prop>
</props>
</property>
</bean>

Did you check the FreeMarker documentation, which contains some hints regarding how to influence template caching at the FreeMarker Configuration level. I'm not sure if you have access to the FreeMarker Configuration object from inside Spring MVC, but if you have, then the documentation page mentioned above could point you towards a possible solution.

I wasted the last two days (note entirely for this project) trying to disable the cache. It turns out I have the two options antiJARLocking and antiResourceLocking set in my context.xml. Then the templates will ALWAYS be cached

I had the same problem which I could solve only by implementing a custom template loader. Here is the working code:
protected void init() throws Exception {
freemarkerConfig = new Configuration();
freemarkerConfig.setObjectWrapper(ObjectWrapper.DEFAULT_WRAPPER);
freemarkerConfig.setTemplateLoader(new CacheAgnosticTemplateLoader(new DefaultResourceLoader(), pdfTemplatePath));
}
protected static class CacheAgnosticTemplateLoader extends SpringTemplateLoader {
public CacheAgnosticTemplateLoader(ResourceLoader resourceLoader, String templateLoaderPath) {
super(resourceLoader, templateLoaderPath);
}
#Override
public long getLastModified(Object templateSource) {
// disabling template caching
return new Date().getTime();
}
}

It seems that in the recently released FreeMarker version 2.3.17, a legal and simpler way to do it has appeared: freemarker.cache.NullCacheStorage.

Related

Can the Spring active profiles be set through a property file?

I want to be able to read the active profiles from a property file so that different environments (dev,prod etc) can be configured with different profiles in a Spring MVC based web application. I know that the active profiles can be set through JVM params or system properties. But I would like to do it through a property file instead. The point is that I dont know the active profile statically and instead want to read it from a properties file. It looks like this is not possible. For eg., if I had 'spring.profiles.active=dev' in application.properties, and allow it to be overridden in override.properties like so:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:/application.properties</value>
<value>file:/overrides.properties</value>
</list>
</property>
</bean>
the profile is not being picked up in the environment. I guess this is because the active profiles are being checked before bean initialization, and therefore do not honor the property being set in a properties file. The only other option I see is to implement an ApplicationContextInitializer that will load those property files in order of priority(override.properties first if it exists, else application.properties) and set the value in context.getEnvironment(). Is there a better way to do it from properties files?
One solution to do it is to read necessary property file with specified profile "manually" - without spring - and set profile at context initialization:
1) Write simple properties loader:
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Properties;
public class PropertiesLoader
{
private static Properties props;
public static String getActiveProfile()
{
if (props == null)
{
props = initProperties();
}
return props.getProperty("profile");
}
private static Properties initProperties()
{
String propertiesFile = "app.properties";
try (Reader in = new FileReader(propertiesFile))
{
props = new Properties();
props.load(in);
}
catch (IOException e)
{
System.out.println("Error while reading properties file: " + e.getMessage());
return null;
}
return props;
}
}
2) Read profile from properties file and set it during Spring container initialization (example with Java-based configuration):
public static void main(String[] args)
{
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles(PropertiesLoader.getActiveProfile());
ctx.register(AppConfig.class);
ctx.refresh();
// you application is running ...
ctx.close();
}

How to make empty configuration if file not found?

Using Apache Commons Configurations 1.9, how to avoid ConfigurationException upon loading a configuration file if the provided file cannot be found?
The Spring app context resembles:
<bean name="foo.config" class="org.apache.commons.configuration.PropertiesConfiguration" init-method="load">
<property name="fileName" value="foo.properties" />
</bean>
However my config file is optional, so I want to make sure the application starts correctly even the file doesn't exist.
How can I achieve this with Commons Configurations? A FactoryBean works, but is there another way?
if (!file.exists()) return new PropertiesConfiguration();
Or using try/catch syntax using an XML configuration:
import org.apache.commons.configuration2.XMLConfiguration;
import org.apache.commons.configuration2.builder.fluent.Configurations;
public class Workspace {
private final XMLConfiguration mConfig;
public Workspace() {
final var configs = new Configurations();
XMLConfiguration config;
try {
config = configs.xml( "filename.xml" );
} catch( final Exception e ) {
config = new XMLConfiguration();
}
mConfig = config;
}
Using a regular properties configuration will work the same way.

How to poll directory for a file?

I need to be able to poll a directory for a specific file using SCP, and once the file has been processed, it needs to keep polling.
Is this possible with Spring Batch?
The normal way to handle this is using Spring Integration. The way I'd address it is with a Spring Integration flow that uses a SFTP Inbound Channel Adapter to retrieve the files, then passes the transferred name to Spring Batch to launch. The flow would actually be similar to the sample in the SpringBatchIntegration in my Spring Batch Webinar here: https://github.com/mminella/SpringBatchWebinar
In that example, I use Twitter to launch the job. The only thing you'd need to change is the twitter piece for the SFTP.
I had to solve the same question (but just accessing to the local filesystem) and I did not find any solution in the framework, so I ended up creating my own class which polls for the file and creates a resource.I know this is just a workaround, but I haven't found a better way to do that so far.
I can't remember where (maybe in the "retry handling" part) but I read in the documentation something like "batch jobs should not try to solve issues like files not found, connections down and so, these kind of errors should make the job raise an error to be handled by operators" so I gave up...
On the other hand Spring Retry was part of Spring batch and now is a new separate library, maybe you just can assume the file is there and if the reader does not find it, let the step fail and establish a "retry policy" for that step, but for me that's overkill.
This is what I did:
<bean id="resourceFactory"
class="com.mycompany.batch.zip.ResourceFactory">
<property name="retryAttemps" value="${attemps}" />
<property name="timeBetweenAttemps" value="${timeBetweenAttemps}"/>
</bean>
<bean id="myResource"
factory-bean="resourceFactory" factory-method="create" scope="step">
<constructor-arg value="${absolutepath}" type="java.lang.String" />
</bean>
<!--step scope to avoid looking for the file when deployment-->
<bean id="myReader"
class="org.springframework.batch.item.xml.StaxEventItemReader" scope="step">
<property name="fragmentRootElementName" value="retailer" />
<property name="unmarshaller" ref="reportUnmarshaller" />
<property name="resource" ref="myResource" />
</bean>
And this is my class:
public class ResourceFactory {
public static final Logger LOG= LoggerFactory.getLogger(ResourceFactory.class);
private int retryAttemps;
private long timeBetweenAttemps;
public Resource create(String resource) throws IOException, InterruptedException {
Resource r;
File f=new File(resource);
int attemps=1;
while (!f.exists()) {
if (attemps<this.retryAttemps) {
attemps++;
LOG.warn("File "+resource+" not found, waiting "+timeBetweenAttemps+
" before retrying. Attemp: "+attemps+" of "+this.retryAttemps);
Thread.sleep(this.timeBetweenAttemps);
} else {
throw new FileNotFoundException(resource);
}
if (resource!=null && resource.endsWith(".zip")) {
ZipFile zipFile = new ZipFile(resource);
ZipEntry entry=zipFile.entries().nextElement();
if (entry==null) {
throw new FileNotFoundException("The zip file has no entries inside");
}
//TODO Test if a buffered Stream is faster than the raw InputStream
InputStream is=new BufferedInputStream(zipFile.getInputStream(entry));
r= new InputStreamResource(is);
if (LOG.isInfoEnabled()) {
int size=(int)entry.getSize();
LOG.info("Opening a compressed file of "+size+" bytes");
}
} else {
LOG.info("Opening a regular file");
r= new FileSystemResource(f);
}
}
return r;
}
}
If anyone knows a better way to do that, I'll gladly remove this answer (and implement the new solution)
PS: BTW, I've found some faults in my code when reviewing this post, so for me this is being helpful even with no other answers :)

Connect LDAP from Spring

I have to realize a web application based on Spring, allowing the user to manage LDAP data. The connection to the LDAP should be done only with the JNDI framework (no SpringLDAP allowed).
For this, I realized a utility class to do the basic operations (add, update, delete, list, ...).
Here is a short block of code of this class :
public class LdapUtility {
private static LdapUtility instance;
private DirContext dirContext;
public static LdapUtility getInstance() {
if(LdapUtility.instance == null)
LdapUtility.instance = new LdapUtility();
return LdapUtility.instance;
}
/**
* Connect to the LDAP
*/
private LdapUtility() {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=Manager,dc=my-domain,dc=com");
env.put(Context.SECURITY_CREDENTIALS, "secret");
try {
dirContext = new InitialDirContext(env);
}
catch(Exception ex) {
dirContext = null;
}
}
public void addUser(User u) {
dirContext.createSubcontext(....); //add user in the LDAP
}
}
With this code, I can access all my methods by calling LdapUtility.getInstance()..., but the connection to the LDAP will never be released.
Another way would be to connect to the LDAP before each operation, but in this case there would be too much connections to the LDAP...
So, here is my question : what is the most elegant/smartest way to access these methods ?
Thank you in advance :-)
Since you're already using Spring, I would recommend using Spring LDAP:
Spring LDAP is a Java library for simplifying LDAP operations, based on the pattern of Spring's JdbcTemplate. The framework relieves the user of common chores, such as looking up and closing contexts, looping through results, encoding/decoding values and filters, and more.
Especially if you're not familiar with LDAP and potential performance problems, it can help to start of using a utility library like this that will do all the heavy lifting for you.
You configure the LDAP connection settings in the spring config:
<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="ldap://localhost:389" />
<property name="base" value="dc=example,dc=com" />
<property name="userDn" value="cn=Manager" />
<property name="password" value="secret" />
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>
You can then just use the LdapTemplate wherever you need to perform an LDAP action:
return ldapTemplate.search(
"", "(objectclass=person)",
new AttributesMapper() {
public Object mapFromAttributes(Attributes attrs)
throws NamingException {
return attrs.get("cn").get();
}
});
without a spring (being forbidden), i would quickly implement something simillar:
(when being lazy) create a simple callback interface (such as you can find in spring -- JpaCallback.execute(EntityManager em)) -- but for LDAP -- MyLdapCallback.execute(LdapConnection connection) -- intead of LdapConnection you can imagine anything you require -- objects from OpenLdap or SDK Context. Something like (just for presentation):
...
interface LdapCallback<T> {
T execute(DirContext ctx) throws NamingException, IOException;
}
...
private <T> T execute(LdapCallback<T> callback) throws NamingException, IOException {
T result = null;
LdapContext ctx = new InitialLdapContext();
try {
result = callback.execute(ctx);
} finally {
if (tls != null) {
tls.close();
}
ctx.close();
}
return result;
}
...
Once done, you will create anonymous classes for each Ldap call an call the callback via execute(callback).
(having more time) implement ad 1. + create AOP that will wrap my methods marked with annotation with aspect that will itself execute my methods within the wrapper above (without explicitly doing so in my code)
There are several ways to connect to ldap. Using javax.naming.* is one of them. In javadoc you may find, that classes in your SPI provider manages their own connections, so you don't care for it -- that may be an answer to your question -- see JDK doc and how Context manages conections and network -- http://docs.oracle.com/javase/6/docs/api/javax/naming/ldap/LdapContext.html .
If you are accustomed to more JDBC-like access, you may find http://www.openldap.org/jldap/ more to your liking. There you have conections completely under your control and you treat them much the same way as in JDBC. You may use any pooling library you like.
Not knowing the exact requirements I interpret the core question as being "when to open/close the connection".
My crystal ball tells me you may want to use a connection pool. True, you don't close the connection explicitly as this is handled by the pool but this may be ok for your assignment. It's fairly easy:
// Enable connection pooling
env.put("com.sun.jndi.ldap.connect.pool", "true");
The complete source code is referenced in Oracle's basic LDAP tutorial.

Spring mixed XML/annotation configuration with overrides

I'm working on setting up a utility that lets us load an annotation-based configuration that overrides an XML configuration (for testing). I have tried a number of different setups, but this is the only one that I've gotten to work:
GenericApplicationContext firstCtx = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(firstCtx );
xmlReader.loadBeanDefinitions("applicationContext.xml");
GenericApplicationContext ctx = new GenericApplicationContext();
AnnotatedBeanDefinitionReader annotatedReader = new AnnotatedBeanDefinitionReader(ctx);
annotatedReader.register(SomeConfigClass.class);
ctx.refresh();
for (String currBeanName : firstCtx.getBeanDefinitionNames())
{
if (!ctx.containsBeanDefinition(currBeanName))
{
ctx.registerBeanDefinition(currBeanName, firstCtx.getBeanDefinition(currBeanName));
}
}
While this technically does work, it seems like a really cumbersome way to do this. Is there a better way to load an annotation-based configuration over an XML-based configuration?
Thanks!
I think a simpler way is to simply declare SomeConfigClass as a bean within your application context and the configured beans in SomeConfigClass will be wired in.
<bean class="..SomeConfigClass"/>
Or <context:component-scan base-package="package of SomeConfigClass"/>
Or the other way round, in SomeClassClass, do #ImportResource("applicationContext.xml")

Resources