Ldap Query - Configuration using Spring Boot - spring-boot

I have a Spring boot application that needs to perform LDAP queries. I'm trying to take the following recommendation from the Spring boot documentation:
"Many Spring configuration examples have been published on the
Internet that use XML configuration. Always try to use the equivalent
Java-base configuration if possible."
In a Spring XML configuration file, I would have used:
<ldap:context-source
url="ldap://localhost:389"
base="cn=Users,dc=test,dc=local"
username="cn=testUser"
password="testPass" />
<ldap:ldap-template id="ldapTemplate" />
<bean id="personRepo" class="com.llpf.ldap.PersonRepoImpl">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
How would I configure this using a Java-based configuration? I need to be able to change URL, base, username, and password attributes of ldap:context-source without a code rebuild.

The <ldap:context-source> XML tag produces an LdapContextSource bean and the <ldap:ldap-template> XML tag produces an LdapTemplate bean so that's what you need to do in your Java configuration:
#Configuration
#EnableAutoConfiguration
#EnableConfigurationProperties
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
#ConfigurationProperties(prefix="ldap.contextSource")
public LdapContextSource contextSource() {
LdapContextSource contextSource = new LdapContextSource();
return contextSource;
}
#Bean
public LdapTemplate ldapTemplate(ContextSource contextSource) {
return new LdapTemplate(contextSource);
}
#Bean
public PersonRepoImpl personRepo(LdapTemplate ldapTemplate) {
PersonRepoImpl personRepo = new PersonRepoImpl();
personRepo.setLdapTemplate(ldapTemplate);
return personRepo;
}
}
To allow you to change the configuration without a rebuild of your code, I've used Spring Boot's #ConfigurationProperties. This will look in your application's environment for properties prefixed with ldap.contextSource and then apply them to the LdapContextSource bean by calling the matching setter methods. To apply the configuration in the question, you can use an application.properties file with four properties:
ldap.contextSource.url=ldap://localhost:389
ldap.contextSource.base=cn=Users,dc=test,dc=local
ldap.contextSource.userDn=cn=testUser
ldap.contextSource.password=testPass

Related

Spring Boot: Using Tomcat context parameters in logback configuration

I have several instances of a Spring Boot app deployed in a unique Tomcat.
Each app is configured with a context.xml file which contains a customer code
<Context path="/myApp1" reloadable="false">
<Parameter name="CUSTOMER_CODE" value="CUSTOMER1" />
</Context>
I wish that each customer has a separate log based on code defined in context.xml.
Unfortunately this config doesn't work in my logback-config.xml:
<property name="LOG_FILE" value="${ROOT_LOG}/${CUSTOMER_CODE}/myApp.log}"/>
A folder CUSTOMER_CODE_IS_UNDEFINED is created in "ROOT_LOG" directory. "ROOT_LOG" is provided by a system property.
Is there any way to make this logback configuration working?
The use of properties defined in application.properties works well (I renamed my logback.xml to logback-spring.xml). It seems to me that Spring boot does not set Tomcat context parameters in Environnement before initialize logging. Any idea for a workaround? Thanks.
I finally found a solution to get my customer code available in Spring Environment bean before logging initialization. Not very pretty but it's working:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application extends SpringBootServletInitializer {
public static String APP_CUSTOMER_CODE;
/**
* Initialization of Spring Boot App with context param customer code
*/
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder builder) {
final Map<String, Object> initProps = new HashMap<>();
initProps.put("CUSTOMER_CODE", APP_CUSTOMER_CODE);
return builder.properties(initProps).sources(Application.class);
}
/**
* Method called before Spring Initialization
*/
#Override
public void onStartup(final ServletContext servletContext) throws ServletException {
APP_CUSTOMER_CODE = servletContext.getInitParameter("CUSTOMER_CODE");
super.onStartup(servletContext);
}
}
In addidtion, i must declare a springProperty tag in logback-spring.xml to use the variable:
<springProperty name="CUSTOMER_CODE" source="CUSTOMER_CODE"/>

Spring + Apache CXF: SearchContextProvider not initialized

