INTEXT-21 Add Splunk adapter

For reference see: https://jira.springsource.org/browse/INTEXT-21
This commit is contained in:
Jarred Li
2012-09-26 13:48:14 +08:00
committed by Gunnar Hillert
parent 68d0ee607b
commit deb09cdf9c
72 changed files with 7331 additions and 0 deletions

View File

@@ -0,0 +1,103 @@
/*
* Copyright 2002-2012 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.splunk.config.xml;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.splunk.inbound.SplunkPollingChannelAdapter;
import org.springframework.integration.splunk.support.ConnectionFactoryFactoryBean;
import org.springframework.integration.splunk.support.SplunkConnectionFactory;
import org.springframework.integration.splunk.support.SplunkDataReader;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* The Splunk Inbound Channel adapter parser
*
* @author Jarred Li
* @since 1.0
*
*/
public class SplunkInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser {
protected BeanMetadataElement parseSource(Element element, ParserContext parserContext) {
BeanDefinitionBuilder splunkPollingChannelAdapterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkPollingChannelAdapter.class);
BeanDefinitionBuilder splunkExecutorBuilder = SplunkParserUtils.getSplunkExecutorBuilder(element, parserContext);
BeanDefinitionBuilder splunkDataReaderBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkDataReader.class);
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataReaderBuilder, element, "mode");
String count = element.getAttribute("count");
if (StringUtils.hasText(count)) {
splunkDataReaderBuilder.addPropertyValue("count", count);
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataReaderBuilder, element, "fieldList");
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataReaderBuilder, element, "search");
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataReaderBuilder, element, "savedSearch");
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataReaderBuilder, element, "owner");
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataReaderBuilder, element, "app");
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataReaderBuilder, element, "initEarliestTime");
String earliestTime = element.getAttribute("earliestTime");
if (StringUtils.hasText(earliestTime)) {
splunkDataReaderBuilder.addPropertyValue("earliestTime", earliestTime);
}
String latestTime = element.getAttribute("latestTime");
if (StringUtils.hasText(latestTime)) {
splunkDataReaderBuilder.addPropertyValue("latestTime", latestTime);
}
BeanDefinitionBuilder connectionFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkConnectionFactory.class);
String splunkServerBeanName = element.getAttribute("splunk-server-ref");
if (StringUtils.hasText(splunkServerBeanName)) {
connectionFactoryBuilder.addConstructorArgReference(splunkServerBeanName);
}
BeanDefinitionBuilder connectionFactoryFactoryBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(ConnectionFactoryFactoryBean.class);
connectionFactoryFactoryBeanBuilder.addConstructorArgValue(connectionFactoryBuilder.getBeanDefinition());
connectionFactoryFactoryBeanBuilder.addConstructorArgValue(element.getAttribute("pool-server-connection"));
splunkDataReaderBuilder.addConstructorArgValue(connectionFactoryFactoryBeanBuilder.getBeanDefinition());
String channelAdapterId = this.resolveId(element, splunkPollingChannelAdapterBuilder.getRawBeanDefinition(),
parserContext);
String splunkExecutorBeanName = channelAdapterId + ".splunkExecutor";
String splunkDataReaderBeanName = splunkExecutorBeanName + ".reader";
parserContext.registerBeanComponent(new BeanComponentDefinition(splunkDataReaderBuilder.getBeanDefinition(),
splunkDataReaderBeanName));
splunkExecutorBuilder.addPropertyReference("reader", splunkDataReaderBeanName);
BeanDefinition splunkExecutorBuilderBeanDefinition = splunkExecutorBuilder.getBeanDefinition();
parserContext.registerBeanComponent(new BeanComponentDefinition(splunkExecutorBuilderBeanDefinition,
splunkExecutorBeanName));
splunkPollingChannelAdapterBuilder.addConstructorArgReference(splunkExecutorBeanName);
return splunkPollingChannelAdapterBuilder.getBeanDefinition();
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2012 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.splunk.config.xml;
import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHandler;
/**
* The namespace handler for the Splunk namespace
*
* @author Jarred Li
* @since 1.0
*
*/
public class SplunkNamespaceHandler extends AbstractIntegrationNamespaceHandler {
/* (non-Javadoc)
* @see org.springframework.beans.factory.xml.NamespaceHandler#init()
*/
public void init() {
registerBeanDefinitionParser("server", new SplunkServerParser());
this.registerBeanDefinitionParser("inbound-channel-adapter", new SplunkInboundChannelAdapterParser());
this.registerBeanDefinitionParser("outbound-channel-adapter", new SplunkOutboundChannelAdapterParser());
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright 2002-2012 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.splunk.config.xml;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
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.AbstractOutboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.splunk.outbound.SplunkOutboundChannelAdapter;
import org.springframework.integration.splunk.support.ConnectionFactoryFactoryBean;
import org.springframework.integration.splunk.support.SplunkDataWriter;
import org.springframework.integration.splunk.support.SplunkConnectionFactory;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* The parser for the Splunk Outbound Channel Adapter.
*
* @author Jarred Li
* @since 1.0
*
*/
public class SplunkOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
@Override
protected boolean shouldGenerateId() {
return false;
}
@Override
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
BeanDefinitionBuilder splunkOutboundChannelAdapterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkOutboundChannelAdapter.class);
BeanDefinitionBuilder splunkExecutorBuilder = SplunkParserUtils.getSplunkExecutorBuilder(element, parserContext);
BeanDefinitionBuilder splunkDataWriterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkDataWriter.class);
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataWriterBuilder, element, "sourceType");
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataWriterBuilder, element, "source");
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataWriterBuilder, element, "index");
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataWriterBuilder, element, "ingest");
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataWriterBuilder, element, "tcpPort");
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataWriterBuilder, element, "host");
IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataWriterBuilder, element, "hostRegex");
BeanDefinitionBuilder connectionFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkConnectionFactory.class);
String splunkServerBeanName = element.getAttribute("splunk-server-ref");
if (StringUtils.hasText(splunkServerBeanName)) {
connectionFactoryBuilder.addConstructorArgReference(splunkServerBeanName);
}
BeanDefinitionBuilder connectionFactoryFactoryBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(ConnectionFactoryFactoryBean.class);
connectionFactoryFactoryBeanBuilder.addConstructorArgValue(connectionFactoryBuilder.getBeanDefinition());
connectionFactoryFactoryBeanBuilder.addConstructorArgValue(element.getAttribute("pool-server-connection"));
splunkDataWriterBuilder.addConstructorArgValue(connectionFactoryFactoryBeanBuilder.getBeanDefinition());
String channelAdapterId = this.resolveId(element, splunkOutboundChannelAdapterBuilder.getRawBeanDefinition(),
parserContext);
String splunkExecutorBeanName = channelAdapterId + ".splunkExecutor";
String splunkDataWriterBeanName = splunkExecutorBeanName + ".writer";
parserContext.registerBeanComponent(new BeanComponentDefinition(splunkDataWriterBuilder.getBeanDefinition(),
splunkDataWriterBeanName));
splunkExecutorBuilder.addPropertyReference("writer", splunkDataWriterBeanName);
BeanDefinition splunkExecutorBuilderBeanDefinition = splunkExecutorBuilder.getBeanDefinition();
parserContext.registerBeanComponent(new BeanComponentDefinition(splunkExecutorBuilderBeanDefinition,
splunkExecutorBeanName));
splunkOutboundChannelAdapterBuilder.addConstructorArgReference(splunkExecutorBeanName);
splunkOutboundChannelAdapterBuilder.addPropertyValue("producesReply", Boolean.FALSE);
return splunkOutboundChannelAdapterBuilder.getBeanDefinition();
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2002-2012 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.splunk.config.xml;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.splunk.support.SplunkExecutor;
import org.springframework.util.Assert;
import org.w3c.dom.Element;
/**
* Contains various utility methods for parsing Splunk Adapter
* specific namesspace elements as well as for the generation of the
* respective {@link BeanDefinition}s.
*
* @author Jarred Li
* @since 1.0
*
*/
public final class SplunkParserUtils {
/** Prevent instantiation. */
private SplunkParserUtils() {
throw new AssertionError();
}
/**
* Create a new {@link BeanDefinitionBuilder} for the class {@link SplunkExecutor}.
* Initialize the wrapped {@link SplunkExecutor} with common properties.
*
* @param element Must not be null
* @param parserContext Must not be null
* @return The BeanDefinitionBuilder for the SplunkExecutor
*/
public static BeanDefinitionBuilder getSplunkExecutorBuilder(final Element element, final ParserContext parserContext) {
Assert.notNull(element, "The provided element must not be null.");
Assert.notNull(parserContext, "The provided parserContext must not be null.");
final BeanDefinitionBuilder splunkExecutorBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkExecutor.class);
return splunkExecutorBuilder;
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2011-2012 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.splunk.config.xml;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.splunk.entity.SplunkServer;
import org.w3c.dom.Element;
/**
* Splunk server element parser.
*
* The XML element is like this:
* <pre>
* {@code
* <splunk:server id="splunkServer" host="host" port="8089" userName="admin" password="password"
* scheme="https" owner="admin" app="search"/>
* }
*
* @author Jarred Li
* @since 1.0
*
*/
public class SplunkServerParser extends AbstractSimpleBeanDefinitionParser {
@Override
public Class<?> getBeanClass(Element element) {
return SplunkServer.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, parserContext, builder);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
BeanDefinitionParserDelegate.SCOPE_ATTRIBUTE);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "host");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "port");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "scheme");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "app");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "owner");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "userName");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "password");
}
}

