BATCHADM-161 - Add Job Launching Gateway

For reference see: https://jira.springsource.org/browse/BATCHADM-161

* Add XML Schema
* Add Namespace Handler
* Add Parser and Gateway classes
* Add tests
This commit is contained in:
Gunnar Hillert
2013-05-01 12:47:45 -04:00
committed by Michael Minella
parent f23dd64740
commit 3909b75151
20 changed files with 904 additions and 4 deletions

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.integration.config.xml;
import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHandler;
/**
* The namespace handler for the Spring Batch Integration namespace.
*
* @author Gunnar Hillert
* @since 1.3
*
*/
public class BatchIntegrationNamespaceHandler extends AbstractIntegrationNamespaceHandler {
/* (non-Javadoc)
* @see org.springframework.beans.factory.xml.NamespaceHandler#init()
*/
public void init() {
this.registerBeanDefinitionParser("job-launching-gateway", new JobLaunchingGatewayParser());
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.integration.config.xml;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.integration.launch.JobLaunchingGateway;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractConsumerEndpointParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* The parser for the Job-Launching Gateway, which will instantiate a
* {@link JobLaunchingGatewayParser}. If no {@link JobLauncher} reference has
* been provided, this parse will use the use the globally registered bean
* 'jobLauncher'.
*
* @author Gunnar Hillert
* @since 1.3
*
*/
public class JobLaunchingGatewayParser extends AbstractConsumerEndpointParser {
private static final Log logger = LogFactory.getLog(JobLaunchingGatewayParser.class);
@Override
protected String getInputChannelAttributeName() {
return "request-channel";
}
@Override
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
final BeanDefinitionBuilder jobLaunchingGatewayBuilder =
BeanDefinitionBuilder.genericBeanDefinition(JobLaunchingGateway.class);
final String jobLauncher = element.getAttribute("job-launcher");
if (StringUtils.hasText(jobLauncher)) {
jobLaunchingGatewayBuilder.addConstructorArgReference(jobLauncher);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("No jobLauncher specified, using default 'jobLauncher' reference instead.");
}
jobLaunchingGatewayBuilder.addConstructorArgReference("jobLauncher");
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(jobLaunchingGatewayBuilder, element, "reply-timeout", "sendTimeout");
final String replyChannel = element.getAttribute("reply-channel");
if (StringUtils.hasText(replyChannel)) {
jobLaunchingGatewayBuilder.addPropertyReference("outputChannel", replyChannel);
}
return jobLaunchingGatewayBuilder;
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.integration.launch;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.integration.Message;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.util.Assert;
/**
* The {@link JobLaunchingGateway} is used to launch Batch Jobs. Internally it
* delegates to a {@link JobLaunchingMessageHandler}.
*
* @author Gunnar Hillert
*
* @since 1.3
*/
public class JobLaunchingGateway extends AbstractReplyProducingMessageHandler {
private final JobLaunchingMessageHandler jobLaunchingMessageHandler;
/**
* Constructor taking a {@link JobLauncher} as parameter.
*
* @param storedProcExecutor Must not be null.
*
*/
public JobLaunchingGateway(JobLauncher jobLauncher) {
Assert.notNull(jobLauncher, "jobLauncher must not be null.");
this.jobLaunchingMessageHandler = new JobLaunchingMessageHandler(jobLauncher);
}
/**
* Launches a Batch Job using the provided request {@link Message}. The payload
* of the {@link Message} <em>must</em> be an instance of {@link JobLaunchRequest}.
*
* @param The provided requestMessage must not be null.
* @return Generally a {@link JobExecution} will always be returned. An
* exception ({@link MessageHandlingException}) will only be thrown if there
* is a failure to start the job. The cause of the exception will be a
* {@link JobExecutionException}.
*
* @throws MessageHandlingException
*/
@Override
protected Object handleRequestMessage(Message<?> requestMessage) {
Assert.notNull(requestMessage, "The provided requestMessage must not be null.");
final Object payload = requestMessage.getPayload();
Assert.isInstanceOf(JobLaunchRequest.class, payload, "The payload must be of type JobLaunchRequest.");
final JobLaunchRequest jobLaunchRequest = (JobLaunchRequest) payload;
final JobExecution jobExecution;
try {
jobExecution = this.jobLaunchingMessageHandler.launch(jobLaunchRequest);
} catch (JobExecutionException e) {
throw new MessageHandlingException(requestMessage, e);
}
return jobExecution;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2007 the original author or authors.
* Copyright 2006-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,7 +27,8 @@ import org.springframework.integration.annotation.ServiceActivator;
* Message handler which uses strategies to convert a Message into a job and a set of job parameters
* @author Jonas Partner
* @author Dave Syer
*
* @author Gunnar Hillert
*
*/
public class JobLaunchingMessageHandler implements JobLaunchRequestHandler {
@@ -46,8 +47,7 @@ public class JobLaunchingMessageHandler implements JobLaunchRequestHandler {
Job job = request.getJob();
JobParameters jobParameters = request.getJobParameters();
JobExecution execution = jobLauncher.run(job, jobParameters);
return execution;
return jobLauncher.run(job, jobParameters);
}
}

View File

@@ -0,0 +1 @@
http\://www.springframework.org/schema/batch-integration=org.springframework.batch.integration.config.xml.BatchIntegrationNamespaceHandler

View File

@@ -0,0 +1,2 @@
http\://www.springframework.org/schema/batch-integration/spring-batch-integration-1.3.xsd=org/springframework/batch/integration/config/xml/spring-batch-integration-1.3.xsd
http\://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd=org/springframework/batch/integration/config/xml/spring-batch-integration-1.3.xsd

View File

@@ -0,0 +1,4 @@
# Tooling related information for the Spring Batch Integration namespace
http\://www.springframework.org/schema/integration/spring-batch-integration@name=Spring Batch Integration Namespace
http\://www.springframework.org/schema/integration/spring-batch-integration@prefix=batch-int
http\://www.springframework.org/schema/integration/spring-batch-integration@icon=org/springframework/batch/integration/config/xml/spring-batch-integration.gif

View File

@@ -0,0 +1,135 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.springframework.org/schema/batch-integration"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:integration="http://www.springframework.org/schema/integration"
targetNamespace="http://www.springframework.org/schema/batch-integration"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans" />
<xsd:import namespace="http://www.springframework.org/schema/tool" />
<xsd:import namespace="http://www.springframework.org/schema/integration"
schemaLocation="http://www.springframework.org/schema/integration/spring-integration.xsd" />
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines the configuration elements for the Spring Batch Integration
Support.
]]></xsd:documentation>
</xsd:annotation>
<xsd:element name="job-launching-gateway">
<xsd:annotation>
<xsd:documentation><![CDATA[
This Outbound Gateway is used to launch Batch Jobs. The
payload of Messages to be processed MUST be an instance
of JobLaunchRequest.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1" />
</xsd:sequence>
<xsd:attributeGroup ref="corespringBatchIntegrationComponentAttributes"/>
<xsd:attribute name="request-channel" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The input Message Channel of this endpoint.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reply-channel" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Message Channel to which the resulting JobExecution
payload will be sent.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reply-timeout" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Allows you to specify how long this gateway will wait for
the reply message to be sent successfully to the reply channel
before throwing an exception. This attribute only applies when the
channel might block, for example when using a bounded queue channel that
is currently full.
Also, keep in mind that when sending to a DirectChannel, the
invocation will occur in the sender's thread. Therefore,
the failing of the send operation may be caused by other
components further downstream.
The "reply-timeout" attribute maps to the "sendTimeout" property of the
underlying 'MessagingTemplate' instance (org.springframework.integration.core.MessagingTemplate).
The attribute will default, if not specified, to '-1', meaning that
by default, the Gateway will wait indefinitely. The value is
specified in milliseconds.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="job-launcher" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<xsd:documentation><![CDATA[
Pass in a custom JobLauncher bean reference.
This attribute is optional. If not specified the
adapter will re-use the default instance (under
the id 'jobLauncher', e.g. when using the
@EnableBatchProcessing annotation via JavaConfig).
If no default instance exists an exception is
thrown.
]]></xsd:documentation>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.batch.core.launch.JobLauncher" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="order">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies the order for invocation when this endpoint
is connected as a subscriber to a SubscribableChannel.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:attributeGroup name="corespringBatchIntegrationComponentAttributes">
<xsd:attribute name="id" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Identifies the underlying Spring bean definition, which is an
instance of either 'EventDrivenConsumer' or 'PollingConsumer',
depending on whether the component's input channel is a
'SubscribableChannel' or 'PollableChannel'.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-startup" default="true" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Flag to indicate that the component should start automatically
on startup (default true).
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
</xsd:attributeGroup>
</xsd:schema>