diff --git a/README.md b/README.md index 0d208ea..6d2698d 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,25 @@ The outbound channel adapter requires a child *-writer element which defines rel ``` +Alternatively, you can configure a Splunk Server failover mechanism + +```xml + + + + + + + + + + + + +``` + Additional server properties include (see [splunk](http://docs.splunk.com/Documentation/Splunk/latest) documentation for details): * app diff --git a/build.gradle b/build.gradle index 5a1b625..29f4f58 100644 --- a/build.gradle +++ b/build.gradle @@ -2,10 +2,10 @@ description = 'Spring Integration Splunk Adapter' buildscript { repositories { - maven { url 'http://repo.springsource.org/plugins-snapshot' } + maven { url 'http://repo.spring.io/plugins-release' } } dependencies { - classpath 'org.springframework.build.gradle:docbook-reference-plugin:0.1.5' + classpath 'org.springframework.build.gradle:docbook-reference-plugin:0.2.8' } } @@ -17,21 +17,20 @@ apply plugin: 'idea' group = 'org.springframework.integration' repositories { - maven { url 'http://repo.springsource.org/libs-milestone' } - maven { url 'http://repo.springsource.org/plugins-release' } // for bundlor + maven { url 'http://repo.spring.io/libs-milestone' } } sourceCompatibility=1.6 targetCompatibility=1.6 ext { - linkHomepage = 'https://github.com/SpringSource/spring-integration-extensions' - linkCi = 'https://build.springsource.org/browse/INTEXT' - linkIssue = 'https://jira.springsource.org/browse/INTEXT' - linkScmUrl = 'https://github.com/SpringSource/spring-integration-extensions' - linkScmConnection = 'https://github.com/SpringSource/spring-integration-extensions.git' - linkScmDevConnection = 'git@github.com:SpringSource/spring-integration-extensions.git' - + linkHomepage = 'https://github.com/spring-projects/spring-integration-extensions' + linkCi = 'https://build.spring.io/browse/INTEXT' + linkIssue = 'https://jira.spring.io/browse/INTEXT' + linkScmUrl = 'https://github.com/spring-projects/spring-integration-extensions' + linkScmConnection = 'https://github.com/spring-projects/spring-integration-extensions.git' + linkScmDevConnection = 'git@github.com:spring-projects/spring-integration-extensions.git' + shortName = 'splunk' } @@ -42,17 +41,13 @@ configurations { } dependencies { - compile("com.splunk:splunk:$splunkVersion") - compile "org.springframework:spring-beans:$springVersion" - compile "org.springframework:spring-context:$springVersion" - compile "org.springframework:spring-expression:$springVersion" + compile "com.splunk:splunk:$splunkVersion" compile "org.springframework.integration:spring-integration-core:$springIntegrationVersion" compile "joda-time:joda-time:$jodaTimeVersion" compile "commons-pool:commons-pool:$commonsPoolVersion" testCompile "org.mockito:mockito-all:$mockitoVersion" - testCompile "org.springframework:spring-test:$springVersion" - testCompile "cglib:cglib-nodep:$cglibVersion" + testCompile "org.springframework.integration:spring-integration-test:$springIntegrationVersion" testCompile "junit:junit-dep:$junitVersion" testCompile "log4j:log4j:$log4jVersion" testCompile "org.springframework.integration:spring-integration-stream:$springIntegrationVersion" @@ -77,7 +72,7 @@ sourceSets { // enable all compiler warnings; individual projects may customize further -ext.xLintArg = '-Xlint:all' +ext.xLintArg = '-Xlint:all,-options' [compileJava, compileTestJava]*.options*.compilerArgs = [xLintArg] test { @@ -255,7 +250,8 @@ task dist(dependsOn: assemble) { task wrapper(type: Wrapper) { description = 'Generates gradlew[.bat] scripts' - gradleVersion = '1.6' + gradleVersion = '1.12' + distributionUrl = "http://services.gradle.org/distributions/gradle-${gradleVersion}-all.zip" } defaultTasks 'build' diff --git a/gradle.properties b/gradle.properties index 44a7dde..bef6f72 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,8 @@ -junitVersion=4.8.2 -jodaTimeVersion=2.1 -springVersion=4.0.0.RELEASE -splunkVersion=1.0.0 -log4jVersion=1.2.12 version=1.1.0.BUILD-SNAPSHOT -springIntegrationVersion=4.0.0.M2 -cglibVersion=2.2 +junitVersion=4.11 +jodaTimeVersion=2.3 +splunkVersion=1.0.0 +log4jVersion=1.2.17 +springIntegrationVersion=4.0.2.RELEASE commonsPoolVersion=1.6 -mockitoVersion=1.9.0 +mockitoVersion=1.9.5 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a7634b0..0087cd3 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ba108aa..3598337 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed May 15 23:11:13 EDT 2013 +#Fri Jun 06 13:11:01 EEST 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip +distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip diff --git a/src/main/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParser.java b/src/main/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParser.java index 16b9f17..b9ccad9 100644 --- a/src/main/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParser.java +++ b/src/main/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -13,12 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.integration.splunk.config.xml; +import org.w3c.dom.Element; + import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser; import org.springframework.integration.config.xml.IntegrationNamespaceUtils; @@ -26,12 +31,12 @@ import org.springframework.integration.splunk.inbound.SplunkPollingChannelAdapte import org.springframework.integration.splunk.support.SplunkDataReader; import org.springframework.integration.splunk.support.SplunkServiceFactory; import org.springframework.util.StringUtils; -import org.w3c.dom.Element; /** * The Splunk Inbound Channel adapter parser * * @author Jarred Li + * @author Olivier Lamy * @since 1.0 * */ @@ -40,17 +45,14 @@ public class SplunkInboundChannelAdapterParser extends AbstractPollingInboundCha protected BeanMetadataElement parseSource(Element element, ParserContext parserContext) { - BeanDefinitionBuilder splunkPollingChannelAdapterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkPollingChannelAdapter.class); + 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, "count"); IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataReaderBuilder, element, "field-list"); IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataReaderBuilder, element, "search"); IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataReaderBuilder, element, "saved-search"); @@ -60,14 +62,20 @@ public class SplunkInboundChannelAdapterParser extends AbstractPollingInboundCha IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataReaderBuilder, element, "earliest-time"); IntegrationNamespaceUtils.setValueIfAttributeDefined(splunkDataReaderBuilder, element, "latest-time"); + // initialize splunk servers references BeanDefinitionBuilder serviceFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkServiceFactory.class); - String splunkServerBeanName = element.getAttribute("splunk-server-ref"); - if (StringUtils.hasText(splunkServerBeanName)) { - serviceFactoryBuilder.addConstructorArgReference(splunkServerBeanName); - } + String splunkServerBeanNames = element.getAttribute("splunk-server-ref"); + if (StringUtils.hasText(splunkServerBeanNames)) { - splunkDataReaderBuilder.addConstructorArgValue(serviceFactoryBuilder.getBeanDefinition()); + ManagedList splunkServersList = new ManagedList(); + + for (String splunkServerBeanName : StringUtils.commaDelimitedListToStringArray(splunkServerBeanNames)) { + splunkServersList.add(new RuntimeBeanReference(splunkServerBeanName)); + } + serviceFactoryBuilder.addConstructorArgValue(splunkServersList); + splunkDataReaderBuilder.addConstructorArgValue(serviceFactoryBuilder.getBeanDefinition()); + } String channelAdapterId = this.resolveId(element, splunkPollingChannelAdapterBuilder.getRawBeanDefinition(), parserContext); diff --git a/src/main/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParser.java b/src/main/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParser.java index a319604..5194a73 100644 --- a/src/main/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParser.java +++ b/src/main/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -13,12 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.integration.splunk.config.xml; +import org.w3c.dom.Element; + import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; 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.support.ManagedList; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser; import org.springframework.integration.config.xml.IntegrationNamespaceUtils; @@ -30,13 +35,13 @@ import org.springframework.integration.splunk.support.SplunkSubmitWriter; import org.springframework.integration.splunk.support.SplunkTcpWriter; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; -import org.w3c.dom.Element; /** * The parser for the Splunk Outbound Channel Adapter. * * @author Jarred Li * @author David Turanski + * @author Olivier Lamy * @since 1.0 * */ @@ -55,7 +60,8 @@ public class SplunkOutboundChannelAdapterParser extends AbstractOutboundChannelA @Override protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) { - BeanDefinitionBuilder splunkOutboundChannelAdapterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkOutboundChannelAdapter.class); + BeanDefinitionBuilder splunkOutboundChannelAdapterBuilder = + BeanDefinitionBuilder.genericBeanDefinition(SplunkOutboundChannelAdapter.class); BeanDefinitionBuilder splunkExecutorBuilder = SplunkParserUtils.getSplunkExecutorBuilder(element, parserContext); BeanDefinitionBuilder argsBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkArgsFactoryBean.class); @@ -64,16 +70,26 @@ public class SplunkOutboundChannelAdapterParser extends AbstractOutboundChannelA IntegrationNamespaceUtils.setValueIfAttributeDefined(argsBuilder, element, "host"); IntegrationNamespaceUtils.setValueIfAttributeDefined(argsBuilder, element, "host-regex"); + BeanDefinitionBuilder dataWriterBuilder = parseDataWriter(element); + + // initialize splunk servers references + BeanDefinitionBuilder serviceFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkServiceFactory.class); - String splunkServerBeanName = element.getAttribute("splunk-server-ref"); - if (StringUtils.hasText(splunkServerBeanName)) { - serviceFactoryBuilder.addConstructorArgReference(splunkServerBeanName); + String splunkServerBeanNames = element.getAttribute("splunk-server-ref"); + if (StringUtils.hasText(splunkServerBeanNames)) { + + ManagedList splunkServersList = new ManagedList(); + + for (String splunkServerBeanName : StringUtils.delimitedListToStringArray(splunkServerBeanNames, ";")) { + splunkServersList.add(new RuntimeBeanReference(splunkServerBeanName)); + } + serviceFactoryBuilder.addConstructorArgValue(splunkServersList); } - - BeanDefinitionBuilder dataWriterBuilder = parseDataWriter(element, parserContext); dataWriterBuilder.addConstructorArgValue(serviceFactoryBuilder.getBeanDefinition()); + + dataWriterBuilder.addConstructorArgValue(argsBuilder.getBeanDefinition()); String channelAdapterId = this.resolveId(element, splunkOutboundChannelAdapterBuilder.getRawBeanDefinition(), @@ -96,30 +112,30 @@ public class SplunkOutboundChannelAdapterParser extends AbstractOutboundChannelA } - private BeanDefinitionBuilder parseDataWriter(Element element, ParserContext parserContext) { + private BeanDefinitionBuilder parseDataWriter(Element element) { BeanDefinitionBuilder dataWriterBuilder = null; - Element dataWriter = null; - if (DomUtils.getChildElementByTagName(element, "index-writer") != null) { - dataWriter = DomUtils.getChildElementByTagName(element, "index-writer"); - dataWriterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkIndexWriter.class); - IntegrationNamespaceUtils.setValueIfAttributeDefined(dataWriterBuilder, dataWriter, "index"); + if (DomUtils.getChildElementByTagName(element, "index-writer") != null) { + Element dataWriter = DomUtils.getChildElementByTagName(element, "index-writer"); + dataWriterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkIndexWriter.class); + IntegrationNamespaceUtils.setValueIfAttributeDefined(dataWriterBuilder, dataWriter, "index"); - } - if (DomUtils.getChildElementByTagName(element, "submit-writer") != null) { - dataWriter = DomUtils.getChildElementByTagName(element, "submit-writer"); - dataWriterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkSubmitWriter.class); - IntegrationNamespaceUtils.setValueIfAttributeDefined(dataWriterBuilder, dataWriter, "index"); - } - if (DomUtils.getChildElementByTagName(element, "tcp-writer") != null) { - dataWriter = DomUtils.getChildElementByTagName(element, "tcp-writer"); - dataWriterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkTcpWriter.class); - IntegrationNamespaceUtils.setValueIfAttributeDefined(dataWriterBuilder, dataWriter, "port"); + } + if (DomUtils.getChildElementByTagName(element, "submit-writer") != null) { + Element dataWriter = DomUtils.getChildElementByTagName(element, "submit-writer"); + dataWriterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkSubmitWriter.class); + IntegrationNamespaceUtils.setValueIfAttributeDefined(dataWriterBuilder, dataWriter, "index"); + } + if (DomUtils.getChildElementByTagName(element, "tcp-writer") != null) { + Element dataWriter = DomUtils.getChildElementByTagName(element, "tcp-writer"); + dataWriterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SplunkTcpWriter.class); + IntegrationNamespaceUtils.setValueIfAttributeDefined(dataWriterBuilder, dataWriter, "port"); - } + } - IntegrationNamespaceUtils.setValueIfAttributeDefined(dataWriterBuilder, element, "auto-startup"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(dataWriterBuilder, element, + IntegrationNamespaceUtils.AUTO_STARTUP); - return dataWriterBuilder; + return dataWriterBuilder; } } diff --git a/src/main/java/org/springframework/integration/splunk/config/xml/SplunkServerParser.java b/src/main/java/org/springframework/integration/splunk/config/xml/SplunkServerParser.java index 3151d1d..e4d4baf 100644 --- a/src/main/java/org/springframework/integration/splunk/config/xml/SplunkServerParser.java +++ b/src/main/java/org/springframework/integration/splunk/config/xml/SplunkServerParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2012 the original author or authors. + * Copyright 2011-2014 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. @@ -13,27 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.integration.splunk.config.xml; +import org.w3c.dom.Element; + 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.support.SplunkServer; -import org.w3c.dom.Element; /** * Splunk server element parser. * * The XML element is like this: - *
+ * 
  * {@code
  * 
  * }
+ * 
* * @author Jarred Li + * @author Olivier Lamy * @since 1.0 * */ @@ -57,8 +61,8 @@ public class SplunkServerParser extends AbstractSimpleBeanDefinitionParser { IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "username"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "password"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "timeout"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "checkServiceOnBorrow"); } - } diff --git a/src/main/java/org/springframework/integration/splunk/support/SplunkIndexWriter.java b/src/main/java/org/springframework/integration/splunk/support/SplunkIndexWriter.java index 7bc341f..66f301e 100644 --- a/src/main/java/org/springframework/integration/splunk/support/SplunkIndexWriter.java +++ b/src/main/java/org/springframework/integration/splunk/support/SplunkIndexWriter.java @@ -38,7 +38,7 @@ public class SplunkIndexWriter extends AbstractSplunkDataWriter { private String indexName; /** * - * @param connectionFactory + * @param serviceFactory * @param args */ public SplunkIndexWriter(ServiceFactory serviceFactory, Args args) { diff --git a/src/main/java/org/springframework/integration/splunk/support/SplunkServer.java b/src/main/java/org/springframework/integration/splunk/support/SplunkServer.java index 157f983..af77494 100644 --- a/src/main/java/org/springframework/integration/splunk/support/SplunkServer.java +++ b/src/main/java/org/springframework/integration/splunk/support/SplunkServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2012 the original author or authors. + * Copyright 2011-2014 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.integration.splunk.support; import com.splunk.Service; @@ -21,20 +22,33 @@ import com.splunk.Service; * Splunk server entity * * @author Jarred Li + * @author Olivier Lamy * @since 1.0 * */ public class SplunkServer { private String host = Service.DEFAULT_HOST; + private int port = Service.DEFAULT_PORT; + private String scheme = Service.DEFAULT_SCHEME; + private String app; + private String owner; + private String username; + private String password; + private int timeout; + /** + * if true the framework will test the connectivity before give back the connection. + */ + private boolean checkServiceOnBorrow = false; + /** * @return the host */ @@ -64,15 +78,15 @@ public class SplunkServer { } /** - * - * @return + * + * @return the used scheme */ public String getScheme() { return scheme; } /** - * + * * @param scheme */ public void setScheme(String scheme) { @@ -80,15 +94,15 @@ public class SplunkServer { } /** - * - * @return + * + * @return the application */ public String getApp() { return app; } /** - * + * * @param app */ public void setApp(String app) { @@ -96,15 +110,15 @@ public class SplunkServer { } /** - * - * @return + * + * @return the owner */ public String getOwner() { return owner; } /** - * + * * @param owner */ public void setOwner(String owner) { @@ -145,7 +159,7 @@ public class SplunkServer { public int getTimeout() { return timeout; } - + /** * set the timeout in ms. * @param timeout @@ -153,4 +167,52 @@ public class SplunkServer { public void setTimeout(int timeout) { this.timeout = timeout; } + + /** + * @return {@code true/false} if there is need to check the underlying Splunk Service + * @since 1.1 + */ + public boolean isCheckServiceOnBorrow() { + return checkServiceOnBorrow; + } + + /** + * @param checkServiceOnBorrow the {@code checkServiceOnBorrow} flag + * @since 1.1 + */ + public void setCheckServiceOnBorrow(boolean checkServiceOnBorrow) { + this.checkServiceOnBorrow = checkServiceOnBorrow; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + SplunkServer that = SplunkServer.class.cast(o); + + return port == that.port && host.equals(that.host); + + } + + @Override + public int hashCode() { + int result = host.hashCode(); + result = 31 * result + port; + return result; + } + + @Override + public String toString() { + return "SplunkServer{" + + "host='" + host + '\'' + + ", port=" + port + + ", scheme='" + scheme + '\'' + + ", app='" + app + '\'' + + '}'; + } } diff --git a/src/main/java/org/springframework/integration/splunk/support/SplunkServiceFactory.java b/src/main/java/org/springframework/integration/splunk/support/SplunkServiceFactory.java index 55af6f9..eb22179 100644 --- a/src/main/java/org/springframework/integration/splunk/support/SplunkServiceFactory.java +++ b/src/main/java/org/springframework/integration/splunk/support/SplunkServiceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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 @@ -10,39 +10,109 @@ * 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.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import com.splunk.Service; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.springframework.beans.factory.FactoryBean; import org.springframework.integration.splunk.core.ServiceFactory; - -import com.splunk.Service; +import org.springframework.util.Assert; /** * A {@link FactoryBean} for creating a {@link Service} * * @author David Turanski + * @author Olivier Lamy */ public class SplunkServiceFactory implements ServiceFactory { - private final SplunkServer splunkServer; - private Service service; + + private static final Log LOGGER = LogFactory.getLog(SplunkServiceFactory.class); + + private final List splunkServers; + + private final Map servicePerServer = new ConcurrentHashMap(); + public SplunkServiceFactory(SplunkServer splunkServer) { - this.splunkServer = splunkServer; + Assert.notNull(splunkServer); + this.splunkServers = Arrays.asList(splunkServer); + } + + /** + * @param splunkServers the {@code List} to build this {@code SplunkServiceFactory} + * @since 1.1 + */ + public SplunkServiceFactory(List splunkServers) { + Assert.notEmpty(splunkServers); + this.splunkServers = new ArrayList(splunkServers); } @Override public synchronized Service getService() { - if (service != null) { - return service; + return getServiceInternal(); + } + + private Service getServiceInternal() { + + for (SplunkServer splunkServer : splunkServers) { + Service service = servicePerServer.get(splunkServer); + // service already exist and no test on borrow it so simply use it + + if (service != null) { + if (!splunkServer.isCheckServiceOnBorrow() || pingService(service)) { + return service; + } + else { + // fail so try next server + continue; + } + } + + ExecutorService executor = Executors.newSingleThreadExecutor(); + + Callable callable = buildServiceCallable(splunkServer); + + Future future = executor.submit(callable); + + try { + if (splunkServer.getTimeout() > 0) { + service = future.get(splunkServer.getTimeout(), TimeUnit.MILLISECONDS); + } + else { + service = future.get(); + } + + servicePerServer.put(splunkServer, service); + return service; + } + catch (Exception e) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info(String.format("could not connect to Splunk Server @ %s:%d - %s, try next one", + splunkServer.getHost(), splunkServer.getPort(), e.getMessage())); + } + } } + String message = String.format("could not connect to any of Splunk Servers %s", this.splunkServers); + LOGGER.error(message); + throw new RuntimeException(message); + } + + private Callable buildServiceCallable(SplunkServer splunkServer) { final Map args = new HashMap(); if (splunkServer.getHost() != null) { args.put("host", splunkServer.getHost()); @@ -63,24 +133,22 @@ public class SplunkServiceFactory implements ServiceFactory { args.put("username", splunkServer.getUsername()); args.put("password", splunkServer.getPassword()); - ExecutorService executor = Executors.newSingleThreadExecutor(); - - Future future = executor.submit(new Callable(){ - public Service call() throws Exception { + return new Callable() { + public Service call() + throws Exception { return Service.connect(args); } - }); - - try { - if (splunkServer.getTimeout() > 0) { - service = future.get(splunkServer.getTimeout(),TimeUnit.MILLISECONDS); - } else { - service = future.get(); - } - } catch (Exception e) { - throw new RuntimeException(String.format("could not connect to Splunk Server @ %s:%d - %s", - splunkServer.getHost(),splunkServer.getPort(),e.getMessage())); - } - return service; + }; } + + private boolean pingService(Service service) { + try { + service.getInfo(); + return true; + } + catch (Exception e) { + return false; + } + } + } diff --git a/src/main/java/org/springframework/integration/splunk/support/SplunkSubmitWriter.java b/src/main/java/org/springframework/integration/splunk/support/SplunkSubmitWriter.java index 27a5fbc..c5e7369 100644 --- a/src/main/java/org/springframework/integration/splunk/support/SplunkSubmitWriter.java +++ b/src/main/java/org/springframework/integration/splunk/support/SplunkSubmitWriter.java @@ -33,7 +33,8 @@ public class SplunkSubmitWriter extends AbstractSplunkDataWriter { private String index; /** - * @param connectionFactory + * @param serviceFactory + * @param args */ public SplunkSubmitWriter(ServiceFactory serviceFactory, Args args) { super(serviceFactory, args); diff --git a/src/main/java/org/springframework/integration/splunk/support/SplunkTcpWriter.java b/src/main/java/org/springframework/integration/splunk/support/SplunkTcpWriter.java index ebbbc7a..0e10542 100644 --- a/src/main/java/org/springframework/integration/splunk/support/SplunkTcpWriter.java +++ b/src/main/java/org/springframework/integration/splunk/support/SplunkTcpWriter.java @@ -1,11 +1,11 @@ /* - * Copyright 2002-2013 the original author or authors. - * + * Copyright 2002-2014 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. @@ -15,43 +15,37 @@ package org.springframework.integration.splunk.support; import java.io.IOException; import java.net.Socket; -import org.springframework.integration.splunk.core.ServiceFactory; -import org.springframework.util.Assert; - import com.splunk.Args; import com.splunk.Input; import com.splunk.Service; +import org.springframework.integration.splunk.core.ServiceFactory; +import org.springframework.util.Assert; + /** - * - * A {@link SplunkStreamWriter} that creates a socket on a given port + * + * A {@code org.springframework.integration.splunk.core.DataWriter} + * that creates a socket on a given port + * * @author David Turanski * */ public class SplunkTcpWriter extends AbstractSplunkDataWriter { private int port; - /** - * @param connectionFactory - * @param args - */ public SplunkTcpWriter(ServiceFactory serviceFactory, Args args) { super(serviceFactory, args); } - - /* (non-Javadoc) - * @see org.springframework.integration.splunk.support.SplunkDataWriter#createSocket(com.splunk.Service) - */ + @Override protected Socket createSocket(Service service) throws IOException { - + Input input = service.getInputs().get(String.valueOf(port)); Assert.notNull(input, "no input defined for port " + port); Assert.isTrue(!input.isDisabled(),String.format("input on port %d is disabled",port)); - Socket socket = service.open(port); - return socket; + return service.open(port); } - + /** * @param port the port to set */ @@ -59,5 +53,5 @@ public class SplunkTcpWriter extends AbstractSplunkDataWriter { this.port = port; } - + } diff --git a/src/main/resources/org/springframework/integration/splunk/config/xml/spring-integration-splunk-1.1.xsd b/src/main/resources/org/springframework/integration/splunk/config/xml/spring-integration-splunk-1.1.xsd new file mode 100644 index 0000000..4fe55b8 --- /dev/null +++ b/src/main/resources/org/springframework/integration/splunk/config/xml/spring-integration-splunk-1.1.xsd @@ -0,0 +1,404 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The definition for the Spring Integration Splunk + Inbound Channel Adapter. + + + + + + + + + + + + + + + + + + + + + + + + + + Search mode: normal, blocking, realtime, export, saved + + + + + + + The maximum number of event record to be return + + + + + + + A comma-separated list of the fields to return + + + + + + + Search String following Splunk syntax. + + + + + + + Time modifier for the start of the time window. + + + + + + + Time modifier for the end of the time window. + + + + + + + Time modifier for the start of the time window for the first search. + + + + + + + Saved search. + + + + + + + Owner of the saved search. + + + + + + + App of the saved search. + + + + + + + + + + + Index to write to. + + + + + + + + + + The port corresponding to a tcp Input + + + + + + + + + Defines an outbound Channel Adapter. + + + + + + + + + + Defines a Data Writer for streaming data to an index, or the default index if not specified. + + + + + + + Defines a Data Writer for streaming data to a tcp input port. + + + + + + + Defines a Data Writer to submit data, using the REST interface, to an index, or the default index if not specified. + + + + + + + + + + + Channel from which messages will be output. + When a message is sent to this channel it will + cause the query + to + be executed. + + + + + + + + + + + Specifies the order for invocation when this + endpoint is connected as a + subscriber to a SubscribableChannel. + + + + + + + Splunk event source + + + + + + + Splunk event source type + + + + + + + + Host where the event occurred + + + + + + + + Host regex can be provided so Splunk can dynamically extract the host value from the log event + + + + + + + + + + + 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'. + + + + + + + Flag to indicate that the component should start + automatically + on startup (default true). + + + + + + + + + + Splunk Server Bean Name + + + + + + diff --git a/src/test/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserTests.java b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserTests.java index 6191822..f10daf3 100644 --- a/src/test/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserTests.java +++ b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserTests.java @@ -15,10 +15,10 @@ */ package org.springframework.integration.splunk.config.xml; -import junit.framework.Assert; - +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.integration.endpoint.SourcePollingChannelAdapter; diff --git a/src/test/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserStreamTests.java b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserStreamTests.java index cbf293b..2ad3693 100644 --- a/src/test/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserStreamTests.java +++ b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserStreamTests.java @@ -15,11 +15,12 @@ */ package org.springframework.integration.splunk.config.xml; -import static org.junit.Assert.assertTrue; -import junit.framework.Assert; +import static org.junit.Assert.*; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.integration.splunk.support.AbstractSplunkDataWriter; diff --git a/src/test/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserTests.java b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserTests.java index 1cbf760..b31fba0 100644 --- a/src/test/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserTests.java +++ b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserTests.java @@ -15,13 +15,12 @@ */ package org.springframework.integration.splunk.config.xml; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import junit.framework.Assert; +import static org.junit.Assert.*; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.integration.splunk.support.AbstractSplunkDataWriter; @@ -52,11 +51,11 @@ public class SplunkOutboundChannelAdapterParserTests { AbstractSplunkDataWriter writer = appContext.getBean("splunkOutboundChannelAdapter.splunkExecutor.writer", AbstractSplunkDataWriter.class); assertNotNull(writer); - + assertTrue(writer instanceof SplunkSubmitWriter); assertEquals(false,writer.isAutoStartup()); assertEquals(false,writer.isRunning()); - + String sourceType = "spring-integration"; assertEquals(sourceType, writer.getArgs().get("sourcetype")); diff --git a/src/test/java/org/springframework/integration/splunk/config/xml/SplunkServerParserTests.java b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkServerParserTests.java index 98c806a..79b0a5a 100644 --- a/src/test/java/org/springframework/integration/splunk/config/xml/SplunkServerParserTests.java +++ b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkServerParserTests.java @@ -15,10 +15,10 @@ */ package org.springframework.integration.splunk.config.xml; -import junit.framework.Assert; - +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.integration.splunk.support.SplunkServer; diff --git a/src/test/java/org/springframework/integration/splunk/event/SplunkEventTests.java b/src/test/java/org/springframework/integration/splunk/event/SplunkEventTests.java index 2728b52..bb45fec 100644 --- a/src/test/java/org/springframework/integration/splunk/event/SplunkEventTests.java +++ b/src/test/java/org/springframework/integration/splunk/event/SplunkEventTests.java @@ -11,6 +11,7 @@ * specific language governing permissions and limitations under the License. */ package org.springframework.integration.splunk.event; + import static org.junit.Assert.assertEquals; import java.util.HashMap; @@ -64,4 +65,4 @@ public class SplunkEventTests { assertEquals(eventData.get(key),event2Data.get(key)); } } -} \ No newline at end of file +} diff --git a/src/test/java/org/springframework/integration/splunk/inbound/SplunkPollingChannelAdapterTests.java b/src/test/java/org/springframework/integration/splunk/inbound/SplunkPollingChannelAdapterTests.java index 8a02e2a..9b6ecfa 100644 --- a/src/test/java/org/springframework/integration/splunk/inbound/SplunkPollingChannelAdapterTests.java +++ b/src/test/java/org/springframework/integration/splunk/inbound/SplunkPollingChannelAdapterTests.java @@ -15,16 +15,15 @@ */ package org.springframework.integration.splunk.inbound; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import java.util.ArrayList; import java.util.List; -import junit.framework.Assert; - +import org.junit.Assert; import org.junit.Before; import org.junit.Test; + import org.springframework.integration.splunk.event.SplunkEvent; import org.springframework.integration.splunk.support.SplunkExecutor; diff --git a/src/test/java/org/springframework/integration/splunk/outbound/SplunkOutboundChannelAdapterTests.java b/src/test/java/org/springframework/integration/splunk/outbound/SplunkOutboundChannelAdapterTests.java index 573039e..cf4fb5b 100644 --- a/src/test/java/org/springframework/integration/splunk/outbound/SplunkOutboundChannelAdapterTests.java +++ b/src/test/java/org/springframework/integration/splunk/outbound/SplunkOutboundChannelAdapterTests.java @@ -15,12 +15,12 @@ */ package org.springframework.integration.splunk.outbound; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import junit.framework.Assert; +import static org.mockito.Mockito.*; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; + import org.springframework.integration.splunk.support.SplunkExecutor; import org.springframework.messaging.Message; diff --git a/src/test/java/org/springframework/integration/splunk/support/SplunkDataReaderTests.java b/src/test/java/org/springframework/integration/splunk/support/SplunkDataReaderTests.java index a7abe7b..3249b1a 100644 --- a/src/test/java/org/springframework/integration/splunk/support/SplunkDataReaderTests.java +++ b/src/test/java/org/springframework/integration/splunk/support/SplunkDataReaderTests.java @@ -15,24 +15,24 @@ */ package org.springframework.integration.splunk.support; +import static org.mockito.Mockito.*; + import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Map; -import junit.framework.Assert; - -import org.junit.Before; -import org.junit.Test; -import static org.mockito.Mockito.*; -import org.springframework.core.io.ClassPathResource; -import org.springframework.integration.splunk.core.ServiceFactory; -import org.springframework.integration.splunk.event.SplunkEvent; - import com.splunk.Job; import com.splunk.JobCollection; import com.splunk.Service; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.integration.splunk.core.ServiceFactory; +import org.springframework.integration.splunk.event.SplunkEvent; /** * @author Jarred Li diff --git a/src/test/java/org/springframework/integration/splunk/support/SplunkExecutorTests.java b/src/test/java/org/springframework/integration/splunk/support/SplunkExecutorTests.java index f0736fa..3434b2f 100644 --- a/src/test/java/org/springframework/integration/splunk/support/SplunkExecutorTests.java +++ b/src/test/java/org/springframework/integration/splunk/support/SplunkExecutorTests.java @@ -15,17 +15,15 @@ */ package org.springframework.integration.splunk.support; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import java.util.ArrayList; import java.util.List; -import junit.framework.Assert; - +import org.junit.Assert; import org.junit.Before; import org.junit.Test; + import org.springframework.integration.splunk.core.DataReader; import org.springframework.integration.splunk.core.DataWriter; import org.springframework.integration.splunk.event.SplunkEvent;