environment specific log4j configuration by spring - spring

I am loading log4j.xml using the traditional way
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:conf/log4j.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
This works fine but now I need to load a different log4j.xml file based on which environment I am in which is defined by a environment variable/jndi entry .. so I was hoping that with new spring 3.1 property management I could just change this to
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:conf/log4j-${ENV-NAME}.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
and spring will load the correct log4j file in each environment but this doesnt works probably because web.xml is loaded before spring. I came across this method
<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>log4j-${ENV-NAME}.xml</value>
</list>
</property>
</bean>
so essentially moving configuration of log4j into spring context file instead of web.xml. But this doesnt works either for some reason logging gets enabled in a way that everything is logged. So how can I use a different log4j.xml file based on an environment variable or loading it programmatically in the servletcontextlistener.

It's too late to help adeelmahmood, but hope others will benefit from my answer.
The thing is adeelmahmood was right, this configuration:
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:conf/log4j-${ENV-NAME}.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
is working, but:
Log4jConfigListener should be registered before ContextLoaderListener in web.xml !!!
You must also remember that Log4jConfigListener assumes an expanded WAR file.
Then, if ENV-NAME environment variable is set, it works as expected.
By the way, ${ENV-NAME} can be used in spring config files as well! That's not everything... You can also use our env.property to set spring profile:
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>${ENV-NAME}</param-value>
</context-param>
This way you can set log4jConfigLocation and spring profile, both with one and the same env. variable.
BTW and just in case: using Maven profiles to have separate builds for dev, test and production isn't good practice. Read eg. http://java.dzone.com/articles/maven-profile-best-practices and remember: "Use profiles to manage build-time variables, not run-time variables and not (with RARE exceptions) alternative versions of your artifact".

This might help too for more recent readers: in Log4j 2.7 (but it's probably older) the parameter name has been altered:
see interface Log4jWebSupport :
/**
* The {#link javax.servlet.ServletContext} parameter name for the location of the configuration.
*/
String LOG4J_CONFIG_LOCATION = "log4jConfiguration";

By default, Spring Boot picks up the native configuration from its default location for the system (such as classpath:logback.xml for Logback), but you can set the location of the config file by using the logging.config property.
logging.config=classpath:log4j-<ENV-NAME>.xml
https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/html/howto-logging.html

Related

Eclipse Spring MVC Project Configuration Files

I have created a Spring MVC project through eclipse. I believe I used some plugins to generate the project directory. I find here there configuration files.
web.xml
root-context.xml
servlet-context.xml
I am kinda of familiar with Spring MVC & its dependency injection. However I have problems understanding the last two configuration files (root-context & servlet-context).
What kind of configurations do they contain?
Also in may online examples I see mvc-dispatcher-servlet.xml. Why did eclipse not generate this xml file in my project?
[IMPORTANT] I wanted to set up strong security and user authentication for my web app. I have been following online tutorials again and they all create a seperate
xml file named spring-security.xml and add the namespace information to that file. Does it suffice if I just create this file and add the name space information? I mean
dont' I need to import this file to a main file that is scanned by Spring framework?
How do I define and where do I put spring application context.xml file and start wiring the dependencies together? Also if I define everything (all dependencies here) how is this file picked up by the framework?
Thanks,
Configuration Files
If you check your web.xml you will find both of root-context.xml and servlet-context.xml files being referred here. One used by Dispatcher Servlet and other by Context Loader Listenter. You can name your files to whatever unless they are being refereed in web.xml
Eclipse Not generating files
Every editor works its own way. some may generate full fledged project/app with both DispatcherServlet and ContextLoaderListner configured or some with only DispatcherServlet ( with minimal configutaion). Check Spring Roo it starts with basic and gives you the flexibility to generate a strong app.
mvc-dispatcher-servlet.xml is not there
Some of the thing in spring projects are convention based, for example if you are not providing any file to your DispatcherServlet in web.xml spring looks for mvc-dispatcher-servlet.xml file, and if you have provided it won't look for.
Spring Security
To Configure Spring Security you need to provide at least some configuration. But the question is where. You need to add this configuration to your web.xml only. and Hence no need to import this to any other file.
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener- class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/spring-security.xml
</param-value>
</context-param>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Where to define application context.xml
Just define it any where, configure beans in it.
You can add this file as follows:
a) Either Import this into some other configuration file like root-context.xml or servlet-context.xml
as <import resource="application-context.xml"/>
b) Add this into web.xml with ContextLoaderListner as context param
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:META-INF/spring/application-context*.xml
classpath*:META-INF/spring/abc*.xml
</param-value>
</context-param>

Spring project not creating spring-config.xml

I have read some tutorials about using spring, and I've seen they speak about "spring-config.xml", but when I create a project I don't have that file, I have "application-config.xml", are they the same? Is the former the updated version of the latter? I am using Eclipse as IDE
The Spring Context only defines the concept of creating a Spring configuration where you will define spring components (beans, services, etc)
The XML itself can be named whatever you want, but in the web.xml file, you have to pass the xml name you choose to the spring context listener
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/thisXMLhaTheBestNameEver.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

Beans injected into Apache Wink with Spring aren't registered

