I am changing some parts of the James POP3Server class and inject it afterwards via IoC.
I need to configure some parts I like to use in my modifications, and I thought it would be handy if I could use the config.xml to store my settings.
POP3Server.class <-> config.xml (direct access possible?)
Is there a easy way of accessing this XML or do I have to access it somewhere deeper inside James?
Look at the code for org.apache.james.pop3server.POP3Server and find public void configure(final Configuration configuration): this handles configuration of the server with the XML from config.xml. For example, if you modify the POP3Server XML configuration block in the james-config file to look like this:
<pop3server enabled="true">
<port>110</port>
<handler>
<helloName autodetect="true">myMailServer</helloName>
<connectiontimeout>120000</connectiontimeout>
</handler>
<myconfigvariable>12</myconfigvariable>
</pop3server>
you'll be able to add a line in configure like this:
int myconfig = configuration.getChild("myconfigvariable").getValueAsInteger(25);
The 25 here is the default in the case where the config variable is missing. Let me know if that does what you want.
Related
i've been working with Spring for some time and have a question regarding the very common configuration properties files (like the common application.properties that comes with every spring boot app you initialize). Recently, i also found that configurations like this can be done in yaml files. I have two questions:
When in a application.properties file, we write something like:
# application.properties
spring.debug = true
some-random-value = 15
does this mean that these values will be injected in the application context?
When we write something like:
# application.properties
spring.debug = true
does this mean, that somewhere, there is some class, that has an attribute that looks something like this? -->
#Component
class SomeClass{
#Value("spring.debug")
boolean shouldIRunInDebugMode;
...
}
2.a. If the answer to question 2 is yes, then how can I, looking at something like this:
# application.properties
spring.debug = true
find that class that is expecting that value. The same would apply to if i was looking at something like:
# application.yaml
someThidPartyLibraryName:
shouldWeLog: true
If i see a yaml configuration file, just looking at all the configuration there usually is not enough for me to know what is happening. How can i find the class that is being affected by this configuration, so that i can better understand what this config is doing?
Thank you!
The response is generally yes. If you declare a property in the application.properties or application.yaml is mainly, because you would use it later in the code, for example injecting in some bean with the support of #Value annotation. However, there are also many built-in properties (let's say for example server.port), which you usually don't have to declare and therefore you won't see explicitly in the code. Use an IDE to search the configuration properties and the manual to check the preconfigured ones in case of need.
Your understanding regarding spring value injections from application.properties is correct. #2 - is Yes. Any property from application.properties can be injected to any java class as #Value.
Regarding #2.a - Yaml is just another format on how you organize your variable hierarchy by indentations. That's a superset to the JSON structure.
For example,
in application.properties file you can add something like this
myapp.db.url=<dburl>
myapp.db.username=<dbuser>
myapp.db.password=<dbpassword>
the same can be represented in Yaml in a much efficient manner as below
myapp:
db:
url:<dburl>
username:<dbuser>
password:<dbpassword>
And in either case, for your Jave file you can inject as
#Value("myapp.db.url"
private String dbUrl;
Properties defined in yaml or a properties file may be accessed using the #Value annotation to inject, or using a #ConfigurationProperties class - see https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-typesafe-configuration-properties for complete details.
Finding the property usage is supported by some IDEs - IntelliJ allows you to click through. Otherwise it's a search through the source. For #ConfigurationProperties, once you find the class then just look for code that calls its accessor methods.
Properties files and yaml files are used in Spring Boot for configurations. The main difference between the two is yaml provides structuring/grouping of configurations where as Properties are usually flat and may be repeating the same information:
For example;
Properties file
server.port = 8080
server.host = localhost
yaml file
server:
port: 8080
host: localhost
But in a Spring Boot AutoConfiguration class regardless of yaml or Properties used, a following looking ConfigurationProperties class will be used which will map server.port and server.host
#ConfigurationProperties(prefix = "server")
public class ServerConfiguration {
private int port;
private String host;
}
#Configuration
#EnableConfigurationProperties(ServerConfiguration.class)
public class ServerAutoConfiguration {
}
Hope this answers your questions.
I am using java8 for my web application. I would like to change the settings of JAVA DNS Cache.
This is the code:
java.security.Security.setProperty("networkaddress.cache.ttl", "60");
java.security.Security.setProperty("sun.net.inetaddr.negative.ttl", "10");
I would like to know where exactly I should write the code (in which class file) to reflect the changes in JVM before DNS chance gets initialised.
I would like to make the change using a java utility class file.Please suggest for the same.
And also suggest how to configure the same change in build.xml(ant)?
I agree with answers updated where they have suggested to change security file.But i would like to know the configuration in other ways too due to limitations that i have in my project.
You can also set it globally by add this line
networkaddress.cache.ttl=60
to $JAVA_HOME/jre/lib/security/java.security file.
Your best bet is to set it directly in the java.security file located in /lib/security
Note: if you are using a shared JVM, you'll need to set this in your startup command -Djava.security.properties=/DirectoryPath/filename and set the value of security.overridePropertiesFile to true.
If you want to set this in code then you have a number of options - you just need to put the code in a place that you know will be executed before the first message is processed after application startup.
My preference would be to register a ContextListener and put the code in there.
I encountered a similar issue where my java application wouldn't resolve the URL.
In addition to what is suggested ( i.e.,networkaddress.cache.ttl and networkaddress.cache.negative.ttl) I had to reset the caches in the URL Object.
URL url = new URL(urlSrt);
URLConnection con = url.openConnection();
con.setUseCaches(false);
I am not aware of (build.xml)ant. I will still give it a try just in case you are using spring framework. Following is what I did to set the networkaddress.cache.ttl at the time of application initialisation.
Define a new Java class as follows.
package com.example.util;
public class SecurityManager {
public SecurityManager() {
java.security.Security.setProperty("networkaddress.cache.ttl", "60");
}
}
Ask spring framework to instantiate the object of above class as a singleton at the time on spring container creation.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="securityManager"
class="com.example.util.SecurityManager" scope="singleton" />
</beans>
I have a Spring 3.1 application. Let's say it has an XML with the following content:
<context:property-placeholder location="classpath:somename.properties" />
<context:property-placeholder location="classpath:xxx.properties" />
I would like some.properties to be always loaded (let's assume it exists), but the xxx part of the second place holder to be replaced by some name depending on the active profile. I've tried with this:
<beans profile="xx1">
<context:property-placeholder location="classpath:xx1.properties" />
</beans>
<beans profile="xx2">
<context:property-placeholder location="classpath:xx2.properties" />
</beans>
Also, both files have properties with the same key but different value.
But it didn't work as some later bean that has a placeholder for one property whose key is defined in xx1.properties (and xx2.properties) makes Spring complain that the key is not found in the application context.
You can do:
<context:property-placeholder location="classpath:${spring.profiles.active}.properties" />
It works fine, but is perhaps not adapted when using multiple profiles in the same time.
When declaring 2 property placeholders, if the 1st one does not contain all the applications keys, you should put the attribute ignoring unresolvable = true, so that the 2nd placeholder can be used.
I'm not sure if it is what you want to do, it may if you want both xx1 and xx2 profiles be active in the same time.
Note that declaring 2 propertyplaceholders like that make them independant, and in the declaration of xx2.properties, you can't reuse the values of xx1.properties.
If you need something more advanced, you can register your PropertySources on application startup.
web.xml
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.xxx.core.spring.properties.PropertySourcesApplicationContextInitializer</param-value>
</context-param>
file you create:
public class PropertySourcesApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final Logger LOGGER = LoggerFactory.getLogger(PropertySourcesApplicationContextInitializer.class);
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
LOGGER.info("Adding some additional property sources");
String profile = System.getProperty("spring.profiles.active");
// ... Add property sources according to selected spring profile
// (note there already are some property sources registered, system properties etc)
applicationContext.getEnvironment().getPropertySources().addLast(myPropertySource);
}
}
Once you've done it you just need to add in your context:
<context:property-placeholder/>
Imho it's the best way to deal with spring properties, because you do not declare local properties everywhere anymore, you have a programmatic control of what is happening, and property source xx1 values can be used in xx2.properties.
At work we are using it and it works nicely. We register 3 additional property sources:
- Infrastructure: provided by Puppet
- Profile: a different property loaded according to the profile.
- Common: contains values as default, when all profiles share the same value etc...
I have decided to submit and answer to this as it has not yet been accepted. It may not be what you are looking for specifically but it works for me. Also note that i am using the new annotation driven configuration however it can be ported to the xml config.
I have a properties file for each environment(dev.properties, test.properties etc)
I then have a RootConfig class that is the class that is used for all the configuration. All that this class has in it is two annotations: #Configuration and #ComponentScan(basePackageClasses=RootConfig.class).
This tells it to scan for anything in the same package as it.
There is then a Configuration Containing all my normal configuration sitting wherever. There is also a configuration for each environment in the same package as the root configuration class above.
The environment specific configurations are simply marker classes that have the following annotations to point it to the environment specific properties files:
#Configuration
#PropertySource("classpath:dev.properties")
#Import(NormalConfig.class)
#Profile("dev")
The import tells it to bring in the normal config class. But when it gets in there it will have the environment specific properties set.
The project I am working at the moment uses camel as the routing framework.
When configuring camel context in spring we pass a property file that contains a bunch of global properties needed when configuring camel routes or for controlling run time behavior:
<camel:camelContext xmlns="http://camel.apache.org/schema/spring" id="my-id">
<camel:propertyPlaceholder location="my-system.properties" id="global-properties"/>
...
</camel:camelContext>
and say my-system.properties has an entry like below:
my-system.properties
# Global properties that control my-system configuration and run time
...
foo={{bar}}
...
When configuring the routes I can access foo property using the {{foo}} notation. It is also available to other beans using #PropertyInject annotation. However there is one use case in my design when a plain POJO not created by spring (an enum instead but this is not relevant) needs to access my foo property. Because this POJO it is passed the CamelContext as a method argument I find it natural to think I should be able to get the value of foo from there. However I spent a bit of time and could not figure out by myself how.
I know I can load the properties file again or even get the system property System.getProperty("bar") and everything will work but it looks like cheating to me.
There is an api on CamelContext to resolve property placeholders - its the resolvePropertyPlaceholders method:
http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/CamelContext.html#resolvePropertyPlaceholders(java.lang.String)
If your POJO is not being managed by the SpringContext I don't see any way you can automatically inject the property. Although your approach may not seem the most fancy or elegant, it has the advantage of not giving you any overhead you could have by using another injection tool.
predhme
You came up with a way to read environment variable into a Spring Bean then "was able to then pass that into the FileSystemResource".
Here:
Can I use an Environment variable based location for Spring FileSystemResource?
Could you please explain how you passed the variable to FileSystemResource?
Thanks!
Charlie
You want to use a PropertyPlaceholderConfigurer.
Once you have that set up, you should be able to pull any environment variable with the:
${variableName}
syntax anywhere in your configuration file.
I don't like the idea of having system properties for individual variables like these. Sooner you might turn into hundreds of system properties that might need to be set. Instead as others suggest, have the property file outside of the build and specify the location of the property file as a system property.
Having the properties that change with environment, in a properties file outside of the build (JAR / WAR..) helps a lot in making good builds.
This blog post might help.
Or something similar as below:
Using a property placeholder configurer
<bean id="myConfigPlaceholder"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="${my.sys.variable}/fooModule/foo.properties"
p:placeholderPrefix="#foo{"
p:placeholderSuffix="}" />
Injecting in beans
#Value("#foo{some.key.defined.in.fooPropertiesFile}")
String myFileSystemResourcePath;
(or)
Using util:properties
<util:properties id="fooProps"
location="file:///${my.sys.variable}/fooModule.properties/>
Injecting in beans
#Value("#fooProps[some.key.defined.in.fooPropertiesFile]")
String myFileSystemResourcePath;
Note: When defining property-placeholder-configurer bean, there are different syntactic variations that are supported. You might choose any. Also instead of injecting with #Value, you can reference the property in the xml file with ${variableName} as dlawrence suggested.
Setting the environment variable
for one project:
Setting the envVariable, in this example my.sys.variable can be just done with
project-->(right click)-->run as-->run as configurations-->vm arguments
and there: -Dmy.sys.variable=file:///D:/myBaseDir
globally as a preference:
If this envProp is to be shared with different projects in eclipse, then you can do
Windows->Preferences->Java->Installed JREs->(select the jre)->edit->default vm arguments->and set it with something like -Dmy.sys.variable=file:///D:/myBaseDir