Overview
The problem is defined
hereI have configured some properties files for the application using the PropertyPlaceholderConfigurer. How can I access these properties in JSP?
We have faced the same problem when we quite often need access from JSP to some configurable parameter. Usually we did the same way as described in the forum thread by having specific beans that were configured by PropertyPlaceholderConfigurer. But with the time they began look like some pretty wrong approach, when we had properties that are not connected to each other in one place and clear understanding that it is a workaround that need to be eliminated.
Idea
Idea was very simple, read all properties configured by PropertyPlaceholderConfigurer and put them to some attribute of the ServletContext, thus getting them accessible via 'application' scope from JSP. However it looks simple but there is no ability to extract resolved properties from PropertyPlaceholderConfigurer, I spend quite time to read code and understand what to do.
Implementation
The simples way I found is extending it with own class that will do the job of exposing properties to the outside.
package com.sonopia.sonoportal.web.util;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
/**
* Bean that should be used instead of the {@link PropertyPlaceholderConfigurer} if you want to have
* access to the resolved properties not obly from the Spring context. e.g. from JSP or so. More
* details about usage here http://wiki.sonopia.com/x/GmQ
*
* @author Mykola Palienko
*/
public class ExposablePropertyPaceholderConfigurer extends PropertyPlaceholderConfigurer {
private Map<String, String> resolvedProps;
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
Properties props) throws BeansException {
super.processProperties(beanFactoryToProcess, props);
resolvedProps = new HashMap<String, String>();
for (Object key : props.keySet()) {
String keyStr = key.toString();
resolvedProps.put(keyStr, parseStringValue(props.getProperty(keyStr), props,
new HashSet()));
}
}
public Map<String, String> getResolvedProps() {
return Collections.unmodifiableMap(resolvedProps);
}
}
and configuring it in the Spring context declaration xml file in your project
<bean id="propertyConfigurer" class="com.sonopia.sonoportal.web.util.ExposablePropertyPaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:sonoportal.properties</value>
<value>classpath:sonoportal.custom.properties</value>
<value>classpath:sonoportal.buildInfo.properties</value>
</list>
</property>
</bean>
The good thing here is that we also resolve ANT style properties like
${dbname} etc.
Then we need to expose that properties to the ServletContext, this job usually is done by implementing ServletContextListener.
/**
* Copyright 2005-2006 Sonopia Corporation
*/
package com.sonopia.sonoportal.web.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.sonopia.sonoportal.web.util.ExposablePropertyPaceholderConfigurer;
/**
* Listener that exposes properties configured by {@link ExposablePropertyPaceholderConfigurer} to
* the web application context.
* More details about usage here http://wiki.sonopia.com/x/GmQ
*
* @author Mykola Palienko
*/
public class ConfigPropertiesExposerListener implements ServletContextListener {
public static final String DEFAULT_PROPERTIES_BEAN_NAME = "propertyConfigurer";
public static final String DEFAULT_CONTEXT_PROPERTY = "configProperties";
private String propertiesBeanName = DEFAULT_PROPERTIES_BEAN_NAME;
private String contextProperty = DEFAULT_CONTEXT_PROPERTY;
public void contextDestroyed(ServletContextEvent sce) {
}
public void contextInitialized(ServletContextEvent sce) {
// TODO add ability to configure non default values via serveltContexParams
ServletContext servletContext = sce.getServletContext();
WebApplicationContext context = WebApplicationContextUtils
.getRequiredWebApplicationContext(servletContext);
ExposablePropertyPaceholderConfigurer configurer =
(ExposablePropertyPaceholderConfigurer) context.getBean(propertiesBeanName);
sce.getServletContext().setAttribute(contextProperty, configurer.getResolvedProps());
}
}
and add several lines to the
web.xml <listener>
<listener-class>
com.sonopia.sonoportal.web.listener.ConfigPropertiesExposerListener
</listener-class>
</listener>
Usage
Having all above done accessing any property from JSP is not harder than
${configProperties['website.hostname']}
The snippet above will print out
website.hostname property configured by
ExposablePropertyPaceholderConfigurer