Following on from How do I inject a Spring bean into Apache Wink?
I'm now using wink-spring-support and I thought I had things set up correctly.
web.xml includes:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:META-INF/wink/wink-core-context.xml
classpath:applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>restServlet</servlet-name>
<servlet-class>org.apache.wink.server.internal.servlet.RestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>restServlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
META-INF/wink/wink-core-context.xml contains:
<bean class="org.apache.wink.spring.Registrar">
<property name="instances">
<set>
<ref bean="myservice" />
</set>
</property>
</bean>
<bean id="myservice" class="mystuff.ServiceImpl"/>
There's a #Autowired annotation in mystuff.ServiceImpl that injects other Spring stuff, and mystuff.ServiceImpl implements a JAX-RS annotated interface and itself includes a JAX-RS #Path("/services") annotation.
I can see Spring loading up this stuff just fine, including the myservice bean. However when I request my resources, I get a 404 not found. As Wink starts, I can see a couple of log entries that might indicate the problem:
applicationConfigLocation property was not defined
Using application classes null named in init-param applicationConfigLocation
Have I missed something somewhere? Any advice?
The problem was my misunderstanding the docs.
There is a Spring configuration META-INF/server/wink-core-context.xml provided with wink-spring-support. This registers the BeanPostProcessors that actually do the setup and must be referenced from contextConfigLocation.
I thought that I put my configuration in there, which explains why the application didn't get registered with Wink on startup.

Defining spring security http element in two different files?

Is it possible to define the security:intercept-url elements and security:custom-filter elements for a single security:http in two different Spring configuration files?
This is so we can cleanly reuse the security:custom-filter definitions which will be common across many applications with intercept rules that will not.
I can't simply duplicate the <security:http> element because I get BeanDefinitionParsingException: Configuration problem: Duplicate <http> element detected. I am well well aware of how to split a normal bean file with import
As requested in comment:
Spring Security versions prior to 3.1.x do not allow multiple http element definitions.
3.1 does however.
Here is the Jira issue for the feature.
This article on 3.1 changes might also be helpful.
You can define another context file in your web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-contexts/context1.xml
/WEB-INF/spring-contexts/context2.xml
</param-value>
</context-param>
Or you can define a directory where your contexts would be and name them any way you like without having to specify each context file separately:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-contexts/*
</param-value>
</context-param>
Regarding Ayusman's answer, you actually can import your security contexts into your bean contexts:
<beans>
<import resource="classpath*:/security-context-*.xml"/>
<bean><!-- blah blah --></bean>
</beans>
use the import in application context file..
custom-filter.appcontext.xml
.
.
<import resource="interceptor-url-file.xml"/>
Note that both files need to have the proper spring xml schema details and MUST be valid XML files.
I have been working on this error for 5 hours. Really stupid problem.
This error is a parse error that when you comment some lines in applicationContext-security.xml, files are not generated correctly.
Let me explain on an example code.
<port-mappings>
<port-mapping http="7001" https="7002" />
</port-mappings>
<!-- <port-mappings>
<port-mapping http="7015" https="7515" />
</port-mappings>
-->
this lines are generated as,
<port-mappings>
<port-mapping http="7001" https="7002" />
</port-mappings>
<port-mappings>
<port-mapping http="7015" https="7515" />
</port-mappings>
-->
so that, compiler tells you "duplicate element detected". Because generated file includes duplicate elements.
I hope to help you .

Error while splitting application context file in spring

I am trying to split the ApplicationContext file in Spring.
For ex. the file is testproject-servlet.xml having all the entries. Now I want to split this single file into multiple files according to logical groups like :
group1-services.xml, group2-services.xml
I have created following entries in web.xml :
<servlet>
<servlet-name>testproject</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/group1-services.xml, /WEB-INF/group2-services.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
I am using SimpleUrlHandlerMapping as:
<bean id="simpleUrlMapping"class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="order" value="0"/>
<property name="mappings">
<props>
<prop key="/register.htm">RegisterController</prop> <prop key="/payroll_services.htm">PayrollServicesController</prop>
</props>
</property>
</bean>
I also have the controller defined as :
<bean id="PayrollServicesController" class="com.triforce.b2bseek.businessservices.controller.PayrollServicesController">
<property name="facadeLookup" ref="FacadeLookup"/>
..
..
</property>
</bean>
The problem is that I have splitted the ApplicationContext file "testproject-servlet.xml" into two different files and I have kept the above entries in "group1-services.xml". Is it fine? I want to group things logically based on their use in seperate .xml files.
But I am getting the following error when I try to access a page inside the application :
org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping for [/TestProject/payroll_services.htm] in DispatcherServlet with name 'testproject'
Please tell me how to resolve it.
Thanks in Advance !
Replace this
/WEB-INF/group1-services.xml, /WEB-INF/group2-services.xml
with
/WEB-INF/group1-services.xml
/WEB-INF/group2-services.xm
Hope this will work...:)
I don't think its a problem with your contextConfigLocation as such
I think its more that the dispatcher needs to know where to send payroll_servives.htm to, and can't find an appropriate handler knowing what to do with this pattern.
See reference documentation
Did you really want *.htm files to be matched to the dispatcher servlet?
If you are using annotation-based controllers (#Controller), then you need to have a line similar to:
<context:component-scan base-package="org.springframework.samples.petclinic.web"/>
This installs an appropriate annotation-based handler, that searchs for classes/methods annotated like:
#Controller
public class PayrollController {
#RequestMapping("payroll_services.htm")
public ModelAndView payrollServices() {
....
}
}
Otherwise, if you are using more traditional handlers/controllers, you need to define this using XML. The reference documentation link earlier in this posting mentions two such handlers: SimpleUrlHandlerMapping or BeanNameUrlHandlerMapping
Perhaps if you updated your question with snippets of handler/controller XML, this may help?
Did you add the ContextLoaderListener to your web.xml? I don't see it:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
You need to include something like this in each of your files:
<context:component-scan base-package="com.example.dao" />
If it is missing from a file, it seems the annotated classes are not known in the context of that file.
You may want to revisit the documentation for details.
Either the handler mapping of your DispatcherServlet is incorrect or you're using the wrong url. If you fix the layout around your SimpleUrlHandlerMapping configuration I can tell you what to change.

Resources