How to get stepExecutionContext in Processor using CompositeItemProcessor? - spring

In XML file i have configured two Processor using CompositeItemProcessor
<processor>
<beans:bean id="CompositeItemProcessor" class="org.springframework.batch.item.support.CompositeItemProcessor" scope="step">
<beans:property name="delegates">
<beans:list>
<beans:ref bean="oldProcessor"/>
<beans:ref bean="newProcessor"/>
</beans:list>
</beans:property>
</beans:bean>
</processor>
and in "oldProcessor" bean java file i have added below code to get StepExecution object.
#BeforeStep
#Order(1)
public void setStepExecution(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
but above code not executing. only process() method calling from "oldProcessor" bean.
and when i tried without configuring CompositeItemProcessor,then this "setStepExecution()" method and process() method are executing of oldProcessor bean.
eg.
<processor>
<beans:ref bean="oldProcessor"/>
</processor>
Please advise me, how to get stepExecutionContext in Processor using CompositeItemProcessor

Try with the following in your processor.
#Value("#{stepExecution}")
private StepExecution stepExecution;
This should work if the scope is step.

Related

How to Over ride BindAuthenticator handleBindException for Spring LDAP Authentication setup in Spring Boot

For Spring security setup in Spring Boot. The LDAP Authentication provider is configured by default to use BindAuthenticator class.
This Class contains method
/**
* Allows subclasses to inspect the exception thrown by an attempt to bind with a
* particular DN. The default implementation just reports the failure to the debug
* logger.
*/
protected void handleBindException(String userDn, String username, Throwable cause) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to bind as " + userDn + ": " + cause);
}
}
This Method is to handle the authentication related Exceptions like invalid credentials.
I want to over-ride this method so i can handle this issue and return proper error message on the basis of error codes returned by LDAP. like invalid password or the account is locked.
Current LDAP implementation always returns "Bad Credentials" that does not give the right picture that why my credentials are invalid. i want to cover the cases
where the account is Locked
password is expired so i can redirect to change password
account locked due to number of invalid password retries
Please help
The issue i fixed by defining the LDAP context instead of using the Spring Boot LDAPAuthenticationProviderConfigurer.
Then created the FilterBasedLdapUserSearch and Over-written the BindAuthentication with my ConnectBindAuthenticator.
i created a separate LDAPConfiguration class for spring boot configuration and registered all these custom objects as Beans.
From the above Objects i created LDAPAuthenticationProvider by passing my Custom Objects to constructor
The Config is as below
#Bean
public DefaultSpringSecurityContextSource contextSource() {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(env.getProperty("ldap.url"));
contextSource.setBase(env.getProperty("ldap.base"));
contextSource.setUserDn(env.getProperty("ldap.managerDn"));
contextSource.setPassword(env.getProperty("ldap.managerPassword"));
return contextSource;
}
#Bean
public ConnectBindAuthenticator bindAuthenticator() {
ConnectBindAuthenticator connectBindAuthenticator = new ConnectBindAuthenticator(contextSource());
connectBindAuthenticator.setUserSearch(ldapUserSearch());
connectBindAuthenticator.setUserDnPatterns(new String[]{env.getProperty("ldap.managerDn")});
return connectBindAuthenticator;
}
#Bean
public LdapUserSearch ldapUserSearch() {
return new FilterBasedLdapUserSearch("", env.getProperty("ldap.userSearchFilter"), contextSource());
}
You have to change your spring security configuration to add your extension of BindAuthenticator:
CustomBindAuthenticator.java
public class CustomBindAuthenticator extends BindAuthenticator {
public CustomBindAuthenticator(BaseLdapPathContextSource contextSource) {
super(contextSource);
}
#Override
protected void handleBindException(String userDn, String username, Throwable cause) {
// TODO: Include here the logic of your custom BindAuthenticator
if (somethingHappens()) {
throw new MyCustomException("Custom error message");
}
super.handleBindException(userDn, username, cause);
}
}
spring-security.xml
<beans:bean id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<beans:constructor-arg value="LDAP_URL" />
<beans:property name="userDn" value="USER_DN" />
<beans:property name="password" value="PASSWORD" />
</beans:bean>
<beans:bean id="userSearch"
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<beans:constructor-arg index="0" value="USER_SEARCH_BASE" />
<beans:constructor-arg index="1" value="USER_SEARCH_FILTER" />
<beans:constructor-arg index="2" ref="contextSource" />
</beans:bean>
<beans:bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<beans:constructor-arg>
<beans:bean class="com.your.project.CustomBindAuthenticator">
<beans:constructor-arg ref="contextSource" />
<beans:property name="userSearch" ref="userSearch" />
</beans:bean>
</beans:constructor-arg>
</beans:bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="ldapAuthProvider" />
</security:authentication-manager>
Hope it's helpful.

