Reading .properties file only once while web app deployment - java

Having a Java web application, how does one read properties file only once when the app is deployed (storing them later in some singleton)? Meaning, configuration changes would require redeployment.
Otherwise, is there an alternative way to prevent an app from constantly reading .properties file? Previously I had settings in my web.xml file, but now .properties is required.
Code used to read app settings from JBoss configuration path:
File f = new File(System.getProperty("jboss.server.config.dir"),
"myappsettings.properties");
Properties p = new Properties();
p.load(new FileInputStream(f));
try {
db_name = p.getProperty("DATABASE_NAME"));
file_path = p.getProperty("FILE_PATH"));
...
} catch (Exception e) {
...
}

Starting with JEE6, another alternative to the ServletContextListener could be using a singleton startup bean:
#Singleton
#Startup
public class PropertyRegistry {
#PostConstruct
private void init(){
//do something
}
}

Implement your own ServletContextListener:
public class PropertiesReadingListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
//read properties here...
event.
getServletContext().
setAttribute("db_name", p.getProperty("DATABASE_NAME"));
}
#Override
public void contextDestroyed(ServletContextEvent event) {
}
}
You must reference this class in web.xml:
<listener>
<listener-class>com.example.PropertiesReadingListener</listener-class>
</listener>

Related

config changes without redeployment

My web application has several integrations with external systems and all these integration Rest URLs are kept in a config file with in web app. My application reads this config file at start up and use the URL values while making connections to external systems. But quite often it happens that one of the external systems is down and we have to use an alternate URL. In that case, we typically will have to modify the config and redeploy the war file. Is there a way to modify config file with new value without going through a redeployment of the war file?
In my projects i usually work with Apache Commons Configuration for the management of config files (properties). This library has the capability of automatic reload the values when file changes.
This is muy suggestion of implementation:
Create a class "MyAppConfigProperties" for load the properties file and read your configuration keys:
public class MyAppConfig {
//Apache Commons library object
private PropertiesConfiguration configFile;
private void init() {
try {
//Load the file
configFile = new PropertiesConfiguration(
MyAppConfig.class.getClassLoader().getResource("configFile.properties"));
// Create refresh strategy with "FileChangedReloadingStrategy"
FileChangedReloadingStrategy fileChangedReloadingStrategy = new FileChangedReloadingStrategy();
fileChangedReloadingStrategy.setRefreshDelay(1000);
configFile.setReloadingStrategy(fileChangedReloadingStrategy);
} catch (ConfigurationException e) {
//Manage the exception
}
}
/**
* Constructor por defecto.
*/
public MyAppConfig() {
super();
init();
}
public String getKey(final String key) {
try {
if (configFile.containsKey(key)) {
return configFile.getString(key);
} else {
return null;
}
} catch (ConversionException e) {
//Manage Exception
}
}
}
Now you have to construct a instance of this class (singleton) and use it in all places in that you need to reed a config key.
Every time you use the method "getKey" you will get the last value of the key without deploy and restart.

Loading web application properties

When I build project by maven, it's OK, but when deploy it by Tomkat, I have NullPointerException.
Class, where can be problem - PropertiesManager.
logline: PropertiesManager.getApplicationProperties(PropertiesManager.java:31)
public class PropertiesManager {
private static final String PROPERTY_FILE_NAME =
"resources/application.properties";
private static PropertiesManager Instance;
private Properties properties;
private PropertiesManager() {
}
public static PropertiesManager getInstance() {
if (Instance == null) {
Instance = new PropertiesManager();
}
return Instance;
}
public Properties getApplicationProperties() {
if (properties == null) {
properties = new Properties();
try (InputStream stream = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream(PROPERTY_FILE_NAME)) {
properties.load(stream);
} catch (IOException e) {
throw new ApplicationException("Failed to load property file", e);
}
}
return properties;
}
}
And logline: ApplicationLifecycleListener.contextInitialized(ApplicationLifecycleListener.java:14)
Class ApplicationLifecycleListener:
public class ApplicationLifecycleListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
Properties applicationProperties = PropertiesManager.getInstance().getApplicationProperties();
DBManager.getInstance().initialize(applicationProperties);
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
DBManager.getInstance().stopDb();
}
}
What is problem can be?
Without providing the file with the exact line you see the NullPointerException (none of the files you provided have the lines shown in log), it is difficult to be sure. But one hint is that although you put your resources files to be built with Maven in the '<project>/src/main/resources' folder, when built and packing the war file, it will put your application resource files in the 'WEB-INF/classes' folder which is part of the application default classpath. Therefore, to correctly reference them using the method Thread.currentThread().getContextClassLoader().getResourceAsStream(...) you should not add the 'resources\...' prefix to the file name, since this method already look files in the default application classpath. Remove the prefix and see if it works. Please, refer to this answer for more detail.

