From 3f167bb28e9ca7dc24286bd04d02b4b20d3c8347 Mon Sep 17 00:00:00 2001 From: Jarred Li Date: Wed, 26 Sep 2012 13:48:14 +0800 Subject: [PATCH] INTEXT-21 Add Splunk adapter For reference see: https://jira.springsource.org/browse/INTEXT-21 --- .gitignore | 8 + README.md | 113 + build.gradle | 288 +++ gradle.properties | 1 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 39860 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 ++ gradlew.bat | 90 + publish-maven.gradle | 60 + src/api/overview.html | 22 + src/dist/changelog.txt | 8 + src/dist/license.txt | 201 ++ src/dist/notice.txt | 21 + src/dist/readme.txt | 13 + .../SplunkInboundChannelAdapterParser.java | 103 + .../config/xml/SplunkNamespaceHandler.java | 37 + .../SplunkOutboundChannelAdapterParser.java | 97 + .../splunk/config/xml/SplunkParserUtils.java | 60 + .../splunk/config/xml/SplunkServerParser.java | 63 + .../splunk/config/xml/package-info.java | 4 + .../integration/splunk/core/Connection.java | 34 + .../splunk/core/ConnectionFactory.java | 29 + .../integration/splunk/core/DataReader.java | 32 + .../integration/splunk/core/DataWriter.java | 31 + .../integration/splunk/core/package-info.java | 4 + .../integration/splunk/entity/SplunkData.java | 2274 +++++++++++++++++ .../splunk/entity/SplunkServer.java | 117 + .../inbound/SplunkPollingChannelAdapter.java | 78 + .../splunk/inbound/package-info.java | 4 + .../SplunkOutboundChannelAdapter.java | 80 + .../splunk/outbound/package-info.java | 4 + .../support/ConnectionFactoryFactoryBean.java | 62 + .../splunk/support/IngestType.java | 41 + .../support/PoolingConnectionFactory.java | 134 + .../splunk/support/SearchMode.java | 33 + .../splunk/support/SplunkConnection.java | 87 + .../support/SplunkConnectionFactory.java | 46 + .../splunk/support/SplunkDataReader.java | 470 ++++ .../splunk/support/SplunkDataWriter.java | 202 ++ .../splunk/support/SplunkExecutor.java | 99 + src/main/resources/META-INF/spring.handlers | 1 + src/main/resources/META-INF/spring.schemas | 2 + src/main/resources/META-INF/spring.tooling | 4 + .../xml/spring-integration-splunk-1.0.xsd | 364 +++ .../config/xml/spring-integration-splunk.gif | Bin 0 -> 572 bytes src/reference/docbook/history.xml | 20 + src/reference/docbook/images/logo.png | Bin 0 -> 17393 bytes src/reference/docbook/index.xml | 64 + src/reference/docbook/resources.xml | 27 + src/reference/docbook/splunk.xml | 218 ++ src/reference/docbook/whats-new.xml | 17 + ...dChannelAdapterParserSavedSearchTests.java | 69 + ...plunkInboundChannelAdapterParserTests.java | 78 + ...tboundChannelAdapterParserStreamTests.java | 64 + ...lunkOutboundChannelAdapterParserTests.java | 65 + .../config/xml/SplunkServerParserTests.java | 56 + .../SplunkPollingChannelAdapterTests.java | 71 + .../SplunkOutboundChannelAdapterTests.java | 64 + .../ConnectionFactoryFactoryBeanTests.java | 88 + .../PoolingConnectionFactoryTests.java | 111 + .../splunk/support/SplunkDataReaderTests.java | 143 ++ .../splunk/support/SplunkDataWriterTests.java | 100 + .../splunk/support/SplunkExecutorTests.java | 90 + src/test/resources/log4j.properties | 5 + .../splunk/SplunkCommon-context.xml | 19 + ...oundChannelAdapterParserCommon-context.xml | 21 + ...lAdapterParserSavedSearchTests-context.xml | 25 + ...boundChannelAdapterParserTests-context.xml | 24 + ...hannelAdapterParserStreamTests-context.xml | 24 + ...boundChannelAdapterParserTests-context.xml | 24 + .../xml/SplunkServerParserTests-context.xml | 17 + src/test/resources/splunk-data.xml | 236 ++ 72 files changed, 7331 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 publish-maven.gradle create mode 100644 src/api/overview.html create mode 100644 src/dist/changelog.txt create mode 100644 src/dist/license.txt create mode 100644 src/dist/notice.txt create mode 100644 src/dist/readme.txt create mode 100644 src/main/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParser.java create mode 100644 src/main/java/org/springframework/integration/splunk/config/xml/SplunkNamespaceHandler.java create mode 100644 src/main/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParser.java create mode 100644 src/main/java/org/springframework/integration/splunk/config/xml/SplunkParserUtils.java create mode 100644 src/main/java/org/springframework/integration/splunk/config/xml/SplunkServerParser.java create mode 100644 src/main/java/org/springframework/integration/splunk/config/xml/package-info.java create mode 100644 src/main/java/org/springframework/integration/splunk/core/Connection.java create mode 100644 src/main/java/org/springframework/integration/splunk/core/ConnectionFactory.java create mode 100644 src/main/java/org/springframework/integration/splunk/core/DataReader.java create mode 100644 src/main/java/org/springframework/integration/splunk/core/DataWriter.java create mode 100644 src/main/java/org/springframework/integration/splunk/core/package-info.java create mode 100644 src/main/java/org/springframework/integration/splunk/entity/SplunkData.java create mode 100644 src/main/java/org/springframework/integration/splunk/entity/SplunkServer.java create mode 100644 src/main/java/org/springframework/integration/splunk/inbound/SplunkPollingChannelAdapter.java create mode 100644 src/main/java/org/springframework/integration/splunk/inbound/package-info.java create mode 100644 src/main/java/org/springframework/integration/splunk/outbound/SplunkOutboundChannelAdapter.java create mode 100644 src/main/java/org/springframework/integration/splunk/outbound/package-info.java create mode 100644 src/main/java/org/springframework/integration/splunk/support/ConnectionFactoryFactoryBean.java create mode 100644 src/main/java/org/springframework/integration/splunk/support/IngestType.java create mode 100644 src/main/java/org/springframework/integration/splunk/support/PoolingConnectionFactory.java create mode 100644 src/main/java/org/springframework/integration/splunk/support/SearchMode.java create mode 100644 src/main/java/org/springframework/integration/splunk/support/SplunkConnection.java create mode 100644 src/main/java/org/springframework/integration/splunk/support/SplunkConnectionFactory.java create mode 100644 src/main/java/org/springframework/integration/splunk/support/SplunkDataReader.java create mode 100644 src/main/java/org/springframework/integration/splunk/support/SplunkDataWriter.java create mode 100644 src/main/java/org/springframework/integration/splunk/support/SplunkExecutor.java create mode 100644 src/main/resources/META-INF/spring.handlers create mode 100644 src/main/resources/META-INF/spring.schemas create mode 100644 src/main/resources/META-INF/spring.tooling create mode 100644 src/main/resources/org/springframework/integration/splunk/config/xml/spring-integration-splunk-1.0.xsd create mode 100644 src/main/resources/org/springframework/integration/splunk/config/xml/spring-integration-splunk.gif create mode 100644 src/reference/docbook/history.xml create mode 100644 src/reference/docbook/images/logo.png create mode 100644 src/reference/docbook/index.xml create mode 100644 src/reference/docbook/resources.xml create mode 100644 src/reference/docbook/splunk.xml create mode 100644 src/reference/docbook/whats-new.xml create mode 100644 src/test/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserSavedSearchTests.java create mode 100644 src/test/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserTests.java create mode 100644 src/test/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserStreamTests.java create mode 100644 src/test/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserTests.java create mode 100644 src/test/java/org/springframework/integration/splunk/config/xml/SplunkServerParserTests.java create mode 100644 src/test/java/org/springframework/integration/splunk/inbound/SplunkPollingChannelAdapterTests.java create mode 100644 src/test/java/org/springframework/integration/splunk/outbound/SplunkOutboundChannelAdapterTests.java create mode 100644 src/test/java/org/springframework/integration/splunk/support/ConnectionFactoryFactoryBeanTests.java create mode 100644 src/test/java/org/springframework/integration/splunk/support/PoolingConnectionFactoryTests.java create mode 100644 src/test/java/org/springframework/integration/splunk/support/SplunkDataReaderTests.java create mode 100644 src/test/java/org/springframework/integration/splunk/support/SplunkDataWriterTests.java create mode 100644 src/test/java/org/springframework/integration/splunk/support/SplunkExecutorTests.java create mode 100644 src/test/resources/log4j.properties create mode 100644 src/test/resources/org/springframework/integration/splunk/SplunkCommon-context.xml create mode 100644 src/test/resources/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserCommon-context.xml create mode 100644 src/test/resources/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserSavedSearchTests-context.xml create mode 100644 src/test/resources/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserTests-context.xml create mode 100644 src/test/resources/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserStreamTests-context.xml create mode 100644 src/test/resources/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserTests-context.xml create mode 100644 src/test/resources/org/springframework/integration/splunk/config/xml/SplunkServerParserTests-context.xml create mode 100644 src/test/resources/splunk-data.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0c7fdb9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.classpath +.project +.settings/ +.gradle +build +target/ +bin/ +derby.log diff --git a/README.md b/README.md new file mode 100644 index 0000000..511b4c0 --- /dev/null +++ b/README.md @@ -0,0 +1,113 @@ +Spring Integration Splunk Adapter +================================================= + +The SI adapter includes Outbound Channel Adapter and Inbound Channel Adapter. + +Inbound channel adapter : +----------------------------------------------------------------------------- +Inbound channel adapter is used to get data out of Splunk and put into +Spring Integration's channel. There are 5 ways to get data out of Splunk: +* Blocking +* Non blocking +* Saved search +* Realtime +* Export + + +### Blocking search: +~~~~~xml + + + +~~~~~ + +### Non blocking search: +~~~~~xml + + + +~~~~~ + +### Saved search: +~~~~~xml + + + +~~~~~ + +### Realtime search: +~~~~~xml + + + +~~~~~ + +### Export: +~~~~~xml + + + +~~~~~ + +Outbound channel adapter: +---------------------------------------------------------------------------------------------- +Outbound channel adapter is used to put data into Splunk from +channels in Spring Integration. There are 3 kinds of method to put data +* REST(submit) +* stream +* tcp + +### Submit: +~~~~~xml + + + +~~~~~ + +### Stream: +~~~~~xml + + + +~~~~~ + +### tcp +~~~~~xml + + + +~~~~~ + + +Development +----------------- +### To build: + + ./gradlew build + +### To generate Eclipse metadata (.classpath and .project files), do the following: + + ./gradlew eclipse + diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..8123c9d --- /dev/null +++ b/build.gradle @@ -0,0 +1,288 @@ +description = 'Spring Integration Splunk Adapter' + +buildscript { + repositories { + maven { url 'http://repo.springsource.org/plugins-snapshot' } + } + dependencies { + classpath 'org.springframework.build.gradle:docbook-reference-plugin:0.1.5' + } +} + +apply plugin: 'java' +apply from: "${rootProject.projectDir}/publish-maven.gradle" +apply plugin: 'eclipse' +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 +} + +sourceCompatibility=1.5 +targetCompatibility=1.5 + +ext { + cglibVersion = '2.2' + junitVersion = '4.8.2' + log4jVersion = '1.2.12' + mockitoVersion = '1.9.0' + springVersion = '3.1.2.RELEASE' + springIntegrationVersion = '2.1.2.RELEASE' + commonsLangVersion = '2.6' + commonsPoolVersion = '1.6' + splunkVersion = '0.8.0' +} + +// See http://www.gradle.org/docs/current/userguide/dependency_management.html#sub:configurations +// and http://www.gradle.org/docs/current/dsl/org.gradle.api.artifacts.ConfigurationContainer.html +configurations { + jacoco //Configuration Group used by Sonar to provide Code Coverage using JaCoCo +} + +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 "org.springframework.integration:spring-integration-core:$springIntegrationVersion" + compile "commons-lang:commons-lang:$commonsLangVersion" + compile "commons-pool:commons-pool:$commonsPoolVersion" + + testCompile "org.mockito:mockito-all:$mockitoVersion" + testCompile "org.springframework:spring-test:$springVersion" + testCompile "cglib:cglib-nodep:$cglibVersion" + testCompile "junit:junit-dep:$junitVersion" + testCompile "log4j:log4j:$log4jVersion" + testCompile "org.springframework.integration:spring-integration-stream:$springIntegrationVersion" + jacoco group: "org.jacoco", name: "org.jacoco.agent", version: "0.5.6.201201232323", classifier: "runtime" +} + + +eclipse { + project { + natures += 'org.springframework.ide.eclipse.core.springnature' + } +} + +sourceSets { + test { + resources { + srcDirs = ['src/test/resources', 'src/test/java'] + } + } +} + + + +// enable all compiler warnings; individual projects may customize further +ext.xLintArg = '-Xlint:all' +[compileJava, compileTestJava]*.options*.compilerArgs = [xLintArg] + +test { + // suppress all console output during testing unless running `gradle -i` + logging.captureStandardOutput(LogLevel.INFO) + jvmArgs "-javaagent:${configurations.jacoco.asPath}=destfile=${buildDir}/jacoco.exec,includes=*" +} + +task sourcesJar(type: Jar) { + classifier = 'sources' + from sourceSets.main.allJava +} + +task javadocJar(type: Jar) { + classifier = 'javadoc' + from javadoc +} + +artifacts { + archives sourcesJar + archives javadocJar +} + +apply plugin: 'docbook-reference' + +reference { + sourceDir = file('src/reference/docbook') +} + +apply plugin: 'sonar' + +sonar { + + if (rootProject.hasProperty('sonarHostUrl')) { + server.url = rootProject.sonarHostUrl + } + + database { + if (rootProject.hasProperty('sonarJdbcUrl')) { + url = rootProject.sonarJdbcUrl + } + if (rootProject.hasProperty('sonarJdbcDriver')) { + driverClassName = rootProject.sonarJdbcDriver + } + if (rootProject.hasProperty('sonarJdbcUsername')) { + username = rootProject.sonarJdbcUsername + } + if (rootProject.hasProperty('sonarJdbcPassword')) { + password = rootProject.sonarJdbcPassword + } + } + + project { + dynamicAnalysis = "reuseReports" + withProjectProperties { props -> + props["sonar.core.codeCoveragePlugin"] = "jacoco" + props["sonar.jacoco.reportPath"] = "${buildDir.name}/jacoco.exec" + } + } + + logger.info("Sonar parameters used: server.url='${server.url}'; database.url='${database.url}'; database.driverClassName='${database.driverClassName}'; database.username='${database.username}'") +} + +task api(type: Javadoc) { + group = 'Documentation' + description = 'Generates aggregated Javadoc API documentation.' + title = "${rootProject.description} ${version} API" + options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED + options.author = true + options.header = rootProject.description + options.overview = 'src/api/overview.html' + source subprojects.collect { project -> + project.sourceSets.main.allJava + } + destinationDir = new File(buildDir, "api") + classpath = files(subprojects.collect { project -> + project.sourceSets.main.compileClasspath + }) +} + +task schemaZip(type: Zip) { + group = 'Distribution' + classifier = 'schema' + description = "Builds -${classifier} archive containing all " + + "XSDs for deployment at static.springframework.org/schema." + + subprojects.each { subproject -> + def Properties schemas = new Properties(); + def shortName = subproject.name.replaceFirst("${rootProject.name}-", '') + if (subproject.name.endsWith("-core")) { + shortName = '' + } + + subproject.sourceSets.main.resources.find { + it.path.endsWith('META-INF/spring.schemas') + }?.withInputStream { schemas.load(it) } + + for (def key : schemas.keySet()) { + File xsdFile = subproject.sourceSets.main.resources.find { + it.path.endsWith(schemas.get(key)) + } + assert xsdFile != null + into ("integration/${shortName}") { + from xsdFile.path + } + } + } +} + +task docsZip(type: Zip) { + group = 'Distribution' + classifier = 'docs' + description = "Builds -${classifier} archive containing api and reference " + + "for deployment at static.springframework.org/spring-integration/docs." + + from('src/dist') { + include 'changelog.txt' + } + + from (api) { + into 'api' + } + + from (reference) { + into 'reference' + } +} + +task distZip(type: Zip, dependsOn: [docsZip, schemaZip]) { + group = 'Distribution' + classifier = 'dist' + description = "Builds -${classifier} archive, containing all jars and docs, " + + "suitable for community download page." + + ext.baseDir = "${project.name}-${project.version}"; + + from('src/dist') { + include 'readme.txt' + include 'license.txt' + include 'notice.txt' + into "${baseDir}" + } + + from(zipTree(docsZip.archivePath)) { + into "${baseDir}/docs" + } + + from(zipTree(schemaZip.archivePath)) { + into "${baseDir}/schema" + } + + subprojects.each { subproject -> + into ("${baseDir}/libs") { + from subproject.jar + from subproject.sourcesJar + from subproject.javadocJar + } + } +} + +// Create an optional "with dependencies" distribution. +// Not published by default; only for use when building from source. +task depsZip(type: Zip, dependsOn: distZip) { zipTask -> + group = 'Distribution' + classifier = 'dist-with-deps' + description = "Builds -${classifier} archive, containing everything " + + "in the -${distZip.classifier} archive plus all dependencies." + + from zipTree(distZip.archivePath) + + gradle.taskGraph.whenReady { taskGraph -> + if (taskGraph.hasTask(":${zipTask.name}")) { + def projectNames = rootProject.subprojects*.name + def artifacts = new HashSet() + subprojects.each { subproject -> + subproject.configurations.runtime.resolvedConfiguration.resolvedArtifacts.each { artifact -> + def dependency = artifact.moduleVersion.id + if (!projectNames.contains(dependency.name)) { + artifacts << artifact.file + } + } + } + + zipTask.from(artifacts) { + into "${distZip.baseDir}/deps" + } + } + } +} + +artifacts { + archives distZip + archives docsZip + archives schemaZip +} + +task dist(dependsOn: assemble) { + group = 'Distribution' + description = 'Builds -dist, -docs and -schema distribution archives.' +} + +task wrapper(type: Wrapper) { + description = 'Generates gradlew[.bat] scripts' + gradleVersion = '1.2' +} + +defaultTasks 'build' diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..5364470 --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +version=0.5.0.BUILD-SNAPSHOT diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e3b3376e6002f9d44543761c8d3dcd199eff1d82 GIT binary patch literal 39860 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%0A3!wsG4uToG`VrIW5Id|4fPyx?=aMz8G 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" +APP_HOME="`pwd -P`" +cd "$SAVED" + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query businessSystem maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/publish-maven.gradle b/publish-maven.gradle new file mode 100644 index 0000000..d61474b --- /dev/null +++ b/publish-maven.gradle @@ -0,0 +1,60 @@ +apply plugin: 'maven' + +ext.optionalDeps = [] +ext.providedDeps = [] +ext.optional = { optionalDeps << it } +ext.provided = { providedDeps << it } + +install { + repositories.mavenInstaller { + customizePom(pom, project) + } +} + +def customizePom(pom, gradleProject) { + pom.whenConfigured { generatedPom -> + // respect 'optional' and 'provided' dependencies + gradleProject.optionalDeps.each { dep -> + generatedPom.dependencies.find { it.artifactId == dep.name }?.optional = true + } + gradleProject.providedDeps.each { dep -> + generatedPom.dependencies.find { it.artifactId == dep.name }?.scope = 'provided' + } + + // eliminate test-scoped dependencies (no need in maven central poms) + generatedPom.dependencies.removeAll { dep -> + dep.scope == 'test' + } + + // add all items necessary for maven central publication + generatedPom.project { + name = gradleProject.description + description = gradleProject.description + url = 'https://github.com/SpringSource/spring-integration-extensions' + organization { + name = 'SpringSource' + url = 'http://springsource.org' + } + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution 'repo' + } + } + scm { + url = 'https://github.com/SpringSource/spring-integration-extensions' + connection = 'scm:git:git://github.com/SpringSource/spring-integration-extensions' + developerConnection = 'scm:git:git://github.com/SpringSource/spring-integration-extensions' + } + + developers { + developer { + id = 'Jarred' + name = 'Jarred Li' + email = 'leejianwei@126.com' + } + } + } + } +} diff --git a/src/api/overview.html b/src/api/overview.html new file mode 100644 index 0000000..fb0198b --- /dev/null +++ b/src/api/overview.html @@ -0,0 +1,22 @@ + + +This document is the API specification for Spring Integration +
+
+

