001/* 002 * Copyright 2014 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.springframework.batch.integration.config.xml; 017 018import org.w3c.dom.Element; 019 020import org.springframework.batch.core.step.item.SimpleChunkProcessor; 021import org.springframework.batch.integration.chunk.ChunkProcessorChunkHandler; 022import org.springframework.batch.item.support.PassThroughItemProcessor; 023import org.springframework.beans.factory.config.BeanDefinition; 024import org.springframework.beans.factory.config.RuntimeBeanReference; 025import org.springframework.beans.factory.support.AbstractBeanDefinition; 026import org.springframework.beans.factory.support.BeanDefinitionBuilder; 027import org.springframework.beans.factory.support.BeanDefinitionRegistry; 028import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; 029import org.springframework.beans.factory.xml.ParserContext; 030import org.springframework.integration.config.ServiceActivatorFactoryBean; 031import org.springframework.integration.config.xml.AbstractConsumerEndpointParser; 032import org.springframework.util.Assert; 033import org.springframework.util.StringUtils; 034 035/** 036 * <p> 037 * Parser for the remote-chunking-slave namespace element. If an 038 * {@link org.springframework.batch.item.ItemProcessor} is not provided, an 039 * {@link org.springframework.batch.item.support.PassThroughItemProcessor} will be 040 * configured. 041 * </p> 042 * 043 * @author Chris Schaefer 044 * @since 3.1 045 */ 046public class RemoteChunkingSlaveParser extends AbstractBeanDefinitionParser { 047 private static final String INPUT_CHANNEL_ATTRIBUTE = "input-channel"; 048 private static final String OUTPUT_CHANNEL_ATTRIBUTE = "output-channel"; 049 private static final String ITEM_PROCESSOR_ATTRIBUTE = "item-processor"; 050 private static final String ITEM_WRITER_ATTRIBUTE = "item-writer"; 051 private static final String ITEM_PROCESSOR_PROPERTY_NAME = "itemProcessor"; 052 private static final String ITEM_WRITER_PROPERTY_NAME = "itemWriter"; 053 private static final String CHUNK_PROCESSOR_PROPERTY_NAME = "chunkProcessor"; 054 private static final String CHUNK_PROCESSOR_CHUNK_HANDLER_BEAN_NAME_PREFIX = "chunkProcessorChunkHandler_"; 055 056 @Override 057 protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { 058 String id = element.getAttribute(ID_ATTRIBUTE); 059 Assert.hasText(id, "The id attribute must be specified"); 060 061 String inputChannel = element.getAttribute(INPUT_CHANNEL_ATTRIBUTE); 062 Assert.hasText(inputChannel, "The input-channel attribute must be specified"); 063 064 String outputChannel = element.getAttribute(OUTPUT_CHANNEL_ATTRIBUTE); 065 Assert.hasText(outputChannel, "The output-channel attribute must be specified"); 066 067 String itemProcessor = element.getAttribute(ITEM_PROCESSOR_ATTRIBUTE); 068 069 String itemWriter = element.getAttribute(ITEM_WRITER_ATTRIBUTE); 070 Assert.hasText(itemWriter, "The item-writer attribute must be specified"); 071 072 BeanDefinitionRegistry beanDefinitionRegistry = parserContext.getRegistry(); 073 074 BeanDefinitionBuilder chunkProcessorBuilder = 075 BeanDefinitionBuilder 076 .genericBeanDefinition(SimpleChunkProcessor.class) 077 .addPropertyReference(ITEM_WRITER_PROPERTY_NAME, itemWriter); 078 079 if(StringUtils.hasText(itemProcessor)) { 080 chunkProcessorBuilder.addPropertyReference(ITEM_PROCESSOR_PROPERTY_NAME, itemProcessor); 081 } else { 082 chunkProcessorBuilder.addPropertyValue(ITEM_PROCESSOR_PROPERTY_NAME, new PassThroughItemProcessor<>()); 083 } 084 085 BeanDefinition chunkProcessorChunkHandler = 086 BeanDefinitionBuilder 087 .genericBeanDefinition(ChunkProcessorChunkHandler.class) 088 .addPropertyValue(CHUNK_PROCESSOR_PROPERTY_NAME, chunkProcessorBuilder.getBeanDefinition()) 089 .getBeanDefinition(); 090 091 beanDefinitionRegistry.registerBeanDefinition(CHUNK_PROCESSOR_CHUNK_HANDLER_BEAN_NAME_PREFIX + id, chunkProcessorChunkHandler); 092 093 new ServiceActivatorParser(id).parse(element, parserContext); 094 095 return null; 096 } 097 098 private static class ServiceActivatorParser extends AbstractConsumerEndpointParser { 099 private static final String TARGET_METHOD_NAME_PROPERTY_NAME = "targetMethodName"; 100 private static final String TARGET_OBJECT_PROPERTY_NAME = "targetObject"; 101 private static final String HANDLE_CHUNK_METHOD_NAME = "handleChunk"; 102 private static final String CHUNK_PROCESSOR_CHUNK_HANDLER_BEAN_NAME_PREFIX = "chunkProcessorChunkHandler_"; 103 104 private String id; 105 106 public ServiceActivatorParser(String id) { 107 this.id = id; 108 } 109 110 @Override 111 protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) { 112 BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ServiceActivatorFactoryBean.class); 113 builder.addPropertyValue(TARGET_METHOD_NAME_PROPERTY_NAME, HANDLE_CHUNK_METHOD_NAME); 114 builder.addPropertyValue(TARGET_OBJECT_PROPERTY_NAME, new RuntimeBeanReference(CHUNK_PROCESSOR_CHUNK_HANDLER_BEAN_NAME_PREFIX + id)); 115 return builder; 116 } 117 } 118}