View File

@@ -0,0 +1,4 @@
/**
* Provides parser classes to provide Xml namespace support for the Splunk components.
*/
package org.springframework.integration.splunk.config.xml;

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2011-2012 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.splunk.core;
/**
* Connection to Splunk service
*
* @author Jarred Li
* @since 1.0
*
*/
public interface Connection<T> {
T getTarget();
void close();
boolean isOpen();
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2011-2012 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.splunk.core;
/**
* Factory pattern to create <code>Connection</code>
*
* @author Jarred Li
* @since 1.0
*
*/
public interface ConnectionFactory<T> {
Connection<T> getConnection() throws Exception;
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2011-2012 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.splunk.core;
import java.util.List;
import org.springframework.integration.splunk.entity.SplunkData;
/**
* Data reader to read Splunk data from the service.
*
* @author Jarred Li
* @since 1.0
*/
public interface DataReader {
List<SplunkData> search() throws Exception;
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2011-2012 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.splunk.core;
import org.springframework.integration.splunk.entity.SplunkData;
/**
* Data writer to write Splunk data into Splunk
*
* @author Jarred Li
* @since 1.0
*
*/
public interface DataWriter {
void write(SplunkData data) throws Exception;
}

View File

@@ -0,0 +1,4 @@
/**
* Provides core classes of the Splunk module.
*/
package org.springframework.integration.splunk.core;

View File

@@ -0,0 +1,117 @@
/*
* Copyright 2011-2012 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.splunk.entity;
/**
* Splunk server entity
*
* @author Jarred Li
* @since 1.0
*
*/
public class SplunkServer {
private String host;
private int port;
private String scheme;
private String app;
private String owner;
private String userName;
private String password;
/**
* @return the host
*/
public String getHost() {
return host;
}
/**
* @param host the host to set
*/
public void setHost(String host) {
this.host = host;
}
/**
* @return the port
*/
public int getPort() {
return port;
}
/**
* @param port the port to set
*/
public void setPort(int port) {
this.port = port;
}
public String getScheme() {
return scheme;
}
public void setScheme(String scheme) {
this.scheme = scheme;
}
public String getApp() {
return app;
}
public void setApp(String app) {
this.app = app;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
/**
* @return the userName
*/
public String getUserName() {
return userName;
}
/**
* @param userName the userName to set
*/
public void setUserName(String userName) {
this.userName = userName;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2002-2012 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.splunk.inbound;
import java.util.List;
import org.springframework.integration.Message;
import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.splunk.entity.SplunkData;
import org.springframework.integration.splunk.support.SplunkExecutor;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
/**
* Polling data from Splunk to generate <code>Message</code>
*
* @author Jarred Li
* @since 1.0
*
*/
public class SplunkPollingChannelAdapter extends IntegrationObjectSupport implements MessageSource<List<SplunkData>> {
private final SplunkExecutor splunkExecutor;
/**
* Constructor taking a {@link SplunkExecutor} that provide all required Splunk
* functionality.
*
* @param splunkExecutor Must not be null.
*/
public SplunkPollingChannelAdapter(SplunkExecutor splunkExecutor) {
super();
Assert.notNull(splunkExecutor, "splunkExecutor must not be null.");
this.splunkExecutor = splunkExecutor;
}
/**
* Check for mandatory attributes
*/
@Override
protected void onInit() throws Exception {
super.onInit();
}
/**
* Uses {@link SplunkExecutor#poll()} to executes the Splunk operation.
*
* If {@link SplunkExecutor#poll()} returns null, this method will return
* <code>null</code>. Otherwise, a new {@link Message} is constructed and returned.
*/
public Message<List<SplunkData>> receive() {
List<SplunkData> payload = splunkExecutor.poll();
if (payload == null) {
return null;
}
return MessageBuilder.withPayload(payload).build();
}
@Override
public String getComponentType() {
return "splunk:inbound-channel-adapter";
}
}

View File

@@ -0,0 +1,4 @@
/**
* Provides inbound Spring Integration Splunk components.
*/
package org.springframework.integration.splunk.inbound;

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2002-2012 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.splunk.outbound;
import org.springframework.integration.Message;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.splunk.support.SplunkExecutor;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
/**
* Handle message and write data into Splunk
*
* @author Jarred Li
* @since 1.0
*
*/
public class SplunkOutboundChannelAdapter extends AbstractReplyProducingMessageHandler {
private final SplunkExecutor splunkExecutor;
private boolean producesReply = true; //false for outbound-channel-adapter, true for outbound-gateway
/**
* Constructor taking an {@link SplunkExecutor} that wraps common
* Splunk Operations.
*
* @param splunkExecutor Must not be null
*
*/
public SplunkOutboundChannelAdapter(SplunkExecutor splunkExecutor) {
Assert.notNull(splunkExecutor, "splunkExecutor must not be null.");
this.splunkExecutor = splunkExecutor;
}
/**
*
*/
@Override
protected void onInit() {
super.onInit();
}
@Override
protected Object handleRequestMessage(Message<?> requestMessage) {
final Object result;
result = this.splunkExecutor.executeOutboundOperation(requestMessage);
if (result == null || !producesReply) {
return null;
}
return MessageBuilder.withPayload(result).copyHeaders(requestMessage.getHeaders()).build();
}
/**
* If set to 'false', this component will act as an Outbound Channel Adapter.
* If not explicitly set this property will default to 'true'.
*
* @param producesReply Defaults to 'true'.
*
*/
public void setProducesReply(boolean producesReply) {
this.producesReply = producesReply;
}
}

View File

@@ -0,0 +1,4 @@
/**
* Provides Spring Integration components for doing outbound operations.
*/
package org.springframework.integration.splunk.outbound;

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2011-2012 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.splunk.support;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.integration.splunk.core.ConnectionFactory;
/**
* Factory bean to create <code>ConnectionFactory</code>.
*
* @author Jarred Li
* @since 1.0
*
*/
public class ConnectionFactoryFactoryBean<T> implements FactoryBean<ConnectionFactory<T>> {
private final ConnectionFactory<T> connectionFactory;
public ConnectionFactoryFactoryBean(ConnectionFactory<T> cf, boolean usePool) {
if (usePool) {
this.connectionFactory = new PoolingConnectionFactory<T>(cf);
}
else {
this.connectionFactory = cf;
}
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
public ConnectionFactory<T> getObject() throws Exception {
return this.connectionFactory;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
public Class<?> getObjectType() {
return connectionFactory.getClass();
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
*/
public boolean isSingleton() {
return true;
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2011-2012 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.splunk.support;
/**
* Method of pushing data into Splunk.
*
* Stream: Establish a connection, keep it open, and stream events until the connection is closed.Better for high volume input.
* Tcp: Create raw socket and send event data into the socket
* Submit: Send event data into Splunk with HTTP REST api
*
* @author Jarred Li
* @since 1.0
*
*/
public enum IngestType {
stream("stream"), tcp("tcp"), submit("submit");
private String type;
IngestType(String ingestType) {
this.type = ingestType;
}
public String getIngestType() {
return type;
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright 2011-2012 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.splunk.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.integration.splunk.core.Connection;
import org.springframework.integration.splunk.core.ConnectionFactory;
/**
* Pooling ConnectionFactory to pool <code>Connection</code> with Apache Commons Pool.
*
* @author Jarred Li
* @since 1.0
*
*/
public class PoolingConnectionFactory<T> implements ConnectionFactory<T>, DisposableBean {
private final Log log = LogFactory.getLog(this.getClass());
private final ConnectionFactory<T> connectionFactory;
private ObjectPool<Connection<T>> pool;
public PoolingConnectionFactory(ConnectionFactory<T> f) {
this.connectionFactory = f;
this.pool = new GenericObjectPool<Connection<T>>(new ConnectionPoolableObjectFactory());
}
/* (non-Javadoc)
* @see org.springframework.integration.splunk.core.ServiceFactory#getService()
*/
public Connection<T> getConnection() throws Exception {
return new PooledConnection(this.pool.borrowObject());
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
public void destroy() throws Exception {
pool.clear();
pool.close();
}
class ConnectionPoolableObjectFactory extends BasePoolableObjectFactory<Connection<T>> {
/* (non-Javadoc)
* @see org.apache.commons.pool.BasePoolableObjectFactory#makeObject()
*/
@Override
public Connection<T> makeObject() throws Exception {
return connectionFactory.getConnection();
}
@Override
public void destroyObject(Connection<T> obj) throws Exception {
obj.close();
}
/**
* Whether the object is valid or not.
*
* @param obj object to be validated
* @return <tt>true</tt>
*/
public boolean validateObject(Connection<T> obj) {
return obj.isOpen();
}
/**
* activate the object
*
* @param obj ignored
*/
public void activateObject(Connection<T> obj) throws Exception {
obj.isOpen();
}
}
class PooledConnection implements Connection<T> {
private Connection<T> connection;
public PooledConnection(Connection<T> con) {
this.connection = con;
}
/* (non-Javadoc)l
* @see org.springframework.integration.splunk.core.IService#close()
*/
public void close() {
try {
pool.returnObject(connection);
} catch (Exception e) {
log.warn("failed to return pooled object", e);
}
}
/* (non-Javadoc)
* @see org.springframework.integration.splunk.core.IService#isOpen()
*/
public boolean isOpen() {
return connection.isOpen();
}
/* (non-Javadoc)
* @see org.springframework.integration.splunk.core.IService#getService()
*/
public T getTarget() {
return connection.getTarget();
}
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2011-2012 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.splunk.support;
/**
* Search mode supported by Splunk.
*
* Blocking: Run synchronous search API
* Normal: Run asynchronous search API
* Realtime: Run the searches which are over a defined real time window
* Export: Run synchronously in your code , best way for bulk exports of events from Splunk
* Saved: Run predefined searches/parameters that are saved in Splunk in a namespace and you can execute them by name
*
* @author Jarred Li
* @since 1.0
*
*/
public enum SearchMode {
blocking, normal, realtime, export, saved;
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright 2011-2012 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.splunk.support;
import java.util.HashMap;
import java.util.Map;
import org.springframework.integration.splunk.core.Connection;
import org.springframework.integration.splunk.entity.SplunkServer;
import com.splunk.Service;
/**
* Connection to Splunk service
*
* @author Jarred Li
* @since 1.0
*
*/
public class SplunkConnection implements Connection<Service> {
private Service service;
public SplunkConnection(SplunkServer splunkServer) {
Map<String, Object> args = new HashMap<String, Object>();
if (splunkServer.getHost() != null) {
args.put("host", splunkServer.getHost());
}
if (splunkServer.getPort() != 0) {
args.put("port", splunkServer.getPort());
}
if (splunkServer.getScheme() != null) {
args.put("scheme", splunkServer.getScheme());
}
if (splunkServer.getApp() != null) {
args.put("app", splunkServer.getApp());
}
if (splunkServer.getOwner() != null) {
args.put("owner", splunkServer.getOwner());
}
args.put("username", splunkServer.getUserName());
args.put("password", splunkServer.getPassword());
service = Service.connect(args);
}
/* (non-Javadoc)
* @see org.springframework.integration.splunk.core.IService#close()
*/
public void close() {
service.logout();
}
/* (non-Javadoc)
* @see org.springframework.integration.splunk.core.IService#isOpen()
*/
public boolean isOpen() {
boolean result = true;
try {
service.getApplications();
} catch (Throwable t) {
result = false;
}
return result;
}
/* (non-Javadoc)
* @see org.springframework.integration.splunk.core.IService#getService()
*/
public Service getTarget() {
return service;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2011-2012 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.splunk.support;
import org.springframework.integration.splunk.core.Connection;
import org.springframework.integration.splunk.core.ConnectionFactory;
import org.springframework.integration.splunk.entity.SplunkServer;
import com.splunk.Service;
/**
* Factory to create Splunk connection.
*
* @author Jarred Li
* @since 1.0
*
*/
public class SplunkConnectionFactory implements ConnectionFactory<Service> {
private SplunkServer splunkServer;
public SplunkConnectionFactory(SplunkServer server) {
this.splunkServer = server;
}
/* (non-Javadoc)
* @see org.springframework.integration.splunk.core.ServiceFactory#getService()
*/
public Connection<Service> getConnection() throws Exception {
return new SplunkConnection(splunkServer);
}
}

View File

@@ -0,0 +1,470 @@
/*
* Copyright 2011-2012 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.splunk.support;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.splunk.core.Connection;
import org.springframework.integration.splunk.core.ConnectionFactory;
import org.springframework.integration.splunk.core.DataReader;
import org.springframework.integration.splunk.entity.SplunkData;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.splunk.Args;
import com.splunk.Job;
import com.splunk.ResultsReader;
import com.splunk.ResultsReaderXml;
import com.splunk.SavedSearch;
import com.splunk.SavedSearchCollection;
import com.splunk.Service;
/**
* Data reader to search data from Splunk.
*
* There are 5 ways to search data provided by Splunk SDK: saved search, blocking search,
* non blocking search, realtime search, export search.
*
* Splunk search also supports time range search with earliestTime and latestTime.
* For the first time start, initEarliestTime is used as earliestTime.
* If user does not specify earliestTime and latestTime, latestTime is "now"
* earliestTime is the time that last polling is run.
*
* @author Jarred Li
* @since 1.0
*
*/
public class SplunkDataReader implements DataReader, InitializingBean {
private static final String DATE_FORMAT = "MM/dd/yy HH:mm:ss:SSS";
private static final String SPLUNK_TIME_FORMAT = "%m/%d/%y %H:%M:%S:%3N";
private static final Log logger = LogFactory.getLog(SplunkDataReader.class);
private ConnectionFactory<Service> connectionFactory;
private SearchMode mode;
private int count = 0;
private String fieldList;
private String search;
private String earliestTime;
private String latestTime;
private String savedSearch;
private String owner;
private String app;
private String initEarliestTime;
private transient Calendar lastSuccessfulReadTime;
public SplunkDataReader(ConnectionFactory<Service> f) {
this.connectionFactory = f;
}
public void setSearch(String searchStr) {
Assert.hasText(searchStr, "search must be neither null nor empty");
this.search = searchStr;
}
public void setEarliestTime(String earliestTime) {
this.earliestTime = earliestTime;
}
public void setLatestTime(String latestTime) {
this.latestTime = latestTime;
}
public void setSavedSearch(String savedSearch) {
this.savedSearch = savedSearch;
}
public void setMode(SearchMode mode) {
Assert.notNull(mode, "mode must be set");
this.mode = mode;
}
public void setCount(int count) {
this.count = count;
}
public void setFieldList(String fieldList) {
this.fieldList = fieldList;
}
public void setOwner(String owner) {
this.owner = owner;
}
public void setApp(String app) {
this.app = app;
}
public void setInitEarliestTime(String initEarliestTime) {
Assert.notNull(initEarliestTime, "initial earliest time can not be null");
this.initEarliestTime = initEarliestTime;
}
public SearchMode getMode() {
return mode;
}
public int getCount() {
return count;
}
public String getFieldList() {
return fieldList;
}
public String getSearch() {
return search;
}
public String getEarliestTime() {
return earliestTime;
}
public String getLatestTime() {
return latestTime;
}
public String getSavedSearch() {
return savedSearch;
}
public String getOwner() {
return owner;
}
public String getInitEarliestTime() {
return initEarliestTime;
}
public String getApp() {
return app;
}
public List<SplunkData> search() throws Exception {
logger.debug("mode:" + mode);
switch (mode) {
case saved: {
return savedSearch();
}
case blocking: {
return blockingSearch();
}
case normal: {
return nonBlockingSearch();
}
case export: {
return exportSearch();
}
case realtime: {
return realtimeSearch();
}
}
return null;
}
/**
* Get the earliestTime of range search.
*
* @param startTime the time where search start
* @param realtime if this is realtime search
*
* @return The time of last successful read if not realtime;
* Time difference between last successful read and start time;
*/
private String calculateEarliestTime(Calendar startTime, boolean realtime) {
String result = null;
if (realtime) {
result = calculateEarliestTimeForRealTime(startTime);
}
DateFormat df = new SimpleDateFormat(DATE_FORMAT);
result = df.format(lastSuccessfulReadTime.getTime());
return result;
}
/**
* get earliest time for realtime search
*
* @param startTime
* @return
*/
private String calculateEarliestTimeForRealTime(Calendar startTime) {
String result = null;
long diff = startTime.getTimeInMillis() - lastSuccessfulReadTime.getTimeInMillis();
result = "-" + diff / 1000 + "s";
return result;
}
private void populateArgs(Args queryArgs, Calendar startTime, boolean realtime) {
String earliestTime = getEarliestTime(startTime, realtime);
if (StringUtils.hasText(earliestTime)) {
queryArgs.put("earliest_time", earliestTime);
}
String latestTime = getLatestTime(startTime, realtime);
if (StringUtils.hasText(latestTime)) {
queryArgs.put("latest_time", latestTime);
}
queryArgs.put("time_format", SPLUNK_TIME_FORMAT);
if (StringUtils.hasText(fieldList)) {
queryArgs.put("field_list", fieldList);
}
}
private String getLatestTime(Calendar startTime, boolean realtime) {
String lTime = null;
if (StringUtils.hasText(latestTime)) {
lTime = latestTime;
}
else {
if (realtime) {
lTime = "rt";
}
else {
DateFormat df = new SimpleDateFormat(DATE_FORMAT);
lTime = df.format(startTime.getTime());
}
}
return lTime;
}
private String getEarliestTime(Calendar startTime, boolean realtime) {
String eTime = null;
if (lastSuccessfulReadTime == null) {
eTime = initEarliestTime;
}
else {
if (StringUtils.hasText(earliestTime)) {
eTime = earliestTime;
}
else {
String calculatedEarliestTime = calculateEarliestTime(startTime, realtime);
if (calculatedEarliestTime != null) {
if (realtime) {
eTime = "rt" + calculatedEarliestTime;
}
else {
eTime = calculatedEarliestTime;
}
}
}
}
return eTime;
}
private List<SplunkData> runQuery(Args queryArgs) throws Exception {
Connection<Service> connection = connectionFactory.getConnection();
try {
Job job = connection.getTarget().getJobs().create(search, queryArgs);
while (!job.isDone()) {
Thread.sleep(2000);
}
return extractData(job);
} finally {
connection.close();
}
}
private List<SplunkData> blockingSearch() throws Exception {
logger.debug("block search start");
Args queryArgs = new Args();
queryArgs.put("exec_mode", "blocking");
Calendar startTime = Calendar.getInstance();
populateArgs(queryArgs, startTime, false);
List<SplunkData> data = runQuery(queryArgs);
lastSuccessfulReadTime = startTime;
return data;
}
private List<SplunkData> nonBlockingSearch() throws Exception {
logger.debug("non block search start");
Args queryArgs = new Args();
queryArgs.put("exec_mode", "normal");
Calendar startTime = Calendar.getInstance();
populateArgs(queryArgs, startTime, false);
List<SplunkData> data = runQuery(queryArgs);
lastSuccessfulReadTime = startTime;
return data;
}
/**
* @return
* @throws Exception
*/
private List<SplunkData> realtimeSearch() throws Exception {
logger.debug("realtime search start");
Args queryArgs = new Args();
queryArgs.put("search_mode", "realtime");
Calendar startTime = Calendar.getInstance();
populateArgs(queryArgs, startTime, true);
List<SplunkData> data = runQuery(queryArgs);
lastSuccessfulReadTime = startTime;
return data;
}
/**
* @throws Exception
*
*/
private List<SplunkData> exportSearch() throws Exception {
logger.debug("export start");
List<SplunkData> result = new ArrayList<SplunkData>();
HashMap<String, String> data;
SplunkData splunkData;
Args queryArgs = new Args();
Calendar startTime = Calendar.getInstance();
populateArgs(queryArgs, startTime, false);
queryArgs.put("output_mode", "xml");
Connection<Service> connection = connectionFactory.getConnection();
try {
InputStream os = connection.getTarget().export(search, queryArgs);
ResultsReaderXml resultsReader = new ResultsReaderXml(os);
while ((data = resultsReader.getNextEvent()) != null) {
splunkData = new SplunkData(data);
result.add(splunkData);
}
return result;
} finally {
connection.close();
}
}
private List<SplunkData> savedSearch() throws Exception {
logger.debug("saved search start");
Args queryArgs = new Args();
queryArgs.put("app", "search");
if (owner != null && owner.length() > 0) {
queryArgs.put("owner", owner);
}
if (app != null && app.length() > 0) {
queryArgs.put("app", app);
}
Calendar startTime = Calendar.getInstance();
Connection<Service> connection = connectionFactory.getConnection();
try {
SavedSearch search = null;
Job job = null;
String latestTime = getLatestTime(startTime, false);
String earliestTime = getEarliestTime(startTime, false);
SavedSearchCollection savedSearches = connection.getTarget().getSavedSearches(queryArgs);
for (SavedSearch s : savedSearches.values()) {
if (s.getName().equals(savedSearch)) {
search = s;
}
}
if (search != null) {
Map<String, String> args = new HashMap<String, String>();
args.put("force_dispatch", "true");
args.put("dispatch.earliest_time", earliestTime);
args.put("dispatch.latest_time", latestTime);
job = search.dispatch(args);
}
while (!job.isDone()) {
Thread.sleep(2000);
}
List<SplunkData> data = extractData(job);
this.lastSuccessfulReadTime = startTime;
return data;
} finally {
connection.close();
}
}
private List<SplunkData> extractData(Job job) throws Exception {
List<SplunkData> result = new ArrayList<SplunkData>();
HashMap<String, String> data;
SplunkData splunkData;
ResultsReader resultsReader;
int total = job.getResultCount();
if (count == 0 || total < count) {
InputStream stream = null;
Args outputArgs = new Args();
outputArgs.put("output_mode", "xml");
stream = job.getResults(outputArgs);
resultsReader = new ResultsReaderXml(stream);
while ((data = resultsReader.getNextEvent()) != null) {
splunkData = new SplunkData(data);
result.add(splunkData);
}
}
else {
int offset = 0;
while (offset < total) {
InputStream stream = null;
Args outputArgs = new Args();
outputArgs.put("output_mode", "xml");
outputArgs.put("count", count);
outputArgs.put("offset", offset);
stream = job.getResults(outputArgs);
resultsReader = new ResultsReaderXml(stream);
while ((data = resultsReader.getNextEvent()) != null) {
splunkData = new SplunkData(data);
result.add(splunkData);
}
offset += count;
}
}
return result;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(initEarliestTime, "initial earliest time can not be null");
}
}

View File

@@ -0,0 +1,202 @@
/*
* Copyright 2011-2012 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.splunk.support;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.splunk.core.Connection;
import org.springframework.integration.splunk.core.DataWriter;
import org.springframework.integration.splunk.core.ConnectionFactory;
import org.springframework.integration.splunk.entity.SplunkData;
import org.springframework.util.Assert;
import com.splunk.Args;
import com.splunk.Index;
import com.splunk.Receiver;
import com.splunk.Service;
/**
* Data writer to write data into Splunk. There are 3 ways to write data:
* REST submit, TCP socket and HTTP stream.
*
* @author Jarred Li
* @since 1.0
*
*/
public class SplunkDataWriter implements DataWriter, InitializingBean {
private static final Log logger = LogFactory.getLog(SplunkDataWriter.class);
private ConnectionFactory<Service> connectionFactory;
private String sourceType;
private String source;
private String index;
private IngestType ingest = IngestType.stream; //tcp, stream, submit
private int tcpPort;
private String host;
private String hostRegex;
public SplunkDataWriter(ConnectionFactory<Service> f) {
this.connectionFactory = f;
}
public void write(SplunkData data) throws Exception {
logger.debug("write message to splunk:" + data);
Connection<Service> connection = connectionFactory.getConnection();
Service service = connection.getTarget();
Index indexObject = null;
Receiver receiver = null;
OutputStream ostream;
Socket socket;
Writer writer = null;
Args args = new Args();
if (sourceType != null) {
args.put("sourcetype", sourceType);
}
if (source != null) {
args.put("source", source);
}
if (host != null) {
args.put("host", host);
}
if (hostRegex != null) {
args.put("host_regex", hostRegex);
}
try {
if (index != null) {
indexObject = service.getIndexes().get(index);
}
else {
receiver = service.getReceiver();
}
if ((ingest.equals(IngestType.stream) || ingest.equals(IngestType.tcp))) {
if (ingest.equals("stream")) {
if (indexObject != null)
socket = indexObject.attach(args);
else
socket = receiver.attach(args);
}
else {
socket = service.open(tcpPort);
}
ostream = socket.getOutputStream();
writer = new OutputStreamWriter(ostream, "UTF8");
}
if ((ingest.equals(IngestType.stream) || ingest.equals(IngestType.tcp))) {
writer.write(data.toString());
writer.flush();
writer.close();
}
else {
if (index != null) {
indexObject.submit(args, data.toString());
}
else {
receiver.submit(args, data.toString());
}
}
} finally {
connection.close();
}
}
public void setSourceType(String sourceType) {
this.sourceType = sourceType;
}
public void setSource(String source) {
this.source = source;
}
public void setIndex(String index) {
this.index = index;
}
public void setIngest(IngestType ingest) {
this.ingest = ingest;
}
public void setTcpPort(int tcpPort) {
this.tcpPort = tcpPort;
}
public void setHost(String host) {
this.host = host;
}
public void setHostRegex(String hostRegex) {
this.hostRegex = hostRegex;
}
public String getSourceType() {
return sourceType;
}
public String getSource() {
return source;
}
public String getIndex() {
return index;
}
public IngestType getIngest() {
return ingest;
}
public int getTcpPort() {
return tcpPort;
}
public String getHost() {
return host;
}
public String getHostRegex() {
return hostRegex;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
Assert.notNull(ingest, "You must specify ingest type");
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2002-2012 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.splunk.support;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.Message;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.MessagingException;
import org.springframework.integration.splunk.core.DataReader;
import org.springframework.integration.splunk.core.DataWriter;
import org.springframework.integration.splunk.entity.SplunkData;
/**
* Bundles common core logic for the Splunk components.
*
* @author Jarred Li
* @since 1.0
*
*/
public class SplunkExecutor implements InitializingBean {
private static final Log logger = LogFactory.getLog(SplunkExecutor.class);
private DataReader reader;
private DataWriter writer;
public SplunkExecutor() {
}
/**
* Verifies and sets the parameters. E.g. initializes the to be used
*/
public void afterPropertiesSet() {
}
/**
* Executes the outbound Splunk Operation.
*
*/
public Object executeOutboundOperation(final Message<?> message) {
try {
SplunkData payload = (SplunkData) message.getPayload();
writer.write(payload);
} catch (Exception e) {
String errorMsg = "error in writing data into Splunk";
logger.warn(errorMsg, e);
throw new MessageHandlingException(message, errorMsg, e);
}
return null;
}
public void handleMessage(final Message<?> message) {
executeOutboundOperation(message);
}
/**
* Execute the Splunk operation.
*/
public List<SplunkData> poll() {
logger.debug("poll start:");
List<SplunkData> queryData = null;
try {
queryData = reader.search();
} catch (Exception e) {
String errorMsg = "search Splunk data failed";
logger.warn(errorMsg, e);
throw new MessagingException(errorMsg, e);
}
return queryData;
}
public void setReader(DataReader reader) {
this.reader = reader;
}
public void setWriter(DataWriter writer) {
this.writer = writer;
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,364 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.springframework.org/schema/integration/splunk"
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/integration/splunk"
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-2.2.xsd" />
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines the configuration elements for the Spring Integration
Splunk Adapter.
]]></xsd:documentation>
</xsd:annotation>
<xsd:element name="server">
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines a Splunk server information.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="host" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates the Splunk server name or IP address
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="direct">
<tool:expected-type type="java.lang.String" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="port" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates the Splunk server port
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="direct">
<tool:expected-type type="java.lang.Integer" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="scheme" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates the Splunk server scheme
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="direct">
<tool:expected-type type="java.lang.String" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="app" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates the Splunk server application name
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="direct">
<tool:expected-type type="java.lang.String" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="owner" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates the Splunk server owner name
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="direct">
<tool:expected-type type="java.lang.String" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="userName" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates the userName to login Splunk server
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="direct">
<tool:expected-type type="java.lang.String" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="password" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates the password to login Splunk server
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="direct">
<tool:expected-type type="java.lang.String" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="scope" type="xsd:string" use="optional" />
<xsd:attribute name="id" type="xsd:ID" use="required" />
</xsd:complexType>
</xsd:element>
<xsd:element name="inbound-channel-adapter">
<xsd:annotation>
<xsd:documentation>
The definition for the Spring Integration Splunk
Inbound Channel Adapter.
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0"
maxOccurs="1" />
</xsd:sequence>
<xsd:attributeGroup ref="coreSplunkComponentAttributes" />
<xsd:attribute name="channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type
type="org.springframework.integration.core.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="send-timeout" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Allows you to specify how long this inbound-channel-adapter
will wait for the message (containing the retrieved entities)
to be sent successfully to the message channel, before throwing
an exception.
Keep in mind that when sending to a DirectChannel, the
invocation will occur in the sender's thread so the failing
of the send operation may be caused by other components
further downstream. By default the Inbound Channel Adapter
will wait indefinitely. The value is specified in milliseconds.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mode" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Search mode: normal, blocking, realtime, export, saved
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="count" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
The maximum number of event record to be return
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="fieldList" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
A comma-separated list of the fields to return
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="search" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Search String following Splunk syntax.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="earliestTime" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Time modifier for the start of the time window.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="latestTime" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Time modifier for the end of the time window.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="initEarliestTime" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>
Time modifier for the start of the time window for the first search.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="savedSearch" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Saved search.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="owner" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Owner of the saved search.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="app" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
App of the saved search.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="outbound-channel-adapter">
<xsd:annotation>
<xsd:documentation>
Defines an outbound Channel Adapter.
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0"
maxOccurs="1" />
</xsd:sequence>
<xsd:attributeGroup ref="coreSplunkComponentAttributes" />
<xsd:attribute name="channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<xsd:documentation>
Channel from which messages will be output.
When a message is sent to this channel it will
cause the query
to
be executed.
</xsd:documentation>
<tool:annotation kind="ref">
<tool:expected-type
type="org.springframework.integration.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="order">
<xsd:annotation>
<xsd:documentation>
Specifies the order for invocation when this
endpoint is connected as a
subscriber to a SubscribableChannel.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="source" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Splunk event source
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="sourceType" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Splunk event source type
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="index" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Splunk index name
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="ingest" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Splunk ingest method: tcp, streaming, submit. Default stream.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="tcpPort" type="xsd:integer">
<xsd:annotation>
<xsd:documentation>
Splunk ingest method: tcp, streaming, submit. Default stream.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="host" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Host where the event occurred
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="hostRegex" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Host regex can be provided so Splunk can dynamically extract the host value from the log event
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:attributeGroup name="coreSplunkComponentAttributes">
<xsd:attribute name="id" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation>
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>
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:attribute name="splunk-server-ref" use="required"
type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Splunk Server Bean Name
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="pool-server-connection" use="optional" default="true"
type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Whether pool the Splunk connection.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:attributeGroup>
</xsd:schema>