Updating Dropwizard config at runtime

Is it possible to have my app update the config settings at runtime? I can easily expose the settings I want in my UI but is there a way to allow the user to update settings and make them permanent ie save them to the config.yaml file? The only way I can see it to update the file by hand then restart the server which seems a bit limiting.
Yes. It is possible to reload the service classes at runtime.
Dropwizard by itself does not have the way to reload the app, but jersey has.
Jersey uses a container object internally to maintain the running application. Dropwizard uses the ServletContainer class of Jersey to run the application.
How to reload the app without restarting it -
Get a handle to the container used internally by jersey
You can do this by registering a AbstractContainerLifeCycleListener in Dropwizard Environment before starting the app. and implement its onStartup method as below -
In your main method where you start the app -
//getting the container instance
environment.jersey().register(new AbstractContainerLifecycleListener() {
#Override
public void onStartup(Container container) {
//initializing container - which will be used to reload the app
_container = container;
}
});
Add a method to your app to reload the app. It will take in the list of string which are the names of the service classes you want to reload. This method will call the reload method of the container with the new custom DropWizardConfiguration instance.
In your Application class
public static synchronized void reloadApp(List<String> reloadClasses) {
DropwizardResourceConfig dropwizardResourceConfig = new DropwizardResourceConfig();
for (String className : reloadClasses) {
try {
Class<?> serviceClass = Class.forName(className);
dropwizardResourceConfig.registerClasses(serviceClass);
System.out.printf(" + loaded class %s.\n", className);
} catch (ClassNotFoundException ex) {
System.out.printf(" ! class %s not found.\n", className);
}
}
_container.reload(dropwizardResourceConfig);
}
For more details see the example documentation of jersey - jersey example for reload
Consider going through the code and documentation of following files in Dropwizard/Jersey for a better understanding -
Container.java
ContainerLifeCycleListener.java
ServletContainer.java
AbstractContainerLifeCycleListener.java
DropWizardResourceConfig.java
ResourceConfig.java
No.
Yaml file is parsed at startup and given to the application as Configuration object once and for all. I believe you can change the file after that but it wouldn't affect your application until you restart it.
Possible follow up question: Can one restart the service programmatically?
AFAIK, no. I've researched and read the code somewhat for that but couldn't find a way to do that yet. If there is, I'd love to hear that :).
I made a task that reloads the main yaml file (it would be useful if something in the file changes). However, it is not reloading the environment. After researching this, Dropwizard uses a lot of final variables and it's quite hard to reload these on the go, without restarting the app.
class ReloadYAMLTask extends Task {
private String yamlFileName;
ReloadYAMLTask(String yamlFileName) {
super("reloadYaml");
this.yamlFileName = yamlFileName;
}
#Override
public void execute(ImmutableMultimap<String, String> parameters, PrintWriter output) throws Exception {
if (yamlFileName != null) {
ConfigurationFactoryFactory configurationFactoryFactory = new DefaultConfigurationFactoryFactory<ReportingServiceConfiguration>();
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
ObjectMapper objectMapper = Jackson.newObjectMapper();
final ConfigurationFactory<ServiceConfiguration> configurationFactory = configurationFactoryFactory.create(ServiceConfiguration.class, validator, objectMapper, "dw");
File confFile = new File(yamlFileName);
configurationFactory.build(new File(confFile.toURI()));
}
}
}
You can change the configuration in the YAML and read it while your application is running. This will not however restart the server or change any server configurations. You will be able to read any changed custom configurations and use them. For example, you can change the logging level at runtime or reload other custom settings.
My solution -
Define a custom server command. You should use this command to start your application instead of the "server" command.
ArgsServerCommand.java
public class ArgsServerCommand<WC extends WebConfiguration> extends EnvironmentCommand<WC> {
private static final Logger LOGGER = LoggerFactory.getLogger(ArgsServerCommand.class);
private final Class<WC> configurationClass;
private Namespace _namespace;
public static String COMMAND_NAME = "args-server";
public ArgsServerCommand(Application<WC> application) {
super(application, "args-server", "Runs the Dropwizard application as an HTTP server specific to my settings");
this.configurationClass = application.getConfigurationClass();
}
/*
* Since we don't subclass ServerCommand, we need a concrete reference to the configuration
* class.
*/
#Override
protected Class<WC> getConfigurationClass() {
return configurationClass;
}
public Namespace getNamespace() {
return _namespace;
}
#Override
protected void run(Environment environment, Namespace namespace, WC configuration) throws Exception {
_namespace = namespace;
final Server server = configuration.getServerFactory().build(environment);
try {
server.addLifeCycleListener(new LifeCycleListener());
cleanupAsynchronously();
server.start();
} catch (Exception e) {
LOGGER.error("Unable to start server, shutting down", e);
server.stop();
cleanup();
throw e;
}
}
private class LifeCycleListener extends AbstractLifeCycle.AbstractLifeCycleListener {
#Override
public void lifeCycleStopped(LifeCycle event) {
cleanup();
}
}
}
Method to reload in your Application -
_ymlFilePath = null; //class variable
public static boolean reloadConfiguration() throws IOException, ConfigurationException {
boolean reloaded = false;
if (_ymlFilePath == null) {
List<Command> commands = _configurationBootstrap.getCommands();
for (Command command : commands) {
String commandName = command.getName();
if (commandName.equals(ArgsServerCommand.COMMAND_NAME)) {
Namespace namespace = ((ArgsServerCommand) command).getNamespace();
if (namespace != null) {
_ymlFilePath = namespace.getString("file");
}
}
}
}
ConfigurationFactoryFactory configurationFactoryFactory = _configurationBootstrap.getConfigurationFactoryFactory();
ValidatorFactory validatorFactory = _configurationBootstrap.getValidatorFactory();
Validator validator = validatorFactory.getValidator();
ObjectMapper objectMapper = _configurationBootstrap.getObjectMapper();
ConfigurationSourceProvider provider = _configurationBootstrap.getConfigurationSourceProvider();
final ConfigurationFactory<CustomWebConfiguration> configurationFactory = configurationFactoryFactory.create(CustomWebConfiguration.class, validator, objectMapper, "dw");
if (_ymlFilePath != null) {
// Refresh logging level.
CustomWebConfiguration webConfiguration = configurationFactory.build(provider, _ymlFilePath);
LoggingFactory loggingFactory = webConfiguration.getLoggingFactory();
loggingFactory.configure(_configurationBootstrap.getMetricRegistry(), _configurationBootstrap.getApplication().getName());
// Get my defined custom settings
CustomSettings customSettings = webConfiguration.getCustomSettings();
reloaded = true;
}
return reloaded;
}
Although this feature isn't supported out of the box by dropwizard, you're able to accomplish this fairly easy with the tools they give you.
Before I get started, note that this isn't a complete solution for the question asked as it doesn't persist the updated config values to the config.yml. However, this would be easy enough to implement yourself simply by writing to the config file from the application. If anyone would like to write this implementation feel free to open a PR on the example project I've linked below.
Code
Start off with a minimal config:
config.yml
myConfigValue: "hello"
And it's corresponding configuration file:
ExampleConfiguration.java
public class ExampleConfiguration extends Configuration {
private String myConfigValue;
public String getMyConfigValue() {
return myConfigValue;
}
public void setMyConfigValue(String value) {
myConfigValue = value;
}
}
Then create a task which updates the config:
UpdateConfigTask.java
public class UpdateConfigTask extends Task {
ExampleConfiguration config;
public UpdateConfigTask(ExampleConfiguration config) {
super("updateconfig");
this.config = config;
}
#Override
public void execute(Map<String, List<String>> parameters, PrintWriter output) {
config.setMyConfigValue("goodbye");
}
}
Also for demonstration purposes, create a resource which allows you to get the config value:
ConfigResource.java
#Path("/config")
public class ConfigResource {
private final ExampleConfiguration config;
public ConfigResource(ExampleConfiguration config) {
this.config = config;
}
#GET
public Response handleGet() {
return Response.ok().entity(config.getMyConfigValue()).build();
}
}
Finally wire everything up in your application:
ExampleApplication.java (exerpt)
environment.jersey().register(new ConfigResource(configuration));
environment.admin().addTask(new UpdateConfigTask(configuration));
Usage
Start up the application then run:
$ curl 'http://localhost:8080/config'
hello
$ curl -X POST 'http://localhost:8081/tasks/updateconfig'
$ curl 'http://localhost:8080/config'
goodbye
How it works
This works simply by passing the same reference to the constructor of ConfigResource.java and UpdateConfigTask.java. If you aren't familiar with the concept see here:
Is Java "pass-by-reference" or "pass-by-value"?
The linked classes above are to a project I've created which demonstrates this as a complete solution. Here's a link to the project:
scottg489/dropwizard-runtime-config-example
Footnote: I haven't verified this works with the built in configuration. However, the dropwizard Configuration class which you need to extend for your own configuration does have various "setters" for internal configuration, but it may not be safe to update those outside of run().
Disclaimer: The project I've linked here was created by me.