+ For further API reference and developer documentation, see the + Spring + Integration reference documentation. + That documentation contains more detailed, developer-targeted + descriptions, with conceptual overviews, definitions of terms, + workarounds, and working code examples. +

+ +

+ If you are interested in commercial training, consultancy, and + support for Spring Integration, please visit + http://www.springsource.com +

+
+ + diff --git a/src/dist/changelog.txt b/src/dist/changelog.txt new file mode 100644 index 0000000..c78641e --- /dev/null +++ b/src/dist/changelog.txt @@ -0,0 +1,8 @@ +Spring Integration Splunk Adapter CHANGELOG +========================================= + +Features in version 1.0.0 + +1. Inbound channel adapter with 5 different ways to search data: bloking, normal(non-blocking), realtime, export, saved search. + +2. Outbound channel adapter with 3 ways to push event data: Stream, tcp, REST diff --git a/src/dist/license.txt b/src/dist/license.txt new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/src/dist/license.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/src/dist/notice.txt b/src/dist/notice.txt new file mode 100644 index 0000000..f62045a --- /dev/null +++ b/src/dist/notice.txt @@ -0,0 +1,21 @@ + ======================================================================== + == NOTICE file corresponding to section 4 d of the Apache License, == + == Version 2.0, in this case for the Spring Integration distribution. == + ======================================================================== + + This product includes software developed by + the Apache Software Foundation (http://www.apache.org). + + The end-user documentation included with a redistribution, if any, + must include the following acknowledgement: + + "This product includes software developed by the Spring Framework + Project (http://www.springframework.org)." + + Alternatively, this acknowledgement may appear in the software itself, + if and wherever such third-party acknowledgements normally appear. + + The names "Spring", "Spring Framework", and "Spring Integration" must + not be used to endorse or promote products derived from this software + without prior written permission. For written permission, please contact + enquiries@springsource.com. diff --git a/src/dist/readme.txt b/src/dist/readme.txt new file mode 100644 index 0000000..886e33e --- /dev/null +++ b/src/dist/readme.txt @@ -0,0 +1,13 @@ +Spring Integration Splunk Adapter +----------------------------------- + +To find out what has changed since any earlier releases, see 'changelog.txt'. + +Please consult the documentation located within the 'docs/reference' directory +of this release and also visit the official Spring Integration home at +http://www.springsource.org/spring-integration + +There you will find links to the forum, issue tracker, and several other resources. + +See https://github.com/SpringSource/spring-integration#readme for additional +information including instructions on building from source. 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 new file mode 100644 index 0000000..c25d161 --- /dev/null +++ b/src/main/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParser.java @@ -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(); + } + +} diff --git a/src/main/java/org/springframework/integration/splunk/config/xml/SplunkNamespaceHandler.java b/src/main/java/org/springframework/integration/splunk/config/xml/SplunkNamespaceHandler.java new file mode 100644 index 0000000..c9789e9 --- /dev/null +++ b/src/main/java/org/springframework/integration/splunk/config/xml/SplunkNamespaceHandler.java @@ -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()); + } +} 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 new file mode 100644 index 0000000..634e052 --- /dev/null +++ b/src/main/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParser.java @@ -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(); + + } + +} diff --git a/src/main/java/org/springframework/integration/splunk/config/xml/SplunkParserUtils.java b/src/main/java/org/springframework/integration/splunk/config/xml/SplunkParserUtils.java new file mode 100644 index 0000000..53cdc7e --- /dev/null +++ b/src/main/java/org/springframework/integration/splunk/config/xml/SplunkParserUtils.java @@ -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; + + } + +} 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 new file mode 100644 index 0000000..cca86e0 --- /dev/null +++ b/src/main/java/org/springframework/integration/splunk/config/xml/SplunkServerParser.java @@ -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: + *
+ * {@code
+ * 
+ * }
+ *
+ * @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");
+
+	}
+
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/config/xml/package-info.java b/src/main/java/org/springframework/integration/splunk/config/xml/package-info.java
new file mode 100644
index 0000000..696859c
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/config/xml/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Provides parser classes to provide Xml namespace support for the Splunk components.
+ */
+package org.springframework.integration.splunk.config.xml;
diff --git a/src/main/java/org/springframework/integration/splunk/core/Connection.java b/src/main/java/org/springframework/integration/splunk/core/Connection.java
new file mode 100644
index 0000000..eebcffe
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/core/Connection.java
@@ -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 getTarget();
+
+	void close();
+
+	boolean isOpen();
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/core/ConnectionFactory.java b/src/main/java/org/springframework/integration/splunk/core/ConnectionFactory.java
new file mode 100644
index 0000000..d69ccdc
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/core/ConnectionFactory.java
@@ -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 Connection
+ *
+ * @author Jarred Li
+ * @since 1.0
+ *
+ */
+public interface ConnectionFactory {
+
+	Connection getConnection() throws Exception;
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/core/DataReader.java b/src/main/java/org/springframework/integration/splunk/core/DataReader.java
new file mode 100644
index 0000000..aef7b68
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/core/DataReader.java
@@ -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 search() throws Exception;
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/core/DataWriter.java b/src/main/java/org/springframework/integration/splunk/core/DataWriter.java
new file mode 100644
index 0000000..69154b5
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/core/DataWriter.java
@@ -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;
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/core/package-info.java b/src/main/java/org/springframework/integration/splunk/core/package-info.java
new file mode 100644
index 0000000..158ac78
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/core/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Provides core classes of the Splunk module.
+ */
+package org.springframework.integration.splunk.core;
diff --git a/src/main/java/org/springframework/integration/splunk/entity/SplunkData.java b/src/main/java/org/springframework/integration/splunk/entity/SplunkData.java
new file mode 100644
index 0000000..782f806
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/entity/SplunkData.java
@@ -0,0 +1,2274 @@
+/*
+ * 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;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+
+import org.apache.commons.lang.time.FastDateFormat;
+
+/**
+ * Splunk data entity
+ *
+ * @author Jarred Li
+ * @author Damien Dallimore damien@dtdsoftware.com
+ * @since 1.0
+ *
+ */
+public class SplunkData implements Serializable {
+
+	private static final long serialVersionUID = -7369254824093658523L;
+
+
+	private Map eventData;
+
+	/**
+	 * Contents of the event message
+	 */
+	private StringBuffer eventMessage;
+
+	/**
+	 * Whether or not to put quotes around values
+	 */
+	private boolean quoteValues = true;
+
+	/**
+	 * Whether or not to add a date to the event string
+	 */
+	private boolean useInternalDate = true;
+
+	/**
+	 * default key value delimiter
+	 */
+	private static final String KVDELIM = "=";
+	/**
+	 * default pair delimiter
+	 */
+	private static final String PAIRDELIM = " ";
+	/**
+	 * default quote char
+	 */
+	private static final char QUOTE = '"';
+	/**
+	 * default date format is using internal generated date
+	 */
+	private static final String DATEFORMATPATTERN = "yyyy-MM-dd HH:mm:ss:SSSZ";
+	/**
+	 * Date Formatter instance
+	 */
+	private static FastDateFormat DATEFORMATTER = FastDateFormat.getInstance(DATEFORMATPATTERN);
+
+	/**
+	 * Event prefix fields
+	 */
+	private static final String PREFIX_NAME = "name";
+	private static final String PREFIX_EVENT_ID = "event_id";
+
+	/**
+	 * Java Throwable type fields
+	 */
+	private static final String THROWABLE_CLASS = "throwable_class";
+	private static final String THROWABLE_MESSAGE = "throwable_message";
+	private static final String THROWABLE_STACKTRACE_ELEMENTS = "stacktrace_elements";
+
+	/**
+	 * Splunk Common Information Model(CIM) Fields
+	 */
+
+	// ------------------
+	// Account management
+	// ------------------
+
+	/**
+	 * The domain containing the user that is affected by the account management
+	 * event.
+	 */
+	public static String AC_MANAGEMENT_DEST_NT_DOMAIN = "dest_nt_domain";
+	/**
+	 * Description of the account management change performed.
+	 */
+	public static String AC_MANAGEMENT_SIGNATURE = "signature";
+	/**
+	 * The NT source of the destination. In the case of an account management
+	 * event, this is the domain that contains the user that generated the
+	 * event.
+	 */
+	public static String AC_MANAGEMENT_SRC_NT_DOMAIN = "src_nt_domain";
+
+	// ----------------------------------
+	// Authentication - Access protection
+	// ----------------------------------
+
+	/**
+	 * The action performed on the resource. success, failure
+	 */
+	public static String AUTH_ACTION = "action";
+	/**
+	 * The application involved in the event (such as ssh, spunk, win:local).
+	 */
+	public static String AUTH_APP = "app";
+	/**
+	 * The target involved in the authentication. If your field is named
+	 * dest_host, dest_ip, dest_ipv6, or dest_nt_host you can alias it as dest
+	 * to make it CIM-compliant.
+	 */
+	public static String AUTH_DEST = "dest";
+	/**
+	 * The source involved in the authentication. In the case of endpoint
+	 * protection authentication the src is the client. If your field is named
+	 * src_host, src_ip, src_ipv6, or src_nt_host you can alias it as src to
+	 * make it CIM-compliant.. It is required for all events dealing with
+	 * endpoint protection (Authentication, change analysis, malware, system
+	 * center, and update). Note: Do not confuse this with the event source or
+	 * sourcetype fields.
+	 */
+	public static String AUTH_SRC = "src";
+	/**
+	 * In privilege escalation events, src_user represents the user who
+	 * initiated the privilege escalation.
+	 */
+	public static String AUTH_SRC_USER = "src_user";
+	/**
+	 * The name of the user involved in the event, or who initiated the event.
+	 * For authentication privilege escalation events this should represent the
+	 * user targeted by the escalation.
+	 */
+	public static String AUTH_USER = "user";
+
+	// ----------------------------------
+	// Change analysis - Endpoint protection
+	// ----------------------------------
+
+	/**
+	 * The action performed on the resource.
+	 */
+	public static String CHANGE_ENDPOINT_PROTECTION_ACTION = "action";
+	/**
+	 * The type of change discovered in the change analysis event.
+	 */
+	public static String CHANGE_ENDPOINT_PROTECTION_CHANGE_TYPE = "change_type";
+	/**
+	 * The host that was affected by the change. If your field is named
+	 * dest_host,dest_ip,dest_ipv6, or dest_nt_host you can alias it as dest to
+	 * make it CIM-compliant.
+	 */
+	public static String CHANGE_ENDPOINT_PROTECTION_DEST = "dest";
+	/**
+	 * The hash signature of the modified resource.
+	 */
+	public static String CHANGE_ENDPOINT_PROTECTION_HASH = "hash";
+	/**
+	 * The group ID of the modified resource.
+	 */
+	public static String CHANGE_ENDPOINT_PROTECTION_GID = "gid";
+	/**
+	 * Indicates whether or not the modified resource is a directory.
+	 */
+	public static String CHANGE_ENDPOINT_PROTECTION_ISDR = "isdr";
+	/**
+	 * The permissions mode of the modified resource.
+	 */
+	public static String CHANGE_ENDPOINT_PROTECTION_MODE = "mode";
+	/**
+	 * The modification time of the modified resource.
+	 */
+	public static String CHANGE_ENDPOINT_PROTECTION_MODTIME = "modtime";
+	/**
+	 * The file path of the modified resource.
+	 */
+	public static String CHANGE_ENDPOINT_PROTECTION_PATH = "path";
+	/**
+	 * The size of the modified resource.
+	 */
+	public static String CHANGE_ENDPOINT_PROTECTION_SIZE = "size";
+	/**
+	 * The user ID of the modified resource.
+	 */
+	public static String CHANGE_ENDPOINT_PROTECTION_UID = "uid";
+
+	// ----------------------------------
+	// Change analysis - Network protection
+	// ----------------------------------
+
+	/**
+	 * The type of change observed.
+	 */
+	public static String CHANGE_NETWORK_PROTECTION_ACTION = "action";
+	/**
+	 * The command that initiated the change.
+	 */
+	public static String CHANGE_NETWORK_PROTECTION_COMMAND = "command";
+	/**
+	 * The device that is directly affected by the change.
+	 */
+	public static String CHANGE_NETWORK_PROTECTION_DVC = "dvc";
+	/**
+	 * The user that initiated the change.
+	 */
+	public static String CHANGE_NETWORK_PROTECTION_USER = "user";
+
+	// ----------------------------------
+	// Common event fields
+	// ----------------------------------
+
+	/**
+	 * A device-specific classification provided as part of the event.
+	 */
+	public static String COMMON_CATEGORY = "category";
+	/**
+	 * A device-specific classification provided as part of the event.
+	 */
+	public static String COMMON_COUNT = "count";
+	/**
+	 * The free-form description of a particular event.
+	 */
+	public static String COMMON_DESC = "desc";
+	/**
+	 * The name of a given DHCP pool on a DHCP server.
+	 */
+	public static String COMMON_DHCP_POOL = "dhcp_pool";
+	/**
+	 * The amount of time the event lasted.
+	 */
+	public static String COMMON_DURATION = "duration";
+	/**
+	 * The fully qualified domain name of the device transmitting or recording
+	 * the log record.
+	 */
+	public static String COMMON_DVC_HOST = "dvc_host";
+	/**
+	 * The IPv4 address of the device reporting the event.
+	 */
+	public static String COMMON_DVC_IP = "dvc_ip";
+	/**
+	 * The IPv6 address of the device reporting the event.
+	 */
+	public static String COMMON_DVC_IP6 = "dvc_ip6";
+	/**
+	 * The free-form description of the device's physical location.
+	 */
+	public static String COMMON_DVC_LOCATION = "dvc_location";
+	/**
+	 * The MAC (layer 2) address of the device reporting the event.
+	 */
+	public static String COMMON_DVC_MAC = "dvc_mac";
+	/**
+	 * The Windows NT domain of the device recording or transmitting the event.
+	 */
+	public static String COMMON_DVC_NT_DOMAIN = "dvc_nt_domain";
+	/**
+	 * The Windows NT host name of the device recording or transmitting the
+	 * event.
+	 */
+	public static String COMMON_DVC_NT_HOST = "dvc_nt_host";
+	/**
+	 * Time at which the device recorded the event.
+	 */
+	public static String COMMON_DVC_TIME = "dvc_time";
+	/**
+	 * The event's specified end time.
+	 */
+	public static String COMMON_END_TIME = "end_time";
+	/**
+	 * A unique identifier that identifies the event. This is unique to the
+	 * reporting device.
+	 */
+	public static String COMMON_EVENT_ID = "event_id";
+	/**
+	 * The length of the datagram, event, message, or packet.
+	 */
+	public static String COMMON_LENGTH = "length";
+	/**
+	 * The log-level that was set on the device and recorded in the event.
+	 */
+	public static String COMMON_LOG_LEVEL = "log_level";
+	/**
+	 * The name of the event as reported by the device. The name should not
+	 * contain information that's already being parsed into other fields from
+	 * the event, such as IP addresses.
+	 */
+	public static String COMMON_NAME = "name";
+	/**
+	 * An integer assigned by the device operating system to the process
+	 * creating the record.
+	 */
+	public static String COMMON_PID = "pid";
+	/**
+	 * An environment-specific assessment of the event's importance, based on
+	 * elements such as event severity, business function of the affected
+	 * system, or other locally defined variables.
+	 */
+	public static String COMMON_PRIORITY = "priority";
+	/**
+	 * The product that generated the event.
+	 */
+	public static String COMMON_PRODUCT = "product";
+	/**
+	 * The version of the product that generated the event.
+	 */
+	public static String COMMON_PRODUCT_VERSION = "product_version";
+	/**
+	 * The result root cause, such as connection refused, timeout, crash, and so
+	 * on.
+	 */
+	public static String COMMON_REASON = "reason";
+	/**
+	 * The action result. Often is a binary choice: succeeded and failed,
+	 * allowed and denied, and so on.
+	 */
+	public static String COMMON_RESULT = "result";
+	/**
+	 * The severity (or priority) of an event as reported by the originating
+	 * device.
+	 */
+	public static String COMMON_SEVERITY = "severity";
+	/**
+	 * The event's specified start time.
+	 */
+	public static String COMMON_START_TIME = "start_time";
+	/**
+	 * The transaction identifier.
+	 */
+	public static String COMMON_TRANSACTION_ID = "transaction_id";
+	/**
+	 * A uniform record locator (a web address, in other words) included in a
+	 * record.
+	 */
+	public static String COMMON_URL = "url";
+	/**
+	 * The vendor who made the product that generated the event.
+	 */
+	public static String COMMON_VENDOR = "vendor";
+
+	// ----------------------------------
+	// DNS protocol
+	// ----------------------------------
+
+	/**
+	 * The DNS domain that has been queried.
+	 */
+	public static String DNS_DEST_DOMAIN = "dest_domain";
+	/**
+	 * The remote DNS resource record being acted upon.
+	 */
+	public static String DNS_DEST_RECORD = "dest_record";
+	/**
+	 * The DNS zone that is being received by the slave as part of a zone
+	 * transfer.
+	 */
+	public static String DNS_DEST_ZONE = "dest_zone";
+	/**
+	 * The DNS resource record class.
+	 */
+	public static String DNS_RECORD_CLASS = "record_class";
+	/**
+	 * The DNS resource record type.
+	 *
+	 * @see see
+	 *      this Wikipedia article on DNS record types
+	 */
+	public static String DNS_RECORD_TYPE = "record_type";
+	/**
+	 * The local DNS domain that is being queried.
+	 */
+	public static String DNS_SRC_DOMAIN = "src_domain";
+	/**
+	 * The local DNS resource record being acted upon.
+	 */
+	public static String DNS_SRC_RECORD = "src_record";
+	/**
+	 * The DNS zone that is being transferred by the master as part of a zone
+	 * transfer.
+	 */
+	public static String DNS_SRC_ZONE = "src_zone";
+
+	// ----------------------------------
+	// Email tracking
+	// ----------------------------------
+
+	/**
+	 * The person to whom an email is sent.
+	 */
+	public static String EMAIL_RECIPIENT = "recipient";
+	/**
+	 * The person responsible for sending an email.
+	 */
+	public static String EMAIL_SENDER = "sender";
+	/**
+	 * The email subject line.
+	 */
+	public static String EMAIL_SUBJECT = "subject";
+
+	// ----------------------------------
+	// File management
+	// ----------------------------------
+
+	/**
+	 * The time the file (the object of the event) was accessed.
+	 */
+	public static String FILE_ACCESS_TIME = "file_access_time";
+	/**
+	 * The time the file (the object of the event) was created.
+	 */
+	public static String FILE_CREATE_TIME = "file_create_time";
+	/**
+	 * A cryptographic identifier assigned to the file object affected by the
+	 * event.
+	 */
+	public static String FILE_HASH = "file_hash";
+	/**
+	 * The time the file (the object of the event) was altered.
+	 */
+	public static String FILE_MODIFY_TIME = "file_modify_time";
+	/**
+	 * The name of the file that is the object of the event (without location
+	 * information related to local file or directory structure).
+	 */
+	public static String FILE_NAME = "file_name";
+	/**
+	 * The location of the file that is the object of the event, in terms of
+	 * local file and directory structure.
+	 */
+	public static String FILE_PATH = "file_path";
+	/**
+	 * Access controls associated with the file affected by the event.
+	 */
+	public static String FILE_PERMISSION = "file_permission";
+	/**
+	 * The size of the file that is the object of the event. Indicate whether
+	 * Bytes, KB, MB, GB.
+	 */
+	public static String FILE_SIZE = "file_size";
+
+	// ----------------------------------
+	// Intrusion detection
+	// ----------------------------------
+
+	/**
+	 * The category of the triggered signature.
+	 */
+	public static String INTRUSION_DETECTION_CATEGORY = "category";
+	/**
+	 * The destination of the attack detected by the intrusion detection system
+	 * (IDS). If your field is named dest_host, dest_ip, dest_ipv6, or
+	 * dest_nt_host you can alias it as dest to make it CIM-compliant.
+	 */
+	public static String INTRUSION_DETECTION_DEST = "dest";
+	/**
+	 * The device that detected the intrusion event.
+	 */
+	public static String INTRUSION_DETECTION_DVC = "dvc";
+	/**
+	 * The type of IDS that generated the event.
+	 */
+	public static String INTRUSION_DETECTION_IDS_TYPE = "ids_type";
+	/**
+	 * The product name of the vendor technology generating network protection
+	 * data, such as IDP, Providentia, and ASA.
+	 *
+	 * Note: Required for all events dealing with network protection (Change
+	 * analysis, proxy, malware, intrusion detection, packet filtering, and
+	 * vulnerability).
+	 */
+	public static String INTRUSION_DETECTION_PRODUCT = "product";
+	/**
+	 * The severity of the network protection event (such as critical, high,
+	 * medium, low, or informational).
+	 *
+	 * Note: This field is a string. Please use a severity_id field for severity
+	 * ID fields that are integer data types.
+	 */
+	public static String INTRUSION_DETECTION_SEVERITY = "severity";
+	/**
+	 * The name of the intrusion detected on the client (the src), such as
+	 * PlugAndPlay_BO and JavaScript_Obfuscation_Fre.
+	 */
+	public static String INTRUSION_DETECTION_SIGNATURE = "signature";
+	/**
+	 * The source involved in the attack detected by the IDS. If your field is
+	 * named src_host, src_ip, src_ipv6, or src_nt_host you can alias it as src
+	 * to make it CIM-compliant.
+	 */
+	public static String INTRUSION_DETECTION_SRC = "src";
+	/**
+	 * The user involved with the intrusion detection event.
+	 */
+	public static String INTRUSION_DETECTION_USER = "user";
+	/**
+	 * The vendor technology used to generate network protection data, such as
+	 * IDP, Providentia, and ASA.
+	 *
+	 * Note: Required for all events dealing with network protection (Change
+	 * analysis, proxy, malware, intrusion detection, packet filtering, and
+	 * vulnerability).
+	 */
+	public static String INTRUSION_DETECTION_VENDOR = "vendor";
+
+	// ----------------------------------
+	// Malware - Endpoint protection
+	// ----------------------------------
+
+	/**
+	 * The outcome of the infection
+	 */
+	public static String MALWARE_ENDPOINT_PROTECTION_ACTION = "action";
+	/**
+	 * The NT domain of the destination (the dest_bestmatch).
+	 */
+	public static String MALWARE_ENDPOINT_PROTECTION_DEST_NT_DOMAIN = "dest_nt_domain";
+	/**
+	 * The cryptographic hash of the file associated with the malware event
+	 * (such as the malicious or infected file).
+	 */
+	public static String MALWARE_ENDPOINT_PROTECTION_FILE_HASH = "file_hash";
+	/**
+	 * The name of the file involved in the malware event (such as the infected
+	 * or malicious file).
+	 */
+	public static String MALWARE_ENDPOINT_PROTECTION_FILE_NAME = "file_name";
+	/**
+	 * The path of the file involved in the malware event (such as the infected
+	 * or malicious file).
+	 */
+	public static String MALWARE_ENDPOINT_PROTECTION_FILE_PATH = "file_path";
+	/**
+	 * The product name of the vendor technology (the vendor field) that is
+	 * generating malware data (such as Antivirus or EPO).
+	 */
+	public static String MALWARE_ENDPOINT_PROTECTION_PRODUCT = "product";
+	/**
+	 * The product version number of the vendor technology installed on the
+	 * client (such as 10.4.3 or 11.0.2).
+	 */
+	public static String MALWARE_ENDPOINT_PROTECTION_PRODUCT_VERSION = "product_version";
+	/**
+	 * The name of the malware infection detected on the client (the src), such
+	 * as Trojan.Vundo,Spyware.Gaobot,W32.Nimbda).
+	 *
+	 * Note: This field is a string. Please use a signature_id field for
+	 * signature ID fields that are integer data types.
+	 */
+	public static String MALWARE_ENDPOINT_PROTECTION_SIGNATURE = "signature";
+	/**
+	 * The current signature definition set running on the client, such as
+	 * 11hsvx)
+	 */
+	public static String MALWARE_ENDPOINT_PROTECTION_SIGNATURE_VERSION = "signature_version";
+	/**
+	 * The target affected or infected by the malware. If your field is named
+	 * dest_host, dest_ip, dest_ipv6, or dest_nt_host you can alias it as dest
+	 * to make it CIM-compliant.
+	 */
+	public static String MALWARE_ENDPOINT_PROTECTION_DEST = "dest";
+	/**
+	 * The NT domain of the source (the src).
+	 */
+	public static String MALWARE_ENDPOINT_PROTECTION_SRC_NT_DOMAIN = "src_nt_domain";
+	/**
+	 * The name of the user involved in the malware event.
+	 */
+	public static String MALWARE_ENDPOINT_PROTECTION_USER = "user";
+	/**
+	 * The name of the vendor technology generating malware data, such as
+	 * Symantec or McAfee.
+	 */
+	public static String MALWARE_ENDPOINT_PROTECTION_VENDOR = "vendor";
+
+	// ----------------------------------
+	// Malware - Network protection
+	// ----------------------------------
+
+	/**
+	 * The product name of the vendor technology generating network protection
+	 * data, such as IDP, Proventia, and ASA.
+	 *
+	 * Note: Required for all events dealing with network protection (Change
+	 * analysis, proxy, malware, intrusion detection, packet filtering, and
+	 * vulnerability).
+	 */
+	public static String MALWARE_NETWORK_PROTECTION_PRODUCT = "product";
+	/**
+	 * The severity of the network protection event (such as critical, high,
+	 * medium, low, or informational).
+	 *
+	 * Note: This field is a string. Please use a severity_id field for severity
+	 * ID fields that are integer data types.
+	 */
+	public static String MALWARE_NETWORK_PROTECTION_SEVERITY = "severity";
+	/**
+	 * The vendor technology used to generate network protection data, such as
+	 * IDP, Proventia, and ASA.
+	 *
+	 * Note: Required for all events dealing with network protection (Change
+	 * analysis, proxy, malware, intrusion detection, packet filtering, and
+	 * vulnerability).
+	 */
+	public static String MALWARE_NETWORK_PROTECTION_VENDOR = "vendor";
+
+	// ----------------------------------
+	// Network traffic - ESS
+	// ----------------------------------
+
+	/**
+	 * The action of the network traffic.
+	 */
+	public static String NETWORK_TRAFFIC_ESS_ACTION = "action";
+	/**
+	 * The destination port of the network traffic.
+	 */
+	public static String NETWORK_TRAFFIC_ESS_DEST_PORT = "dest_port";
+	/**
+	 * The product name of the vendor technology generating NetworkProtection
+	 * data, such as IDP, Proventia, and ASA.
+	 *
+	 * Note: Required for all events dealing with network protection (Change
+	 * analysis, proxy, malware, intrusion detection, packet filtering, and
+	 * vulnerability).
+	 */
+	public static String NETWORK_TRAFFIC_ESS_PRODUCT = "product";
+	/**
+	 * The source port of the network traffic.
+	 */
+	public static String NETWORK_TRAFFIC_ESS_SRC_PORT = "src_port";
+	/**
+	 * The vendor technology used to generate NetworkProtection data, such as
+	 * IDP, Proventia, and ASA.
+	 *
+	 * Note: Required for all events dealing with network protection (Change
+	 * analysis, proxy, malware, intrusion detection, packet filtering, and
+	 * vulnerability).
+	 */
+	public static String NETWORK_TRAFFIC_ESS_VENDOR = "vendor";
+
+	// ----------------------------------
+	// Network traffic - Generic
+	// ----------------------------------
+
+	/**
+	 * The ISO layer 7 (application layer) protocol, such as HTTP, HTTPS, SSH,
+	 * and IMAP.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_APP_LAYER = "app_layer";
+	/**
+	 * How many bytes this device/interface received.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_BYTES_IN = "bytes_in";
+	/**
+	 * How many bytes this device/interface transmitted.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_BYTES_OUT = "bytes_out";
+	/**
+	 * 802.11 channel number used by a wireless network.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_CHANNEL = "channel";
+	/**
+	 * The Common Vulnerabilities and Exposures (CVE) reference value.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_CVE = "cve";
+	/**
+	 * The destination application being targeted.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_APP = "dest_app";
+	/**
+	 * The destination command and control service channel.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_CNC_CHANNEL = "dest_cnc_channel";
+	/**
+	 * The destination command and control service name.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_CNC_NAME = "dest_cnc_name";
+	/**
+	 * The destination command and control service port.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_CNC_PORT = "dest_cnc_port";
+	/**
+	 * The country associated with a packet's recipient.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_COUNTRY = "dest_country";
+	/**
+	 * The fully qualified host name of a packet's recipient. For HTTP sessions,
+	 * this is the host header.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_HOST = "dest_host";
+	/**
+	 * The interface that is listening remotely or receiving packets locally.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_INT = "dest_int";
+	/**
+	 * The IPv4 address of a packet's recipient.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_IP = "dest_ip";
+	/**
+	 * The IPv6 address of a packet's recipient.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_IPV6 = "dest_ipv6";
+	/**
+	 * The (physical) latitude of a packet's destination.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_LAT = "dest_lat";
+	/**
+	 * The (physical) longitude of a packet's destination.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_LONG = "dest_long";
+	/**
+	 * The destination TCP/IP layer 2 Media Access Control (MAC) address of a
+	 * packet's destination.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_MAC = "dest_mac";
+	/**
+	 * The Windows NT domain containing a packet's destination.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_NT_DOMAIN = "dest_nt_domain";
+	/**
+	 * The Windows NT host name of a packet's destination.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_NT_HOST = "dest_nt_host";
+	/**
+	 * TCP/IP port to which a packet is being sent.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_PORT = "dest_port";
+	/**
+	 * The NATed IPv4 address to which a packet has been sent.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_TRANSLATED_IP = "dest_translated_ip";
+	/**
+	 * The NATed port to which a packet has been sent.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_DEST_TRANSLATED_PORT = "dest_translated_port";
+	/**
+	 * The numbered Internet Protocol version.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_IP_VERSION = "ip_version";
+	/**
+	 * The network interface through which a packet was transmitted.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_OUTBOUND_INTERFACE = "outbound_interface";
+	/**
+	 * How many packets this device/interface received.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_PACKETS_IN = "packets_in";
+	/**
+	 * How many packets this device/interface transmitted.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_PACKETS_OUT = "packets_out";
+	/**
+	 * The OSI layer 3 (Network Layer) protocol, such as IPv4/IPv6, ICMP, IPsec,
+	 * IGMP or RIP.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_PROTO = "proto";
+	/**
+	 * The session identifier. Multiple transactions build a session.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SESSION_ID = "session_id";
+	/**
+	 * The 802.11 service set identifier (ssid) assigned to a wireless session.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SSID = "ssid";
+	/**
+	 * The country from which the packet was sent.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SRC_COUNTRY = "src_country";
+	/**
+	 * The fully qualified host name of the system that transmitted the packet.
+	 * For Web logs, this is the HTTP client.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SRC_HOST = "src_host";
+	/**
+	 * The interface that is listening locally or sending packets remotely.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SRC_INT = "src_int";
+	/**
+	 * The IPv4 address of the packet's source. For Web logs, this is the http
+	 * client.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SRC_IP = "src_ip";
+	/**
+	 * The IPv6 address of the packet's source.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SRC_IPV6 = "src_ipv6";
+	/**
+	 * The (physical) latitude of the packet's source.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SRC_LAT = "src_lat";
+	/**
+	 * The (physical) longitude of the packet's source.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SRC_LONG = "src_long";
+	/**
+	 * The Media Access Control (MAC) address from which a packet was
+	 * transmitted.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SRC_MAC = "src_mac";
+	/**
+	 * The Windows NT domain containing the machines that generated the event.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SRC_NT_DOMAIN = "src_nt_domain";
+	/**
+	 * The Windows NT hostname of the system that generated the event.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SRC_NT_HOST = "src_nt_host";
+	/**
+	 * The network port from which a packet originated.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SRC_PORT = "src_port";
+	/**
+	 * The NATed IPv4 address from which a packet has been sent.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SRC_TRANSLATED_IP = "src_translated_ip";
+	/**
+	 * The NATed network port from which a packet has been sent.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SRC_TRANSLATED_PORT = "src_translated_port";
+	/**
+	 * The application, process, or OS subsystem that generated the event.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SYSLOG_ID = "syslog_id";
+	/**
+	 * The criticality of an event, as recorded by UNIX syslog.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_SYSLOG_PRIORITY = "syslog_priority";
+	/**
+	 * The TCP flag(s) specified in the event.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_TCP_FLAG = "tcp_flag";
+	/**
+	 * The hex bit that specifies TCP 'type of service'
+	 *
+	 * @see Type of
+	 *      Service
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_TOS = "tos";
+	/**
+	 * The transport protocol.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_TRANSPORT = "transport";
+	/**
+	 * The "time to live" of a packet or datagram.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_TTL = "ttl";
+	/**
+	 * The numeric identifier assigned to the virtual local area network (VLAN)
+	 * specified in the record.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_VLAN_ID = "vlan_id";
+	/**
+	 * The name assigned to the virtual local area network (VLAN) specified in
+	 * the record.
+	 */
+	public static String NETWORK_TRAFFIC_GENERIC_VLAN_NAME = "vlan_name";
+
+	// ----------------------------------
+	// Packet filtering
+	// ----------------------------------
+
+	/**
+	 * The action the filtering device (the dvc_bestmatch field) performed on
+	 * the communication.
+	 */
+	public static String PACKET_FILTERING_ACTION = "action";
+	/**
+	 * The IP port of the packet's destination, such as 22.
+	 */
+	public static String PACKET_FILTERING_DEST_PORT = "dest_port";
+	/**
+	 * The direction the packet is traveling.
+	 */
+	public static String PACKET_FILTERING_DIRECTION = "direction";
+	/**
+	 * The name of the packet filtering device. If your field is named dvc_host,
+	 * dvc_ip, or dvc_nt_host you can alias it as dvc to make it CIM-compliant.
+	 */
+	public static String PACKET_FILTERING_DVC = "dvc";
+	/**
+	 * The rule which took action on the packet, such as 143.
+	 */
+	public static String PACKET_FILTERING_RULE = "rule";
+	/**
+	 * The IP port of the packet's source, such as 34541.
+	 */
+	public static String PACKET_FILTERING_SVC_PORT = "svc_port";
+
+	// ----------------------------------
+	// Proxy
+	// ----------------------------------
+
+	/**
+	 * The action taken by the proxy.
+	 */
+	public static String PROXY_ACTION = "action";
+	/**
+	 * The destination of the network traffic (the remote host).
+	 */
+	public static String PROXY_DEST = "dest";
+	/**
+	 * The content-type of the requested HTTP resource.
+	 */
+	public static String PROXY_HTTP_CONTENT_TYPE = "http_content_type";
+	/**
+	 * The HTTP method used to request the resource.
+	 */
+	public static String PROXY_HTTP_METHOD = "http_method";
+	/**
+	 * The HTTP referrer used to request the HTTP resource.
+	 */
+	public static String PROXY_HTTP_REFER = "http_refer";
+	/**
+	 * The HTTP response code.
+	 */
+	public static String PROXY_HTTP_RESPONSE = "http_response";
+	/**
+	 * The user agent used to request the HTTP resource.
+	 */
+	public static String PROXY_HTTP_USER_AGENT = "http_user_agent";
+	/**
+	 * The product name of the vendor technology generating Network Protection
+	 * data, such as IDP, Providentia, and ASA.
+	 */
+	public static String PROXY_PRODUCT = "product";
+	/**
+	 * The source of the network traffic (the client requesting the connection).
+	 */
+	public static String PROXY_SRC = "src";
+	/**
+	 * The HTTP response code indicating the status of the proxy request.
+	 */
+	public static String PROXY_STATUS = "status";
+	/**
+	 * The user that requested the HTTP resource.
+	 */
+	public static String PROXY_USER = "user";
+	/**
+	 * The URL of the requested HTTP resource.
+	 */
+	public static String PROXY_URL = "url";
+	/**
+	 * The vendor technology generating Network Protection data, such as IDP,
+	 * Providentia, and ASA.
+	 */
+	public static String PROXY_VENDOR = "vendor";
+
+	// ----------------------------------
+	// System center
+	// ----------------------------------
+
+	/**
+	 * The running application or service on the system (the src field), such as
+	 * explorer.exe or sshd.
+	 */
+	public static String SYSTEM_CENTER_APP = "app";
+	/**
+	 * The amount of disk space available per drive or mount (the mount field)
+	 * on the system (the src field).
+	 */
+	public static String SYSTEM_CENTER_FREEMBYTES = "FreeMBytes";
+	/**
+	 * The version of operating system installed on the host (the src field),
+	 * such as 6.0.1.4 or 2.6.27.30-170.2.82.fc10.x86_64.
+	 */
+	public static String SYSTEM_CENTER_KERNEL_RELEASE = "kernel_release";
+	/**
+	 * Human-readable version of the SystemUptime value.
+	 */
+	public static String SYSTEM_CENTER_LABEL = "label";
+	/**
+	 * The drive or mount reporting available disk space (the FreeMBytes field)
+	 * on the system (the src field).
+	 */
+	public static String SYSTEM_CENTER_MOUNT = "mount";
+	/**
+	 * The name of the operating system installed on the host (the src), such as
+	 * Microsoft Windows Server 2003 or GNU/Linux).
+	 */
+	public static String SYSTEM_CENTER_OS = "os";
+	/**
+	 * The percentage of processor utilization.
+	 */
+	public static String SYSTEM_CENTER_PERCENTPROCESSORTIME = "PercentProcessorTime";
+	/**
+	 * The setlocaldefs setting from the SE Linux configuration.
+	 */
+	public static String SYSTEM_CENTER_SETLOCALDEFS = "setlocaldefs";
+	/**
+	 * Values from the SE Linux configuration file.
+	 */
+	public static String SYSTEM_CENTER_SELINUX = "selinux";
+	/**
+	 * The SE Linux type (such as targeted).
+	 */
+	public static String SYSTEM_CENTER_SELINUXTYPE = "selinuxtype";
+	/**
+	 * The shell provided to the User Account (the user field) upon logging into
+	 * the system (the src field).
+	 */
+	public static String SYSTEM_CENTER_SHELL = "shell";
+	/**
+	 * The TCP/UDP source port on the system (the src field).
+	 */
+	public static String SYSTEM_CENTER_SRC_PORT = "src_port";
+	/**
+	 * The sshd protocol version.
+	 */
+	public static String SYSTEM_CENTER_SSHD_PROTOCOL = "sshd_protocol";
+	/**
+	 * The start mode of the given service.
+	 */
+	public static String SYSTEM_CENTER_STARTMODE = "Startmode";
+	/**
+	 * The number of seconds since the system (the src) has been "up."
+	 */
+	public static String SYSTEM_CENTER_SYSTEMUPTIME = "SystemUptime";
+	/**
+	 * The total amount of available memory on the system (the src).
+	 */
+	public static String SYSTEM_CENTER_TOTALMBYTES = "TotalMBytes";
+	/**
+	 * The amount of used memory on the system (the src).
+	 */
+	public static String SYSTEM_CENTER_USEDMBYTES = "UsedMBytes";
+	/**
+	 * The User Account present on the system (the src).
+	 */
+	public static String SYSTEM_CENTER_USER = "user";
+	/**
+	 * The number of updates the system (the src) is missing.
+	 */
+	public static String SYSTEM_CENTER_UPDATES = "updates";
+
+	// ----------------------------------
+	// Traffic
+	// ----------------------------------
+
+	/**
+	 * The destination of the network traffic. If your field is named dest_host,
+	 * dest_ip, dest_ipv6, or dest_nt_host you can alias it as dest to make it
+	 * CIM-compliant.
+	 */
+	public static String TRAFFIC_DEST = "dest";
+	/**
+	 * The name of the packet filtering device. If your field is named dvc_host,
+	 * dvc_ip, or dvc_nt_host you can alias it as dvc to make it CIM-compliant.
+	 */
+	public static String TRAFFIC_DVC = "dvc";
+	/**
+	 * The source of the network traffic. If your field is named src_host,
+	 * src_ip, src_ipv6, or src_nt_host you can alias it as src to make it
+	 * CIM-compliant.
+	 */
+	public static String TRAFFIC_SRC = "src";
+
+	// ----------------------------------
+	// Update
+	// ----------------------------------
+
+	/**
+	 * The name of the installed update.
+	 */
+	public static String UPDATE_PACKAGE = "package";
+
+	// ----------------------------------
+	// User information updates
+	// ----------------------------------
+
+	/**
+	 * A user that has been affected by a change. For example, user fflanda
+	 * changed the name of user rhallen, so affected_user=rhallen.
+	 */
+	public static String USER_INFO_UPDATES_AFFECTED_USER = "affected_user";
+	/**
+	 * The user group affected by a change.
+	 */
+	public static String USER_INFO_UPDATES_AFFECTED_USER_GROUP = "affected_user_group";
+	/**
+	 * The identifier of the user group affected by a change.
+	 */
+	public static String USER_INFO_UPDATES_AFFECTED_USER_GROUP_ID = "affected_user_group_id";
+	/**
+	 * The identifier of the user affected by a change.
+	 */
+	public static String USER_INFO_UPDATES_AFFECTED_USER_ID = "affected_user_id";
+	/**
+	 * The security context associated with the user affected by a change.
+	 */
+	public static String USER_INFO_UPDATES_AFFECTED_USER_PRIVILEGE = "affected_user_privilege";
+	/**
+	 * The name of the user affected by the recorded event.
+	 */
+	public static String USER_INFO_UPDATES_USER = "user";
+	/**
+	 * A user group that is the object of an event, expressed in human-readable
+	 * terms.
+	 */
+	public static String USER_INFO_UPDATES_USER_GROUP = "user_group";
+	/**
+	 * The numeric identifier assigned to the user group event object.
+	 */
+	public static String USER_INFO_UPDATES_USER_GROUP_ID = "user_group_id";
+	/**
+	 * The system-assigned identifier for the user affected by an event.
+	 */
+	public static String USER_INFO_UPDATES_USER_ID = "user_id";
+	/**
+	 * The security context associated with the object of an event (the affected
+	 * user).
+	 */
+	public static String USER_INFO_UPDATES_USER_PRIVILEGE = "user_privilege";
+	/**
+	 * The name of the user that is the subject of an event--the user executing
+	 * the action, in other words.
+	 */
+	public static String USER_INFO_UPDATES_USER_SUBJECT = "user_subject";
+	/**
+	 * The ID number of the user that is the subject of an event.
+	 */
+	public static String USER_INFO_UPDATES_USER_SUBJECT_ID = "user_subject_id";
+	/**
+	 * The security context associated with the subject of an event (the user
+	 * causing a change).
+	 */
+	public static String USER_INFO_UPDATES_USER_SUBJECT_PRIVILEGE = "user_subject_privilege";
+
+	// ----------------------------------
+	// Vulnerability
+	// ----------------------------------
+
+	/**
+	 * The category of the discovered vulnerability.
+	 */
+	public static String VULNERABILITY_CATEGORY = "category";
+	/**
+	 * The host with the discovered vulnerability. If your field is named
+	 * dest_host, dest_ip, dest_ipv6, or dest_nt_host you can alias it as dest
+	 * to make it CIM-compliant.
+	 */
+	public static String VULNERABILITY_DEST = "dest";
+	/**
+	 * The operating system of the host containing the vulnerability detected on
+	 * the client (the src field), such as SuSE Security Update, or cups
+	 * security update.
+	 */
+	public static String VULNERABILITY_OS = "os";
+	/**
+	 * The severity of the discovered vulnerability.
+	 */
+	public static String VULNERABILITY_SEVERITY = "severity";
+	/**
+	 * The name of the vulnerability detected on the client (the src field),
+	 * such as SuSE Security Update, or cups security update.
+	 */
+	public static String VULNERABILITY_SIGNATURE = "signature";
+
+	// ----------------------------------
+	// Windows administration
+	// ----------------------------------
+
+	/**
+	 * The object name (associated only with Windows).
+	 */
+	public static String WINDOWS_ADMIN_OBJECT_NAME = "object_name";
+	/**
+	 * The object type (associated only with Windows).
+	 */
+	public static String WINDOWS_ADMIN_OBJECT_TYPE = "object_type";
+	/**
+	 * The object handle (associated only with Windows).
+	 */
+	public static String WINDOWS_ADMIN_OBJECT_HANDLE = "object_handle";
+
+
+	public SplunkData(Map data) {
+		this.eventMessage = new StringBuffer();
+		this.eventData = data;
+		for (String key : data.keySet()) {
+			this.addPair(key, data.get(key));
+		}
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param eventName
+	 *            the event name
+	 * @param eventID
+	 *            the event id
+	 * @param useInternalDate
+	 *            Whether or not to add a date to the event string
+	 * @param quoteValues
+	 *            Whether or not to put quotes around values
+	 */
+	public SplunkData(String eventName, String eventID, boolean useInternalDate, boolean quoteValues) {
+
+		this.eventMessage = new StringBuffer();
+		this.quoteValues = quoteValues;
+		this.useInternalDate = useInternalDate;
+
+		addPair(PREFIX_NAME, eventName);
+		addPair(PREFIX_EVENT_ID, eventID);
+	}
+
+	/**
+	 * Constructor.Will add internally generated date and put quotes around
+	 * values.
+	 *
+	 * @param eventName
+	 *            the event name
+	 * @param eventID
+	 *            the event ID
+	 */
+	public SplunkData(String eventName, String eventID) {
+
+		this(eventName, eventID, true, true);
+	}
+
+	/**
+	 * Default constructor
+	 */
+	public SplunkData() {
+		this.eventMessage = new StringBuffer();
+	}
+
+	/**
+	 * Simple shallow cloning method
+	 */
+	public SplunkData clone() {
+		SplunkData clone = new SplunkData();
+		clone.quoteValues = this.quoteValues;
+		clone.useInternalDate = this.useInternalDate;
+		clone.eventMessage.append(this.eventMessage);
+
+		return clone;
+	}
+
+
+	public Map getEventData() {
+		return eventData;
+	}
+
+	/**
+	 * Add a key value pair
+	 *
+	 * @param key
+	 * @param value
+	 */
+	public void addPair(String key, char value) {
+		addPair(key, String.valueOf(value));
+	}
+
+	/**
+	 * Add a key value pair
+	 *
+	 * @param key
+	 * @param value
+	 */
+	public void addPair(String key, boolean value) {
+		addPair(key, String.valueOf(value));
+	}
+
+	/**
+	 * Add a key value pair
+	 *
+	 * @param key
+	 * @param value
+	 */
+	public void addPair(String key, double value) {
+		addPair(key, String.valueOf(value));
+	}
+
+	/**
+	 * Add a key value pair
+	 *
+	 * @param key
+	 * @param value
+	 */
+	public void addPair(String key, long value) {
+		addPair(key, String.valueOf(value));
+	}
+
+	/**
+	 * Add a key value pair
+	 *
+	 * @param key
+	 * @param value
+	 */
+	public void addPair(String key, int value) {
+		addPair(key, String.valueOf(value));
+	}
+
+	/**
+	 * Add a key value pair
+	 *
+	 * @param key
+	 * @param value
+	 */
+	public void addPair(String key, Object value) {
+		addPair(key, value.toString());
+	}
+
+	/**
+	 * Utility method for formatting Throwable,Error,Exception objects in a more
+	 * linear and Splunk friendly manner than printStackTrace
+	 *
+	 * @param throwable
+	 *            the Throwable object to add to the event
+	 */
+	public void addThrowable(Throwable throwable) {
+
+		addThrowableObject(throwable, -1);
+	}
+
+	/**
+	 * Utility method for formatting Throwable,Error,Exception objects in a more
+	 * linear and Splunk friendly manner than printStackTrace
+	 *
+	 * @param throwable
+	 *            the Throwable object to add to the event
+	 * @param stackTraceDepth
+	 *            maximum number of stacktrace elements to log
+	 */
+	public void addThrowable(Throwable throwable, int stackTraceDepth) {
+
+		addThrowableObject(throwable, stackTraceDepth);
+	}
+
+	/**
+	 * Internal private method for formatting Throwable,Error,Exception objects
+	 * in a more linear and Splunk friendly manner than printStackTrace
+	 *
+	 * @param throwable
+	 *            the Throwable object to add to the event
+	 * @param stackTraceDepth
+	 *            maximum number of stacktrace elements to log, -1 for all
+	 */
+
+	private void addThrowableObject(Throwable throwable, int stackTraceDepth) {
+
+		addPair(THROWABLE_CLASS, throwable.getClass().getCanonicalName());
+		addPair(THROWABLE_MESSAGE, throwable.getMessage());
+		StackTraceElement[] elements = throwable.getStackTrace();
+		StringBuffer sb = new StringBuffer();
+		int depth = 0;
+		for (StackTraceElement element : elements) {
+			depth++;
+			if (stackTraceDepth == -1 || stackTraceDepth >= depth)
+				sb.append(element.toString()).append(",");
+			else
+				break;
+
+		}
+		addPair(THROWABLE_STACKTRACE_ELEMENTS, sb.toString());
+	}
+
+	/**
+	 * Add a key value pair
+	 *
+	 * @param key
+	 * @param value
+	 */
+	public void addPair(String key, String value) {
+
+		if (quoteValues)
+			this.eventMessage.append(key).append(KVDELIM).append(QUOTE).append(value).append(QUOTE).append(PAIRDELIM);
+		else
+			this.eventMessage.append(key).append(KVDELIM).append(value).append(PAIRDELIM);
+
+	}
+
+	@Override
+	/**
+	 * return the completed event message
+	 */
+	public String toString() {
+
+		String event = "";
+
+		if (useInternalDate) {
+			StringBuffer clonedMessage = new StringBuffer();
+			clonedMessage.append(DATEFORMATTER.format(new Date())).append(PAIRDELIM).append(this.eventMessage);
+			event = clonedMessage.toString();
+		}
+		else
+			event = eventMessage.toString();
+		// trim off trailing pair delim char(s)
+		return event.substring(0, event.length() - PAIRDELIM.length());
+	}
+
+	public void setAcManagementDestNtDomain(String acManagementDestNtDomain) {
+		addPair(AC_MANAGEMENT_DEST_NT_DOMAIN, acManagementDestNtDomain);
+	}
+
+	public void setAcManagementSignature(String acManagementSignature) {
+		addPair(AC_MANAGEMENT_SIGNATURE, acManagementSignature);
+	}
+
+	public void setAcManagementSrcNtDomain(String acManagementSrcNtDomain) {
+		addPair(AC_MANAGEMENT_SRC_NT_DOMAIN, acManagementSrcNtDomain);
+	}
+
+	public void setAuthAction(String authAction) {
+		addPair(AUTH_ACTION, authAction);
+	}
+
+	public void setAuthApp(String authApp) {
+		addPair(AUTH_APP, authApp);
+	}
+
+	public void setAuthDest(String authDest) {
+		addPair(AUTH_DEST, authDest);
+	}
+
+	public void setAuthSrc(String authSrc) {
+		addPair(AUTH_SRC, authSrc);
+	}
+
+	public void setAuthSrcUser(String authSrcUser) {
+		addPair(AUTH_SRC_USER, authSrcUser);
+	}
+
+	public void setAuthUser(String authUser) {
+		addPair(AUTH_USER, authUser);
+	}
+
+	public void setChangeEndpointProtectionAction(String changeEndpointProtectionAction) {
+		addPair(CHANGE_ENDPOINT_PROTECTION_ACTION, changeEndpointProtectionAction);
+	}
+
+	public void setChangeEndpointProtectionChangeType(String changeEndpointProtectionChangeType) {
+		addPair(CHANGE_ENDPOINT_PROTECTION_CHANGE_TYPE, changeEndpointProtectionChangeType);
+	}
+
+	public void setChangeEndpointProtectionDest(String changeEndpointProtectionDest) {
+		addPair(CHANGE_ENDPOINT_PROTECTION_DEST, changeEndpointProtectionDest);
+	}
+
+	public void setChangeEndpointProtectionHash(String changeEndpointProtectionHash) {
+		addPair(CHANGE_ENDPOINT_PROTECTION_HASH, changeEndpointProtectionHash);
+	}
+
+	public void setChangeEndpointProtectionGid(long changeEndpointProtectionGid) {
+		addPair(CHANGE_ENDPOINT_PROTECTION_GID, changeEndpointProtectionGid);
+	}
+
+	public void setChangeEndpointProtectionIsdr(boolean changeEndpointProtectionIsdr) {
+		addPair(CHANGE_ENDPOINT_PROTECTION_ISDR, changeEndpointProtectionIsdr);
+	}
+
+	public void setChangeEndpointProtectionMode(long changeEndpointProtectionMode) {
+		addPair(CHANGE_ENDPOINT_PROTECTION_MODE, changeEndpointProtectionMode);
+	}
+
+	public void setChangeEndpointProtectionModtime(String changeEndpointProtectionModtime) {
+		addPair(CHANGE_ENDPOINT_PROTECTION_MODTIME, changeEndpointProtectionModtime);
+	}
+
+	public void setChangeEndpointProtectionPath(String changeEndpointProtectionPath) {
+		addPair(CHANGE_ENDPOINT_PROTECTION_PATH, changeEndpointProtectionPath);
+	}
+
+	public void setChangeEndpointProtectionSize(long changeEndpointProtectionSize) {
+		addPair(CHANGE_ENDPOINT_PROTECTION_SIZE, changeEndpointProtectionSize);
+	}
+
+	public void setChangeEndpointProtectionUid(long changeEndpointProtectionUid) {
+		addPair(CHANGE_ENDPOINT_PROTECTION_UID, changeEndpointProtectionUid);
+	}
+
+	public void setChangeNetworkProtectionAction(String changeNetworkProtectionAction) {
+		addPair(CHANGE_NETWORK_PROTECTION_ACTION, changeNetworkProtectionAction);
+	}
+
+	public void setChangeNetworkProtectionCommand(String changeNetworkProtectionCommand) {
+		addPair(CHANGE_NETWORK_PROTECTION_COMMAND, changeNetworkProtectionCommand);
+	}
+
+	public void setChangeNetworkProtectionDvc(String changeNetworkProtectionDvc) {
+		addPair(CHANGE_NETWORK_PROTECTION_DVC, changeNetworkProtectionDvc);
+	}
+
+	public void setChangeNetworkProtectionUser(String changeNetworkProtectionUser) {
+		addPair(CHANGE_NETWORK_PROTECTION_USER, changeNetworkProtectionUser);
+	}
+
+	public void setCommonCategory(String commonCategory) {
+		addPair(COMMON_CATEGORY, commonCategory);
+	}
+
+	public void setCommonCount(String commonCount) {
+		addPair(COMMON_COUNT, commonCount);
+	}
+
+	public void setCommonDesc(String commonDesc) {
+		addPair(COMMON_DESC, commonDesc);
+	}
+
+	public void setCommonDhcpPool(String commonDhcpPool) {
+		addPair(COMMON_DHCP_POOL, commonDhcpPool);
+	}
+
+	public void setCommonDuration(long commonDuration) {
+		addPair(COMMON_DURATION, commonDuration);
+	}
+
+	public void setCommonDvcHost(String commonDvcHost) {
+		addPair(COMMON_DVC_HOST, commonDvcHost);
+	}
+
+	public void setCommonDvcIp(String commonDvcIp) {
+		addPair(COMMON_DVC_IP, commonDvcIp);
+	}
+
+	public void setCommonDvcIp6(String commonDvcIp6) {
+		addPair(COMMON_DVC_IP6, commonDvcIp6);
+	}
+
+	public void setCommonDvcLocation(String commonDvcLocation) {
+		addPair(COMMON_DVC_LOCATION, commonDvcLocation);
+	}
+
+	public void setCommonDvcMac(String commonDvcMac) {
+		addPair(COMMON_DVC_MAC, commonDvcMac);
+	}
+
+	public void setCommonDvcNtDomain(String commonDvcNtDomain) {
+		addPair(COMMON_DVC_NT_DOMAIN, commonDvcNtDomain);
+	}
+
+	public void setCommonDvcNtHost(String commonDvcNtHost) {
+		addPair(COMMON_DVC_NT_HOST, commonDvcNtHost);
+	}
+
+	public void setCommonDvcTime(long commonDvcTime) {
+		addPair(COMMON_DVC_TIME, commonDvcTime);
+	}
+
+	public void setCommonEndTime(long commonEndTime) {
+		addPair(COMMON_END_TIME, commonEndTime);
+	}
+
+	public void setCommonEventId(long commonEventId) {
+		addPair(COMMON_EVENT_ID, commonEventId);
+	}
+
+	public void setCommonLength(long commonLength) {
+		addPair(COMMON_LENGTH, commonLength);
+	}
+
+	public void setCommonLogLevel(String commonLogLevel) {
+		addPair(COMMON_LOG_LEVEL, commonLogLevel);
+	}
+
+	public void setCommonName(String commonName) {
+		addPair(COMMON_NAME, commonName);
+	}
+
+	public void setCommonPid(long commonPid) {
+		addPair(COMMON_PID, commonPid);
+	}
+
+	public void setCommonPriority(long commonPriority) {
+		addPair(COMMON_PRIORITY, commonPriority);
+	}
+
+	public void setCommonProduct(String commonProduct) {
+		addPair(COMMON_PRODUCT, commonProduct);
+	}
+
+	public void setCommonProductVersion(long commonProductVersion) {
+		addPair(COMMON_PRODUCT_VERSION, commonProductVersion);
+	}
+
+	public void setCommonReason(String commonReason) {
+		addPair(COMMON_REASON, commonReason);
+	}
+
+	public void setCommonResult(String commonResult) {
+		addPair(COMMON_RESULT, commonResult);
+	}
+
+	public void setCommonSeverity(String commonSeverity) {
+		addPair(COMMON_SEVERITY, commonSeverity);
+	}
+
+	public void setCommonStartTime(long commonStartTime) {
+		addPair(COMMON_START_TIME, commonStartTime);
+	}
+
+	public void setCommonTransactionId(String commonTransactionId) {
+		addPair(COMMON_TRANSACTION_ID, commonTransactionId);
+	}
+
+	public void setCommonUrl(String commonUrl) {
+		addPair(COMMON_URL, commonUrl);
+	}
+
+	public void setCommonVendor(String commonVendor) {
+		addPair(COMMON_VENDOR, commonVendor);
+	}
+
+	public void setDnsDestDomain(String dnsDestDomain) {
+		addPair(DNS_DEST_DOMAIN, dnsDestDomain);
+	}
+
+	public void setDnsDestRecord(String dnsDestRecord) {
+		addPair(DNS_DEST_RECORD, dnsDestRecord);
+	}
+
+	public void setDnsDestZone(String dnsDestZone) {
+		addPair(DNS_DEST_ZONE, dnsDestZone);
+	}
+
+	public void setDnsRecordClass(String dnsRecordClass) {
+		addPair(DNS_RECORD_CLASS, dnsRecordClass);
+	}
+
+	public void setDnsRecordType(String dnsRecordType) {
+		addPair(DNS_RECORD_TYPE, dnsRecordType);
+	}
+
+	public void setDnsSrcDomain(String dnsSrcDomain) {
+		addPair(DNS_SRC_DOMAIN, dnsSrcDomain);
+	}
+
+	public void setDnsSrcRecord(String dnsSrcRecord) {
+		addPair(DNS_SRC_RECORD, dnsSrcRecord);
+	}
+
+	public void setDnsSrcZone(String dnsSrcZone) {
+		addPair(DNS_SRC_ZONE, dnsSrcZone);
+	}
+
+	public void setEmailRecipient(String emailRecipient) {
+		addPair(EMAIL_RECIPIENT, emailRecipient);
+	}
+
+	public void setEmailSender(String emailSender) {
+		addPair(EMAIL_SENDER, emailSender);
+	}
+
+	public void setEmailSubject(String emailSubject) {
+		addPair(EMAIL_SUBJECT, emailSubject);
+	}
+
+	public void setFileAccessTime(long fileAccessTime) {
+		addPair(FILE_ACCESS_TIME, fileAccessTime);
+	}
+
+	public void setFileCreateTime(long fileCreateTime) {
+		addPair(FILE_CREATE_TIME, fileCreateTime);
+	}
+
+	public void setFileHash(String fileHash) {
+		addPair(FILE_HASH, fileHash);
+	}
+
+	public void setFileModifyTime(long fileModifyTime) {
+		addPair(FILE_MODIFY_TIME, fileModifyTime);
+	}
+
+	public void setFileName(String fileName) {
+		addPair(FILE_NAME, fileName);
+	}
+
+	public void setFilePath(String filePath) {
+		addPair(FILE_PATH, filePath);
+	}
+
+	public void setFilePermission(String filePermission) {
+		addPair(FILE_PERMISSION, filePermission);
+	}
+
+	public void setFileSize(long fileSize) {
+		addPair(FILE_SIZE, fileSize);
+	}
+
+	public void setIntrusionDetectionCategory(String intrusionDetectionCategory) {
+		addPair(INTRUSION_DETECTION_CATEGORY, intrusionDetectionCategory);
+	}
+
+	public void setIntrusionDetectionDest(String intrusionDetectionDest) {
+		addPair(INTRUSION_DETECTION_DEST, intrusionDetectionDest);
+	}
+
+	public void setIntrusionDetectionDvc(String intrusionDetectionDvc) {
+		addPair(INTRUSION_DETECTION_DVC, intrusionDetectionDvc);
+	}
+
+	public void setIntrusionDetectionIdsType(String intrusionDetectionIdsType) {
+		addPair(INTRUSION_DETECTION_IDS_TYPE, intrusionDetectionIdsType);
+	}
+
+	public void setIntrusionDetectionProduct(String intrusionDetectionProduct) {
+		addPair(INTRUSION_DETECTION_PRODUCT, intrusionDetectionProduct);
+	}
+
+	public void setIntrusionDetectionSeverity(String intrusionDetectionSeverity) {
+		addPair(INTRUSION_DETECTION_SEVERITY, intrusionDetectionSeverity);
+	}
+
+	public void setIntrusionDetectionSignature(String intrusionDetectionSignature) {
+		addPair(INTRUSION_DETECTION_SIGNATURE, intrusionDetectionSignature);
+	}
+
+	public void setIntrusionDetectionSrc(String intrusionDetectionSrc) {
+		addPair(INTRUSION_DETECTION_SRC, intrusionDetectionSrc);
+	}
+
+	public void setIntrusionDetectionUser(String intrusionDetectionUser) {
+		addPair(INTRUSION_DETECTION_USER, intrusionDetectionUser);
+	}
+
+	public void setIntrusionDetectionVendor(String intrusionDetectionVendor) {
+		addPair(INTRUSION_DETECTION_VENDOR, intrusionDetectionVendor);
+	}
+
+	public void setMalwareEndpointProtectionAction(String malwareEndpointProtectionAction) {
+		addPair(MALWARE_ENDPOINT_PROTECTION_ACTION, malwareEndpointProtectionAction);
+	}
+
+	public void setMalwareEndpointProtectionDestNtDomain(String malwareEndpointProtectionDestNtDomain) {
+		addPair(MALWARE_ENDPOINT_PROTECTION_DEST_NT_DOMAIN, malwareEndpointProtectionDestNtDomain);
+	}
+
+	public void setMalwareEndpointProtectionFileHash(String malwareEndpointProtectionFileHash) {
+		addPair(MALWARE_ENDPOINT_PROTECTION_FILE_HASH, malwareEndpointProtectionFileHash);
+	}
+
+	public void setMalwareEndpointProtectionFileName(String malwareEndpointProtectionFileName) {
+		addPair(MALWARE_ENDPOINT_PROTECTION_FILE_NAME, malwareEndpointProtectionFileName);
+	}
+
+	public void setMalwareEndpointProtectionFilePath(String malwareEndpointProtectionFilePath) {
+		addPair(MALWARE_ENDPOINT_PROTECTION_FILE_PATH, malwareEndpointProtectionFilePath);
+	}
+
+	public void setMalwareEndpointProtectionProduct(String malwareEndpointProtectionProduct) {
+		addPair(MALWARE_ENDPOINT_PROTECTION_PRODUCT, malwareEndpointProtectionProduct);
+	}
+
+	public void setMalwareEndpointProtectionProductVersion(String malwareEndpointProtectionProductVersion) {
+		addPair(MALWARE_ENDPOINT_PROTECTION_PRODUCT_VERSION, malwareEndpointProtectionProductVersion);
+	}
+
+	public void setMalwareEndpointProtectionSignature(String malwareEndpointProtectionSignature) {
+		addPair(MALWARE_ENDPOINT_PROTECTION_SIGNATURE, malwareEndpointProtectionSignature);
+	}
+
+	public void setMalwareEndpointProtectionSignatureVersion(String malwareEndpointProtectionSignatureVersion) {
+		addPair(MALWARE_ENDPOINT_PROTECTION_SIGNATURE_VERSION, malwareEndpointProtectionSignatureVersion);
+	}
+
+	public void setMalwareEndpointProtectionDest(String malwareEndpointProtectionDest) {
+		addPair(MALWARE_ENDPOINT_PROTECTION_DEST, malwareEndpointProtectionDest);
+	}
+
+	public void setMalwareEndpointProtectionSrcNtDomain(String malwareEndpointProtectionSrcNtDomain) {
+		addPair(MALWARE_ENDPOINT_PROTECTION_SRC_NT_DOMAIN, malwareEndpointProtectionSrcNtDomain);
+	}
+
+	public void setMalwareEndpointProtectionUser(String malwareEndpointProtectionUser) {
+		addPair(MALWARE_ENDPOINT_PROTECTION_USER, malwareEndpointProtectionUser);
+	}
+
+	public void setMalwareEndpointProtectionVendor(String malwareEndpointProtectionVendor) {
+		addPair(MALWARE_ENDPOINT_PROTECTION_VENDOR, malwareEndpointProtectionVendor);
+	}
+
+	public void setMalwareNetworkProtectionProduct(String malwareNetworkProtectionProduct) {
+		addPair(MALWARE_NETWORK_PROTECTION_PRODUCT, malwareNetworkProtectionProduct);
+	}
+
+	public void setMalwareNetworkProtectionSeverity(String malwareNetworkProtectionSeverity) {
+		addPair(MALWARE_NETWORK_PROTECTION_SEVERITY, malwareNetworkProtectionSeverity);
+	}
+
+	public void setMalwareNetworkProtectionVendor(String malwareNetworkProtectionVendor) {
+		addPair(MALWARE_NETWORK_PROTECTION_VENDOR, malwareNetworkProtectionVendor);
+	}
+
+	public void setNetworkTrafficEssAction(String networkTrafficEssAction) {
+		addPair(NETWORK_TRAFFIC_ESS_ACTION, networkTrafficEssAction);
+	}
+
+	public void setNetworkTrafficEssDestPort(int networkTrafficEssDestPort) {
+		addPair(NETWORK_TRAFFIC_ESS_DEST_PORT, networkTrafficEssDestPort);
+	}
+
+	public void setNetworkTrafficEssProduct(String networkTrafficEssProduct) {
+		addPair(NETWORK_TRAFFIC_ESS_PRODUCT, networkTrafficEssProduct);
+	}
+
+	public void setNetworkTrafficEssSrcPort(int networkTrafficEssSrcPort) {
+		addPair(NETWORK_TRAFFIC_ESS_SRC_PORT, networkTrafficEssSrcPort);
+	}
+
+	public void setNetworkTrafficEssVendor(String networkTrafficEssVendor) {
+		addPair(NETWORK_TRAFFIC_ESS_VENDOR, networkTrafficEssVendor);
+	}
+
+	public void setNetworkTrafficGenericAppLayer(String networkTrafficGenericAppLayer) {
+		addPair(NETWORK_TRAFFIC_GENERIC_APP_LAYER, networkTrafficGenericAppLayer);
+	}
+
+	public void setNetworkTrafficGenericBytesIn(long networkTrafficGenericBytesIn) {
+		addPair(NETWORK_TRAFFIC_GENERIC_BYTES_IN, networkTrafficGenericBytesIn);
+	}
+
+	public void setNetworkTrafficGenericBytesOut(long networkTrafficGenericBytesOut) {
+		addPair(NETWORK_TRAFFIC_GENERIC_BYTES_OUT, networkTrafficGenericBytesOut);
+	}
+
+	public void setNetworkTrafficGenericChannel(String networkTrafficGenericChannel) {
+		addPair(NETWORK_TRAFFIC_GENERIC_CHANNEL, networkTrafficGenericChannel);
+	}
+
+	public void setNetworkTrafficGenericCve(String networkTrafficGenericCve) {
+		addPair(NETWORK_TRAFFIC_GENERIC_CVE, networkTrafficGenericCve);
+	}
+
+	public void setNetworkTrafficGenericDestApp(String networkTrafficGenericDestApp) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_APP, networkTrafficGenericDestApp);
+	}
+
+	public void setNetworkTrafficGenericDestCncChannel(String networkTrafficGenericDestCncChannel) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_CNC_CHANNEL, networkTrafficGenericDestCncChannel);
+	}
+
+	public void setNetworkTrafficGenericDestCncName(String networkTrafficGenericDestCncName) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_CNC_NAME, networkTrafficGenericDestCncName);
+	}
+
+	public void setNetworkTrafficGenericDestCncPort(String networkTrafficGenericDestCncPort) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_CNC_PORT, networkTrafficGenericDestCncPort);
+	}
+
+	public void setNetworkTrafficGenericDestCountry(String networkTrafficGenericDestCountry) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_COUNTRY, networkTrafficGenericDestCountry);
+	}
+
+	public void setNetworkTrafficGenericDestHost(String networkTrafficGenericDestHost) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_HOST, networkTrafficGenericDestHost);
+	}
+
+	public void setNetworkTrafficGenericDestInt(String networkTrafficGenericDestInt) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_INT, networkTrafficGenericDestInt);
+	}
+
+	public void setNetworkTrafficGenericDestIp(String networkTrafficGenericDestIp) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_IP, networkTrafficGenericDestIp);
+	}
+
+	public void setNetworkTrafficGenericDestIpv6(String networkTrafficGenericDestIpv6) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_IPV6, networkTrafficGenericDestIpv6);
+	}
+
+	public void setNetworkTrafficGenericDestLat(int networkTrafficGenericDestLat) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_LAT, networkTrafficGenericDestLat);
+	}
+
+	public void setNetworkTrafficGenericDestLong(int networkTrafficGenericDestLong) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_LONG, networkTrafficGenericDestLong);
+	}
+
+	public void setNetworkTrafficGenericDestMac(String networkTrafficGenericDestMac) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_MAC, networkTrafficGenericDestMac);
+	}
+
+	public void setNetworkTrafficGenericDestNtDomain(String networkTrafficGenericDestNtDomain) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_NT_DOMAIN, networkTrafficGenericDestNtDomain);
+	}
+
+	public void setNetworkTrafficGenericDestNtHost(String networkTrafficGenericDestNtHost) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_NT_HOST, networkTrafficGenericDestNtHost);
+	}
+
+	public void setNetworkTrafficGenericDestPort(int networkTrafficGenericDestPort) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_PORT, networkTrafficGenericDestPort);
+	}
+
+	public void setNetworkTrafficGenericDestTranslatedIp(String networkTrafficGenericDestTranslatedIp) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_TRANSLATED_IP, networkTrafficGenericDestTranslatedIp);
+	}
+
+	public void setNetworkTrafficGenericDestTranslatedPort(int networkTrafficGenericDestTranslatedPort) {
+		addPair(NETWORK_TRAFFIC_GENERIC_DEST_TRANSLATED_PORT, networkTrafficGenericDestTranslatedPort);
+	}
+
+	public void setNetworkTrafficGenericIpVersion(int networkTrafficGenericIpVersion) {
+		addPair(NETWORK_TRAFFIC_GENERIC_IP_VERSION, networkTrafficGenericIpVersion);
+	}
+
+	public void setNetworkTrafficGenericOutboundInterface(String networkTrafficGenericOutboundInterface) {
+		addPair(NETWORK_TRAFFIC_GENERIC_OUTBOUND_INTERFACE, networkTrafficGenericOutboundInterface);
+	}
+
+	public void setNetworkTrafficGenericPacketsIn(long networkTrafficGenericPacketsIn) {
+		addPair(NETWORK_TRAFFIC_GENERIC_PACKETS_IN, networkTrafficGenericPacketsIn);
+	}
+
+	public void setNetworkTrafficGenericPacketsOut(long networkTrafficGenericPacketsOut) {
+		addPair(NETWORK_TRAFFIC_GENERIC_PACKETS_OUT, networkTrafficGenericPacketsOut);
+	}
+
+	public void setNetworkTrafficGenericProto(String networkTrafficGenericProto) {
+		addPair(NETWORK_TRAFFIC_GENERIC_PROTO, networkTrafficGenericProto);
+	}
+
+	public void setNetworkTrafficGenericSessionId(String networkTrafficGenericSessionId) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SESSION_ID, networkTrafficGenericSessionId);
+	}
+
+	public void setNetworkTrafficGenericSsid(String networkTrafficGenericSsid) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SSID, networkTrafficGenericSsid);
+	}
+
+	public void setNetworkTrafficGenericSrcCountry(String networkTrafficGenericSrcCountry) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SRC_COUNTRY, networkTrafficGenericSrcCountry);
+	}
+
+	public void setNetworkTrafficGenericSrcHost(String networkTrafficGenericSrcHost) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SRC_HOST, networkTrafficGenericSrcHost);
+	}
+
+	public void setNetworkTrafficGenericSrcInt(String networkTrafficGenericSrcInt) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SRC_INT, networkTrafficGenericSrcInt);
+	}
+
+	public void setNetworkTrafficGenericSrcIp(String networkTrafficGenericSrcIp) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SRC_IP, networkTrafficGenericSrcIp);
+	}
+
+	public void setNetworkTrafficGenericSrcIpv6(String networkTrafficGenericSrcIpv6) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SRC_IPV6, networkTrafficGenericSrcIpv6);
+	}
+
+	public void setNetworkTrafficGenericSrcLat(int networkTrafficGenericSrcLat) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SRC_LAT, networkTrafficGenericSrcLat);
+	}
+
+	public void setNetworkTrafficGenericSrcLong(int networkTrafficGenericSrcLong) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SRC_LONG, networkTrafficGenericSrcLong);
+	}
+
+	public void setNetworkTrafficGenericSrcMac(String networkTrafficGenericSrcMac) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SRC_MAC, networkTrafficGenericSrcMac);
+	}
+
+	public void setNetworkTrafficGenericSrcNtDomain(String networkTrafficGenericSrcNtDomain) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SRC_NT_DOMAIN, networkTrafficGenericSrcNtDomain);
+	}
+
+	public void setNetworkTrafficGenericSrcNtHost(String networkTrafficGenericSrcNtHost) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SRC_NT_HOST, networkTrafficGenericSrcNtHost);
+	}
+
+	public void setNetworkTrafficGenericSrcPort(int networkTrafficGenericSrcPort) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SRC_PORT, networkTrafficGenericSrcPort);
+	}
+
+	public void setNetworkTrafficGenericSrcTranslatedIp(String networkTrafficGenericSrcTranslatedIp) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SRC_TRANSLATED_IP, networkTrafficGenericSrcTranslatedIp);
+	}
+
+	public void setNetworkTrafficGenericSrcTranslatedPort(int networkTrafficGenericSrcTranslatedPort) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SRC_TRANSLATED_PORT, networkTrafficGenericSrcTranslatedPort);
+	}
+
+	public void setNetworkTrafficGenericSyslogId(String networkTrafficGenericSyslogId) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SYSLOG_ID, networkTrafficGenericSyslogId);
+	}
+
+	public void setNetworkTrafficGenericSyslogPriority(String networkTrafficGenericSyslogPriority) {
+		addPair(NETWORK_TRAFFIC_GENERIC_SYSLOG_PRIORITY, networkTrafficGenericSyslogPriority);
+	}
+
+	public void setNetworkTrafficGenericTcpFlag(String networkTrafficGenericTcpFlag) {
+		addPair(NETWORK_TRAFFIC_GENERIC_TCP_FLAG, networkTrafficGenericTcpFlag);
+	}
+
+	public void setNetworkTrafficGenericTos(String networkTrafficGenericTos) {
+		addPair(NETWORK_TRAFFIC_GENERIC_TOS, networkTrafficGenericTos);
+	}
+
+	public void setNetworkTrafficGenericTransport(String networkTrafficGenericTransport) {
+		addPair(NETWORK_TRAFFIC_GENERIC_TRANSPORT, networkTrafficGenericTransport);
+	}
+
+	public void setNetworkTrafficGenericTtl(int networkTrafficGenericTtl) {
+		addPair(NETWORK_TRAFFIC_GENERIC_TTL, networkTrafficGenericTtl);
+	}
+
+	public void setNetworkTrafficGenericVlanId(long networkTrafficGenericVlanId) {
+		addPair(NETWORK_TRAFFIC_GENERIC_VLAN_ID, networkTrafficGenericVlanId);
+	}
+
+	public void setNetworkTrafficGenericVlanName(String networkTrafficGenericVlanName) {
+		addPair(NETWORK_TRAFFIC_GENERIC_VLAN_NAME, networkTrafficGenericVlanName);
+	}
+
+	public void setPacketFilteringAction(String packetFilteringAction) {
+		addPair(PACKET_FILTERING_ACTION, packetFilteringAction);
+	}
+
+	public void setPacketFilteringDestPort(int packetFilteringDestPort) {
+		addPair(PACKET_FILTERING_DEST_PORT, packetFilteringDestPort);
+	}
+
+	public void setPacketFilteringDirection(String packetFilteringDirection) {
+		addPair(PACKET_FILTERING_DIRECTION, packetFilteringDirection);
+	}
+
+	public void setPacketFilteringDvc(String packetFilteringDvc) {
+		addPair(PACKET_FILTERING_DVC, packetFilteringDvc);
+	}
+
+	public void setPacketFilteringRule(String packetFilteringRule) {
+		addPair(PACKET_FILTERING_RULE, packetFilteringRule);
+	}
+
+	public void setPacketFilteringSvcPort(int packetFilteringSvcPort) {
+		addPair(PACKET_FILTERING_SVC_PORT, packetFilteringSvcPort);
+	}
+
+	public void setProxyAction(String proxyAction) {
+		addPair(PROXY_ACTION, proxyAction);
+	}
+
+	public void setProxyDest(String proxyDest) {
+		addPair(PROXY_DEST, proxyDest);
+	}
+
+	public void setProxyHttpContentType(String proxyHttpContentType) {
+		addPair(PROXY_HTTP_CONTENT_TYPE, proxyHttpContentType);
+	}
+
+	public void setProxyHttpMethod(String proxyHttpMethod) {
+		addPair(PROXY_HTTP_METHOD, proxyHttpMethod);
+	}
+
+	public void setProxyHttpRefer(String proxyHttpRefer) {
+		addPair(PROXY_HTTP_REFER, proxyHttpRefer);
+	}
+
+	public void setProxyHttpResponse(int proxyHttpResponse) {
+		addPair(PROXY_HTTP_RESPONSE, proxyHttpResponse);
+	}
+
+	public void setProxyHttpUserAgent(String proxyHttpUserAgent) {
+		addPair(PROXY_HTTP_USER_AGENT, proxyHttpUserAgent);
+	}
+
+	public void setProxyProduct(String proxyProduct) {
+		addPair(PROXY_PRODUCT, proxyProduct);
+	}
+
+	public void setProxySrc(String proxySrc) {
+		addPair(PROXY_SRC, proxySrc);
+	}
+
+	public void setProxyStatus(int proxyStatus) {
+		addPair(PROXY_STATUS, proxyStatus);
+	}
+
+	public void setProxyUser(String proxyUser) {
+		addPair(PROXY_USER, proxyUser);
+	}
+
+	public void setProxyUrl(String proxyUrl) {
+		addPair(PROXY_URL, proxyUrl);
+	}
+
+	public void setProxyVendor(String proxyVendor) {
+		addPair(PROXY_VENDOR, proxyVendor);
+	}
+
+	public void setSystemCenterApp(String systemCenterApp) {
+		addPair(SYSTEM_CENTER_APP, systemCenterApp);
+	}
+
+	public void setSystemCenterFreembytes(long systemCenterFreembytes) {
+		addPair(SYSTEM_CENTER_FREEMBYTES, systemCenterFreembytes);
+	}
+
+	public void setSystemCenterKernelRelease(String systemCenterKernelRelease) {
+		addPair(SYSTEM_CENTER_KERNEL_RELEASE, systemCenterKernelRelease);
+	}
+
+	public void setSystemCenterLabel(String systemCenterLabel) {
+		addPair(SYSTEM_CENTER_LABEL, systemCenterLabel);
+	}
+
+	public void setSystemCenterMount(String systemCenterMount) {
+		addPair(SYSTEM_CENTER_MOUNT, systemCenterMount);
+	}
+
+	public void setSystemCenterOs(String systemCenterOs) {
+		addPair(SYSTEM_CENTER_OS, systemCenterOs);
+	}
+
+	public void setSystemCenterPercentprocessortime(int systemCenterPercentprocessortime) {
+		addPair(SYSTEM_CENTER_PERCENTPROCESSORTIME, systemCenterPercentprocessortime);
+	}
+
+	public void setSystemCenterSetlocaldefs(int systemCenterSetlocaldefs) {
+		addPair(SYSTEM_CENTER_SETLOCALDEFS, systemCenterSetlocaldefs);
+	}
+
+	public void setSystemCenterSelinux(String systemCenterSelinux) {
+		addPair(SYSTEM_CENTER_SELINUX, systemCenterSelinux);
+	}
+
+	public void setSystemCenterSelinuxtype(String systemCenterSelinuxtype) {
+		addPair(SYSTEM_CENTER_SELINUXTYPE, systemCenterSelinuxtype);
+	}
+
+	public void setSystemCenterShell(String systemCenterShell) {
+		addPair(SYSTEM_CENTER_SHELL, systemCenterShell);
+	}
+
+	public void setSystemCenterSrcPort(int systemCenterSrcPort) {
+		addPair(SYSTEM_CENTER_SRC_PORT, systemCenterSrcPort);
+	}
+
+	public void setSystemCenterSshdProtocol(String systemCenterSshdProtocol) {
+		addPair(SYSTEM_CENTER_SSHD_PROTOCOL, systemCenterSshdProtocol);
+	}
+
+	public void setSystemCenterStartmode(String systemCenterStartmode) {
+		addPair(SYSTEM_CENTER_STARTMODE, systemCenterStartmode);
+	}
+
+	public void setSystemCenterSystemuptime(long systemCenterSystemuptime) {
+		addPair(SYSTEM_CENTER_SYSTEMUPTIME, systemCenterSystemuptime);
+	}
+
+	public void setSystemCenterTotalmbytes(long systemCenterTotalmbytes) {
+		addPair(SYSTEM_CENTER_TOTALMBYTES, systemCenterTotalmbytes);
+	}
+
+	public void setSystemCenterUsedmbytes(long systemCenterUsedmbytes) {
+		addPair(SYSTEM_CENTER_USEDMBYTES, systemCenterUsedmbytes);
+	}
+
+	public void setSystemCenterUser(String systemCenterUser) {
+		addPair(SYSTEM_CENTER_USER, systemCenterUser);
+	}
+
+	public void setSystemCenterUpdates(long systemCenterUpdates) {
+		addPair(SYSTEM_CENTER_UPDATES, systemCenterUpdates);
+	}
+
+	public void setTrafficDest(String trafficDest) {
+		addPair(TRAFFIC_DEST, trafficDest);
+	}
+
+	public void setTrafficDvc(String trafficDvc) {
+		addPair(TRAFFIC_DVC, trafficDvc);
+	}
+
+	public void setTrafficSrc(String trafficSrc) {
+		addPair(TRAFFIC_SRC, trafficSrc);
+	}
+
+	public void setUpdatePackage(String updatePackage) {
+		addPair(UPDATE_PACKAGE, updatePackage);
+	}
+
+	public void setUserInfoUpdatesAffectedUser(String userInfoUpdatesAffectedUser) {
+		addPair(USER_INFO_UPDATES_AFFECTED_USER, userInfoUpdatesAffectedUser);
+	}
+
+	public void setUserInfoUpdatesAffectedUserGroup(String userInfoUpdatesAffectedUserGroup) {
+		addPair(USER_INFO_UPDATES_AFFECTED_USER_GROUP, userInfoUpdatesAffectedUserGroup);
+	}
+
+	public void setUserInfoUpdatesAffectedUserGroupId(int userInfoUpdatesAffectedUserGroupId) {
+		addPair(USER_INFO_UPDATES_AFFECTED_USER_GROUP_ID, userInfoUpdatesAffectedUserGroupId);
+	}
+
+	public void setUserInfoUpdatesAffectedUserId(int userInfoUpdatesAffectedUserId) {
+		addPair(USER_INFO_UPDATES_AFFECTED_USER_ID, userInfoUpdatesAffectedUserId);
+	}
+
+	public void setUserInfoUpdatesAffectedUserPrivilege(String userInfoUpdatesAffectedUserPrivilege) {
+		addPair(USER_INFO_UPDATES_AFFECTED_USER_PRIVILEGE, userInfoUpdatesAffectedUserPrivilege);
+	}
+
+	public void setUserInfoUpdatesUser(String userInfoUpdatesUser) {
+		addPair(USER_INFO_UPDATES_USER, userInfoUpdatesUser);
+	}
+
+	public void setUserInfoUpdatesUserGroup(String userInfoUpdatesUserGroup) {
+		addPair(USER_INFO_UPDATES_USER_GROUP, userInfoUpdatesUserGroup);
+	}
+
+	public void setUserInfoUpdatesUserGroupId(int userInfoUpdatesUserGroupId) {
+		addPair(USER_INFO_UPDATES_USER_GROUP_ID, userInfoUpdatesUserGroupId);
+	}
+
+	public void setUserInfoUpdatesUserId(int userInfoUpdatesUserId) {
+		addPair(USER_INFO_UPDATES_USER_ID, userInfoUpdatesUserId);
+	}
+
+	public void setUserInfoUpdatesUserPrivilege(String userInfoUpdatesUserPrivilege) {
+		addPair(USER_INFO_UPDATES_USER_PRIVILEGE, userInfoUpdatesUserPrivilege);
+	}
+
+	public void setUserInfoUpdatesUserSubject(String userInfoUpdatesUserSubject) {
+		addPair(USER_INFO_UPDATES_USER_SUBJECT, userInfoUpdatesUserSubject);
+	}
+
+	public void setUserInfoUpdatesUserSubjectId(int userInfoUpdatesUserSubjectId) {
+		addPair(USER_INFO_UPDATES_USER_SUBJECT_ID, userInfoUpdatesUserSubjectId);
+	}
+
+	public void setUserInfoUpdatesUserSubjectPrivilege(String userInfoUpdatesUserSubjectPrivilege) {
+		addPair(USER_INFO_UPDATES_USER_SUBJECT_PRIVILEGE, userInfoUpdatesUserSubjectPrivilege);
+	}
+
+	public void setVulnerabilityCategory(String vulnerabilityCategory) {
+		addPair(VULNERABILITY_CATEGORY, vulnerabilityCategory);
+	}
+
+	public void setVulnerabilityDest(String vulnerabilityDest) {
+		addPair(VULNERABILITY_DEST, vulnerabilityDest);
+	}
+
+	public void setVulnerabilityOs(String vulnerabilityOs) {
+		addPair(VULNERABILITY_OS, vulnerabilityOs);
+	}
+
+	public void setVulnerabilitySeverity(String vulnerabilitySeverity) {
+		addPair(VULNERABILITY_SEVERITY, vulnerabilitySeverity);
+	}
+
+	public void setVulnerabilitySignature(String vulnerabilitySignature) {
+		addPair(VULNERABILITY_SIGNATURE, vulnerabilitySignature);
+	}
+
+	public void setWindowsAdminObjectName(String windowsAdminObjectName) {
+		addPair(WINDOWS_ADMIN_OBJECT_NAME, windowsAdminObjectName);
+	}
+
+	public void setWindowsAdminObjectType(String windowsAdminObjectType) {
+		addPair(WINDOWS_ADMIN_OBJECT_TYPE, windowsAdminObjectType);
+	}
+
+	public void setWindowsAdminObjectHandle(String windowsAdminObjectHandle) {
+		addPair(WINDOWS_ADMIN_OBJECT_HANDLE, windowsAdminObjectHandle);
+	}
+
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/entity/SplunkServer.java b/src/main/java/org/springframework/integration/splunk/entity/SplunkServer.java
new file mode 100644
index 0000000..b8b703b
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/entity/SplunkServer.java
@@ -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;
+	}
+
+
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/inbound/SplunkPollingChannelAdapter.java b/src/main/java/org/springframework/integration/splunk/inbound/SplunkPollingChannelAdapter.java
new file mode 100644
index 0000000..c99ed67
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/inbound/SplunkPollingChannelAdapter.java
@@ -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 Message
+ *
+ * @author Jarred Li
+ * @since 1.0
+ *
+ */
+public class SplunkPollingChannelAdapter extends IntegrationObjectSupport implements MessageSource> {
+
+	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
+	 * null. Otherwise, a new {@link Message} is constructed and returned.
+	 */
+	public Message> receive() {
+		List payload = splunkExecutor.poll();
+		if (payload == null) {
+			return null;
+		}
+		return MessageBuilder.withPayload(payload).build();
+	}
+
+	@Override
+	public String getComponentType() {
+		return "splunk:inbound-channel-adapter";
+	}
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/inbound/package-info.java b/src/main/java/org/springframework/integration/splunk/inbound/package-info.java
new file mode 100644
index 0000000..f72820a
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/inbound/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Provides inbound Spring Integration Splunk components.
+ */
+package org.springframework.integration.splunk.inbound;
diff --git a/src/main/java/org/springframework/integration/splunk/outbound/SplunkOutboundChannelAdapter.java b/src/main/java/org/springframework/integration/splunk/outbound/SplunkOutboundChannelAdapter.java
new file mode 100644
index 0000000..3c78da0
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/outbound/SplunkOutboundChannelAdapter.java
@@ -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;
+	}
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/outbound/package-info.java b/src/main/java/org/springframework/integration/splunk/outbound/package-info.java
new file mode 100644
index 0000000..0ce1585
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/outbound/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Provides Spring Integration components for doing outbound operations.
+ */
+package org.springframework.integration.splunk.outbound;
diff --git a/src/main/java/org/springframework/integration/splunk/support/ConnectionFactoryFactoryBean.java b/src/main/java/org/springframework/integration/splunk/support/ConnectionFactoryFactoryBean.java
new file mode 100644
index 0000000..a5c1204
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/support/ConnectionFactoryFactoryBean.java
@@ -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 ConnectionFactory.
+ *
+ * @author Jarred Li
+ * @since 1.0
+ *
+ */
+public class ConnectionFactoryFactoryBean implements FactoryBean> {
+
+	private final ConnectionFactory connectionFactory;
+
+	public ConnectionFactoryFactoryBean(ConnectionFactory cf, boolean usePool) {
+		if (usePool) {
+			this.connectionFactory = new PoolingConnectionFactory(cf);
+		}
+		else {
+			this.connectionFactory = cf;
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see org.springframework.beans.factory.FactoryBean#getObject()
+	 */
+	public ConnectionFactory 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;
+	}
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/support/IngestType.java b/src/main/java/org/springframework/integration/splunk/support/IngestType.java
new file mode 100644
index 0000000..a03f505
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/support/IngestType.java
@@ -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;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/springframework/integration/splunk/support/PoolingConnectionFactory.java b/src/main/java/org/springframework/integration/splunk/support/PoolingConnectionFactory.java
new file mode 100644
index 0000000..2bf6efe
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/support/PoolingConnectionFactory.java
@@ -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 Connection with Apache Commons Pool.
+ *
+ * @author Jarred Li
+ * @since 1.0
+ *
+ */
+public class PoolingConnectionFactory implements ConnectionFactory, DisposableBean {
+
+	private final Log log = LogFactory.getLog(this.getClass());
+
+	private final ConnectionFactory connectionFactory;
+
+	private ObjectPool> pool;
+
+	public PoolingConnectionFactory(ConnectionFactory f) {
+		this.connectionFactory = f;
+		this.pool = new GenericObjectPool>(new ConnectionPoolableObjectFactory());
+	}
+
+	/* (non-Javadoc)
+	 * @see org.springframework.integration.splunk.core.ServiceFactory#getService()
+	 */
+	public Connection 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> {
+
+		/* (non-Javadoc)
+		 * @see org.apache.commons.pool.BasePoolableObjectFactory#makeObject()
+		 */
+		@Override
+		public Connection makeObject() throws Exception {
+			return connectionFactory.getConnection();
+		}
+
+		@Override
+		public void destroyObject(Connection obj) throws Exception {
+			obj.close();
+		}
+
+		/**
+		 * Whether the object is valid or not.
+		 *
+		 * @param obj object to be validated
+		 * @return true
+		 */
+		public boolean validateObject(Connection obj) {
+			return obj.isOpen();
+		}
+
+		/**
+		 *  activate the object
+		 *
+		 *  @param obj ignored
+		 */
+		public void activateObject(Connection obj) throws Exception {
+			obj.isOpen();
+		}
+
+
+	}
+
+	class PooledConnection implements Connection {
+
+		private Connection connection;
+
+		public PooledConnection(Connection 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();
+		}
+
+	}
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/support/SearchMode.java b/src/main/java/org/springframework/integration/splunk/support/SearchMode.java
new file mode 100644
index 0000000..3d4c62a
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/support/SearchMode.java
@@ -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;
+}
\ No newline at end of file
diff --git a/src/main/java/org/springframework/integration/splunk/support/SplunkConnection.java b/src/main/java/org/springframework/integration/splunk/support/SplunkConnection.java
new file mode 100644
index 0000000..233fcc0
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/support/SplunkConnection.java
@@ -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 {
+
+	private Service service;
+
+	public SplunkConnection(SplunkServer splunkServer) {
+		Map args = new HashMap();
+		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;
+	}
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/support/SplunkConnectionFactory.java b/src/main/java/org/springframework/integration/splunk/support/SplunkConnectionFactory.java
new file mode 100644
index 0000000..5eba652
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/support/SplunkConnectionFactory.java
@@ -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 {
+
+	private SplunkServer splunkServer;
+
+	public SplunkConnectionFactory(SplunkServer server) {
+		this.splunkServer = server;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.springframework.integration.splunk.core.ServiceFactory#getService()
+	 */
+	public Connection getConnection() throws Exception {
+		return new SplunkConnection(splunkServer);
+	}
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/support/SplunkDataReader.java b/src/main/java/org/springframework/integration/splunk/support/SplunkDataReader.java
new file mode 100644
index 0000000..b0fce88
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/support/SplunkDataReader.java
@@ -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 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 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 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 runQuery(Args queryArgs) throws Exception {
+		Connection 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 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 data = runQuery(queryArgs);
+		lastSuccessfulReadTime = startTime;
+		return data;
+	}
+
+
+	private List 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 data = runQuery(queryArgs);
+		lastSuccessfulReadTime = startTime;
+		return data;
+	}
+
+
+	/**
+	 * @return
+	 * @throws Exception
+	 */
+	private List 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 data = runQuery(queryArgs);
+		lastSuccessfulReadTime = startTime;
+		return data;
+	}
+
+	/**
+	 * @throws Exception
+	 *
+	 */
+	private List exportSearch() throws Exception {
+		logger.debug("export start");
+		List result = new ArrayList();
+		HashMap data;
+		SplunkData splunkData;
+
+		Args queryArgs = new Args();
+		Calendar startTime = Calendar.getInstance();
+		populateArgs(queryArgs, startTime, false);
+		queryArgs.put("output_mode", "xml");
+
+		Connection 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 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 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 args = new HashMap();
+				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 data = extractData(job);
+			this.lastSuccessfulReadTime = startTime;
+			return data;
+		} finally {
+			connection.close();
+		}
+	}
+
+	private List extractData(Job job) throws Exception {
+		List result = new ArrayList();
+		HashMap 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");
+	}
+
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/springframework/integration/splunk/support/SplunkDataWriter.java b/src/main/java/org/springframework/integration/splunk/support/SplunkDataWriter.java
new file mode 100644
index 0000000..15a53fe
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/support/SplunkDataWriter.java
@@ -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 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 f) {
+		this.connectionFactory = f;
+	}
+
+	public void write(SplunkData data) throws Exception {
+		logger.debug("write message to splunk:" + data);
+
+		Connection 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");
+	}
+
+}
diff --git a/src/main/java/org/springframework/integration/splunk/support/SplunkExecutor.java b/src/main/java/org/springframework/integration/splunk/support/SplunkExecutor.java
new file mode 100644
index 0000000..0dd1b5d
--- /dev/null
+++ b/src/main/java/org/springframework/integration/splunk/support/SplunkExecutor.java
@@ -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 poll() {
+		logger.debug("poll start:");
+		List 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;
+	}
+
+
+}
diff --git a/src/main/resources/META-INF/spring.handlers b/src/main/resources/META-INF/spring.handlers
new file mode 100644
index 0000000..4d4111e
--- /dev/null
+++ b/src/main/resources/META-INF/spring.handlers
@@ -0,0 +1 @@
+http\://www.springframework.org/schema/integration/splunk=org.springframework.integration.splunk.config.xml.SplunkNamespaceHandler
diff --git a/src/main/resources/META-INF/spring.schemas b/src/main/resources/META-INF/spring.schemas
new file mode 100644
index 0000000..cc8649e
--- /dev/null
+++ b/src/main/resources/META-INF/spring.schemas
@@ -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
diff --git a/src/main/resources/META-INF/spring.tooling b/src/main/resources/META-INF/spring.tooling
new file mode 100644
index 0000000..cf031eb
--- /dev/null
+++ b/src/main/resources/META-INF/spring.tooling
@@ -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
diff --git a/src/main/resources/org/springframework/integration/splunk/config/xml/spring-integration-splunk-1.0.xsd b/src/main/resources/org/springframework/integration/splunk/config/xml/spring-integration-splunk-1.0.xsd
new file mode 100644
index 0000000..c452f4f
--- /dev/null
+++ b/src/main/resources/org/springframework/integration/splunk/config/xml/spring-integration-splunk-1.0.xsd
@@ -0,0 +1,364 @@
+
+
+
+	
+	
+	
+
+	
+		
+	
+
+	
+		
+			
+		
+		
+			
+				
+					
+					
+						
+							
+						
+					
+				
+			
+			
+				
+					
+					
+						
+							
+						
+					
+				
+			
+			
+				
+					
+					
+						
+							
+						
+					
+				
+			
+			
+				
+					
+					
+						
+							
+						
+					
+				
+			
+			
+				
+					
+					
+						
+							
+						
+					
+				
+			
+			
+				
+					
+					
+						
+							
+						
+					
+				
+			
+			
+				
+					
+					
+						
+							
+						
+					
+				
+			
+			
+			
+		
+	
+
+	
+		
+			
+				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.
+					
+				
+			
+		
+	
+
+	
+		
+			
+				Defines an outbound Channel Adapter.
+			
+		
+		
+			
+				
+			
+			
+			
+				
+					
+						
+							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
+					
+				
+			
+			
+				
+					
+						Splunk index name
+					
+				
+			
+			
+				
+					
+						Splunk ingest method: tcp, streaming, submit. Default stream.
+					
+				
+			
+			
+				
+					
+						Splunk ingest method: tcp, streaming, submit. Default stream.
+					
+				
+			
+			
+				
+					
+						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
+				
+			
+		
+		
+			
+				
+					Whether pool the Splunk connection.
+				
+			
+		
+	
+
+
diff --git a/src/main/resources/org/springframework/integration/splunk/config/xml/spring-integration-splunk.gif b/src/main/resources/org/springframework/integration/splunk/config/xml/spring-integration-splunk.gif
new file mode 100644
index 0000000000000000000000000000000000000000..41b369fece0e576ecd920400b221fd33abbaf5c4
GIT binary patch
literal 572
zcmZ?wbhEHb6krfwc*Xz%|NsBj^POrMHnn5wI!WKA$M#t>l?H4BPzO?b&{cRWSFFSB<
z^|`x}P0QyVy|U`SiF40CoO%A?(2mZdyE;$q?mn}(`^J&Ji~DRU^KH0`_S=*f
zu`(xWd1~172%niTfzv{QrUeE70}32q)Fc#tvM@3*q%i1!3doJ
z$QZroAYKk;o)!}g_c$BZP}??kHkSD;%JZ2d6u9}BT8+&ujM`ePV%-d#6T`zi);F^_
zIR!9@O3I6^oV(z-tdN`(pX{#l&0dZgror~-%^VCYeSN$`0@iCL`334n#7Fs`w{uBO
x(B)aWd{Qfm5=#n`xT2uIN}aG328D}QI)&6(d>(9QbkfS;6w=UeP!nLV1^^EL*)#wE

literal 0
HcmV?d00001

diff --git a/src/reference/docbook/history.xml b/src/reference/docbook/history.xml
new file mode 100644
index 0000000..d8fde4b
--- /dev/null
+++ b/src/reference/docbook/history.xml
@@ -0,0 +1,20 @@
+
+
+	Change History
+		
+			
+			
+			
+			
+		
+		
+		
+			
+			
+			
+		
+		
+	
ReleaseDateChanges
0.5.02012.9.28Initial release
+
diff --git a/src/reference/docbook/images/logo.png b/src/reference/docbook/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8c71c13a0e5606e9d87f75e37fe2874cb44beb51 GIT binary patch literal 17393 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 + + + Spring Integration Splunk Adapter + Splunk Adapter ${version} + Spring Integration + ${version} + + + + + + + + + + + + + + Jarred Li + Mark Pollack + Damien Dallimore + + + © SpringSource Inc., 2012 + + + + + + + What's new? + + + If you are interested in the changes and features, that were introduced in + earlier versions, please take a look at chapter: + + + + + + + + + + Integration Adapters + + + Spring Integration adapter for Splunk includes inbound channel adapter to + read data from Splunk and outbound channel adapter to write data into + Splunk. + + + + + + Appendices + + + + diff --git a/src/reference/docbook/resources.xml b/src/reference/docbook/resources.xml new file mode 100644 index 0000000..c3ffb46 --- /dev/null +++ b/src/reference/docbook/resources.xml @@ -0,0 +1,27 @@ + + + Additional Resources + +
+ Spring Integration Home + + The definitive source of information about Spring Integration is the + Spring Integration Home at + http://www.springsource.org. That site serves as a hub of + information and is the best place to find up-to-date announcements about the project as well as links to + articles, blogs, and new sample applications. + +
+ +
+ Splunk Home + + You can get more information on Splunk from Splunk Home. + + + Splunk SDK API is in Splunk Dev. + +
+ +
diff --git a/src/reference/docbook/splunk.xml b/src/reference/docbook/splunk.xml new file mode 100644 index 0000000..10da20e --- /dev/null +++ b/src/reference/docbook/splunk.xml @@ -0,0 +1,218 @@ + + + Splunk Adapter + + The Spring Integration Splunk Adapter provides outbound and inbound channel adapters: + + + + + + Outbound Channel adapter + + + + + + + Inbound Channel Adapter + + + + + + + To use Spring Integration adapter for Splunk, you have to import the XML namespace. For example, you can + have following XML: + + + + +]]> + + + Meanwhile, you have to define your Splunk server information. For example + you can define server as following: + + + + ... + + ... +]]> + +
+ Outbound Channel Adapter + + Outbound channel adapter is used to put data into Splunk from + channels in Spring Integration. + There are 3 kinds of method to put data: + + + + Submit (HTTP REST) + Stream + Tcp + + + + The main difference between using the REST inputs vs plain TCP/UDP inputs is really + in the Splunk event handling pipeline. + + + + With REST , you have to declare your event meta data (index, source, source type…) + in the HTTP request at the source. You can't really transform the log event anymore + after you have created and sent it to Splunk.Typically though, for people using REST, + this is fine because they are well formatting their log events before sending them + anyway ie: no further processing/transforming and manipulation is required. + You can however still do dynamic search time transforms/filtering on the + data when later searching over it in Splunk. + + + To use outbound channel adapter with submit, you can define the adapter as following: + + +]]> + + + With TCP inputs , you can manipulate and transform the event data in Splunk before + it gets indexed (using entrys in props.conf/transforms.conf). The event meta data + (index, source, source type…) gets declared on the Splunk side when you establish + the TCP/UDP input and can also be dynamically created, so essentially you have + a lot more control over the indexing of the event data.This is generally more + important when you don't control the format of the data at the source and it needs + manipulating/filtering ie: network devices syslogging etc… + + + + To use outbound channel adapter with tcp, you can define the adapter as following: + + +]]> + + + To use outbound channel adapter with stream, you can define the adapter as following: + + + +]]> + +
+ +
+ Inbound Channel Adapter + + Inbound channel adapter is used to get data out of Splunk and put + into Spring Integration's channel. + There are 5 ways to get data out of Splunk: + + + + Blocking + Non blocking + Saved search + Realtime + Export + + + + For more information on the difference, please refer + Splunk SDK + + + + To use bloking inbound channel adapter, you can define the adapter as following: + + + +]]> + + + To use non blocking inbound channel adapter, you can define the adapter as following: + + + +]]> + + + To use saved search inbound channel adapter, you can define the adapter as following: + + + +]]> + + + To use realtime search inbound channel adapter, you can define the adapter as following: + + + +]]> + + To use export inbound channel adapter, you can define the adapter as following: + + + +]]> + + + As Splunk support range search, you can specify the search rage by using + "latestTime", "earliestTime", "initEarliestTime". + + + "initEarliestTime" is the value for "earliestTime" when the application first start. + If you specify "earliestTime" and "latestTime", the poller will only search data + in that range. Otherwise, the range will move forward as time goes. That means, the + "latestTime" is equal to the time where the polling trigger, the "earliestTime" is + equal to the time where the last polling is run. + + + You can get more information on the rage search from + + Splunk. + +
+
diff --git a/src/reference/docbook/whats-new.xml b/src/reference/docbook/whats-new.xml new file mode 100644 index 0000000..cd9d2cd --- /dev/null +++ b/src/reference/docbook/whats-new.xml @@ -0,0 +1,17 @@ + + + What's new? + + The Spring Integration adapter for Splunk includes two adapters: + + + + Inbound Channel Adapter to search data from Splunk. + + + Outbound Channel Adapter to push event data into Splunk. + + + diff --git a/src/test/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserSavedSearchTests.java b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserSavedSearchTests.java new file mode 100644 index 0000000..ba6756a --- /dev/null +++ b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserSavedSearchTests.java @@ -0,0 +1,69 @@ +/* + * 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 junit.framework.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; +import org.springframework.integration.splunk.support.SearchMode; +import org.springframework.integration.splunk.support.SplunkDataReader; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Jarred Li + * @since 1.0 + * + */ + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class SplunkInboundChannelAdapterParserSavedSearchTests { + + @Autowired + private ApplicationContext appContext; + + /** + * Test method for {@link org.springframework.integration.splunk.config.xml.SplunkInboundChannelAdapterParser#parseSource(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)}. + */ + @Test + public void testParseSourceElementParserContext() { + SourcePollingChannelAdapter adapter = appContext.getBean("splunkInboundChannelAdapter", + SourcePollingChannelAdapter.class); + Assert.assertNotNull(adapter); + + SplunkDataReader reader = appContext.getBean("splunkInboundChannelAdapter.splunkExecutor.reader", + SplunkDataReader.class); + Assert.assertNotNull(reader); + + SearchMode mode = SearchMode.saved; + Assert.assertEquals(mode, reader.getMode()); + + String savedSearch = "savedSearch"; + Assert.assertEquals(savedSearch, reader.getSavedSearch()); + + String owner = "admin"; + Assert.assertEquals(owner, reader.getOwner()); + + String app = "search"; + Assert.assertEquals(app, reader.getApp()); + } + +} 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 new file mode 100644 index 0000000..e3a8f8b --- /dev/null +++ b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserTests.java @@ -0,0 +1,78 @@ +/* + * 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 junit.framework.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; +import org.springframework.integration.splunk.support.SearchMode; +import org.springframework.integration.splunk.support.SplunkDataReader; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Jarred Li + * @since 1.0 + * + */ + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class SplunkInboundChannelAdapterParserTests { + + @Autowired + private ApplicationContext appContext; + + /** + * Test method for {@link org.springframework.integration.splunk.config.xml.SplunkInboundChannelAdapterParser#parseSource(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)}. + */ + @Test + //@Ignore + public void testParseSourceElementParserContext() { + SourcePollingChannelAdapter adapter = appContext.getBean("splunkInboundChannelAdapter", + SourcePollingChannelAdapter.class); + Assert.assertNotNull(adapter); + Assert.assertFalse(adapter.isAutoStartup()); + + SplunkDataReader reader = appContext.getBean("splunkInboundChannelAdapter.splunkExecutor.reader", + SplunkDataReader.class); + Assert.assertNotNull(reader); + + String searchString = "search spring:example"; + Assert.assertEquals(searchString, reader.getSearch()); + + SearchMode mode = SearchMode.blocking; + Assert.assertEquals(mode, reader.getMode()); + + String earliestTime = "-1d"; + Assert.assertEquals(earliestTime, reader.getEarliestTime()); + + String latestTime = "now"; + Assert.assertEquals(latestTime, reader.getLatestTime()); + + String initEarliestTime = "-1d"; + Assert.assertEquals(initEarliestTime, reader.getInitEarliestTime()); + + String fieldList = "field1, field2"; + Assert.assertEquals(fieldList, reader.getFieldList()); + + } + +} 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 new file mode 100644 index 0000000..5b70423 --- /dev/null +++ b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserStreamTests.java @@ -0,0 +1,64 @@ +/* + * 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 junit.framework.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.IngestType; +import org.springframework.integration.splunk.support.SplunkDataWriter; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Jarred Li + * @since 1.0 + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class SplunkOutboundChannelAdapterParserStreamTests { + + @Autowired + private ApplicationContext appContext; + + /** + * Test method for {@link org.springframework.integration.splunk.config.xml.SplunkOutboundChannelAdapterParser#parseConsumer(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)}. + */ + @Test + public void testParseConsumerElementParserContext() { + Object adapter = appContext.getBean("splunkOutboundChannelAdapter"); + Assert.assertNotNull(adapter); + + SplunkDataWriter writer = appContext.getBean("splunkOutboundChannelAdapter.splunkExecutor.writer", + SplunkDataWriter.class); + Assert.assertNotNull(writer); + + IngestType ingest = IngestType.stream; + Assert.assertEquals(ingest, writer.getIngest()); + + String host = "test.host"; + Assert.assertEquals(host, writer.getHost()); + + String hostRegex = "test.host.*"; + Assert.assertEquals(hostRegex, writer.getHostRegex()); + + } + +} 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 new file mode 100644 index 0000000..99dd49b --- /dev/null +++ b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserTests.java @@ -0,0 +1,65 @@ +/* + * 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 junit.framework.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.IngestType; +import org.springframework.integration.splunk.support.SplunkDataWriter; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Jarred Li + * @since 1.0 + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class SplunkOutboundChannelAdapterParserTests { + + @Autowired + private ApplicationContext appContext; + + /** + * Test method for {@link org.springframework.integration.splunk.config.xml.SplunkOutboundChannelAdapterParser#parseConsumer(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)}. + */ + @Test + public void testParseConsumerElementParserContext() { + Object adapter = appContext.getBean("splunkOutboundChannelAdapter"); + Assert.assertNotNull(adapter); + + SplunkDataWriter writer = appContext.getBean("splunkOutboundChannelAdapter.splunkExecutor.writer", + SplunkDataWriter.class); + Assert.assertNotNull(writer); + + String sourceType = "spring-integration"; + Assert.assertEquals(sourceType, writer.getSourceType()); + + String source = "example5"; + Assert.assertEquals(source, writer.getSource()); + + IngestType ingest = IngestType.submit; + Assert.assertEquals(ingest, writer.getIngest()); + + + } + +} 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 new file mode 100644 index 0000000..50c26bf --- /dev/null +++ b/src/test/java/org/springframework/integration/splunk/config/xml/SplunkServerParserTests.java @@ -0,0 +1,56 @@ +/* + * 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 junit.framework.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.entity.SplunkServer; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Jarred Li + * @since 1.0 + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class SplunkServerParserTests { + + @Autowired + private ApplicationContext appContext; + + /** + * Test method for {@link org.springframework.integration.splunk.config.xml.SplunkServerParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)}. + */ + @Test + public void testDoParseElementParserContextBeanDefinitionBuilder() { + SplunkServer server = appContext.getBean("splunkServer", SplunkServer.class); + + Assert.assertEquals("test.splunk.server", server.getHost()); + Assert.assertEquals(8089, server.getPort()); + Assert.assertEquals("admin", server.getUserName()); + Assert.assertEquals("password", server.getPassword()); + Assert.assertEquals("https", server.getScheme()); + Assert.assertEquals("admin", server.getOwner()); + Assert.assertEquals("search", server.getApp()); + } + +} diff --git a/src/test/java/org/springframework/integration/splunk/inbound/SplunkPollingChannelAdapterTests.java b/src/test/java/org/springframework/integration/splunk/inbound/SplunkPollingChannelAdapterTests.java new file mode 100644 index 0000000..b32b685 --- /dev/null +++ b/src/test/java/org/springframework/integration/splunk/inbound/SplunkPollingChannelAdapterTests.java @@ -0,0 +1,71 @@ +/* + * 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.inbound; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.integration.splunk.entity.SplunkData; +import org.springframework.integration.splunk.support.SplunkExecutor; + +/** + * @author Jarred Li + * @since 1.0 + * + */ +public class SplunkPollingChannelAdapterTests { + + private SplunkPollingChannelAdapter inboundAdapter; + + private SplunkExecutor executor; + + @Before + public void init() { + executor = mock(SplunkExecutor.class); + inboundAdapter = new SplunkPollingChannelAdapter(executor); + } + + /** + * Test method for {@link org.springframework.integration.splunk.inbound.SplunkPollingChannelAdapter#receive()}. + */ + @Test + public void testReceive() { + List data = new ArrayList(); + SplunkData sd = new SplunkData("spring", "spring:example"); + sd.setCommonDesc("description"); + data.add(sd); + when(executor.poll()).thenReturn(data); + + List received = inboundAdapter.receive().getPayload(); + Assert.assertEquals(1, received.size()); + } + + /** + * Test method for {@link org.springframework.integration.splunk.inbound.SplunkPollingChannelAdapter#getComponentType()}. + */ + @Test + public void testGetComponentType() { + Assert.assertEquals("splunk:inbound-channel-adapter", inboundAdapter.getComponentType()); + } + +} diff --git a/src/test/java/org/springframework/integration/splunk/outbound/SplunkOutboundChannelAdapterTests.java b/src/test/java/org/springframework/integration/splunk/outbound/SplunkOutboundChannelAdapterTests.java new file mode 100644 index 0000000..dc4fbff --- /dev/null +++ b/src/test/java/org/springframework/integration/splunk/outbound/SplunkOutboundChannelAdapterTests.java @@ -0,0 +1,64 @@ +/* + * 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.outbound; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.integration.Message; +import org.springframework.integration.splunk.support.SplunkExecutor; + +/** + * @author Jarred Li + * @since 1.0 + * + */ +public class SplunkOutboundChannelAdapterTests { + + private SplunkOutboundChannelAdapter outboundAdapter; + + private SplunkExecutor executor; + + @Before + public void init() { + executor = mock(SplunkExecutor.class); + outboundAdapter = new SplunkOutboundChannelAdapter(executor); + } + + /** + * Test method for {@link org.springframework.integration.splunk.outbound.SplunkOutboundChannelAdapter#handleRequestMessage(org.springframework.integration.Message)}. + */ + @Test + public void testHandleRequestMessage() { + Message message = null; + when(executor.executeOutboundOperation(message)).thenReturn(null); + + Object ret = outboundAdapter.handleRequestMessage(message); + Assert.assertNull(ret); + } + + /** + * Test method for {@link org.springframework.integration.splunk.outbound.SplunkOutboundChannelAdapter#setProducesReply(boolean)}. + */ + @Test + public void testSetProducesReply() { + outboundAdapter.setProducesReply(false); + } + +} diff --git a/src/test/java/org/springframework/integration/splunk/support/ConnectionFactoryFactoryBeanTests.java b/src/test/java/org/springframework/integration/splunk/support/ConnectionFactoryFactoryBeanTests.java new file mode 100644 index 0000000..9036d79 --- /dev/null +++ b/src/test/java/org/springframework/integration/splunk/support/ConnectionFactoryFactoryBeanTests.java @@ -0,0 +1,88 @@ +/* + * 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 junit.framework.Assert; + +import org.junit.Test; +import org.springframework.integration.splunk.core.ConnectionFactory; +import org.springframework.integration.splunk.entity.SplunkServer; + +import com.splunk.Service; + +/** + * @author Jarred Li + * @since 1.0 + * + */ +public class ConnectionFactoryFactoryBeanTests { + + private ConnectionFactoryFactoryBean factoryBean; + + + /** + * Test method for {@link org.springframework.integration.splunk.support.ConnectionFactoryFactoryBean#ConnectionFactoryFactoryBean(org.springframework.integration.splunk.core.ConnectionFactory, boolean)}. + * @throws Exception + */ + @Test + public void testConnectionFactoryFactoryBean() throws Exception { + SplunkServer server = new SplunkServer(); + SplunkConnectionFactory factory = new SplunkConnectionFactory(server); + factoryBean = new ConnectionFactoryFactoryBean(factory, false); + + ConnectionFactory generatedByFactoryBean = factoryBean.getObject(); + Assert.assertTrue(generatedByFactoryBean instanceof SplunkConnectionFactory); + + } + + @Test + public void testConnectionFactoryFactoryBean_withPoll() throws Exception { + SplunkServer server = new SplunkServer(); + SplunkConnectionFactory factory = new SplunkConnectionFactory(server); + factoryBean = new ConnectionFactoryFactoryBean(factory, true); + + ConnectionFactory generatedByFactoryBean = factoryBean.getObject(); + Assert.assertTrue(generatedByFactoryBean instanceof PoolingConnectionFactory); + + } + + + /** + * Test method for {@link org.springframework.integration.splunk.support.ConnectionFactoryFactoryBean#getObjectType()}. + */ + @Test + public void testGetObjectType() { + SplunkServer server = new SplunkServer(); + SplunkConnectionFactory factory = new SplunkConnectionFactory(server); + factoryBean = new ConnectionFactoryFactoryBean(factory, true); + + Class clazz = factoryBean.getObjectType(); + Assert.assertEquals(PoolingConnectionFactory.class, clazz); + } + + /** + * Test method for {@link org.springframework.integration.splunk.support.ConnectionFactoryFactoryBean#isSingleton()}. + */ + @Test + public void testIsSingleton() { + SplunkServer server = new SplunkServer(); + SplunkConnectionFactory factory = new SplunkConnectionFactory(server); + factoryBean = new ConnectionFactoryFactoryBean(factory, false); + + Assert.assertTrue(factoryBean.isSingleton()); + } + +} diff --git a/src/test/java/org/springframework/integration/splunk/support/PoolingConnectionFactoryTests.java b/src/test/java/org/springframework/integration/splunk/support/PoolingConnectionFactoryTests.java new file mode 100644 index 0000000..328be7e --- /dev/null +++ b/src/test/java/org/springframework/integration/splunk/support/PoolingConnectionFactoryTests.java @@ -0,0 +1,111 @@ +/* + * 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 static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.integration.splunk.core.Connection; +import org.springframework.integration.splunk.core.ConnectionFactory; + +/** + * @author Jarred Li + * @since 1.0 + * + */ +public class PoolingConnectionFactoryTests { + + private ConnectionFactory conFactory; + + private PoolingConnectionFactory poolConFactory; + + @SuppressWarnings("unchecked") + @Before + public void before() { + conFactory = mock(ConnectionFactory.class); + poolConFactory = new PoolingConnectionFactory(conFactory); + } + + + /** + * Test method for {@link org.springframework.integration.splunk.support.PoolingConnectionFactory#getConnection()}. + * @throws Exception + */ + @Test + public void testGetConnection() throws Exception { + @SuppressWarnings("unchecked") + Connection con = mock(Connection.class); + + when(con.getTarget()).thenReturn(new TestEntity("entity1")); + when(conFactory.getConnection()).thenReturn(con); + Connection returnCon = poolConFactory.getConnection(); + TestEntity obj1 = returnCon.getTarget(); + Assert.assertNotNull(obj1); + Assert.assertEquals("entity1", obj1.getName()); + + when(con.getTarget()).thenReturn(new TestEntity("entity2")); + when(conFactory.getConnection()).thenReturn(con); + returnCon = poolConFactory.getConnection(); + TestEntity obj2 = returnCon.getTarget(); + Assert.assertNotNull(obj2); + Assert.assertEquals("entity2", obj2.getName()); + + when(con.getTarget()).thenReturn(new TestEntity("entity3")); + when(conFactory.getConnection()).thenReturn(con); + returnCon = poolConFactory.getConnection(); + TestEntity obj3 = returnCon.getTarget(); + Assert.assertNotNull(obj3); + Assert.assertEquals("entity3", obj3.getName()); + + + } + + /** + * Test method for {@link org.springframework.integration.splunk.support.PoolingConnectionFactory#destroy()}. + * @throws Exception + */ + @Test(expected = IllegalStateException.class) + public void testDestroy() throws Exception { + try { + poolConFactory.destroy(); + } catch (Exception e) { + fail("exception when destoying pool connection factory"); + } + poolConFactory.getConnection(); + } + + public static class TestEntity { + private String name; + + public TestEntity(String n) { + this.name = n; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + +} diff --git a/src/test/java/org/springframework/integration/splunk/support/SplunkDataReaderTests.java b/src/test/java/org/springframework/integration/splunk/support/SplunkDataReaderTests.java new file mode 100644 index 0000000..7fcde9e --- /dev/null +++ b/src/test/java/org/springframework/integration/splunk/support/SplunkDataReaderTests.java @@ -0,0 +1,143 @@ +/* + * 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 static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +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 org.springframework.core.io.ClassPathResource; +import org.springframework.integration.splunk.core.Connection; +import org.springframework.integration.splunk.core.ConnectionFactory; +import org.springframework.integration.splunk.entity.SplunkData; + +import com.splunk.Job; +import com.splunk.JobCollection; +import com.splunk.Service; + +/** + * @author Jarred Li + * @since 1.0 + * + */ +public class SplunkDataReaderTests { + + private SplunkDataReader reader; + + @Before + public void before() { + reader = new SplunkDataReader(new TestConnectioniFactory()); + } + + /** + * Test method for {@link org.springframework.integration.splunk.support.SplunkDataReader#search()}. + * @throws Exception + */ + @Test + public void testBlockingSearch() throws Exception { + reader.setMode(SearchMode.blocking); + reader.setSearch("search spring:example"); + List data = reader.search(); + Assert.assertNotNull(data); + Assert.assertEquals(5, data.size()); + } + + @Test + public void testNonBlockingSearch() throws Exception { + reader.setMode(SearchMode.normal); + reader.setSearch("search spring:example"); + List data = reader.search(); + Assert.assertNotNull(data); + Assert.assertEquals(5, data.size()); + } + + + @Test + public void testRealtimeSearch() throws Exception { + reader.setMode(SearchMode.realtime); + reader.setSearch("search spring:example"); + List data = reader.search(); + Assert.assertNotNull(data); + Assert.assertEquals(5, data.size()); + } + + public static class TestConnectioniFactory implements ConnectionFactory { + + /* (non-Javadoc) + * @see org.springframework.integration.splunk.core.ConnectionFactory#getConnection() + */ + public Connection getConnection() throws Exception { + return new TestConnection(); + } + } + + public static class TestConnection implements Connection { + + private Service service = mock(Service.class); + + /* (non-Javadoc) + * @see org.springframework.integration.splunk.core.Connection#getTarget() + */ + public Service getTarget() { + InputStream is = null; + + try { + is = new ClassPathResource("splunk-data.xml").getInputStream(); + } catch (FileNotFoundException e) { + Assert.fail("can not read splunk data file"); + } catch (IOException e) { + Assert.fail("can not read splunk data file"); + } + + + service.setToken("token"); + JobCollection jobCollection = mock(JobCollection.class); + Job blockingJob = mock(Job.class); + when(blockingJob.isDone()).thenReturn(true); + when(blockingJob.getResultCount()).thenReturn(5); + when(blockingJob.getResults(any(Map.class))).thenReturn(is); + when(jobCollection.create(any(String.class), any(Map.class))).thenReturn(blockingJob); + when(service.getJobs()).thenReturn(jobCollection); + return service; + } + + /* (non-Javadoc) + * @see org.springframework.integration.splunk.core.Connection#close() + */ + public void close() { + + } + + /* (non-Javadoc) + * @see org.springframework.integration.splunk.core.Connection#isOpen() + */ + public boolean isOpen() { + return true; + } + + } + +} diff --git a/src/test/java/org/springframework/integration/splunk/support/SplunkDataWriterTests.java b/src/test/java/org/springframework/integration/splunk/support/SplunkDataWriterTests.java new file mode 100644 index 0000000..7fea6b8 --- /dev/null +++ b/src/test/java/org/springframework/integration/splunk/support/SplunkDataWriterTests.java @@ -0,0 +1,100 @@ +/* + * 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 static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.integration.splunk.core.Connection; +import org.springframework.integration.splunk.core.ConnectionFactory; +import org.springframework.integration.splunk.entity.SplunkData; + +import com.splunk.Args; +import com.splunk.Receiver; +import com.splunk.Service; + +/** + * @author Jarred Li + * @since 1.0 + * + */ +public class SplunkDataWriterTests { + + private SplunkDataWriter writer; + + private static Receiver receiver = mock(Receiver.class); + + @Before + public void before() { + writer = new SplunkDataWriter(new TestConnectioniFactory()); + } + + /** + * Test method for {@link org.springframework.integration.splunk.support.SplunkDataWriter#write(org.springframework.integration.splunk.entity.SplunkData)}. + * @throws Exception + */ + @Test + public void testWrite() throws Exception { + writer.setIngest(IngestType.submit); + + SplunkData sd = new SplunkData("spring", "spring:example"); + sd.setCommonDesc("description"); + writer.write(sd); + Args args = new Args(); + verify(receiver).submit(eq(args), matches(".*spring:example.*")); + } + + public static class TestConnectioniFactory implements ConnectionFactory { + + /* (non-Javadoc) + * @see org.springframework.integration.splunk.core.ConnectionFactory#getConnection() + */ + public Connection getConnection() throws Exception { + return new TestConnection(); + } + } + + public static class TestConnection implements Connection { + + private Service service = mock(Service.class); + + /* (non-Javadoc) + * @see org.springframework.integration.splunk.core.Connection#getTarget() + */ + public Service getTarget() { + service.setToken("token"); + when(service.getReceiver()).thenReturn(receiver); + return service; + } + + /* (non-Javadoc) + * @see org.springframework.integration.splunk.core.Connection#close() + */ + public void close() { + + } + + /* (non-Javadoc) + * @see org.springframework.integration.splunk.core.Connection#isOpen() + */ + public boolean isOpen() { + return true; + } + + } +} diff --git a/src/test/java/org/springframework/integration/splunk/support/SplunkExecutorTests.java b/src/test/java/org/springframework/integration/splunk/support/SplunkExecutorTests.java new file mode 100644 index 0000000..9163964 --- /dev/null +++ b/src/test/java/org/springframework/integration/splunk/support/SplunkExecutorTests.java @@ -0,0 +1,90 @@ +/* + * 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 static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.integration.Message; +import org.springframework.integration.splunk.core.DataReader; +import org.springframework.integration.splunk.core.DataWriter; +import org.springframework.integration.splunk.entity.SplunkData; +import org.springframework.integration.support.MessageBuilder; + +/** + * @author Jarred Li + * @since 1.0 + * + */ +public class SplunkExecutorTests { + + private SplunkExecutor executor; + + private DataReader reader = mock(DataReader.class); + + private DataWriter writer = mock(DataWriter.class); + + @Before + public void before() { + executor = new SplunkExecutor(); + executor.setReader(reader); + executor.setWriter(writer); + } + + + /** + * Test method for {@link org.springframework.integration.splunk.support.SplunkExecutor#handleMessage(org.springframework.integration.Message)}. + * @throws Exception + */ + @Test + public void testHandleMessage() throws Exception { + SplunkData sd = new SplunkData("spring", "spring:example"); + sd.setCommonDesc("description"); + Message message = MessageBuilder.withPayload(sd).build(); + executor.handleMessage(message); + verify(writer).write(sd); + } + + /** + * Test method for {@link org.springframework.integration.splunk.support.SplunkExecutor#poll()}. + * @throws Exception + */ + @Test + public void testPoll() throws Exception { + List data = new ArrayList(); + SplunkData sd = new SplunkData("spring", "spring:example"); + sd.setCommonDesc("description"); + data.add(sd); + + sd = new SplunkData("spring", "spring:example"); + sd.setCommonDesc("description"); + data.add(sd); + when(reader.search()).thenReturn(data); + + List result = executor.poll(); + Assert.assertEquals(2, result.size()); + + } + +} diff --git a/src/test/resources/log4j.properties b/src/test/resources/log4j.properties new file mode 100644 index 0000000..6142a0d --- /dev/null +++ b/src/test/resources/log4j.properties @@ -0,0 +1,5 @@ +log4j.rootCategory=INFO, stdout + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss.SSS} %-5p [%t][%c] %m%n diff --git a/src/test/resources/org/springframework/integration/splunk/SplunkCommon-context.xml b/src/test/resources/org/springframework/integration/splunk/SplunkCommon-context.xml new file mode 100644 index 0000000..4cdbdf3 --- /dev/null +++ b/src/test/resources/org/springframework/integration/splunk/SplunkCommon-context.xml @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserCommon-context.xml b/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserCommon-context.xml new file mode 100644 index 0000000..7bf4b88 --- /dev/null +++ b/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserCommon-context.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserSavedSearchTests-context.xml b/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserSavedSearchTests-context.xml new file mode 100644 index 0000000..8a0ab3f --- /dev/null +++ b/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserSavedSearchTests-context.xml @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserTests-context.xml b/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserTests-context.xml new file mode 100644 index 0000000..0bd2da1 --- /dev/null +++ b/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkInboundChannelAdapterParserTests-context.xml @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserStreamTests-context.xml b/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserStreamTests-context.xml new file mode 100644 index 0000000..3462ff6 --- /dev/null +++ b/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserStreamTests-context.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + diff --git a/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserTests-context.xml b/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserTests-context.xml new file mode 100644 index 0000000..57ec361 --- /dev/null +++ b/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkOutboundChannelAdapterParserTests-context.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + diff --git a/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkServerParserTests-context.xml b/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkServerParserTests-context.xml new file mode 100644 index 0000000..e263634 --- /dev/null +++ b/src/test/resources/org/springframework/integration/splunk/config/xml/SplunkServerParserTests-context.xml @@ -0,0 +1,17 @@ + + + + + + diff --git a/src/test/resources/splunk-data.xml b/src/test/resources/splunk-data.xml new file mode 100644 index 0000000..c492d7e --- /dev/null +++ b/src/test/resources/splunk-data.xml @@ -0,0 +1,236 @@ + + + + +_cd +_indextime +_raw +_serial +_si +_sourcetype +_subsecond +_time +host +index +linecount +source +sourcetype +splunk_server + + + + + 9:30 + + + 1348478076 + + 2012-09-24 17:19:43:792+0800 name="spring" event_id="spring:example" desc="description" + + 0 + + + jarred-virtual-machine + main + + + spring-integration + + + .792 + + + 2012-09-24T17:19:43.792+08:00 + + + test.host + + + main + + + 1 + + + example5 + + + spring-integration + + + jarred-virtual-machine + + + + + 9:26 + + + 1348478076 + + 2012-09-24 17:19:43:756+0800 name="spring" event_id="spring:example" desc="description" + + 1 + + + jarred-virtual-machine + main + + + spring-integration + + + .756 + + + 2012-09-24T17:19:43.756+08:00 + + + test.host + + + main + + + 1 + + + example5 + + + spring-integration + + + jarred-virtual-machine + + + + + 9:21 + + + 1348464748 + + 2012-09-24 13:37:34:860+0800 name="spring" event_id="spring:example" desc="description" + + 2 + + + jarred-virtual-machine + main + + + spring-integration + + + .860 + + + 2012-09-24T13:37:34.860+08:00 + + + test.host + + + main + + + 1 + + + example5 + + + spring-integration + + + jarred-virtual-machine + + + + + 9:17 + + + 1348464748 + + 2012-09-24 13:37:34:789+0800 name="spring" event_id="spring:example" desc="description" + + 3 + + + jarred-virtual-machine + main + + + spring-integration + + + .789 + + + 2012-09-24T13:37:34.789+08:00 + + + test.host + + + main + + + 1 + + + example5 + + + spring-integration + + + jarred-virtual-machine + + + + + 9:12 + + + 1348464606 + + 2012-09-24 13:35:13:621+0800 name="spring" event_id="spring:example" desc="description" + + 4 + + + jarred-virtual-machine + main + + + spring-integration + + + .621 + + + 2012-09-24T13:35:13.621+08:00 + + + test.host + + + main + + + 1 + + + example5 + + + spring-integration + + + jarred-virtual-machine + + + \ No newline at end of file