I'm integrating Spring Boot with Apache CXF. Everyhthing is OK, but I cannot get the SearchContext to work inside the controllers:
#Context
private SearchContext context;
public #ResponseBody List<Users> getAll(#Context SearchContext context, #RequestParam String search){
....
}
The SearchContext is not correctly injected, as is not created by the SearchContextProvider in the package org.apache.cxf.jaxrs.ext.search.
I'm launching the CXF Servlet with this Bean:
#Bean
public ServletRegistrationBean cxfServlet() {
CXFServlet cxf = new CXFServlet();
ServletRegistrationBean registration = new ServletRegistrationBean(cxf, "/api/*");
return registration;
}
I'm using a Java-based configuration, no XML.
In an XML based configuration, it seems that this tag is required:
<jaxrs:providers>
<bean class="org.apache.cxf.jaxrs.ext.search.SearchContextProvider"/>
</jaxrs:providers>
How can I declare the provider in a Java based configuration of the servlet?
In your main config class, add:
#ComponentScan("org.apache.cxf.jaxrs")
Since the class (SearchContextProvider) is already annotated with #Provider annotation, Spring will be able to pick it up if it is being scanned. Assuming that you are already doing component-scan on your own package, you can just add the jaxrs package like:
#ComponentScan({ "com.something", "org.apache.cxf.jaxrs" })

Mixing XML and java configuration

I am migrating an application from an XmlWebApplicationContext to a pure java configuration solution using AnnotationConfigApplicationContext. I am having a problem reusing existing xml configuration files via #ImportResource. We are using spring 3.2.11.
When I use the xml based context, beans defined in the xml files that are java configuration (#Configuration) are automatically picked up by the context and any beans they define are visible. However, when imported through #ImportResource, #Beans in the configuration objects are not created.
Here is a unit test that illustrates my problem:
XmlConfigTest.java
#Test
public void testAnnotationContext()
{
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(XmlFromJava.class);
ctx.refresh();
assertEquals("xml value", ctx.getBean("xmlBean", String.class));
assertEquals("nested value", ctx.getBean("nestedBean", String.class));
}
#Test
public void testXmlContext()
{
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:test.xml");
ctx.refresh();
assertEquals("xml value", ctx.getBean("xmlBean", String.class));
// fails here
assertEquals("nested value", ctx.getBean("nestedBean", String.class));
}
#Configuration
#ImportResource("classpath:test.xml")
public static class XmlFromJava { }
NestedConfig.java
#Configuration
public class NestedConfig
{
#Bean
public String nestedBean()
{
return "nested value";
}
}
test.xml
<context:annotation-config/>
<bean class="NestedConfig"/>
<bean name="xmlBean" class="java.lang.String">
<constructor-arg value="xml value"/>
</bean>
I would expect the bean 'nestedBean' to exist from the NestedConfig class. testAnnotationContext() fails to load the 'nestedBean' but testXmlContext() works.

Using spring to load properties as System properties

I'm using Spring 4.1.6.
I have something like the following:
foo.properties:
valueX=a
valueY=b
Spring bean:
<context:property-placeholder location="classpath:foo.properties" ignore-unresolvable="false" ignore-resource-not-found="false" />
<bean id="foo" class="com.foo.bar.MyClass" >
<property name="someValue" value="${valueX}" />
</bean>
I have a non-Spring class which also needs to use a value from foo.properties.
Non Spring Class:
public void doSomething() {
String valueY = System.getProperty("valueY");
}
When Spring loads foo.properties, is there a way to populate all the properties into System properties so that I can get "valueY" using System.getProperty("valueY").
I don't want to load foo.properties again in my non-Spring class.
The context:property-placeholder will create a PropertySourcesPlaceholderConfigurer config bean for you. You cannot access the properties from this bean programatically as stated here.
What you can do is to load the properties into a separate spring bean as given below.
#Bean(name = "mapper")
public PropertiesFactoryBean mapper() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("application.properties"));
return bean;
}
and then set the system property when the context load is finished using a listener as given below. Got the code from this answer
#Component
public class YourJobClass implements ApplicationListener<ContextRefreshedEvent> {
#Resource(name = "mapper")
private Properties myTranslator;
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.setProperties(myTranslator);
}
}

Spring MVC HandlerInterceptor ignored in Java config

I'm trying to convert a Spring project from XML to Java config and have run into the following issue with HandlerInterceptors:
XML Config (works):
<mvc:annotation-driven />
<mvc:interceptors>
<bean class="com.mycompany.MyHandlerInterceptor" />
</mvc:interceptors>
Java Config (interceptor is never called)
#Configuration
public class MvcConfig extends WebMvcConfigurationSupport {
#Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyHandlerInterceptor());
}
// ...
}
According to the documentation, these two configurations should be equivalent, however in the Java config example the neither the pre or post handle methods are ever called?
What am I missing?
Thanks.
This was my own fault. I had overridden requestMappingHandlerMapping() in my MVC Java config and did not set the interceptors property on the custom HandlerMapping class.
#Bean
#Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
CustomRequestHandlerMapping handlerMapping = new CustomRequestHandlerMapping();
handlerMapping.setOrder(0);
handlerMapping.setInterceptors(getInterceptors()); // <-- This was missing
return handlerMapping;
}

Resources