WebApplicationContext not being shut down on Servlet Context reload

When I shut down Tomcat, I observe a correct shutdown and cleanup of the Spring WebApplicationContext. However, when I redeploy my Spring-based WAR (by copying the new WAR to webapps), normal shutdown does not occur. This is a problem for me due to all the ensuing resource leaks:
org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [] appears to have started a thread named [hz.hazelcast-swipe-instance.scheduled] but has failed to stop it. This is very likely to create a memory leak.
org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [] appears to have started a thread named [hz.hazelcast-swipe-instance.operation.thread-0] but has failed to stop it. This is very likely to create a memory leak.
... and many more. I am using XML-less configuration, this is my WebApplicationInitializer:
public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
#Override protected Class<?>[] getRootConfigClasses() {
return new Class[] { WebSecurityConfig.class, WebMvcConfig.class };
}
#Override protected Class<?>[] getServletConfigClasses() { return null; }
#Override protected String[] getServletMappings() { return new String[] { "/" }; }
#Override public void onStartup(ServletContext ctx) throws ServletException {
ctx.setInitParameter("spring.profiles.active", "production");
super.onStartup(ctx);
}
}
There is no configuration specific to controlling the behavior upon servlet context reload, and I assume this should have worked out of the box.
Is there a way to make the WebApplicationContext close properly before continuing the servlet context reloading procedure?
I am on Spring 4.0.5, Tomcat 7.0.54, Hazelcast 3.2.1, Hibernate 4.3.4.Final.
Update
I have added a Spring application listener for the ContextClosedEvent and printed the stack trace of its invocation:
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:333) [spring-context-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:335) [spring-context-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:880) [spring-context-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:841) [spring-context-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.destroy(FrameworkServlet.java:819) [spring-webmvc-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.apache.catalina.core.StandardWrapper.unload(StandardWrapper.java:1486) [catalina.jar:7.0.54]
at org.apache.catalina.core.StandardWrapper.stopInternal(StandardWrapper.java:1847) [catalina.jar:7.0.54]
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232) [catalina.jar:7.0.54]
at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5647) [catalina.jar:7.0.54]
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232) [catalina.jar:7.0.54]
at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1575) [catalina.jar:7.0.54]
at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1564) [catalina.jar:7.0.54]
This indicates that the Spring shutdown occurs in its Servlet#destroy method. This is the relevant snippet from AbstractApplicationContext#close():
if (logger.isInfoEnabled()) {
logger.info("Closing " + this);
}
LiveBeansView.unregisterApplicationContext(this);
try {
// Publish shutdown event.
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
// Stop all Lifecycle beans, to avoid delays during individual destruction.
try {
getLifecycleProcessor().onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
// Destroy all cached singletons in the context's BeanFactory.
destroyBeans();
// Close the state of this context itself.
closeBeanFactory();
// Let subclasses do some final clean-up if they wish...
onClose();
synchronized (this.activeMonitor) {
this.active = false;
}
I see the log entry from the start of this snippet, and I get my ContextClosedEvent. I also see an entry DefaultLifecycleProcessor - Stopping beans in phase 2147483647, which probably comes from the getLifecycleProcessor.onClose() line. It seems that some error occurs downstream from that. Some exception may be swallowed.
Update 2
As requested, this is how I configure Hazelcast:
#Bean(destroyMethod="shutdown") public HazelcastInstance hazelcast() {
final Config c = hzConfig();
final JoinConfig join = c.getNetworkConfig().getJoin();
join.getMulticastConfig().setEnabled(false);
join.getTcpIpConfig().setEnabled(true);
return getOrCreateHazelcastInstance(c);
}
hzConfig() is a method where instance name, group name and password, map names, and map indices are configured, so I don't think it is of interest here.
And this is my Hibernate SessionFactory config:
#Bean
public LocalSessionFactoryBean sessionFactory() {
final LocalSessionFactoryBean b = new LocalSessionFactoryBean();
b.setDataSource(dataSource);
b.setHibernateProperties(props(
"hibernate.connection.release_mode", "on_close",
"hibernate.id.new_generator_mappings", "true",
"hibernate.hbm2ddl.auto", "update",
"hibernate.order_inserts", "true",
"hibernate.order_updates", "true",
"hibernate.max_fetch_depth", "0",
"hibernate.jdbc.fetch_size", "200",
"hibernate.jdbc.batch_size", "50",
"hibernate.jdbc.batch_versioned_data", "true",
"hibernate.jdbc.use_streams_for_binary", "true",
"hibernate.use_sql_comments", "true"
));
return b;
}
At some point, you mentioned that there was a NoClassDefFoundError for Logback. You got this fixed by removing this dependency, but then the problem moved to a another class - one of Spring's own classes.
This can mean that either one of the libraries you have does something buggy with class loaders or maybe Tomcat needs instructions not to keep locks on some resources. See here more about Tomcat resources being locked and the <Context> setting to try: in your Tomcat's conf/context.xml place a antiResourceLocking="true" to the element.
Have you tried upping unloadDelay (defaults to 2000ms) for Tomcat contexts? See http://tomcat.apache.org/tomcat-7.0-doc/config/context.html
UPDATE: I see that you are having issues with logback as well, it might be worth the shot to try and register this listener as well:
class LogbackShutdownListener implements ServletContextListener {
#Override
public void contextDestroyed(ServletContextEvent event) {
LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory();
System.out.println("Shutting down Logback context '" + loggerContext.getName() + "' for " + contextRootFor(event));
loggerContext.stop();
}
#Override
public void contextInitialized(ServletContextEvent event) {
System.out.println("Logback context shutdown listener registered for " + contextRootFor(event));
}
private String contextRootFor(ServletContextEvent event) {
return event.getServletContext().getContextPath();
}
}
Be sure to declare this listener before the spring context loader listener so that it is invoked after the context listener upon shutdown.
UPDATE 2: Also it might be worth the try to register another bean to handle closing of the Hazelcast stuff manually (be sure to also remove destroyMethod from the hazelcast bean):
#Component
class HazelcastDestructor {
#Autowired
private HazelcastInstance instance;
#PreDestroy
public void shutdown() {
try {
instance.shutdown();
} catch (Exception e) {
System.out.println("Hazelcast failed to shutdown(): " + e);
throw e;
}
}
}
UPDATE 3: Just out of curiosity, have you tried parallel deployment: http://www.javacodegeeks.com/2011/06/zero-downtime-deployment-and-rollback.html. It might behave differently than reloading the very same context. At the very least you should be able to undeploy the old version lazily and see if that makes a difference.
There is a similar issue on the dangling threads while container restarting here.
Of all the answers, one particular answer of interest was by Howard - which shows the way these threads are cleared.
There is some good discussion and reasoning as to how this can terminate the threads here.
Now implement ServletContextListener and take care of these threads in the contextDestroyed() method as:
public class YourListener implements ServletContextListener{
....
#Override
public void contextDestroyed(ServletContextEvent event) {
//Call the immolate method here
}
}
Register this listener in WebApplicationInitilizer as:
ctx.addListener(new YourListener());
So when server is restarted - contextDestroyed method is called and this takes care of all these threads.
From Web App development point of view, ServletContainer can only notify the before started and before end process of app.
It is using ServletContextListener.
Config ServletContextListener in web.xml
<listener>
<listener-class>com.var.YourListener</listener-class>
</listener>
YourListener.java
public class YourListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
//initialization process
}
public void contextDestroyed(ServletContextEvent sce) {
//destory process
}
}
Update -XML Less
Programmatically
#Override
public void onStartup(ServletContext ctx) throws ServletException {
ctx.addListener(new YourContextListener());
ctx.setInitParameter("spring.profiles.active", "production");
super.onStartup(ctx);
}
Annotation
#WebListener / #WebServletContextListener
public class YourContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
Update- ShoutDown Hook In Spring
I never use it before my app development, we can register shoutdownhook event into AbstractApplicationContext of Spring.
I am not sure it will be ok or not for you.
AbstractApplicationContext context = ...
context.registerShutdownHook();
Reference 1 Reference 2