Can't resolve a Locale

I have a problem with Locale's. I'm trying to do a simple thing where I can choose english or german.
So I have two property files called
messages_en and
messages_de.
So far these files have a single line:
contactbook = Contact Book
and
contactbook = Adressbuch
respectively.
Now in my JSP view I have this :
<spring:message code="contactbook"/>
The idea is that the message in the view changes depending on which locale we're using. Now the locale itself should be changed with this line:
English|German
If I remove the everything works great but of course it's not locale specified. So the rest of the view is good.
In my dispatcher-servlet.xml file I have this:
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en" />
</bean>
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="language" />
</bean>
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" >
<property name="interceptors">
<list>
<ref bean="localeChangeInterceptor" />
</list>
</property>
</bean>
Again, without it everything works well. There's something wrong with my understanding here. The localeChangeInterceptor stops any change done to the locale and the ControllerClassNameHandlerMapping does what? I keep on looking at my controller and wondering should I add something to it but it seems to me that all these lines in the dispatcher should be enough.
The exception I get is
No message found under code 'contactbook' for locale 'en'
Despite a myriad of examples out there I keep on failing to understand or resolve the problem. Any help would be greatly appreciated.
You need configure a ReloadableResourceBundleMessageSource.
look at java doc Here.
Example.
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<!--classpath of your messages-->
<property name="basename" value="classpath:/i18n/messages" />
<property name="useCodeAsDefaultMessage" value="true" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
If you need working example of JavaConfig SpringMVC app I can help you with my code. I've been developing the same kind of simple app. Here is configuration of SpringMVC:
#Configuration
#EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Bean(name = "viewResolver")
public InternalResourceViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/views/");
resolver.setSuffix(".jsp");
resolver.setContentType("text/html; charset=UTF-8");
return resolver;
}
#Bean(name = "messageSource")
public ReloadableResourceBundleMessageSource getReloadableResourceBundle(){
ReloadableResourceBundleMessageSource resourceBundle = new ReloadableResourceBundleMessageSource();
resourceBundle.setBasename("classpath:messages");
resourceBundle.setDefaultEncoding("UTF-8");
return resourceBundle;
}
#Bean(name = "localeResolver")
public SessionLocaleResolver getSessionLocaleResolver(){
SessionLocaleResolver resolver = new SessionLocaleResolver();
resolver.setDefaultLocale(Locale.ENGLISH);
return resolver;
}
#Bean(name = "localeChangeInterceptor")
public LocaleChangeInterceptor getLocaleChangeInterceptor(){
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("language");
return interceptor;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/css*").addResourceLocations("/resources/css/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getLocaleChangeInterceptor());
}
}
Also if it won't solve your problem and your config will be working fine, just try to put line spacer before the very first message in every .message file in your message bundle. (It helped me once when I've been getting the same exception you got and I don't know why, just saying ;P )

