From 79086558834b47e416012fd48c80d6afde072258 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Mon, 8 Apr 2013 17:32:55 -0400 Subject: [PATCH] INT-2982 Add Syslog Inbound Channel Adapter * Supports UDP/TCP syslog messages. * See docbook patch for more information. For reference see: https://jira.springsource.org/browse/INT-2982 --- build.gradle | 8 + settings.gradle | 1 + .../transformer/SyslogToMapTransformer.java | 21 +- .../xml/SyslogTransformerParserTests.java | 2 +- .../transformer/SysLogTransformerTests.java | 2 +- .../UdpInboundChannelAdapterParser.java | 1 + .../ip/config/spring-integration-ip-3.0.xsd | 86 ++++--- .../syslog/DefaultMessageConverter.java | 60 +++++ .../integration/syslog/MessageConverter.java | 31 +++ .../integration/syslog/SyslogHeaders.java | 41 ++++ .../SyslogInboundChannelAdapterParser.java | 67 ++++++ .../syslog/config/SyslogNamespaceHandler.java | 33 +++ ...logReceivingChannelAdapterFactoryBean.java | 209 ++++++++++++++++++ .../syslog/config/package-info.java | 4 + .../SyslogReceivingChannelAdapterSupport.java | 80 +++++++ .../TcpSyslogReceivingChannelAdapter.java | 72 ++++++ .../UdpSyslogReceivingChannelAdapter.java | 67 ++++++ .../syslog/inbound/package-info.java | 4 + .../integration/syslog/package-info.java | 4 + .../main/resources/META-INF/spring.handlers | 1 + .../main/resources/META-INF/spring.schemas | 2 + .../main/resources/META-INF/spring.tooling | 4 + .../config/spring-integration-syslog-3.0.xsd | 114 ++++++++++ .../config/spring-integration-syslog.gif | Bin 0 -> 512 bytes ...ivingChannelAdapterParserTests-context.xml | 62 ++++++ ...hannelAdapterParserTests-fail1-context.xml | 29 +++ ...hannelAdapterParserTests-fail2-context.xml | 29 +++ ...hannelAdapterParserTests-fail3-context.xml | 29 +++ ...hannelAdapterParserTests-fail4-context.xml | 28 +++ ...logReceivingChannelAdapterParserTests.java | 208 +++++++++++++++++ .../SyslogReceivingChannelAdapterTests.java | 82 +++++++ src/reference/docbook/index.xml | 1 + src/reference/docbook/syslog.xml | 92 ++++++++ src/reference/docbook/whats-new.xml | 10 + 34 files changed, 1440 insertions(+), 44 deletions(-) create mode 100644 spring-integration-syslog/src/main/java/org/springframework/integration/syslog/DefaultMessageConverter.java create mode 100644 spring-integration-syslog/src/main/java/org/springframework/integration/syslog/MessageConverter.java create mode 100644 spring-integration-syslog/src/main/java/org/springframework/integration/syslog/SyslogHeaders.java create mode 100644 spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogInboundChannelAdapterParser.java create mode 100644 spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogNamespaceHandler.java create mode 100644 spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterFactoryBean.java create mode 100644 spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/package-info.java create mode 100644 spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterSupport.java create mode 100644 spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/TcpSyslogReceivingChannelAdapter.java create mode 100644 spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/UdpSyslogReceivingChannelAdapter.java create mode 100644 spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/package-info.java create mode 100644 spring-integration-syslog/src/main/java/org/springframework/integration/syslog/package-info.java create mode 100644 spring-integration-syslog/src/main/resources/META-INF/spring.handlers create mode 100644 spring-integration-syslog/src/main/resources/META-INF/spring.schemas create mode 100644 spring-integration-syslog/src/main/resources/META-INF/spring.tooling create mode 100644 spring-integration-syslog/src/main/resources/org/springframework/integration/syslog/config/spring-integration-syslog-3.0.xsd create mode 100644 spring-integration-syslog/src/main/resources/org/springframework/integration/syslog/config/spring-integration-syslog.gif create mode 100644 spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-context.xml create mode 100644 spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail1-context.xml create mode 100644 spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail2-context.xml create mode 100644 spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail3-context.xml create mode 100644 spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail4-context.xml create mode 100644 spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests.java create mode 100644 spring-integration-syslog/src/test/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterTests.java create mode 100644 src/reference/docbook/syslog.xml diff --git a/build.gradle b/build.gradle index 70e511ad1c..c18d6eb0e9 100644 --- a/build.gradle +++ b/build.gradle @@ -480,6 +480,14 @@ project('spring-integration-stream') { } } +project('spring-integration-syslog') { + description = 'Spring Integration Syslog Support' + dependencies { + compile project(":spring-integration-ip") + testCompile project(":spring-integration-test") + } +} + project('spring-integration-test') { description = 'Spring Integration Test Support' dependencies { diff --git a/settings.gradle b/settings.gradle index 3c5030623f..ac37638a58 100644 --- a/settings.gradle +++ b/settings.gradle @@ -22,6 +22,7 @@ include 'spring-integration-scripting' include 'spring-integration-security' include 'spring-integration-sftp' include 'spring-integration-stream' +include 'spring-integration-syslog' include 'spring-integration-test' include 'spring-integration-twitter' include 'spring-integration-ws' diff --git a/spring-integration-core/src/main/java/org/springframework/integration/transformer/SyslogToMapTransformer.java b/spring-integration-core/src/main/java/org/springframework/integration/transformer/SyslogToMapTransformer.java index 955e18e630..ce9f7ca2c2 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/transformer/SyslogToMapTransformer.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/transformer/SyslogToMapTransformer.java @@ -42,7 +42,13 @@ public class SyslogToMapTransformer extends AbstractPayloadTransformer transformPayload(Object payload) throws Exception { - Assert.isTrue(payload instanceof byte[] || payload instanceof String, - "payload must be String or byte[]"); - if (payload instanceof byte[]) { + boolean isByteArray = payload instanceof byte[]; + boolean isString = payload instanceof String; + Assert.isTrue(isByteArray || isString, "payload must be String or byte[]"); + if (isByteArray) { return this.transform((byte[]) payload); } - else if (payload instanceof String) { + else if (isString) { return this.transform((String) payload); } return null; diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/SyslogTransformerParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/SyslogTransformerParserTests.java index a57dea7654..fba6b28f11 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/SyslogTransformerParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/SyslogTransformerParserTests.java @@ -56,7 +56,7 @@ public class SyslogTransformerParserTests { assertEquals(6, map.size()); assertEquals(19, map.get(SyslogToMapTransformer.FACILITY)); assertEquals(5, map.get(SyslogToMapTransformer.SEVERITY)); - Object date = map.get(SyslogToMapTransformer.TIMESAMP); + Object date = map.get(SyslogToMapTransformer.TIMESTAMP); assertTrue(date instanceof Date || date instanceof String); assertEquals("WEBERN", map.get(SyslogToMapTransformer.HOST)); assertEquals("TESTING[70729]", map.get(SyslogToMapTransformer.TAG)); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/transformer/SysLogTransformerTests.java b/spring-integration-core/src/test/java/org/springframework/integration/transformer/SysLogTransformerTests.java index da77625675..a66857a441 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/transformer/SysLogTransformerTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/transformer/SysLogTransformerTests.java @@ -39,7 +39,7 @@ public class SysLogTransformerTests { assertEquals(6, transformed.size()); assertEquals(19, transformed.get(SyslogToMapTransformer.FACILITY)); assertEquals(6, transformed.get(SyslogToMapTransformer.SEVERITY)); - Object date = transformed.get(SyslogToMapTransformer.TIMESAMP); + Object date = transformed.get(SyslogToMapTransformer.TIMESTAMP); assertTrue(date instanceof Date || date instanceof String); assertEquals("WEBERN", transformed.get(SyslogToMapTransformer.HOST)); assertEquals("TESTING[70729]", transformed.get(SyslogToMapTransformer.TAG)); diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/config/UdpInboundChannelAdapterParser.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/config/UdpInboundChannelAdapterParser.java index 0c4005780d..bab65eca2c 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/config/UdpInboundChannelAdapterParser.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/config/UdpInboundChannelAdapterParser.java @@ -34,6 +34,7 @@ import org.w3c.dom.Element; */ public class UdpInboundChannelAdapterParser extends AbstractChannelAdapterParser { + @Override protected AbstractBeanDefinition doParse(Element element, ParserContext parserContext, String channelName) { BeanDefinitionBuilder builder = parseUdp(element, parserContext); IpAdapterParserUtils.addCommonSocketOptions(builder, element); diff --git a/spring-integration-ip/src/main/resources/org/springframework/integration/ip/config/spring-integration-ip-3.0.xsd b/spring-integration-ip/src/main/resources/org/springframework/integration/ip/config/spring-integration-ip-3.0.xsd index ed103413b8..01fda0ff28 100644 --- a/spring-integration-ip/src/main/resources/org/springframework/integration/ip/config/spring-integration-ip-3.0.xsd +++ b/spring-integration-ip/src/main/resources/org/springframework/integration/ip/config/spring-integration-ip-3.0.xsd @@ -27,25 +27,14 @@ - - + + - -The number of threads that will be used for socket/channel handling. Only applies -if an external task-executor is NOT being used. When using an external task executor, -its configuration specifies the number of threads. - - - - - - - - - Specifies a specific Executor to be used for socket handling. If not supplied, an internal - pooled executor will be used (See pool-size). Needed on some platforms that require the use of specific - task executors such as a WorkManagerTaskExecutor. - + + + + + @@ -62,14 +51,6 @@ its configuration specifies the number of threads. - - - -Whether or not to do a DNS reverse-lookup on the remote ip address to insert the host name into the -message headers (ip_hostName). Default "true". - - - @@ -87,6 +68,15 @@ message headers (ip_hostName). Default "true". + + + + + + + + + @@ -668,6 +658,41 @@ setCustomHeaders(). Default is TcpMessageMapper. + + + + + + +The number of threads that will be used for socket/channel handling. Only applies +if an external task-executor is NOT being used. When using an external task executor, +its configuration specifies the number of threads. + + + + + + + + +Specifies a specific Executor to be used for socket handling. If not supplied, an internal +pooled executor will be used (See pool-size). Needed on some platforms that require the use of specific +task executors such as a WorkManagerTaskExecutor. + + + + + + +Whether or not to do a DNS reverse-lookup on the remote ip address to insert the host name into the +message headers (ip_hostName). Default "true". + + + + + + + @@ -676,15 +701,6 @@ setCustomHeaders(). Default is TcpMessageMapper. - - - - - - - - - diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/DefaultMessageConverter.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/DefaultMessageConverter.java new file mode 100644 index 0000000000..aceb7e2e31 --- /dev/null +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/DefaultMessageConverter.java @@ -0,0 +1,60 @@ +/* + * 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.integration.syslog; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.springframework.integration.Message; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.integration.transformer.SyslogToMapTransformer; + +/** + * Default {@link MessageConverter}; delegates to a {@link SyslogToMapTransformer} + * to convert the payload to a map of values and also provides some of the map + * contents as message headers. + * See @link {@link SyslogHeaders} for the headers that are mapped. + * @author Gary Russell + * @since 3.0 + * + */ +public class DefaultMessageConverter implements MessageConverter { + + private final SyslogToMapTransformer transformer = new SyslogToMapTransformer(); + + public static final Set SYSLOG_PAYLOAD_ENTRIES = new HashSet( + Arrays.asList(new String[] {SyslogToMapTransformer.MESSAGE, SyslogToMapTransformer.UNDECODED})); + + @Override + public Message fromSyslog(Message message) throws Exception { + Map map = this.transformer.doTransform(message); + Map out = new HashMap(); + for (Entry entry : map.entrySet()) { + String key = entry.getKey(); + if (!SYSLOG_PAYLOAD_ENTRIES.contains(key)) { + out.put(SyslogHeaders.PREFIX + entry.getKey(), entry.getValue()); + } + } + return MessageBuilder.withPayload(map) + .copyHeaders(out) + .build(); + } + +} diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/MessageConverter.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/MessageConverter.java new file mode 100644 index 0000000000..851fd5343b --- /dev/null +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/MessageConverter.java @@ -0,0 +1,31 @@ +/* + * 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.integration.syslog; + +import org.springframework.integration.Message; + + +/** + * A converter to convert the raw message created by the underlying + * UDP/TCP endpoint to a specific form of Syslog message. + * @author Gary Russell + * @since 3.0 + * + */ +public interface MessageConverter { + + Message fromSyslog(Message syslog) throws Exception; +} diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/SyslogHeaders.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/SyslogHeaders.java new file mode 100644 index 0000000000..47e96e899e --- /dev/null +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/SyslogHeaders.java @@ -0,0 +1,41 @@ +/* + * 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.integration.syslog; + +import org.springframework.integration.transformer.SyslogToMapTransformer; + +/** + * Headers in a {@code Map} generated by the @link {@link SyslogToMapTransformer} that + * will be added to Spring Integration messages as headers, prefixed by {@link #PREFIX}. + * @author Gary Russell + * @since 3.0 + * + */ +public class SyslogHeaders { + + public static String PREFIX = "syslog_"; + + public static final String FACILITY = PREFIX + SyslogToMapTransformer.FACILITY; + + public static final String SEVERITY = PREFIX + SyslogToMapTransformer.SEVERITY; + + public static final String TIMESTAMP = PREFIX + SyslogToMapTransformer.TIMESTAMP; + + public static final String HOST = PREFIX + SyslogToMapTransformer.HOST; + + public static final String TAG = PREFIX + SyslogToMapTransformer.TAG; + +} diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogInboundChannelAdapterParser.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogInboundChannelAdapterParser.java new file mode 100644 index 0000000000..869a925dbd --- /dev/null +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogInboundChannelAdapterParser.java @@ -0,0 +1,67 @@ +/* + * 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.integration.syslog.config; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.config.xml.IntegrationNamespaceUtils; +import org.springframework.integration.ip.config.UdpInboundChannelAdapterParser; +import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; + +/** + * Parses a {@code }. + * @author Gary Russell + * @since 3.0 + * + */ +public class SyslogInboundChannelAdapterParser extends UdpInboundChannelAdapterParser { + + + @Override + protected AbstractBeanDefinition doParse(Element element, ParserContext parserContext, String channelName) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SyslogReceivingChannelAdapterFactoryBean.class); + String protocol = element.getAttribute("protocol"); + if (!StringUtils.hasText(protocol)) { + protocol = SyslogReceivingChannelAdapterFactoryBean.Protocol.udp.toString(); + } + builder.addConstructorArgValue(protocol); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "port"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, + "connection-factory"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "converter"); + Element udpAdapterElement = DomUtils.getChildElementByTagName(element, "udp-attributes"); + if (udpAdapterElement != null) { + if (StringUtils.hasText(element.getAttribute("port"))) { + parserContext.getReaderContext().error( + "When child element 'udp-attributes' is present, 'port' must be defined there", element); + } + BeanDefinition udpAdapterDef = super.doParse(udpAdapterElement, parserContext, channelName); + builder.addPropertyValue("udpAdapter", udpAdapterDef); + } + builder.addPropertyReference("outputChannel", channelName); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, + element, "error-channel", "errorChannel"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "send-timeout"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-startup"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "phase"); + return builder.getBeanDefinition(); + } + +} diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogNamespaceHandler.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogNamespaceHandler.java new file mode 100644 index 0000000000..68de1ab8bb --- /dev/null +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogNamespaceHandler.java @@ -0,0 +1,33 @@ +/* + * 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.integration.syslog.config; + +import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHandler; + +/** + * Namspace handler for spring-integration-syslog. + * @author Gary Russell + * @since 3.0 + * + */ +public class SyslogNamespaceHandler extends AbstractIntegrationNamespaceHandler { + + @Override + public void init() { + this.registerBeanDefinitionParser("inbound-channel-adapter", new SyslogInboundChannelAdapterParser()); + } + +} diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterFactoryBean.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterFactoryBean.java new file mode 100644 index 0000000000..96d9ee8d8e --- /dev/null +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterFactoryBean.java @@ -0,0 +1,209 @@ +/* + * 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.integration.syslog.config; + +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.config.AbstractFactoryBean; +import org.springframework.context.SmartLifecycle; +import org.springframework.integration.MessageChannel; +import org.springframework.integration.ip.tcp.connection.AbstractServerConnectionFactory; +import org.springframework.integration.ip.udp.UnicastReceivingChannelAdapter; +import org.springframework.integration.syslog.MessageConverter; +import org.springframework.integration.syslog.inbound.SyslogReceivingChannelAdapterSupport; +import org.springframework.integration.syslog.inbound.TcpSyslogReceivingChannelAdapter; +import org.springframework.integration.syslog.inbound.UdpSyslogReceivingChannelAdapter; +import org.springframework.util.Assert; + +/** + * Factory bean to create syslog inbound adapters (UDP or TCP). + * @author Gary Russell + * @since 3.0 + * + */ +public class SyslogReceivingChannelAdapterFactoryBean extends AbstractFactoryBean + implements SmartLifecycle, BeanNameAware { + + public enum Protocol { udp, tcp }; + + private volatile SyslogReceivingChannelAdapterSupport adapter; + + private final Protocol protocol; + + private volatile MessageChannel outputChannel; + + private volatile boolean autoStartup = true; + + private volatile MessageChannel errorChannel; + + private volatile int phase; + + private volatile Long sendTimeout; + + private volatile AbstractServerConnectionFactory connectionFactory; + + private volatile UnicastReceivingChannelAdapter udpAdapter; + + private volatile Integer port; + + private volatile MessageConverter converter; + + private volatile String beanName; + + /** + * Instantiates a factory bean that creates a {@link UdpSyslogReceivingChannelAdapter} + * if the protocol is {@link Protocol#udp} or a {@link TcpSyslogReceivingChannelAdapter} if + * the protocol is {@link Protocol#tcp}. + * @param protocol The protocol. + */ + public SyslogReceivingChannelAdapterFactoryBean(Protocol protocol) { + Assert.notNull(protocol, "'protocol' cannot be null"); + this.protocol = protocol; + } + + public void setOutputChannel(MessageChannel outputChannel) { + this.outputChannel = outputChannel; + } + + public void setAutoStartup(boolean autoStartup) { + this.autoStartup = autoStartup; + } + + public void setErrorChannel(MessageChannel errorChannel) { + this.errorChannel = errorChannel; + } + + public void setPhase(int phase) { + this.phase = phase; + } + + public void setSendTimeout(long sendTimeout) { + this.sendTimeout = sendTimeout; + } + + public void setConnectionFactory(AbstractServerConnectionFactory connectionFactory) { + this.connectionFactory = connectionFactory; + } + + public void setUdpAdapter(UnicastReceivingChannelAdapter udpAdapter) { + this.udpAdapter = udpAdapter; + } + + public void setPort(int port) { + this.port = port; + } + + public void setConverter(MessageConverter converter) { + this.converter = converter; + } + + @Override + public void start() { + if (this.adapter != null) { + this.adapter.start(); + } + } + + @Override + public void stop() { + if (this.adapter != null) { + this.adapter.stop(); + } + } + + @Override + public boolean isRunning() { + if (this.adapter != null) { + return this.adapter.isRunning(); + } + return false; + } + + @Override + public int getPhase() { + return this.phase; + } + + @Override + public void setBeanName(String name) { + this.beanName = name; + } + + @Override + public boolean isAutoStartup() { + return this.autoStartup; + } + + @Override + public void stop(Runnable callback) { + if (this.adapter != null) { + this.adapter.stop(callback); + } + } + + @Override + public Class getObjectType() { + return this.adapter == null ? SyslogReceivingChannelAdapterSupport.class : + this.adapter.getClass(); + } + + @Override + protected SyslogReceivingChannelAdapterSupport createInstance() throws Exception { + SyslogReceivingChannelAdapterSupport adapter; + if (this.protocol == Protocol.tcp) { + adapter = new TcpSyslogReceivingChannelAdapter(); + if (this.connectionFactory != null) { + Assert.isNull(this.port, "Cannot specify both 'port' and 'connectionFactory'"); + ((TcpSyslogReceivingChannelAdapter) adapter).setConnectionFactory(this.connectionFactory); + } + Assert.isNull(this.udpAdapter, "Cannot specifiy 'udp-attributes' when the protocol is 'tcp'"); + } + else if(this.protocol == Protocol.udp) { + adapter = new UdpSyslogReceivingChannelAdapter(); + if (this.udpAdapter != null) { + Assert.isNull(this.port, "Cannot specify both 'port' and 'udpAdapter'"); + ((UdpSyslogReceivingChannelAdapter) adapter).setUdpAdapter(this.udpAdapter); + } + Assert.isNull(this.connectionFactory, "Cannot specifiy 'connection-factory' unless the protocol is 'tcp'"); + } + else { + throw new IllegalStateException("Unsupported protocol: " + this.protocol.toString()); + } + if (this.port != null) { + adapter.setPort(this.port); + } + if (this.outputChannel != null) { + adapter.setOutputChannel(this.outputChannel); + } + adapter.setAutoStartup(this.autoStartup); + adapter.setPhase(this.phase); + if (this.errorChannel != null) { + adapter.setErrorChannel(this.errorChannel); + } + if (this.sendTimeout != null) { + adapter.setSendTimeout(this.sendTimeout); + } + if (this.converter != null) { + adapter.setConverter(this.converter); + } + if (this.beanName != null) { + adapter.setBeanName(this.beanName); + } + adapter.afterPropertiesSet(); + this.adapter = adapter; + return adapter; + } + +} diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/package-info.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/package-info.java new file mode 100644 index 0000000000..584cdc2355 --- /dev/null +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/package-info.java @@ -0,0 +1,4 @@ +/** + * Provides classes for configuration - parsers, namespace handlers, factory beans. + */ +package org.springframework.integration.syslog.config; \ No newline at end of file diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterSupport.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterSupport.java new file mode 100644 index 0000000000..3090b944ed --- /dev/null +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterSupport.java @@ -0,0 +1,80 @@ +/* + * 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.integration.syslog.inbound; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.integration.Message; +import org.springframework.integration.MessagingException; +import org.springframework.integration.endpoint.MessageProducerSupport; +import org.springframework.integration.syslog.DefaultMessageConverter; +import org.springframework.integration.syslog.MessageConverter; + +/** + * Base support class for inbound channel adapters. The default port is 514. + * + * @author Gary Russell + * @since 3.0 + * + */ +public abstract class SyslogReceivingChannelAdapterSupport extends MessageProducerSupport { + + protected static final int DEFAULT_PORT = 514; + + private volatile int port = DEFAULT_PORT; + + protected final Log logger = LogFactory.getLog(this.getClass()); + + private volatile MessageConverter converter = new DefaultMessageConverter(); + + /** + * @return The port on which this adapter listens. + */ + protected int getPort() { + return this.port; + } + + /** + * Sets the port on which the adapter listens; default is 514; note that + * the RFC does not specify a well known port for TCP; 514 is the well-known + * port for UDP. Many admins also use 514 for TCP; see RFC-6587 for more + * information about TCP and RFC-3164/5424 for more information about UDP. + * @param port The port. + */ + public void setPort(int port) { + this.port = port; + } + + /** + * A {@link MessageConverter} to convert the byte array payload + * of the underlying UDP/TCP message to a Spring Integration message + * with decoded payload and headers; default is {@link DefaultMessageConverter}. + * @param converter The converter. + */ + public void setConverter(MessageConverter converter) { + this.converter = converter; + } + + protected void convertAndSend(Message message) { + try { + this.sendMessage(this.converter.fromSyslog(message)); + } + catch (Exception e) { + throw new MessagingException(message, e); + } + } + +} diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/TcpSyslogReceivingChannelAdapter.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/TcpSyslogReceivingChannelAdapter.java new file mode 100644 index 0000000000..11f6857f72 --- /dev/null +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/TcpSyslogReceivingChannelAdapter.java @@ -0,0 +1,72 @@ +/* + * 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.integration.syslog.inbound; + + +import org.springframework.integration.Message; +import org.springframework.integration.ip.tcp.connection.AbstractServerConnectionFactory; +import org.springframework.integration.ip.tcp.connection.TcpListener; +import org.springframework.integration.ip.tcp.connection.TcpNioServerConnectionFactory; +import org.springframework.integration.ip.tcp.serializer.ByteArrayLfSerializer; + +/** + * TCP implementation of a syslog inbound channel adapter. + * + * @author Gary Russell + * @since 3.0 + * + */ +public class TcpSyslogReceivingChannelAdapter extends SyslogReceivingChannelAdapterSupport + implements TcpListener { + + private volatile AbstractServerConnectionFactory connectionFactory; + + /** + * @param connectionFactory + */ + public void setConnectionFactory(AbstractServerConnectionFactory connectionFactory) { + this.connectionFactory = connectionFactory; + } + + @Override + protected void onInit() { + super.onInit(); + if (this.connectionFactory == null) { + this.connectionFactory = new TcpNioServerConnectionFactory(this.getPort()); + this.connectionFactory.setDeserializer(new ByteArrayLfSerializer()); + } + this.connectionFactory.registerListener(this); + } + + @Override + protected void doStart() { + super.doStart(); + this.connectionFactory.start(); + } + + @Override + protected void doStop() { + super.doStop(); + this.connectionFactory.stop(); + } + + @Override + public boolean onMessage(Message message) { + this.convertAndSend(message); + return false; + } + +} diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/UdpSyslogReceivingChannelAdapter.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/UdpSyslogReceivingChannelAdapter.java new file mode 100644 index 0000000000..528bfdcf15 --- /dev/null +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/UdpSyslogReceivingChannelAdapter.java @@ -0,0 +1,67 @@ +/* + * 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.integration.syslog.inbound; + +import org.springframework.integration.Message; +import org.springframework.integration.MessagingException; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.core.MessageHandler; +import org.springframework.integration.ip.udp.UnicastReceivingChannelAdapter; + +/** + * UDP implementation of a syslog inbound channel adapter. + * + * @author Gary Russell + * @since 3.0 + * + */ +public class UdpSyslogReceivingChannelAdapter extends SyslogReceivingChannelAdapterSupport { + + private volatile UnicastReceivingChannelAdapter udpAdapter; + + public void setUdpAdapter(UnicastReceivingChannelAdapter udpAdpter) { + this.udpAdapter = udpAdpter; + } + + @Override + protected void onInit() { + if (this.udpAdapter == null) { + this.udpAdapter = new UnicastReceivingChannelAdapter(this.getPort()); + } + DirectChannel outputChannel = new DirectChannel(); + outputChannel.subscribe(new MessageHandler() { + + @Override + public void handleMessage(Message message) throws MessagingException { + convertAndSend(message); + } + }); + this.udpAdapter.setOutputChannel(outputChannel); + } + + @Override + protected void doStart() { + super.doStart(); + this.udpAdapter.start(); + } + + @Override + protected void doStop() { + super.doStop(); + this.udpAdapter.stop(); + } + +} diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/package-info.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/package-info.java new file mode 100644 index 0000000000..c9ec2538c3 --- /dev/null +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/package-info.java @@ -0,0 +1,4 @@ +/** + * Provides classes for inbound endpoints. + */ +package org.springframework.integration.syslog.inbound; \ No newline at end of file diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/package-info.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/package-info.java new file mode 100644 index 0000000000..3a342a4f42 --- /dev/null +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/package-info.java @@ -0,0 +1,4 @@ +/** + * Base package for Syslog Support. + */ +package org.springframework.integration.syslog; \ No newline at end of file diff --git a/spring-integration-syslog/src/main/resources/META-INF/spring.handlers b/spring-integration-syslog/src/main/resources/META-INF/spring.handlers new file mode 100644 index 0000000000..f4369e2753 --- /dev/null +++ b/spring-integration-syslog/src/main/resources/META-INF/spring.handlers @@ -0,0 +1 @@ +http\://www.springframework.org/schema/integration/syslog=org.springframework.integration.syslog.config.SyslogNamespaceHandler \ No newline at end of file diff --git a/spring-integration-syslog/src/main/resources/META-INF/spring.schemas b/spring-integration-syslog/src/main/resources/META-INF/spring.schemas new file mode 100644 index 0000000000..5c1f6ae7ad --- /dev/null +++ b/spring-integration-syslog/src/main/resources/META-INF/spring.schemas @@ -0,0 +1,2 @@ +http\://www.springframework.org/schema/integration/syslog/spring-integration-syslog-3.0.xsd=org/springframework/integration/syslog/config/spring-integration-syslog-3.0.xsd +http\://www.springframework.org/schema/integration/syslog/spring-integration-syslog.xsd=org/springframework/integration/syslog/config/spring-integration-syslog-3.0.xsd \ No newline at end of file diff --git a/spring-integration-syslog/src/main/resources/META-INF/spring.tooling b/spring-integration-syslog/src/main/resources/META-INF/spring.tooling new file mode 100644 index 0000000000..d1c810dfa0 --- /dev/null +++ b/spring-integration-syslog/src/main/resources/META-INF/spring.tooling @@ -0,0 +1,4 @@ +# Tooling related information for the integration syslog namespace +http\://www.springframework.org/schema/integration/syslog@name=integration syslog Namespace +http\://www.springframework.org/schema/integration/syslog@prefix=int-syslog +http\://www.springframework.org/schema/integration/syslog@icon=org/springframework/integration/syslog/config/spring-integration-syslog.gif diff --git a/spring-integration-syslog/src/main/resources/org/springframework/integration/syslog/config/spring-integration-syslog-3.0.xsd b/spring-integration-syslog/src/main/resources/org/springframework/integration/syslog/config/spring-integration-syslog-3.0.xsd new file mode 100644 index 0000000000..27aa232183 --- /dev/null +++ b/spring-integration-syslog/src/main/resources/org/springframework/integration/syslog/config/spring-integration-syslog-3.0.xsd @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + An explicit tcp connection factory; requires protocol="tcp" and incompatible with the 'port' attribute. + Use this if you want to set advanced configuration options on the factory. The default factory uses + NIO. + + + + + + + + + + + + + + + + + + + + + If a (synchronous) downstream exception is thrown and an "error-channel" is specified, + the MessagingException will be sent to this channel. Otherwise, any such exception + will simply be logged by the channel adapter. + + + + + + + The protocol used to listen for syslog packets, 'udp' or 'tcp'. Default + is 'udp'. + + + + + + + The port on which this adapter listens for syslog packets. Default is 514. This is + standard for UDP, but no standard is esablished for TCP - in many cases 514 is + used for TCP, but 514 is actually allocated to another protocol. + + + + + + + + + + + + A converter used to map the UDP/TCP message to a Spring Integration message. + Default is DefaultSyslogMessageConverter. + + + + + + + A timeout (milliseconds) when sending messages to 'channel' or 'error-channel'. Only + applies if the send might block - such as when sending to a bounded QueueChannel that + is currently full. Default is infinity. + + + + + + + + + diff --git a/spring-integration-syslog/src/main/resources/org/springframework/integration/syslog/config/spring-integration-syslog.gif b/spring-integration-syslog/src/main/resources/org/springframework/integration/syslog/config/spring-integration-syslog.gif new file mode 100644 index 0000000000000000000000000000000000000000..a8766bc9bb859e079e161431bf7f1c99ec26d1a4 GIT binary patch literal 512 zcmZ?wbhEHb6krfwIL62T1poj4@0hx7?utFT4_`dAqx0yl&Xc>l&+P5Kais6!{+^fD z7VKLXcJoNzgL8{s-`oFuz3!)d?(YsIy}3B$?eXg6ZQjc}16K6}KiFJ6A=|Py)1o!O zs4>>CC(XPvRQuF|f?QA4LSOYlU(F|r6YnibO>tBx@Kozdvba7Y;pUu_nT0-Ct{M{) zY^EgJ<#_5{ofNybD|uaG{PC8M(g5?httFdhcO7jA&2v!i2(vs=8$3VFbz5n`v4)79 zwJ}+C>RU^KH0`_S=*fu`(xWd1~172%niTfzv{QrUeE7y*9{!;!hS}B-AtL zfMNm^Ck*Vd4fRdUEv;?s9ra>T(xRPBx+>ffmP(!C+*&U38rBLOlFE#Wmn?0ObzZuP zv4zKjkzwP8jSOpA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail1-context.xml b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail1-context.xml new file mode 100644 index 0000000000..9a5360f634 --- /dev/null +++ b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail1-context.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + diff --git a/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail2-context.xml b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail2-context.xml new file mode 100644 index 0000000000..c6afecb3cb --- /dev/null +++ b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail2-context.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + diff --git a/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail3-context.xml b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail3-context.xml new file mode 100644 index 0000000000..ad8a5b286f --- /dev/null +++ b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail3-context.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + diff --git a/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail4-context.xml b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail4-context.xml new file mode 100644 index 0000000000..65f7c9114e --- /dev/null +++ b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests-fail4-context.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + diff --git a/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests.java b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests.java new file mode 100644 index 0000000000..9b220681c4 --- /dev/null +++ b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterParserTests.java @@ -0,0 +1,208 @@ +/* + * 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.integration.syslog.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; +import java.net.Socket; + +import javax.net.SocketFactory; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.integration.Message; +import org.springframework.integration.core.PollableChannel; +import org.springframework.integration.ip.tcp.connection.AbstractServerConnectionFactory; +import org.springframework.integration.syslog.MessageConverter; +import org.springframework.integration.syslog.inbound.TcpSyslogReceivingChannelAdapter; +import org.springframework.integration.syslog.inbound.UdpSyslogReceivingChannelAdapter; +import org.springframework.integration.test.util.TestUtils; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Gary Russell + * @since 3.0 + * + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class SyslogReceivingChannelAdapterParserTests { + + @Autowired @Qualifier("foo.adapter") + private UdpSyslogReceivingChannelAdapter adapter1; + + @Autowired + private UdpSyslogReceivingChannelAdapter foobar; + + @Autowired + private PollableChannel foo; + + @Autowired @Qualifier("explicitUdp.adapter") + private UdpSyslogReceivingChannelAdapter explicitUdpAdapter; + + @Autowired + private PollableChannel explicitUdp; + + @Autowired + private PollableChannel errors; + + @Autowired + private UdpSyslogReceivingChannelAdapter fullBoatUdp; + + @Autowired + private PassThruConverter converter; + + @Autowired @Qualifier("bar.adapter") + private TcpSyslogReceivingChannelAdapter adapter2; + + @Autowired + private PollableChannel bar; + + @Autowired + private TcpSyslogReceivingChannelAdapter fullBoatTcp; + + @Autowired + private AbstractServerConnectionFactory cf; + + @Test + public void testSimplestUdp() throws Exception { + int port = TestUtils.getPropertyValue(adapter1, "udpAdapter.port", Integer.class); + byte[] buf = "<157>JUL 26 22:08:35 WEBERN TESTING[70729]: TEST SYSLOG MESSAGE".getBytes("UTF-8"); + DatagramPacket packet = new DatagramPacket(buf, buf.length, new InetSocketAddress("localhost", port)); + DatagramSocket socket = new DatagramSocket(); + Thread.sleep(1000); + socket.send(packet); + socket.close(); + Message message = foo.receive(10000); + assertNotNull(message); + adapter1.stop(); + } + + @Test + public void testExplicitChannelUdp() throws Exception { + assertEquals(1514, TestUtils.getPropertyValue(foobar, "udpAdapter.port")); + assertSame(foo, TestUtils.getPropertyValue(foobar, "outputChannel")); + } + + @Test + public void testExplicitUdp() throws Exception { + assertSame(explicitUdp, TestUtils.getPropertyValue(explicitUdpAdapter, "outputChannel")); + } + + @Test + public void testFullBoatUdp() { + assertSame(foo, TestUtils.getPropertyValue(fullBoatUdp, "outputChannel")); + assertFalse(fullBoatUdp.isAutoStartup()); + assertEquals(123, fullBoatUdp.getPhase()); + assertEquals(456L, TestUtils.getPropertyValue(fullBoatUdp, "messagingTemplate.sendTimeout")); + assertSame(converter, TestUtils.getPropertyValue(fullBoatUdp, "converter")); + assertSame(errors, TestUtils.getPropertyValue(fullBoatUdp, "errorChannel")); + assertFalse(TestUtils.getPropertyValue(fullBoatUdp, "udpAdapter.mapper.lookupHost", Boolean.class)); + } + + @Test + public void testSimplestTcp() throws Exception { + byte[] buf = "<157>JUL 26 22:08:35 WEBERN TESTING[70729]: TEST SYSLOG MESSAGE\n".getBytes("UTF-8"); + Socket socket = SocketFactory.getDefault().createSocket("localhost", 1514); + Thread.sleep(1000); + socket.getOutputStream().write(buf); + socket.close(); + Message message = bar.receive(10000); + assertNotNull(message); + adapter2.stop(); + } + + @Test + public void testFullBoatTcp() { + assertSame(bar, TestUtils.getPropertyValue(fullBoatTcp, "outputChannel")); + assertFalse(fullBoatTcp.isAutoStartup()); + assertEquals(123, fullBoatTcp.getPhase()); + assertEquals(456L, TestUtils.getPropertyValue(fullBoatUdp, "messagingTemplate.sendTimeout")); + assertSame(converter, TestUtils.getPropertyValue(fullBoatTcp, "converter")); + assertSame(errors, TestUtils.getPropertyValue(fullBoatTcp, "errorChannel")); + assertSame(cf, TestUtils.getPropertyValue(fullBoatTcp, "connectionFactory")); + } + + @Test + public void testPortOnUdpChild() { + try { + new ClassPathXmlApplicationContext(this.getClass().getSimpleName() + "-fail1-context.xml", this.getClass()); + fail("Expected exception"); + } + catch (BeanDefinitionParsingException e) { + assertTrue(e.getMessage().startsWith( + "Configuration problem: When child element 'udp-attributes' is present, 'port' must be defined there")); + } + } + + @Test + public void testPortWithTCPFactory() { + try { + new ClassPathXmlApplicationContext(this.getClass().getSimpleName() + "-fail2-context.xml", this.getClass()); + fail("Expected exception"); + } + catch (BeanCreationException e) { + assertEquals("Cannot specify both 'port' and 'connectionFactory'", e.getCause().getMessage()); + } + } + + @Test + public void testUdpChildWithTcp() { + try { + new ClassPathXmlApplicationContext(this.getClass().getSimpleName() + "-fail3-context.xml", this.getClass()); + fail("Expected exception"); + } + catch (BeanCreationException e) { + e.printStackTrace(); + + assertEquals("Cannot specifiy 'udp-attributes' when the protocol is 'tcp'", e.getCause().getMessage()); + } + } + + @Test + public void testUDPWithTCPFactory() { + try { + new ClassPathXmlApplicationContext(this.getClass().getSimpleName() + "-fail4-context.xml", this.getClass()); + fail("Expected exception"); + } + catch (BeanCreationException e) { + assertEquals("Cannot specifiy 'connection-factory' unless the protocol is 'tcp'", e.getCause().getMessage()); + } + } + + public static class PassThruConverter implements MessageConverter { + + @Override + public Message fromSyslog(Message syslog) throws Exception { + return syslog; + } + + } +} diff --git a/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterTests.java b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterTests.java new file mode 100644 index 0000000000..e4add28295 --- /dev/null +++ b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterTests.java @@ -0,0 +1,82 @@ +/* + * 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.integration.syslog.inbound; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; +import java.net.Socket; + +import javax.net.SocketFactory; + +import org.junit.Test; +import org.springframework.integration.Message; +import org.springframework.integration.channel.QueueChannel; +import org.springframework.integration.core.PollableChannel; +import org.springframework.integration.syslog.config.SyslogReceivingChannelAdapterFactoryBean; + +/** + * @author Gary Russell + * @since 3.0 + * + */ +public class SyslogReceivingChannelAdapterTests { + + @Test + public void testUdp() throws Exception { + SyslogReceivingChannelAdapterFactoryBean factory = new SyslogReceivingChannelAdapterFactoryBean( + SyslogReceivingChannelAdapterFactoryBean.Protocol.udp); + factory.setPort(1514); + PollableChannel outputChannel = new QueueChannel(); + factory.setOutputChannel(outputChannel); + factory.afterPropertiesSet(); + factory.start(); + UdpSyslogReceivingChannelAdapter adapter = (UdpSyslogReceivingChannelAdapter) factory.getObject(); + Thread.sleep(1000); + byte[] buf = "<157>JUL 26 22:08:35 WEBERN TESTING[70729]: TEST SYSLOG MESSAGE".getBytes("UTF-8"); + DatagramPacket packet = new DatagramPacket(buf, buf.length, new InetSocketAddress("localhost", 1514)); + DatagramSocket socket = new DatagramSocket(); + socket.send(packet); + socket.close(); + Message message = outputChannel.receive(10000); + assertNotNull(message); + assertEquals("WEBERN", message.getHeaders().get("syslog_HOST")); + } + + @Test + public void testTcp() throws Exception { + SyslogReceivingChannelAdapterFactoryBean factory = new SyslogReceivingChannelAdapterFactoryBean( + SyslogReceivingChannelAdapterFactoryBean.Protocol.tcp); + factory.setPort(1514); + PollableChannel outputChannel = new QueueChannel(); + factory.setOutputChannel(outputChannel); + factory.afterPropertiesSet(); + factory.start(); + TcpSyslogReceivingChannelAdapter adapter = (TcpSyslogReceivingChannelAdapter) factory.getObject(); + Thread.sleep(1000); + byte[] buf = "<157>JUL 26 22:08:35 WEBERN TESTING[70729]: TEST SYSLOG MESSAGE\n".getBytes("UTF-8"); + Socket socket = SocketFactory.getDefault().createSocket("localhost", 1514); + socket.getOutputStream().write(buf); + socket.close(); + Message message = outputChannel.receive(10000); + assertNotNull(message); + assertEquals("WEBERN", message.getHeaders().get("syslog_HOST")); + } + +} diff --git a/src/reference/docbook/index.xml b/src/reference/docbook/index.xml index ebfbc8f431..1fb64c584f 100644 --- a/src/reference/docbook/index.xml +++ b/src/reference/docbook/index.xml @@ -150,6 +150,7 @@ + diff --git a/src/reference/docbook/syslog.xml b/src/reference/docbook/syslog.xml new file mode 100644 index 0000000000..3d3b83e9d4 --- /dev/null +++ b/src/reference/docbook/syslog.xml @@ -0,0 +1,92 @@ + + + Syslog Support + +
+ Introduction + + Spring Integration 2.2 introduced the Syslog transformer + SyslogToMapTransformer. This transformer, together with + a UDP or TCP inbound adapter could be used to receive + and analyze syslog records from other hosts. The transformer creates a message + payload containing a map of the elements from the syslog message. + + + Spring Integration 3.0 introduced convenient namespace support for configuring a + Syslog inbound adapter in a single element. + +
+ +
+ Syslog <inbound-channel-adapter> + + This element encompases a UDP or TCP inbound channel adapter + and a MessageConverter to convert the Syslog message to + a Spring Integration message. The DefaultMessageConverter delegates + to the SyslogToMapTransformer, creating a message with its payload + being the Map of Syslog fields. In addition, all fields except the message + are also made available as headers in the message, prefixed with syslog_. + +
+ Example Configuration + ]]> + + A UDP adapter that sends messages to channel syslogIn (the adapter bean + name is syslogIn.adapter). The adapter listens on port 1514. + + ]]> + + A UDP adapter that sends message to channel fromSyslog (the adapter bean + name is syslogIn). The adapter listens on port 1514. + + ]]> + + A TCP adapter that sends messages to channel syslogIn (the adapter bean + name is syslogIn.adapter). The adapter listens on port 1514. + + + Note the addition of the protocol attribute. This attribute can contain udp + or tcp; it defaults to udp. + + + +]]> + + A UDP adapter that sends messages to channel fromSyslog. It also shows the + SmartLifecyle attributes auto-startup and + phase. It has a reference to a custom + org.springframework.integration.syslog.MessageConverter + with id converter and an error-channel. Also notice the + udp-attributes child element. You can set various UDP attributes here, as defined + in . + + + When using the udp-attributes element, the port attribute must be + provided there rather than on the inbound-channel-adapter element itself. + + + +]]> + + A TCP adapter that sends messages to channel fromSyslog. It also shows + how to reference an externally defined connection factory, which can be used for advanced + configuration (socket keep alive etc). For more information, see . + + + The externally configured connection-factory must be of type server and, + the port is defined there rather than on the inbound-channel-adapter element itself. + +
+
+
diff --git a/src/reference/docbook/whats-new.xml b/src/reference/docbook/whats-new.xml index 1e11b53c88..211d82d9c4 100644 --- a/src/reference/docbook/whats-new.xml +++ b/src/reference/docbook/whats-new.xml @@ -50,6 +50,16 @@ For more information see . +
+ Syslog Support + + Building on the 2.2 SyslogToMapTransformer Spring + Integration 3.0 now introduces + UDP and TCP inbound channel adapters especially tailored + for receiving SYSLOG messages. For more information, see + . + +