Read properties file on glassfish 4

I need to read a properties file in a glassfish 4 application. The file needs to be somewhere in the application (i.e. not at some random place in the file system).
If it matters, I'm developing with eclipse, the project builds with maven, and the artifact is a war.
It seems to me there are three things I need to know to make this work.
1) Where does the original file need to be?
2) Where does the file need to end up?
3) How do I read it?
So far I created the file:
src/main/resources/version.properties
which ends up in
WEB-INF/classes/version.properties
I don't know if that is the correct location.
Based on similar questions, I have defined a ServletContextListener:
public class ServletContextClass implements ServletContextListener {
...
#Override
public void contextInitialized(ServletContextEvent arg0) {
ServletContext ctx = arg0.getServletContext();
InputStream istream = ctx.getResourceAsStream("version.properties");
// at this point, istream is null
Properties p = new Properties();
p.load(istream);
}
}
I'm not sure if I have the file in the wrong place, if I'm reading it wrong, or both.
update: the following "works":
#Override
public void contextInitialized(ServletContextEvent arg0) {
ResourceBundle bundle = ResourceBundle.getBundle("version");
if (bundle == null) {
logger.info("bundle is null");
} else {
logger.info("bundle is not null");
logger.info("version: " + bundle.getString("myversion"));
}
}
However, I don't think this is the correct solution. Bundles are for locale support, and this does not fall under that category.
Update 2: I corrected the location where the file ends up.
1) Putting the version.properties file in
src/main/resources/version.properties
seems to be correct.
2) In the target war, the file does in fact end up in
WEB-INF/classes/version.properties
3) To read the file: I already had a ServletContextListener defined. If you don't you need to define one and configure it in web.xml. Here is a portion of my ServletContextListener:
package com.mycompany.service;
public class ServletContextClass implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent arg0) {
ServletContext ctx=arg0.getServletContext();
try {
Properties p = new Properties();
InputStream istream = ctx.getResourceAsStream("/WEB-INF/classes/version.properties");
p.load(istream);
Properties sysProps = System.getProperties();
sysProps.putAll(p);
} catch (IOException e) {
logger.error("Error reading " + "version.properties");
}
}
}
It is configured with this piece of the web.xml:
<listener>
<listener-class>com.mycompany.service.ServletContextClass</listener-class>
</listener>

Categories

Resources