Bean into bean injection [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
Have no experience with Spring beans injection.
<beans:bean id="ModeService"
class="<path>Service">
<beans:property name="Mode" value="true"/>
</beans:bean>
<beans:bean id="Filter"
class="<path>.RequestFilter">
<custom-filter position="FIRST" />
</beans:bean>
How to inject ModeService bean into Filter bean ?
ok, I've got injection in Spring thx #William
So have:
<beans:bean id="maintenanceModeService"
class="<path>.MaintenanceService">
<beans:property name="maintenanceMode" value="true"/>
</beans:bean>
<beans:bean id="maintenanceFilter"
class="<path>.MaintenanceRequestFilter">
<custom-filter position="FIRST" />
<beans:property name="modeService" ref="maintenanceModeService"/>
</beans:bean>
In MaintenanceService, I've append setter/getter for invoking variable:
boolean maintenanceMode;
public void setMaintenanceMode(boolean mode)
{
this.maintenanceMode = mode;
}
public boolean getMaintenanceMode()
{
return maintenanceMode;
}
And append setter/getter into MaintenanceRequestFilter:
boolean modeService;
public void setModeService(MaintenanceService maintenanceMode)
{
this.modeService = maintenanceMode;
}
public MaintenanceService getMaintenanceMode()
{
return modeService;
}
And then invoke modeService in doFilter()
But smth wrong...
<beans:bean id="Filter" class="<path>.RequestFilter">
<custom-filter position="FIRST" />
<beans:property name="modeService" ref="ModService"/>
</beans:bean>
And you should have a getter/setter method in your class
class RequestFilter{
public void setModeService(ModService modService){
// some set code here
}
public ModeService getModeService(){
// some set code here
return modService;
}
}
You can use ref attribute to define reference to another bean. Filter class should have property of type ModeService so that you can define it in <property> tag using ref attribute.
<beans:bean id="Filter" class="<path>.RequestFilter">
<custom-filter position="FIRST" />
<beans:property name="modeService" ref="ModeService"/>
</beans:bean>

I want the current resource processed by MultiResourceItemReader available in beforeStep method

Is there any way to make the currentResource processed by MultiResourceItemReader to make it available in the beforeStep method.Kindly provide me a working code sample. I tried injected multiresourcereader reference in to stepexecutionlistener , but the spring cglib only accepts an interface type to be injected ,i dont know whether to use ItemReader or ItemStream interface.
The MultiResourceItemReader now has a method getCurrentResource() that returns the current Resource.
Retrieving of currentResource from MultiResourceItemReader is not possible at the moment. If you need this API enhancement, create one in Spring Batch JIRA.
Even if there is a getter for currentResource, it's value is not valid in beforeStep(). It is valid between open() and close().
it is possible, if you use a Partition Step and the Binding Input Data to Steps concept
simple code example, with concurrency limit 1 to imitate "serial" processing:
<bean name="businessStep:master" class="org.springframework.batch.core.partition.support.PartitionStep">
<property name="jobRepository" ref="jobRepository"/>
<property name="stepExecutionSplitter">
<bean class="org.springframework.batch.core.partition.support.SimpleStepExecutionSplitter">
<constructor-arg ref="jobRepository"/>
<constructor-arg ref="concreteBusinessStep"/>
<constructor-arg>
<bean class="org.spring...MultiResourcePartitioner" scope="step">
<property name="resources" value="#{jobParameters['input.file.pattern']}"/>
</bean>
</constructor-arg>
</bean>
</property>
<property name="partitionHandler">
<bean class="org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler">
<property name="taskExecutor">
<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor">
<property name="concurrencyLimit" value="1" />
</bean>
</property>
<property name="step" ref="concreteBusinessStep"/>
</bean>
</property>
</bean>
<bean id="whateverClass" class="..." scope="step">
<property name="resource" value="#{stepExecutionContext['fileName']}" />
</bean>
example step configuration:
<job id="renameFilesPartitionJob">
<step id="businessStep"
parent="businessStep:master" />
</job>
<step id="concreteBusinessStep">
<tasklet>
<chunk reader="itemReader"
writer="itemWriter"
commit-interval="5" />
</tasklet>
</step>
potential drawbacks:
distinct steps for each file instead of one step
more complicated configuration
Using the getCurrentResource() method from MultiResourceItemReader, update the stepExecution. Example code as below
private StepExecution stepExecution;
#Override
public Resource getCurrentResource() {
this.stepExecution.getJobExecution().getExecutionContext().put("FILE_NAME", super.getCurrentResource().getFilename());
return super.getCurrentResource();
}
#BeforeStep
public void beforeStep(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
If you make the item you are reading implement ResourceAware, the current resource is set as it is read
public class MyItem implements ResourceAware {
private Resource resource;
//others
public void setResource(Resource resource) {
this.resource = resource;
}
public Resource getResource() {
return resource;
}
}
and in your reader, processor or writer
myItem.getResource()
will return the resource it was loaded from

spring 3 my converter is not used

...but registered
Using Spring 3
I have two converters registered as follows:
<beans:bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<beans:property name="converters">
<beans:list>
<beans:bean class="mypackage.CalendarToStringConverter" />
<beans:bean class="mypackage.StringToCalendarConverter" />
</beans:list>
</beans:property>
</beans:bean>
The converters look like this:
public class StringToCalendarConverter implements Converter< String, Calendar > {
public Calendar convert( String value ) {
return Calendar.getInstance();
}
}
public class CalendarToStringConverter implements Converter< Calendar, String > {
public String convert( Calendar arg0 ) {
return "23.10.1985";
}
}
The problem is that they are not used during conversion in post and get requests.
What am I doing wrong?
What do I havt to do to get this working?
THX!
Are you using <mvc:annotation-driven> and if so, are you pointing to conversionService in the conversion-service attribute?
Here's the converters configuration that works for me. The differences you might try changing:
I pass in a set instead of a list. (setConverters takes a Set parameter)
I use FormattingConversionServiceFactoryBean instead of ConversionServiceFactoryBean. (Should not matter)
My converters are defined as top level beans and referenced. (Also should not matter)
Hopefully one of this will fix your problem.
<util:set id="converters" >
<ref bean="userDao" />
<ref bean="orderDao" />
<util:set>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters" ref="converters"/>
</bean>

Resources