Projects >> splunk-sdk-java >>a98f3751e1bd8f8ee1d77e4c55440ccf6c1c48bd

Chunk
Conflicting content
 */
     *

    /**
<<<<<<< HEAD
/*
 * Copyright 2012 Splunk, Inc.
 *
 * 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 com.splunk;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.Map;

/**
     *
 * The {@code Service} class represents a Splunk service instance at a given
 * address (host:port), accessed using the {@code http} or {@code https}
 * protocol scheme.
 * 

* A {@code Service} instance also captures an optional namespace context * consisting of an optional owner name (or "-" wildcard) and optional app name * (or "-" wildcard). *

* To access {@code Service} members, the {@code Service} instance must be * authenticated by presenting credentials using the {@code login} method, or * by constructing the {@code Service} instance using the {@code connect} * method, which both creates and authenticates the instance. */ public class Service extends BaseService { /** The current app context. */ protected String app = null; /** The current session token. */ protected String token = null; /** The current owner context. A value of "nobody" means that all users * have access to the resource. */ protected String owner = null; /** The Splunk account username, which is used to authenticate the Splunk * instance. */ protected String username = null; /** The password, which is used to authenticate the Splunk instance. */ protected String password = null; /** The default simple receiver endpoint. */ protected String simpleReceiverEndPoint = "receivers/simple"; /** The default password endpoint, can change over Splunk versions. */ protected String passwordEndPoint = "admin/passwords"; /** The version of this Splunk instance, once logged in. */ public String version = null; /** The default host name, which is used when a host name is not provided.*/ public static String DEFAULT_HOST = "localhost"; /** The default port number, which is used when a port number is not * provided. */ public static int DEFAULT_PORT = 8089; /** The default scheme, which is used when a scheme is not provided. */ public static String DEFAULT_SCHEME = "https"; /** * Creates a new {@code Service} instance using a host. * * @param host The host name. */ public Service(String host) { super(host); } /** * Creates a new {@code Service} instance using a host and port. * * @param host The host name. * @param port The port number. */ public Service(String host, int port) { super(host, port); } /** * Creates a new {@code Service} instance using a host, port, and * scheme for accessing the service ({@code http} or {@code https}). * * @param host The host name. * @param port The port number. * @param scheme The scheme ({@code http} or {@code https}). */ public Service(String host, int port, String scheme) { super(host, port, scheme); } /** * Creates a new {@code Service} instance using a collection of arguments. * * @param args The {@code ServiceArgs} to initialize the service. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. @SuppressWarnings("deprecation") public Service(ServiceArgs args) { super(); // NOTE: Must read the deprecated fields for backward compatibility. // (Consider the case where the fields are initialized directly, // rather than using the new setters.) // NOTE: Must also read the underlying dictionary for forward compatibility. /** // (Consider the case where the user calls Map.put() directly, // rather than using the new setters.) this.app = Args.get(args, "app", args.app != null ? args.app : null); this.host = Args.get(args, "host", args.host != null ? args.host : DEFAULT_HOST); this.owner = Args.get(args, "owner", args.owner != null ? args.owner : null); this.port = Args.get(args, "port", args.port != null ? args.port : DEFAULT_PORT); this.scheme = Args.get(args, "scheme", args.scheme != null ? args.scheme : DEFAULT_SCHEME); this.token = Args.get(args, "token", args.token != null ? args.token : null); this.username = (String)args.get("username"); this.password = (String)args.get("password"); } /** * Creates a new {@code Service} instance using a map of arguments. * * @param args A {@code Map} of arguments to initialize the service. */ public Service(Map args) { super(); this.app = Args.get(args, "app", null); this.host = Args.get(args, "host", DEFAULT_HOST); this.owner = Args.get(args, "owner", null); this.port = Args.get(args, "port", DEFAULT_PORT); this.scheme = Args.get(args, "scheme", DEFAULT_SCHEME); this.token = Args.get(args, "token", null); this.username = (String)args.get("username"); this.password = (String)args.get("password"); } /** * Establishes a connection to a Splunk service using a map of arguments. * This member creates a new {@code Service} instance and authenticates * the session using credentials passed in from the {@code args} map. * * @param args The {@code args} map. * @return A new {@code Service} instance. */ public static Service connect(Map args) { Service service = new Service(args); if (args.containsKey("username")) { service.login(); } return service; } /** * Runs a search using the {@code search/jobs/export} endpoint, which * streams results back in an input stream. * * @param search The search query to run. * @return The {@code InputStream} object that contains the search results. */ public InputStream export(String search) { return export(search, null); } /** * Runs a search with arguments using the {@code search/jobs/export} * endpoint, which streams results back in an input stream. * * @param search The search query to run. * @param args Additional search arguments. * For a list of possible parameters, see * Saved search parameters on * dev.splunk.com. * @return The {@code InputStream} object that contains the search results. */ public InputStream export(String search, Map args) { args = Args.create(args).add("search", search); ResponseMessage response = get("search/jobs/export", args); return new ExportResultsStream(response.getContent()); } /** * Runs a search with arguments using the {@code search/jobs/export} * endpoint, which streams results back in an input stream. * * @param search The search query to run. * @param args Additional search arguments (see {@code JobExportArgs}). * @return The {@code InputStream} object that contains the search results. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. public InputStream export(String search, JobExportArgs args) { return export(search, (Map) args); } * Ensures that the given path is fully qualified, prepending a path * prefix if necessary. The path prefix is constructed using the current * owner and app context when available. * * @param path The path to verify. * @return A fully-qualified resource path. */ String fullpath(String path) { return fullpath(path, null); } /** * Ensures that the given path is fully qualified, prepending a path * prefix if necessarry. The path prefix is constructed using the * current owner and app context when available. * * @param path The path to verify. * @param namespace The name space dictionary (app, owner, sharing). * @return A fully-qualified resource path. */ public String fullpath(String path, Args namespace) { // if already fully qualified (i.e. root begins with /) then return // the already qualified path. if (path.startsWith("/")) return path; // if no namespace at all, and no service instance of app, and no // sharing, return base service endpoint + path. if (namespace == null && app == null) { return "/services/" + path; } // base namespace values String localApp = app; String localOwner = owner; String localSharing = ""; // override with invocation namespace if set. if (namespace != null) { if (namespace.containsKey("app")) localApp = (String)namespace.get("app"); if (namespace.containsKey("owner")) localOwner = (String)namespace.get("owner"); if (namespace.containsKey("sharing")) localSharing = (String)namespace.get("sharing"); } // sharing, if set calls for special mapping, override here. // "user" --> {user}/{app} // "app" --> nobody/{app} // "global" --> nobody/{app} // "system" --> nobody/system if (localSharing.equals("app") || localSharing.equals("global")) localOwner = "nobody"; else if (localSharing.equals("system")) { localApp = "system"; localOwner = "nobody"; } return String.format("/servicesNS/%s/%s/%s", localOwner == null ? "-" : localOwner, localApp == null ? "-" : localApp, path); } /** * Returns the app context for this {@code Service} instance. * A {@code null} value indicates no app context, and a value of * {@code "-"} indicates an app wildcard. * * @return The app context. */ public String getApp() { return this.app; } /** * Returns the collection of applications. * * @return The application collection. */ public EntityCollection getApplications() { return new EntityCollection( this, "/services/apps/local", Application.class); } /** * Returns the collection of configurations. * * @return The configurations collection. */ */ public ConfCollection getConfs() { return getConfs(null); } /** * Returns the collection of configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return The configurations collection. */ public ConfCollection getConfs(Args args) { return new ConfCollection(this, args); } /** * Returns an array of system capabilities. * * @return An array of capabilities. */ public String[] getCapabilities() { Entity caps = new Entity(this, "authorization/capabilities"); return caps.getStringArray("capabilities"); } /** * Returns the configuration and status of a deployment client. * * @return The configuration and status. */ public DeploymentClient getDeploymentClient() { return new DeploymentClient(this); } /** * Returns the configuration of all deployment servers. * * @return The configuration of deployment servers. */ public EntityCollection getDeploymentServers() { return getDeploymentServers(null); } /** * Returns the collection of deployment servers. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return The configuration of deployment servers. */ public EntityCollection getDeploymentServers(Args args) { return new EntityCollection( this, "deployment/server", DeploymentServer.class, args); } /** * Returns a collection of class configurations for a deployment server. * * @return A collection of class configurations. */ public EntityCollection getDeploymentServerClasses(){ return getDeploymentServerClasses(null); } /** * Returns a collection of class configurations for a deployment server. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of server class configurations. */ public EntityCollection getDeploymentServerClasses( Args args) { return new EntityCollection( this, "deployment/serverclass", DeploymentServerClass.class, args); } /** * Returns a collection of multi-tenant configurations. * * @return A collection of multi-tenant configurations. */ public EntityCollection getDeploymentTenants() { return getDeploymentTenants(null); } /** * Returns a collection of multi-tenant configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of multi-tenant configurations. */ public EntityCollection getDeploymentTenants(Args args) { return new EntityCollection( this, "deployment/tenants", DeploymentTenant.class, args); } /** * Returns information about distributed search options. * * @return Distributed search information. public DistributedConfiguration getDistributedConfiguration() { return new DistributedConfiguration(this); } /** * Returns a collection of distributed search peers. A search peer * is a Splunk server to which another Splunk server distributes searches. * The Splunk server where the search originates is referred to as the * search head. * * @return A collection of search peers. */ public EntityCollection getDistributedPeers() { return getDistributedPeers(null); } /** * Returns a collection of distributed search peers. A search peer * is a Splunk server to which another Splunk server distributes searches. * The Splunk server where the search originates is referred to as the * search head. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of search peers. */ public EntityCollection getDistributedPeers(Args args) { return new EntityCollection( this, "search/distributed/peers", DistributedPeer.class, args); } /** * Returns a collection of saved event types. * * @return A collection of saved event types. */ public EventTypeCollection getEventTypes() { return getEventTypes(null); } /** * Returns a collection of saved event types. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of saved event types. */ public EventTypeCollection getEventTypes(Args args) { return new EventTypeCollection(this, args); } /** * Returns a collection of alerts that have been fired by the service. * * @return A collection of fired alerts. */ public FiredAlertGroupCollection getFiredAlertGroups() { return getFiredAlertsGroups(null); } /** * Returns a collection of alerts that have been fired by the service. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of fired alerts. */ public FiredAlertGroupCollection getFiredAlertsGroups(Args args) { return new FiredAlertGroupCollection(this, args); } /** * Returns a collection of Splunk indexes. * * @return A collection of indexes. */ public IndexCollection getIndexes() { return getIndexes((IndexCollectionArgs)null); } /** * Returns a collection of Splunk indexes. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link IndexCollectionArgs}. * @return A collection of indexes. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. public IndexCollection getIndexes(IndexCollectionArgs args) { return getIndexes((Args)args); } /** * Returns a collection of Splunk indexes. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link IndexCollectionArgs}. * @return A collection of indexes. */ public IndexCollection getIndexes(Args args) { return new IndexCollection(this, args); } /** * Returns information about the Splunk service. * @return Splunk service information. */ public ServiceInfo getInfo() { return new ServiceInfo(this); } /** * Returns a collection of configured inputs. * * @return A collection of inputs. */ public InputCollection getInputs() { return getInputs(null); } /** * Returns a collection of configured inputs. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of inputs. */ public InputCollection getInputs(Args args) { return new InputCollection(this, args); } /** * Returns a collection of current search jobs. * * @return A collection of search jobs. */ public JobCollection getJobs() { return getJobs((CollectionArgs)null); } /** * Returns a collection of current search jobs. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of search jobs. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. public JobCollection getJobs(CollectionArgs args) { return getJobs((Args)args); } /** * Returns a collection of current search jobs. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of search jobs. */ public JobCollection getJobs(Args args) { return new JobCollection(this, args); } /** * Returns a collection of license group configurations. * * @return A collection of license group configurations. */ public EntityCollection getLicenseGroups() { return getLicenseGroups(null); } /** * Returns a collection of license group configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of license group configurations. */ public EntityCollection getLicenseGroups(Args args) { return new EntityCollection( this, "licenser/groups", LicenseGroup.class, args); } /** * Returns a collection of messages from the licenser. * * @return A collection of licenser messages. */ public EntityCollection getLicenseMessages() { return getLicenseMessages(null); } /** * Returns a collection of messages from the licenser. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of licenser messages. */ public EntityCollection getLicenseMessages(Args args) { return new EntityCollection( this, "licenser/messages", LicenseMessage.class, args); } /** * Returns the current owner context for this {@code Service} instance. * Returns a collection of saved searches. * A value of {@code "-"} indicates a wildcard, and a {@code null} value * indicates no owner context. * * @return The current owner context. */ public String getOwner() { return this.owner; } /** * Returns a collection of licenser pool configurations. * * @return A collection of licenser pool configurations. */ public LicensePoolCollection getLicensePools() { return getLicensePools(null); } /** * Returns a collection of licenser pool configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of licenser pool configurations. */ public LicensePoolCollection getLicensePools(Args args) { return new LicensePoolCollection(this, args); } /** * Returns a collection of slaves reporting to this license master. * * @return A collection of licenser slaves. */ public EntityCollection getLicenseSlaves() { return getLicenseSlaves(null); } /** * Returns a collection of slaves reporting to this license master. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of licenser slaves. */ public EntityCollection getLicenseSlaves(Args args) { return new EntityCollection( this, "licenser/slaves", LicenseSlave.class, args); } /** * Returns a collection of license stack configurations. * * @return A collection of license stack configurations. */ public EntityCollection getLicenseStacks() { return getLicenseStacks(null); } /** * Returns a collection of license stack configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of license stack configurations. */ public EntityCollection getLicenseStacks(Args args) { return new EntityCollection( this, "licenser/stacks", LicenseStack.class, args); } /** * Returns a collection of licenses for this service. * * @return A collection of licenses. */ public EntityCollection getLicenses() { return getLicenses(null); } /** * Returns a collection of licenses for this service. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of licenses. */ public EntityCollection getLicenses(Args args) { return new EntityCollection( this, "licenser/licenses", License.class, args); } /** * Returns a collection of service logging categories and their status. * * @return A collection of logging categories. */ public EntityCollection getLoggers() { return getLoggers(null); } /** * Returns a collection of service logging categories and their status. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of logging categories. */ public EntityCollection getLoggers(Args args) { return new EntityCollection( this, "server/logger", Logger.class, args); } /** * Returns a collection of system messages. * * @return A collection of system messages. */ public MessageCollection getMessages() { return getMessages(null); } /** * Returns a collection of system messages. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of system messages. */ public MessageCollection getMessages(Args args) { return new MessageCollection(this, args); } /** * Returns a collection of modular inputs. * * @return A collection of modular inputs. */ public ResourceCollection getModularInputKinds() { return getModularInputKinds(null); } /** * Returns a collection of modular inputs. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of modular inputs. */ public ResourceCollection getModularInputKinds(Args args) { return new ResourceCollection( this, "data/modular-inputs", ModularInputKind.class, args); } /** * Returns global TCP output properties. * * @return Global TCP output properties. */ public OutputDefault getOutputDefault() { return new OutputDefault(this); } /** * Returns a collection of output group configurations. * * @return A collection of output group configurations. */ public EntityCollection getOutputGroups() { return getOutputGroups(null); } /** * Returns a collection of output group configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of output group configurations. */ public EntityCollection getOutputGroups(Args args) { return new EntityCollection( this, "data/outputs/tcp/group", OutputGroup.class, args); } /** * Returns a collection of data-forwarding configurations. * * @return A collection of data-forwarding configurations. */ public EntityCollection getOutputServers() { return getOutputServers(null); } /** * Returns a collection of data-forwarding configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of data-forwarding configurations. */ */ public EntityCollection getOutputServers(Args args) { return new EntityCollection( this, "data/outputs/tcp/server", OutputServer.class, args); } /** * * Returns a collection of configurations for forwarding data in standard * syslog format. * * @return A collection of syslog forwarders. */ public EntityCollection getOutputSyslogs() { return getOutputSyslogs(null); } /** * Returns a collection of configurations for forwarding data in standard * syslog format. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of syslog forwarders. */ public EntityCollection getOutputSyslogs(Args args) { return new EntityCollection( this, "data/outputs/tcp/syslog", OutputSyslog.class, args); } /** * Returns the current password that was used to authenticate the session. * * @return The current password. */ public String getPassword() { return this.password; } /** * Returns a collection of passwords. This collection is used for managing * secure credentials. * * @return A collection of passwords. */ public PasswordCollection getPasswords() { return getPasswords(null); } /** * Returns a collection of passwords. This collection is used for managing * secure credentials. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of passwords. */ public PasswordCollection getPasswords(Args args) { return new PasswordCollection(this, args); } /** * Returns the receiver object for the Splunk service. * * @return A Splunk receiver object. */ public Receiver getReceiver() { return new Receiver(this); } /** * Returns a collection of Splunk user roles. * * @return A collection of user roles. */ public EntityCollection getRoles() { return getRoles(null); } /** * Returns a collection of Splunk user roles. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of user roles. */ public EntityCollection getRoles(Args args) { return new EntityCollection( this, "authentication/roles", Role.class, args); } /** * Returns a collection of saved searches. * * @return A collection of saved searches. */ public SavedSearchCollection getSavedSearches() { return getSavedSearches((SavedSearchCollectionArgs)null); } /** * Returns a collection of saved searches. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link SavedSearchCollectionArgs}. * @return A collection of saved searches. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. public SavedSearchCollection getSavedSearches(SavedSearchCollectionArgs args) { return getSavedSearches((Args)args); } * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of saved searches. */ public SavedSearchCollection getSavedSearches(Args args) { return new SavedSearchCollection(this, args); } /** * Returns service configuration information for an instance of Splunk. * * @return Service configuration information. */ public Settings getSettings() { return new Settings(this); } /** * Returns the current session token. Session tokens can be shared across * multiple {@code Service} instances. * * @return The session token. */ public String getToken() { return this.token; } /** * Returns a collection of in-progress oneshot uploads. * * @return A collection of in-progress oneshot uploads */ public EntityCollection getUploads() { return getUploads(null); } /** * Returns a collection of in-progress oneshot uploads. * * @param namespace This collection's namespace; there are no other * optional arguments for this endpoint. * @return A collection of in-progress oneshot uploads */ public EntityCollection getUploads(Args namespace) { return new EntityCollection( this, "data/inputs/oneshot", Upload.class, namespace); } /** * Returns the Splunk account username that was used to authenticate the * current session. * * @return The current username. */ public String getUsername() { return this.username; } /** * Returns a collection of Splunk users. * * @return A collection of users. */ public UserCollection getUsers() { return getUsers(null); } /** * Returns a collection of Splunk users. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of users. */ public UserCollection getUsers(Args args) { return new UserCollection(this, args); } /** * Authenticates the {@code Service} instance with the username and password * that were specified when the instance was created. * * @return The current {@code Service} instance. */ public Service login() { if (this.username == null || this.password == null) { throw new IllegalStateException("Missing username or password."); } else { return login(this.username, this.password); } } /** * Authenticates the {@code Service} instance with a specified username and * password. Note that these values override any previously-set values for * username and password. * * @param username The Splunk account username. * @param password The password for the username. * @return The current {@code Service} instance. */ public Service login(String username, String password) { this.username = username; this.password = password; Args args = new Args(); args.put("username", username); args.put("password", password); ResponseMessage response = post("/services/auth/login", args); String sessionKey = Xml.parse(response.getContent()) .getElementsByTagName("sessionKey") .item(0) .getTextContent(); this.token = "Splunk " + sessionKey; this.version = this.getInfo().getVersion(); if (versionCompare("4.3") >= 0) this.passwordEndPoint = "storage/passwords"; return this; } /** * Forgets the current session token. * * @return The current {@code Service} instance. */ public Service logout() { this.token = null; return this; } /** * Creates a oneshot synchronous search. * * @param query The search query. * @return The search results. */ public InputStream oneshotSearch(String query) { return oneshotSearch(query, null); } /** * Creates a oneshot synchronous search using search arguments. * * @param query The search query. * @param args The search arguments:

    *
  • "output_mode": Specifies the output format of the results (XML, JSON, * or CSV).
  • *
  • "earliest_time": Specifies the earliest time in the time range to * search. The time string can be a UTC time (with fractional seconds), a * relative time specifier (to now), or a formatted time string.
  • *
  • "latest_time": Specifies the latest time in the time range to search. * The time string can be a UTC time (with fractional seconds), a relative * time specifier (to now), or a formatted time string.
  • *
  • "rf": Specifies one or more fields to add to the search.
* @return The search results. */ public InputStream oneshotSearch(String query, Map args) { args = Args.create(args); args.put("search", query); args.put("exec_mode", "oneshot"); ResponseMessage response = post("search/jobs", args); return response.getContent(); } /** * Creates a oneshot synchronous search using search arguments. * * @param query The search query. * @param args The search arguments:
    *
  • "output_mode": Specifies the output format of the results (XML, JSON, * or CSV).
  • *
  • "earliest_time": Specifies the earliest time in the time range to * search. The time string can be a UTC time (with fractional seconds), a * relative time specifier (to now), or a formatted time string.
  • *
  • "latest_time": Specifies the latest time in the time range to search. * The time string can be a UTC time (with fractional seconds), a relative * time specifier (to now), or a formatted time string.
  • *
  • "rf": Specifies one or more fields to add to the search.
* @return The search results. */ public InputStream oneshotSearch(String query, Args args) { return oneshotSearch(query, (Map)args); } /** * Opens a raw socket to this service. * * @param port The port to open. This port must already have been * created as an allowable TCP input to the service. * @return The socket. * @throws java.io.IOException */ public Socket open(int port) throws IOException { return new Socket(this.host, port); } /** * Parses a search query and returns a semantic map for the search in JSON * format. * * @param query The search query. * @return The parse response message. */ public ResponseMessage parse(String query) { return parse(query, null); } /** * Parses a search query with additional arguments and returns a semantic * map for the search in JSON format. * * @param query The search query. * @param args Additional parse arguments. * @return The parse response message. */ public ResponseMessage parse(String query, Map args) { args = Args.create(args).add("q", query); return get("search/parser", args); } /** * Restarts the service. The service will be unavailable until it has * sucessfully restarted. * * @return The restart response message. */ public ResponseMessage restart() { return get("server/control/restart"); } /** * Creates an asynchronous search using the given query. Use this * method for simple searches. * * @param query The search query. * @return The search job. */ public Job search(String query) { return search(query, null); } /** * Creates an asynchronous search job using the given query and * search arguments. * * @param query The search query. * @param args The search arguments. * @return The search job. */ public Job search(String query, Map args) { args = Args.create(args); args.put("search", query); return this.getJobs().create(query, args); } /** * Issues an HTTP request against the service using a request path and * message. * This method overrides the base {@code HttpService.send} method * and applies the Splunk authorization header, which is required for * authenticated interactions with the Splunk service. * * @param path The request path. * @param request The request message. * @return The HTTP response. */ @Override public ResponseMessage send(String path, RequestMessage request) { request.getHeader().put("Authorization", token); return super.send(fullpath(path), request); } /** * Provides a session token for use by this {@code Service} instance. * Session tokens can be shared across multiple {@code Service} instances. * * @param value The session token. */ public void setToken(String value) { this.token = value; } /** * Returns true if this Splunk instance's version is no earlier than * the version specified in {@code version}. * * So when called on a Splunk 4.3.2 instance: * * {@code versionIsAtLeast("4.3.2")} is {@code true}. * * {@code versionIsAtLeast("4.1.0")} is {@code true}. * * {@code versionIsAtLeast("5.0.0")} is {@code false}. * * @param version The version to compare this Splunk instance's version against. * @return {@code true} if this Splunk instance's version is equal or * greater than {@code version}; {@code false} otherwise. boolean versionIsAtLeast(String version) { return versionCompare(version) >= 0; } /** * Returns true if this Splunk instance's version is earlier than * the version specified in {@code version}. * So when called on a Splunk 4.3.2 instance: * * {@code versionIsEarlierThan("4.3.2")} is {@code false}. * * {@code versionIsEarlierThan("4.1.0")} is {@code false}. * * {@code versionIsEarlierThan("5.0.0")} is {@code true}. * * @param version The version to compare this Splunk instance's version against. * @return {@code true} if this Splunk instance's version is less * than {@code version}; {@code false} otherwise. */ boolean versionIsEarlierThan(String version) { return versionCompare(version) < 0; } /** * Returns {@code -1} if {@code this.version < otherVersion}. * Returns {@code 0} if {@code this.version &eq; otherVersion}. * Returns {@code 1} if {@code this.version > otherVersion}. * * @param otherVersion The version to compare this Splunk instance's version against. * @return {@code -1} if {@code this.version < otherVersion}, * {@code 0} if {@code this.version &eq; otherVersion}, or * {@code 1} if {@code this.version > otherVersion}. */ public int versionCompare(String otherVersion) { String[] components1 = this.version.split("\\."); String[] components2 = otherVersion.split("\\."); int numComponents = Math.max(components1.length, components2.length); for (int i = 0; i < numComponents; i++) { int c1 = (i < components1.length) ? Integer.parseInt(components1[i], 10) : 0; int c2 = (i < components2.length) ? Integer.parseInt(components2[i], 10) : 0; if (c1 < c2) { return -1; } else if (c1 > c2) { return 1; } } return 0; } } ======= /* * Copyright 2012 Splunk, Inc. * * 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 com.splunk; import java.io.IOException; import java.io.InputStream; import java.net.Socket; import java.util.Map; /** * The {@code Service} class represents a Splunk service instance at a given * address (host:port), accessed using the {@code http} or {@code https} * protocol scheme. *

* A {@code Service} instance also captures an optional namespace context * consisting of an optional owner name (or "-" wildcard) and optional app name * (or "-" wildcard). *

* To access {@code Service} members, the {@code Service} instance must be * authenticated by presenting credentials using the {@code login} method, or * by constructing the {@code Service} instance using the {@code connect} * method, which both creates and authenticates the instance. */ public class Service extends BaseService { /** The current app context. */ protected String app = null; /** The current session token. */ protected String token = null; /** The current owner context. A value of "nobody" means that all users * have access to the resource. */ protected String owner = null; /** The Splunk account username, which is used to authenticate the Splunk * instance. */ protected String username = null; /** The password, which is used to authenticate the Splunk instance. */ protected String password = null; /** The default simple receiver endpoint. */ protected String simpleReceiverEndPoint = "receivers/simple"; /** The default password endpoint, can change over Splunk versions. */ protected String passwordEndPoint = "admin/passwords"; /** The version of this Splunk instance, once logged in. */ public String version = null; /** The default host name, which is used when a host name is not provided.*/ public static String DEFAULT_HOST = "localhost"; /** The default port number, which is used when a port number is not * provided. */ public static int DEFAULT_PORT = 8089; /** The default scheme, which is used when a scheme is not provided. */ public static String DEFAULT_SCHEME = "https"; /** * Creates a new {@code Service} instance using a host. * * @param host The host name. */ public Service(String host) { super(host); } /** * Creates a new {@code Service} instance using a host and port. * * @param host The host name. * @param port The port number. */ public Service(String host, int port) { super(host, port); } /** * Creates a new {@code Service} instance using a host, port, and * scheme for accessing the service ({@code http} or {@code https}). * * @param host The host name. * @param port The port number. * @param scheme The scheme ({@code http} or {@code https}). */ public Service(String host, int port, String scheme) { super(host, port, scheme); } /** * Creates a new {@code Service} instance using a collection of arguments. * * @param args The {@code ServiceArgs} to initialize the service. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. @SuppressWarnings("deprecation") public Service(ServiceArgs args) { super(); // NOTE: Must read the deprecated fields for backward compatibility. // (Consider the case where the fields are initialized directly, // rather than using the new setters.) // NOTE: Must also read the underlying dictionary for forward compatibility. // (Consider the case where the user calls Map.put() directly, // rather than using the new setters.) this.app = Args.get(args, "app", args.app != null ? args.app : null); this.host = Args.get(args, "host", args.host != null ? args.host : DEFAULT_HOST); this.owner = Args.get(args, "owner", args.owner != null ? args.owner : null); this.port = Args.get(args, "port", args.port != null ? args.port : DEFAULT_PORT); this.scheme = Args.get(args, "scheme", args.scheme != null ? args.scheme : DEFAULT_SCHEME); this.token = Args.get(args, "token", args.token != null ? args.token : null); this.username = (String)args.get("username"); this.password = (String)args.get("password"); } /** * Creates a new {@code Service} instance using a map of arguments. * * @param args A {@code Map} of arguments to initialize the service. */ public Service(Map args) { super(); this.app = Args.get(args, "app", null); this.host = Args.get(args, "host", DEFAULT_HOST); this.owner = Args.get(args, "owner", null); this.port = Args.get(args, "port", DEFAULT_PORT); this.scheme = Args.get(args, "scheme", DEFAULT_SCHEME); this.token = Args.get(args, "token", null); this.username = (String)args.get("username"); this.password = (String)args.get("password"); } /** * Establishes a connection to a Splunk service using a map of arguments. * This member creates a new {@code Service} instance and authenticates * the session using credentials passed in from the {@code args} map. * * @param args The {@code args} map. * @return A new {@code Service} instance. */ public static Service connect(Map args) { Service service = new Service(args); if (args.containsKey("username")) { service.login(); } return service; } /** * Runs a search using the {@code search/jobs/export} endpoint, which * streams results back in an input stream. * * @param search The search query to run. * @return The {@code InputStream} object that contains the search results. */ public InputStream export(String search) { return export(search, null); } /** * Runs a search with arguments using the {@code search/jobs/export} * endpoint, which streams results back in an input stream. * * @param search The search query to run. * @param args Additional search arguments. * For a list of possible parameters, see * Saved search parameters on * dev.splunk.com. * @return The {@code InputStream} object that contains the search results. */ public InputStream export(String search, Map args) { args = Args.create(args).add("search", search); // By default don't highlight search terms in the output. if (!args.containsKey("segmentation")) { args.put("segmentation", "none"); } ResponseMessage response = get("search/jobs/export", args); return response.getContent(); } /** * Runs a search with arguments using the {@code search/jobs/export} * endpoint, which streams results back in an input stream. * * @param search The search query to run. * @param args Additional search arguments (see {@code JobExportArgs}). * @return The {@code InputStream} object that contains the search results. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. public InputStream export(String search, JobExportArgs args) { return export(search, (Map) args); } /** * Ensures that the given path is fully qualified, prepending a path * prefix if necessary. The path prefix is constructed using the current * owner and app context when available. * * @param path The path to verify. * @return A fully-qualified resource path. */ String fullpath(String path) { return fullpath(path, null); } /** * Ensures that the given path is fully qualified, prepending a path * prefix if necessarry. The path prefix is constructed using the * current owner and app context when available. * * @param path The path to verify. * @param namespace The name space dictionary (app, owner, sharing). * @return A fully-qualified resource path. */ public String fullpath(String path, Args namespace) { // if already fully qualified (i.e. root begins with /) then return // the already qualified path. if (path.startsWith("/")) return path; // if no namespace at all, and no service instance of app, and no // sharing, return base service endpoint + path. if (namespace == null && app == null) { return "/services/" + path; } // base namespace values String localApp = app; String localOwner = owner; String localSharing = ""; // override with invocation namespace if set. if (namespace != null) { if (namespace.containsKey("app")) localApp = (String)namespace.get("app"); if (namespace.containsKey("owner")) localOwner = (String)namespace.get("owner"); if (namespace.containsKey("sharing")) localSharing = (String)namespace.get("sharing"); } // sharing, if set calls for special mapping, override here. // "user" --> {user}/{app} // "app" --> nobody/{app} // "global" --> nobody/{app} // "system" --> nobody/system if (localSharing.equals("app") || localSharing.equals("global")) localOwner = "nobody"; else if (localSharing.equals("system")) { localApp = "system"; localOwner = "nobody"; } return String.format("/servicesNS/%s/%s/%s", localOwner == null ? "-" : localOwner, localApp == null ? "-" : localApp, path); } /** * Returns the app context for this {@code Service} instance. * A {@code null} value indicates no app context, and a value of * {@code "-"} indicates an app wildcard. * * @return The app context. */ public String getApp() { return this.app; } /** * Returns the collection of applications. * * @return The application collection. */ public EntityCollection getApplications() { return new EntityCollection( this, "/services/apps/local", Application.class); } /** * Returns the collection of configurations. * * @return The configurations collection. */ public ConfCollection getConfs() { return getConfs(null); } /** * Returns the collection of configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return The configurations collection. */ public ConfCollection getConfs(Args args) { return new ConfCollection(this, args); } /** * Returns an array of system capabilities. * * @return An array of capabilities. */ public String[] getCapabilities() { Entity caps = new Entity(this, "authorization/capabilities"); return caps.getStringArray("capabilities"); } /** * Returns the configuration and status of a deployment client. * * @return The configuration and status. */ public DeploymentClient getDeploymentClient() { return new DeploymentClient(this); } /** * Returns the configuration of all deployment servers. * * @return The configuration of deployment servers. */ public EntityCollection getDeploymentServers() { return getDeploymentServers(null); } /** * Returns the collection of deployment servers. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return The configuration of deployment servers. */ public EntityCollection getDeploymentServers(Args args) { return new EntityCollection( this, "deployment/server", DeploymentServer.class, args); } /** * Returns a collection of class configurations for a deployment server. * * @return A collection of class configurations. */ public EntityCollection getDeploymentServerClasses(){ return getDeploymentServerClasses(null); } /** * Returns a collection of class configurations for a deployment server. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of server class configurations. */ public EntityCollection getDeploymentServerClasses( Args args) { return new EntityCollection( this, "deployment/serverclass", DeploymentServerClass.class, args); } /** * Returns a collection of multi-tenant configurations. * * @return A collection of multi-tenant configurations. */ public EntityCollection getDeploymentTenants() { return getDeploymentTenants(null); } /** * Returns a collection of multi-tenant configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of multi-tenant configurations. */ public EntityCollection getDeploymentTenants(Args args) { return new EntityCollection( this, "deployment/tenants", DeploymentTenant.class, args); } /** * Returns information about distributed search options. * * @return Distributed search information. */ public DistributedConfiguration getDistributedConfiguration() { return new DistributedConfiguration(this); } /** * Returns a collection of distributed search peers. A search peer * is a Splunk server to which another Splunk server distributes searches. * The Splunk server where the search originates is referred to as the * search head. * * @return A collection of search peers. */ public EntityCollection getDistributedPeers() { return getDistributedPeers(null); } /** * Returns a collection of distributed search peers. A search peer * is a Splunk server to which another Splunk server distributes searches. * The Splunk server where the search originates is referred to as the * search head. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of search peers. */ public EntityCollection getDistributedPeers(Args args) { return new EntityCollection( this, "search/distributed/peers", DistributedPeer.class, args); } /** * Returns a collection of saved event types. * * @return A collection of saved event types. */ public EventTypeCollection getEventTypes() { return getEventTypes(null); } /** * Returns a collection of saved event types. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of saved event types. */ public EventTypeCollection getEventTypes(Args args) { return new EventTypeCollection(this, args); } /** * Returns a collection of alerts that have been fired by the service. * * @return A collection of fired alerts. */ public FiredAlertGroupCollection getFiredAlertGroups() { return getFiredAlertsGroups(null); } /** * Returns a collection of alerts that have been fired by the service. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of fired alerts. */ public FiredAlertGroupCollection getFiredAlertsGroups(Args args) { return new FiredAlertGroupCollection(this, args); } /** * Returns a collection of Splunk indexes. * * @return A collection of indexes. */ public IndexCollection getIndexes() { return getIndexes((IndexCollectionArgs)null); } /** * Returns a collection of Splunk indexes. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link IndexCollectionArgs}. * @return A collection of indexes. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. public IndexCollection getIndexes(IndexCollectionArgs args) { return getIndexes((Args)args); } /** * Returns a collection of Splunk indexes. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link IndexCollectionArgs}. * @return A collection of indexes. */ public IndexCollection getIndexes(Args args) { return new IndexCollection(this, args); } /** * Returns information about the Splunk service. * * @return Splunk service information. */ public ServiceInfo getInfo() { return new ServiceInfo(this); } /** * Returns a collection of configured inputs. * * @return A collection of inputs. */ public InputCollection getInputs() { return getInputs(null); } /** * Returns a collection of configured inputs. * /** * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of inputs. */ public InputCollection getInputs(Args args) { return new InputCollection(this, args); } /** * Returns a collection of current search jobs. * * @return A collection of search jobs. */ public JobCollection getJobs() { return getJobs((CollectionArgs)null); } /** * Returns a collection of current search jobs. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of search jobs. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. public JobCollection getJobs(CollectionArgs args) { return getJobs((Args)args); } /** * Returns a collection of current search jobs. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of search jobs. */ public JobCollection getJobs(Args args) { return new JobCollection(this, args); } /** * Returns a collection of license group configurations. * * @return A collection of license group configurations. */ public EntityCollection getLicenseGroups() { return getLicenseGroups(null); } /** * Returns a collection of license group configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of license group configurations. */ public EntityCollection getLicenseGroups(Args args) { return new EntityCollection( this, "licenser/groups", LicenseGroup.class, args); } /** * Returns a collection of messages from the licenser. * * @return A collection of licenser messages. */ public EntityCollection getLicenseMessages() { return getLicenseMessages(null); } /** * Returns a collection of messages from the licenser. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of licenser messages. */ public EntityCollection getLicenseMessages(Args args) { return new EntityCollection( this, "licenser/messages", LicenseMessage.class, args); } /** * Returns the current owner context for this {@code Service} instance. * A value of {@code "-"} indicates a wildcard, and a {@code null} value * indicates no owner context. * * @return The current owner context. */ public String getOwner() { return this.owner; } /** * Returns a collection of licenser pool configurations. * * @return A collection of licenser pool configurations. */ public LicensePoolCollection getLicensePools() { return getLicensePools(null); } /** * Returns a collection of licenser pool configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of licenser pool configurations. */ public LicensePoolCollection getLicensePools(Args args) { return new LicensePoolCollection(this, args); } /** * Returns a collection of slaves reporting to this license master. * * @return A collection of licenser slaves. */ public EntityCollection getLicenseSlaves() { return getLicenseSlaves(null); } /** * Returns a collection of slaves reporting to this license master. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of licenser slaves. */ public EntityCollection getLicenseSlaves(Args args) { return new EntityCollection( this, "licenser/slaves", LicenseSlave.class, args); } /** * Returns a collection of license stack configurations. * * @return A collection of license stack configurations. */ public EntityCollection getLicenseStacks() { return getLicenseStacks(null); } /** * Returns a collection of license stack configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of license stack configurations. */ public EntityCollection getLicenseStacks(Args args) { return new EntityCollection( this, "licenser/stacks", LicenseStack.class, args); } /** * Returns a collection of licenses for this service. * * @return A collection of licenses. */ public EntityCollection getLicenses() { return getLicenses(null); } /** * Returns a collection of licenses for this service. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of licenses. */ public EntityCollection getLicenses(Args args) { return new EntityCollection( this, "licenser/licenses", License.class, args); } /** * Returns a collection of service logging categories and their status. * * @return A collection of logging categories. */ public EntityCollection getLoggers() { return getLoggers(null); } /** * Returns a collection of service logging categories and their status. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of logging categories. */ public EntityCollection getLoggers(Args args) { return new EntityCollection( this, "server/logger", Logger.class, args); } /** * Returns a collection of system messages. * * @return A collection of system messages. */ public MessageCollection getMessages() { return getMessages(null); } * Returns a collection of system messages. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of system messages. */ public MessageCollection getMessages(Args args) { return new MessageCollection(this, args); } /** * Returns a collection of modular inputs. * * @return A collection of modular inputs. */ public ResourceCollection getModularInputKinds() { return getModularInputKinds(null); } /** * Returns a collection of modular inputs. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of modular inputs. */ public ResourceCollection getModularInputKinds(Args args) { return new ResourceCollection( this, "data/modular-inputs", ModularInputKind.class, args); } /** * Returns global TCP output properties. * * @return Global TCP output properties. */ public OutputDefault getOutputDefault() { return new OutputDefault(this); } /** * Returns a collection of output group configurations. * * @return A collection of output group configurations. */ public EntityCollection getOutputGroups() { return getOutputGroups(null); } /** * Returns a collection of output group configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of output group configurations. */ public EntityCollection getOutputGroups(Args args) { return new EntityCollection( this, "data/outputs/tcp/group", OutputGroup.class, args); } /** * Returns a collection of data-forwarding configurations. * * @return A collection of data-forwarding configurations. */ public EntityCollection getOutputServers() { return getOutputServers(null); } /** * Returns a collection of data-forwarding configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of data-forwarding configurations. */ public EntityCollection getOutputServers(Args args) { return new EntityCollection( this, "data/outputs/tcp/server", OutputServer.class, args); } /** * Returns a collection of configurations for forwarding data in standard * syslog format. * * @return A collection of syslog forwarders. */ public EntityCollection getOutputSyslogs() { return getOutputSyslogs(null); } /** * Returns a collection of configurations for forwarding data in standard * syslog format. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of syslog forwarders. */ public EntityCollection getOutputSyslogs(Args args) { return new EntityCollection( this, "data/outputs/tcp/syslog", OutputSyslog.class, args); } /** * Returns the current password that was used to authenticate the session. * * @return The current password. */ public String getPassword() { return this.password; } /** * Returns a collection of passwords. This collection is used for managing * secure credentials. * * @return A collection of passwords. */ public PasswordCollection getPasswords() { return getPasswords(null); } /** * Returns a collection of passwords. This collection is used for managing * secure credentials. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of passwords. */ public PasswordCollection getPasswords(Args args) { return new PasswordCollection(this, args); } /** * Returns the receiver object for the Splunk service. * * @return A Splunk receiver object. */ public Receiver getReceiver() { return new Receiver(this); } /** * Returns a collection of Splunk user roles. * * @return A collection of user roles. */ public EntityCollection getRoles() { return getRoles(null); } /** * Returns a collection of Splunk user roles. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of user roles. */ public EntityCollection getRoles(Args args) { return new EntityCollection( this, "authentication/roles", Role.class, args); } /** * Returns a collection of saved searches. * * @return A collection of saved searches. */ public SavedSearchCollection getSavedSearches() { return getSavedSearches((SavedSearchCollectionArgs)null); } /** * Returns a collection of saved searches. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link SavedSearchCollectionArgs}. * @return A collection of saved searches. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. public SavedSearchCollection getSavedSearches(SavedSearchCollectionArgs args) { return getSavedSearches((Args)args); } /** * Returns a collection of saved searches. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of saved searches. */ public SavedSearchCollection getSavedSearches(Args args) { return new SavedSearchCollection(this, args); } /** * Returns service configuration information for an instance of Splunk. * * @return Service configuration information. */ public Settings getSettings() { return new Settings(this); } /** * Returns the current session token. Session tokens can be shared across * multiple {@code Service} instances. * * @return The session token. */ public String getToken() { return this.token; } /** * Returns a collection of in-progress oneshot uploads. * * @return A collection of in-progress oneshot uploads */ public EntityCollection getUploads() { return getUploads(null); } /** * Returns a collection of in-progress oneshot uploads. * * @param namespace This collection's namespace; there are no other * optional arguments for this endpoint. * @return A collection of in-progress oneshot uploads */ public EntityCollection getUploads(Args namespace) { return new EntityCollection( this, "data/inputs/oneshot", Upload.class, namespace); } /** * Returns the Splunk account username that was used to authenticate the * current session. * * @return The current username. */ public String getUsername() { return this.username; } /** * Returns a collection of Splunk users. * * @return A collection of users. */ public UserCollection getUsers() { return getUsers(null); } /** * Returns a collection of Splunk users. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of users. */ public UserCollection getUsers(Args args) { return new UserCollection(this, args); } /** * Authenticates the {@code Service} instance with the username and password * that were specified when the instance was created. * * @return The current {@code Service} instance. */ public Service login() { if (this.username == null || this.password == null) { throw new IllegalStateException("Missing username or password."); } else { return login(this.username, this.password); } } /** * Authenticates the {@code Service} instance with a specified username and * password. Note that these values override any previously-set values for * username and password. * * @param username The Splunk account username. * @param password The password for the username. * @return The current {@code Service} instance. */ public Service login(String username, String password) { this.username = username; this.password = password; Args args = new Args(); args.put("username", username); args.put("password", password); ResponseMessage response = post("/services/auth/login", args); String sessionKey = Xml.parse(response.getContent()) .getElementsByTagName("sessionKey") .item(0) .getTextContent(); this.token = "Splunk " + sessionKey; this.version = this.getInfo().getVersion(); if (versionCompare("4.3") >= 0) this.passwordEndPoint = "storage/passwords"; return this; } /** * Forgets the current session token. * * @return The current {@code Service} instance. */ public Service logout() { this.token = null; return this; } /** * Creates a oneshot synchronous search. * * @param query The search query. * @return The search results. */ public InputStream oneshotSearch(String query) { return oneshotSearch(query, null); } /** * Creates a oneshot synchronous search using search arguments. * * @param query The search query. * @param args The search arguments:

    *
  • "output_mode": Specifies the output format of the results (XML, JSON, * or CSV).
  • *
  • "earliest_time": Specifies the earliest time in the time range to * search. The time string can be a UTC time (with fractional seconds), a * relative time specifier (to now), or a formatted time string.
  • *
  • "latest_time": Specifies the latest time in the time range to search. * The time string can be a UTC time (with fractional seconds), a relative * time specifier (to now), or a formatted time string.
  • *
  • "rf": Specifies one or more fields to add to the search.
* @return The search results. */ public InputStream oneshotSearch(String query, Map args) { args = Args.create(args); args.put("search", query); args.put("exec_mode", "oneshot"); // By default, don't highlight search terms in the search output. if (!args.containsKey("segmentation")) { args.put("segmentation", "none"); } ResponseMessage response = post("search/jobs", args); return response.getContent(); } /** * Creates a oneshot synchronous search using search arguments. * * @param query The search query. * @param args The search arguments:
    *
  • "output_mode": Specifies the output format of the results (XML, JSON, * or CSV).
  • *
  • "earliest_time": Specifies the earliest time in the time range to * search. The time string can be a UTC time (with fractional seconds), a * relative time specifier (to now), or a formatted time string.
  • *
  • "latest_time": Specifies the latest time in the time range to search. * The time string can be a UTC time (with fractional seconds), a relative * time specifier (to now), or a formatted time string.
  • *
  • "rf": Specifies one or more fields to add to the search.
* @return The search results. */ public InputStream oneshotSearch(String query, Args args) { return oneshotSearch(query, (Map)args); } /** * Opens a raw socket to this service. * * @param port The port to open. This port must already have been * created as an allowable TCP input to the service. * @return The socket. * @throws java.io.IOException */ public Socket open(int port) throws IOException { return new Socket(this.host, port); } /** * Parses a search query and returns a semantic map for the search in JSON * format. * * @param query The search query. * @return The parse response message. */ public ResponseMessage parse(String query) { return parse(query, null); } /** * Parses a search query with additional arguments and returns a semantic * map for the search in JSON format. * */ * @param query The search query. * @param args Additional parse arguments. * @return The parse response message. */ public ResponseMessage parse(String query, Map args) { args = Args.create(args).add("q", query); return get("search/parser", args); } /** * Restarts the service. The service will be unavailable until it has * sucessfully restarted. * * @return The restart response message. */ public ResponseMessage restart() { return get("server/control/restart"); } /** * Creates an asynchronous search using the given query. Use this * method for simple searches. * * @param query The search query. * @return The search job. */ public Job search(String query) { return search(query, null); } /** * Creates an asynchronous search job using the given query and * search arguments. * * @param query The search query. * @param args The search arguments. * @return The search job. */ public Job search(String query, Map args) { args = Args.create(args); return this.getJobs().create(query, args); } /** * Issues an HTTP request against the service using a request path and * message. * This method overrides the base {@code HttpService.send} method * and applies the Splunk authorization header, which is required for * authenticated interactions with the Splunk service. * * @param path The request path. * @param request The request message. * @return The HTTP response. */ @Override public ResponseMessage send(String path, RequestMessage request) { request.getHeader().put("Authorization", token); return super.send(fullpath(path), request); } /** * Provides a session token for use by this {@code Service} instance. * Session tokens can be shared across multiple {@code Service} instances. * * @param value The session token. */ public void setToken(String value) { this.token = value; } /** * Returns true if this Splunk instance's version is no earlier than * the version specified in {@code version}. * * So when called on a Splunk 4.3.2 instance: * * {@code versionIsAtLeast("4.3.2")} is {@code true}. * * {@code versionIsAtLeast("4.1.0")} is {@code true}. * * {@code versionIsAtLeast("5.0.0")} is {@code false}. * * @param version The version to compare this Splunk instance's version against. * @return {@code true} if this Splunk instance's version is equal or * greater than {@code version}; {@code false} otherwise. */ boolean versionIsAtLeast(String version) { return versionCompare(version) >= 0; } /** * Returns true if this Splunk instance's version is earlier than * the version specified in {@code version}. * * So when called on a Splunk 4.3.2 instance: * * {@code versionIsEarlierThan("4.3.2")} is {@code false}. * * {@code versionIsEarlierThan("4.1.0")} is {@code false}. * * {@code versionIsEarlierThan("5.0.0")} is {@code true}. * * @param version The version to compare this Splunk instance's version against. * @return {@code true} if this Splunk instance's version is less * than {@code version}; {@code false} otherwise. boolean versionIsEarlierThan(String version) { return versionCompare(version) < 0; } /** * Returns {@code -1} if {@code this.version < otherVersion}. * Returns {@code 0} if {@code this.version &eq; otherVersion}. * Returns {@code 1} if {@code this.version > otherVersion}. * * @param otherVersion The version to compare this Splunk instance's version against. * @return {@code -1} if {@code this.version < otherVersion}, * {@code 0} if {@code this.version &eq; otherVersion}, or * {@code 1} if {@code this.version > otherVersion}. */ public int versionCompare(String otherVersion) { String[] components1 = this.version.split("\\."); String[] components2 = otherVersion.split("\\."); int numComponents = Math.max(components1.length, components2.length); for (int i = 0; i < numComponents; i++) { int c1 = (i < components1.length) ? Integer.parseInt(components1[i], 10) : 0; int c2 = (i < components2.length) ? Integer.parseInt(components2[i], 10) : 0; if (c1 < c2) { return -1; } else if (c1 > c2) { return 1; } } return 0; } } >>>>>>> f563e76db159871a759ce6fb1dff30448b6f3800
Solution content
/*
 * Copyright 2012 Splunk, Inc.
 *
 * 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 com.splunk;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.Map;

/**
 * The {@code Service} class represents a Splunk service instance at a given
 * address (host:port), accessed using the {@code http} or {@code https}
 * protocol scheme.
 * 

* A {@code Service} instance also captures an optional namespace context * consisting of an optional owner name (or "-" wildcard) and optional app name * (or "-" wildcard). *

* To access {@code Service} members, the {@code Service} instance must be * authenticated by presenting credentials using the {@code login} method, or * by constructing the {@code Service} instance using the {@code connect} * method, which both creates and authenticates the instance. */ public class Service extends BaseService { /** The current app context. */ protected String app = null; /** The current session token. */ protected String token = null; /** The current owner context. A value of "nobody" means that all users * have access to the resource. */ protected String owner = null; /** The Splunk account username, which is used to authenticate the Splunk * instance. */ protected String username = null; /** The password, which is used to authenticate the Splunk instance. */ protected String password = null; /** The default simple receiver endpoint. */ protected String simpleReceiverEndPoint = "receivers/simple"; /** The default password endpoint, can change over Splunk versions. */ protected String passwordEndPoint = "admin/passwords"; /** The version of this Splunk instance, once logged in. */ public String version = null; /** The default host name, which is used when a host name is not provided.*/ public static String DEFAULT_HOST = "localhost"; /** The default port number, which is used when a port number is not * provided. */ public static int DEFAULT_PORT = 8089; /** The default scheme, which is used when a scheme is not provided. */ public static String DEFAULT_SCHEME = "https"; /** * Creates a new {@code Service} instance using a host. * * @param host The host name. */ public Service(String host) { super(host); } /** * Creates a new {@code Service} instance using a host and port. * * @param host The host name. * @param port The port number. */ public Service(String host, int port) { super(host, port); } /** * Creates a new {@code Service} instance using a host, port, and * scheme for accessing the service ({@code http} or {@code https}). * * @param host The host name. * @param port The port number. * @param scheme The scheme ({@code http} or {@code https}). */ public Service(String host, int port, String scheme) { super(host, port, scheme); } /** * Creates a new {@code Service} instance using a collection of arguments. * * @param args The {@code ServiceArgs} to initialize the service. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. @SuppressWarnings("deprecation") public Service(ServiceArgs args) { super(); // NOTE: Must read the deprecated fields for backward compatibility. // (Consider the case where the fields are initialized directly, // rather than using the new setters.) // NOTE: Must also read the underlying dictionary for forward compatibility. // (Consider the case where the user calls Map.put() directly, // rather than using the new setters.) this.app = Args.get(args, "app", args.app != null ? args.app : null); this.host = Args.get(args, "host", args.host != null ? args.host : DEFAULT_HOST); this.owner = Args.get(args, "owner", args.owner != null ? args.owner : null); this.port = Args.get(args, "port", args.port != null ? args.port : DEFAULT_PORT); this.scheme = Args.get(args, "scheme", args.scheme != null ? args.scheme : DEFAULT_SCHEME); this.token = Args.get(args, "token", args.token != null ? args.token : null); this.username = (String)args.get("username"); this.password = (String)args.get("password"); } /** * Creates a new {@code Service} instance using a map of arguments. * * @param args A {@code Map} of arguments to initialize the service. */ public Service(Map args) { super(); this.app = Args.get(args, "app", null); this.host = Args.get(args, "host", DEFAULT_HOST); this.owner = Args.get(args, "owner", null); this.port = Args.get(args, "port", DEFAULT_PORT); this.scheme = Args.get(args, "scheme", DEFAULT_SCHEME); this.token = Args.get(args, "token", null); this.username = (String)args.get("username"); this.password = (String)args.get("password"); } /** * Establishes a connection to a Splunk service using a map of arguments. * This member creates a new {@code Service} instance and authenticates * the session using credentials passed in from the {@code args} map. * * @param args The {@code args} map. * @return A new {@code Service} instance. */ public static Service connect(Map args) { Service service = new Service(args); if (args.containsKey("username")) { service.login(); } return service; } /** * Runs a search using the {@code search/jobs/export} endpoint, which * streams results back in an input stream. * * @param search The search query to run. * @return The {@code InputStream} object that contains the search results. */ public InputStream export(String search) { return export(search, null); } /** * Runs a search with arguments using the {@code search/jobs/export} * endpoint, which streams results back in an input stream. * * @param search The search query to run. * @param args Additional search arguments. * For a list of possible parameters, see * Saved search parameters on * dev.splunk.com. * @return The {@code InputStream} object that contains the search results. */ public InputStream export(String search, Map args) { args = Args.create(args).add("search", search); // By default don't highlight search terms in the output. if (!args.containsKey("segmentation")) { args.put("segmentation", "none"); } ResponseMessage response = get("search/jobs/export", args); return new ExportResultsStream(response.getContent()); } /** * Runs a search with arguments using the {@code search/jobs/export} * endpoint, which streams results back in an input stream. * * @param search The search query to run. * @param args Additional search arguments (see {@code JobExportArgs}). * @return The {@code InputStream} object that contains the search results. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. public InputStream export(String search, JobExportArgs args) { return export(search, (Map) args); } /** * Ensures that the given path is fully qualified, prepending a path * prefix if necessary. The path prefix is constructed using the current * owner and app context when available. * * @param path The path to verify. * @return A fully-qualified resource path. */ String fullpath(String path) { return fullpath(path, null); } /** * Ensures that the given path is fully qualified, prepending a path * prefix if necessarry. The path prefix is constructed using the * current owner and app context when available. * * @param path The path to verify. * @param namespace The name space dictionary (app, owner, sharing). * @return A fully-qualified resource path. */ public String fullpath(String path, Args namespace) { // if already fully qualified (i.e. root begins with /) then return // the already qualified path. if (path.startsWith("/")) return path; // if no namespace at all, and no service instance of app, and no // sharing, return base service endpoint + path. if (namespace == null && app == null) { return "/services/" + path; } // base namespace values String localApp = app; String localOwner = owner; String localSharing = ""; // override with invocation namespace if set. if (namespace != null) { if (namespace.containsKey("app")) localApp = (String)namespace.get("app"); if (namespace.containsKey("owner")) localOwner = (String)namespace.get("owner"); if (namespace.containsKey("sharing")) localSharing = (String)namespace.get("sharing"); } // sharing, if set calls for special mapping, override here. // "user" --> {user}/{app} // "app" --> nobody/{app} // "global" --> nobody/{app} // "system" --> nobody/system if (localSharing.equals("app") || localSharing.equals("global")) localOwner = "nobody"; else if (localSharing.equals("system")) { localApp = "system"; localOwner = "nobody"; } return String.format("/servicesNS/%s/%s/%s", localOwner == null ? "-" : localOwner, localApp == null ? "-" : localApp, path); } /** * Returns the app context for this {@code Service} instance. * A {@code null} value indicates no app context, and a value of * {@code "-"} indicates an app wildcard. * * @return The app context. */ public String getApp() { return this.app; } /** * Returns the collection of applications. * * @return The application collection. */ public EntityCollection getApplications() { return new EntityCollection( this, "/services/apps/local", Application.class); } /** * Returns the collection of configurations. * * @return The configurations collection. */ public ConfCollection getConfs() { return getConfs(null); } /** * Returns the collection of configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return The configurations collection. */ public ConfCollection getConfs(Args args) { return new ConfCollection(this, args); } /** * Returns an array of system capabilities. * * @return An array of capabilities. */ public String[] getCapabilities() { Entity caps = new Entity(this, "authorization/capabilities"); return caps.getStringArray("capabilities"); } /** * Returns the configuration and status of a deployment client. * * @return The configuration and status. */ public DeploymentClient getDeploymentClient() { return new DeploymentClient(this); } /** * Returns the configuration of all deployment servers. * * @return The configuration of deployment servers. */ public EntityCollection getDeploymentServers() { return getDeploymentServers(null); } /** * Returns the collection of deployment servers. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return The configuration of deployment servers. */ public EntityCollection getDeploymentServers(Args args) { return new EntityCollection( this, "deployment/server", DeploymentServer.class, args); } /** * Returns a collection of class configurations for a deployment server. * * @return A collection of class configurations. */ public EntityCollection getDeploymentServerClasses(){ return getDeploymentServerClasses(null); } /** * Returns a collection of class configurations for a deployment server. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of server class configurations. */ public EntityCollection getDeploymentServerClasses( Args args) { return new EntityCollection( this, "deployment/serverclass", DeploymentServerClass.class, args); } /** * Returns a collection of multi-tenant configurations. * * @return A collection of multi-tenant configurations. */ public EntityCollection getDeploymentTenants() { return getDeploymentTenants(null); } /** * Returns a collection of multi-tenant configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of multi-tenant configurations. */ public EntityCollection getDeploymentTenants(Args args) { return new EntityCollection( this, "deployment/tenants", DeploymentTenant.class, args); } /** * Returns information about distributed search options. * * @return Distributed search information. */ public DistributedConfiguration getDistributedConfiguration() { return new DistributedConfiguration(this); } /** * Returns a collection of distributed search peers. A search peer * is a Splunk server to which another Splunk server distributes searches. * The Splunk server where the search originates is referred to as the * search head. * * @return A collection of search peers. */ public EntityCollection getDistributedPeers() { return getDistributedPeers(null); } /** * Returns a collection of distributed search peers. A search peer * is a Splunk server to which another Splunk server distributes searches. * The Splunk server where the search originates is referred to as the */ * /** * search head. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of search peers. */ public EntityCollection getDistributedPeers(Args args) { return new EntityCollection( this, "search/distributed/peers", DistributedPeer.class, args); } /** * Returns a collection of saved event types. * * @return A collection of saved event types. */ public EventTypeCollection getEventTypes() { return getEventTypes(null); } /** * Returns a collection of saved event types. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of saved event types. */ public EventTypeCollection getEventTypes(Args args) { return new EventTypeCollection(this, args); } /** * Returns a collection of alerts that have been fired by the service. * * @return A collection of fired alerts. */ public FiredAlertGroupCollection getFiredAlertGroups() { return getFiredAlertsGroups(null); } /** * Returns a collection of alerts that have been fired by the service. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of fired alerts. */ public FiredAlertGroupCollection getFiredAlertsGroups(Args args) { return new FiredAlertGroupCollection(this, args); } /** * Returns a collection of Splunk indexes. * * @return A collection of indexes. */ public IndexCollection getIndexes() { return getIndexes((IndexCollectionArgs)null); } /** * Returns a collection of Splunk indexes. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link IndexCollectionArgs}. * @return A collection of indexes. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. public IndexCollection getIndexes(IndexCollectionArgs args) { return getIndexes((Args)args); } /** * Returns a collection of Splunk indexes. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link IndexCollectionArgs}. * @return A collection of indexes. */ public IndexCollection getIndexes(Args args) { return new IndexCollection(this, args); } /** * Returns information about the Splunk service. * * @return Splunk service information. */ public ServiceInfo getInfo() { return new ServiceInfo(this); } /** * Returns a collection of configured inputs. * * @return A collection of inputs. */ public InputCollection getInputs() { return getInputs(null); } /** * Returns a collection of configured inputs. * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of inputs. */ public InputCollection getInputs(Args args) { return new InputCollection(this, args); } /** * Returns a collection of current search jobs. * * @return A collection of search jobs. */ public JobCollection getJobs() { return getJobs((CollectionArgs)null); } /** * Returns a collection of current search jobs. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of search jobs. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. public JobCollection getJobs(CollectionArgs args) { return getJobs((Args)args); } /** * Returns a collection of current search jobs. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of search jobs. */ public JobCollection getJobs(Args args) { return new JobCollection(this, args); } /** * Returns a collection of license group configurations. * * @return A collection of license group configurations. */ public EntityCollection getLicenseGroups() { return getLicenseGroups(null); } /** * Returns a collection of license group configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of license group configurations. */ public EntityCollection getLicenseGroups(Args args) { return new EntityCollection( this, "licenser/groups", LicenseGroup.class, args); } /** * Returns a collection of messages from the licenser. * * @return A collection of licenser messages. */ public EntityCollection getLicenseMessages() { return getLicenseMessages(null); } /** * Returns a collection of messages from the licenser. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of licenser messages. */ public EntityCollection getLicenseMessages(Args args) { return new EntityCollection( this, "licenser/messages", LicenseMessage.class, args); } /** * Returns the current owner context for this {@code Service} instance. * A value of {@code "-"} indicates a wildcard, and a {@code null} value * indicates no owner context. * * @return The current owner context. */ public String getOwner() { return this.owner; } /** * Returns a collection of licenser pool configurations. * * @return A collection of licenser pool configurations. */ public LicensePoolCollection getLicensePools() { return getLicensePools(null); } * Returns a collection of licenser pool configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of licenser pool configurations. */ public LicensePoolCollection getLicensePools(Args args) { return new LicensePoolCollection(this, args); } /** * Returns a collection of slaves reporting to this license master. * * @return A collection of licenser slaves. */ public EntityCollection getLicenseSlaves() { return getLicenseSlaves(null); } /** * Returns a collection of slaves reporting to this license master. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of licenser slaves. */ public EntityCollection getLicenseSlaves(Args args) { return new EntityCollection( this, "licenser/slaves", LicenseSlave.class, args); } /** * Returns a collection of license stack configurations. * * @return A collection of license stack configurations. */ public EntityCollection getLicenseStacks() { return getLicenseStacks(null); } /** * Returns a collection of license stack configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of license stack configurations. */ public EntityCollection getLicenseStacks(Args args) { return new EntityCollection( this, "licenser/stacks", LicenseStack.class, args); } /** * Returns a collection of licenses for this service. * * @return A collection of licenses. */ public EntityCollection getLicenses() { return getLicenses(null); } /** * Returns a collection of licenses for this service. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of licenses. */ public EntityCollection getLicenses(Args args) { return new EntityCollection( this, "licenser/licenses", License.class, args); } /** * Returns a collection of service logging categories and their status. * * @return A collection of logging categories. */ public EntityCollection getLoggers() { return getLoggers(null); } /** * Returns a collection of service logging categories and their status. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of logging categories. */ public EntityCollection getLoggers(Args args) { return new EntityCollection( this, "server/logger", Logger.class, args); } /** * Returns a collection of system messages. * * @return A collection of system messages. */ public MessageCollection getMessages() { return getMessages(null); } /** * Returns a collection of system messages. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of system messages. */ public MessageCollection getMessages(Args args) { return new MessageCollection(this, args); } /** * Returns a collection of modular inputs. * * @return A collection of modular inputs. */ public ResourceCollection getModularInputKinds() { return getModularInputKinds(null); } /** * Returns a collection of modular inputs. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of modular inputs. public ResourceCollection getModularInputKinds(Args args) { return new ResourceCollection( this, "data/modular-inputs", ModularInputKind.class, args); } /** * Returns global TCP output properties. * * @return Global TCP output properties. */ public OutputDefault getOutputDefault() { return new OutputDefault(this); } /** * Returns a collection of output group configurations. * * @return A collection of output group configurations. */ public EntityCollection getOutputGroups() { return getOutputGroups(null); } /** * Returns a collection of output group configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of output group configurations. */ public EntityCollection getOutputGroups(Args args) { return new EntityCollection( this, "data/outputs/tcp/group", OutputGroup.class, args); } /** * Returns a collection of data-forwarding configurations. * * @return A collection of data-forwarding configurations. */ public EntityCollection getOutputServers() { return getOutputServers(null); } /** * Returns a collection of data-forwarding configurations. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of data-forwarding configurations. */ public EntityCollection getOutputServers(Args args) { return new EntityCollection( this, "data/outputs/tcp/server", OutputServer.class, args); } /** * Returns a collection of configurations for forwarding data in standard * syslog format. * * @return A collection of syslog forwarders. */ public EntityCollection getOutputSyslogs() { return getOutputSyslogs(null); } /** * Returns a collection of configurations for forwarding data in standard * syslog format. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of syslog forwarders. */ public EntityCollection getOutputSyslogs(Args args) { return new EntityCollection( this, "data/outputs/tcp/syslog", OutputSyslog.class, args); } /** * Returns the current password that was used to authenticate the session. * * @return The current password. */ public String getPassword() { return this.password; } /** * Returns a collection of passwords. This collection is used for managing * secure credentials. * * @return A collection of passwords. */ public PasswordCollection getPasswords() { return getPasswords(null); } /** * Returns a collection of passwords. This collection is used for managing * secure credentials. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of passwords. */ public PasswordCollection getPasswords(Args args) { return new PasswordCollection(this, args); } /** * Returns the receiver object for the Splunk service. * * @return A Splunk receiver object. */ public Receiver getReceiver() { return new Receiver(this); } /** * Returns a collection of Splunk user roles. * * @return A collection of user roles. */ public EntityCollection getRoles() { return getRoles(null); } /** * Returns a collection of Splunk user roles. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of user roles. */ public EntityCollection getRoles(Args args) { return new EntityCollection( this, "authentication/roles", Role.class, args); } /** * Returns a collection of saved searches. * * @return A collection of saved searches. */ public SavedSearchCollection getSavedSearches() { return getSavedSearches((SavedSearchCollectionArgs)null); } /** * Returns a collection of saved searches. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link SavedSearchCollectionArgs}. * @return A collection of saved searches. */ // NOTE: This overload exists primarily to provide better documentation // for the "args" parameter. public SavedSearchCollection getSavedSearches(SavedSearchCollectionArgs args) { return getSavedSearches((Args)args); } /** * Returns a collection of saved searches. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of saved searches. */ public SavedSearchCollection getSavedSearches(Args args) { return new SavedSearchCollection(this, args); } /** * Returns service configuration information for an instance of Splunk. * * @return Service configuration information. */ public Settings getSettings() { return new Settings(this); } /** * Returns the current session token. Session tokens can be shared across * multiple {@code Service} instances. * * @return The session token. */ public String getToken() { return this.token; } /** * Returns a collection of in-progress oneshot uploads. * * @return A collection of in-progress oneshot uploads */ public EntityCollection getUploads() { return getUploads(null); } /** * Returns a collection of in-progress oneshot uploads. * * @param namespace This collection's namespace; there are no other * optional arguments for this endpoint. * @return A collection of in-progress oneshot uploads */ public EntityCollection getUploads(Args namespace) { return new EntityCollection( this, "data/inputs/oneshot", Upload.class, namespace); } /** * Returns the Splunk account username that was used to authenticate the * current session. * * @return The current username. */ public String getUsername() { return this.username; } /** * Returns a collection of Splunk users. * * @return A collection of users. */ public UserCollection getUsers() { return getUsers(null); } /** * Returns a collection of Splunk users. * * @param args Collection arguments that specify the number of entities to * return and how to sort them. See {@link CollectionArgs}. * @return A collection of users. */ public UserCollection getUsers(Args args) { return new UserCollection(this, args); } /** * Authenticates the {@code Service} instance with the username and password * that were specified when the instance was created. * * @return The current {@code Service} instance. */ public Service login() { if (this.username == null || this.password == null) { throw new IllegalStateException("Missing username or password."); } else { return login(this.username, this.password); } } /** * Authenticates the {@code Service} instance with a specified username and * password. Note that these values override any previously-set values for * username and password. * * @param username The Splunk account username. * @param password The password for the username. * @return The current {@code Service} instance. */ public Service login(String username, String password) { this.username = username; this.password = password; Args args = new Args(); args.put("username", username); args.put("password", password); ResponseMessage response = post("/services/auth/login", args); String sessionKey = Xml.parse(response.getContent()) .getElementsByTagName("sessionKey") .item(0) .getTextContent(); this.token = "Splunk " + sessionKey; this.version = this.getInfo().getVersion(); if (versionCompare("4.3") >= 0) this.passwordEndPoint = "storage/passwords"; return this; } /** * Forgets the current session token. * * @return The current {@code Service} instance. */ public Service logout() { this.token = null; return this; } /** * Creates a oneshot synchronous search. * * @param query The search query. * @return The search results. */ public InputStream oneshotSearch(String query) { return oneshotSearch(query, null); } /** * Creates a oneshot synchronous search using search arguments. * * @param query The search query. * @param args The search arguments:

    *
  • "output_mode": Specifies the output format of the results (XML, JSON, * or CSV).
  • public Job search(String query) { *
  • "earliest_time": Specifies the earliest time in the time range to * search. The time string can be a UTC time (with fractional seconds), a * relative time specifier (to now), or a formatted time string.
  • *
  • "latest_time": Specifies the latest time in the time range to search. * The time string can be a UTC time (with fractional seconds), a relative * time specifier (to now), or a formatted time string.
  • *
  • "rf": Specifies one or more fields to add to the search.
* @return The search results. */ public InputStream oneshotSearch(String query, Map args) { args = Args.create(args); args.put("search", query); args.put("exec_mode", "oneshot"); // By default, don't highlight search terms in the search output. if (!args.containsKey("segmentation")) { args.put("segmentation", "none"); } ResponseMessage response = post("search/jobs", args); return response.getContent(); } /** * Creates a oneshot synchronous search using search arguments. * * @param query The search query. * @param args The search arguments:
    *
  • "output_mode": Specifies the output format of the results (XML, JSON, * or CSV).
  • *
  • "earliest_time": Specifies the earliest time in the time range to * search. The time string can be a UTC time (with fractional seconds), a * relative time specifier (to now), or a formatted time string.
  • *
  • "latest_time": Specifies the latest time in the time range to search. * The time string can be a UTC time (with fractional seconds), a relative * time specifier (to now), or a formatted time string.
  • *
  • "rf": Specifies one or more fields to add to the search.
* @return The search results. */ public InputStream oneshotSearch(String query, Args args) { return oneshotSearch(query, (Map)args); } /** * Opens a raw socket to this service. * * @param port The port to open. This port must already have been * created as an allowable TCP input to the service. * @return The socket. * @throws java.io.IOException */ public Socket open(int port) throws IOException { return new Socket(this.host, port); } /** * Parses a search query and returns a semantic map for the search in JSON * format. * * @param query The search query. * @return The parse response message. */ public ResponseMessage parse(String query) { return parse(query, null); } /** * Parses a search query with additional arguments and returns a semantic * map for the search in JSON format. * * @param query The search query. * @param args Additional parse arguments. * @return The parse response message. */ public ResponseMessage parse(String query, Map args) { args = Args.create(args).add("q", query); return get("search/parser", args); } /** * Restarts the service. The service will be unavailable until it has * sucessfully restarted. * * @return The restart response message. */ public ResponseMessage restart() { return get("server/control/restart"); } /** * Creates an asynchronous search using the given query. Use this * method for simple searches. * * @param query The search query. * @return The search job. */ return search(query, null); } /** * Creates an asynchronous search job using the given query and * search arguments. * * @param query The search query. * @param args The search arguments. * @return The search job. */ public Job search(String query, Map args) { args = Args.create(args); return this.getJobs().create(query, args); } /** * Issues an HTTP request against the service using a request path and * message. * This method overrides the base {@code HttpService.send} method * and applies the Splunk authorization header, which is required for * authenticated interactions with the Splunk service. * * @param path The request path. * @param request The request message. * @return The HTTP response. */ @Override public ResponseMessage send(String path, RequestMessage request) { request.getHeader().put("Authorization", token); return super.send(fullpath(path), request); } /** * Provides a session token for use by this {@code Service} instance. * Session tokens can be shared across multiple {@code Service} instances. * * @param value The session token. */ public void setToken(String value) { this.token = value; } /** * Returns true if this Splunk instance's version is no earlier than * the version specified in {@code version}. * * So when called on a Splunk 4.3.2 instance: * * {@code versionIsAtLeast("4.3.2")} is {@code true}. * * {@code versionIsAtLeast("4.1.0")} is {@code true}. * * {@code versionIsAtLeast("5.0.0")} is {@code false}. * * @param version The version to compare this Splunk instance's version against. * @return {@code true} if this Splunk instance's version is equal or * greater than {@code version}; {@code false} otherwise. */ boolean versionIsAtLeast(String version) { return versionCompare(version) >= 0; } /** * Returns true if this Splunk instance's version is earlier than * the version specified in {@code version}. * * So when called on a Splunk 4.3.2 instance: * * {@code versionIsEarlierThan("4.3.2")} is {@code false}. * * {@code versionIsEarlierThan("4.1.0")} is {@code false}. * * {@code versionIsEarlierThan("5.0.0")} is {@code true}. * * @param version The version to compare this Splunk instance's version against. * @return {@code true} if this Splunk instance's version is less * than {@code version}; {@code false} otherwise. */ boolean versionIsEarlierThan(String version) { return versionCompare(version) < 0; } /** * Returns {@code -1} if {@code this.version < otherVersion}. * Returns {@code 0} if {@code this.version &eq; otherVersion}. * Returns {@code 1} if {@code this.version > otherVersion}. * * @param otherVersion The version to compare this Splunk instance's version against. * @return {@code -1} if {@code this.version < otherVersion}, * {@code 0} if {@code this.version &eq; otherVersion}, or * {@code 1} if {@code this.version > otherVersion}. */ public int versionCompare(String otherVersion) { String[] components1 = this.version.split("\\."); String[] components2 = otherVersion.split("\\."); int numComponents = Math.max(components1.length, components2.length); for (int i = 0; i < numComponents; i++) { int c1 = (i < components1.length) ? Integer.parseInt(components1[i], 10) : 0; int c2 = (i < components2.length) ? Integer.parseInt(components2[i], 10) : 0; if (c1 < c2) { return -1; } else if (c1 > c2) { return 1; } } return 0; } }
File
Service.java
Developer's decision
Combination
Kind of conflict
Class declaration
Comment
Import
Package declaration
Chunk
Conflicting content
<<<<<<< HEAD
/*
 * Copyright 2012 Splunk, Inc.
 *
 * 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 com.splunk;

import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

public class ResultsReaderTest extends SDKTestCase {

    @Before
    @Override
    public void setUp() throws Exception {
        super.setUp();
    }
    
    private InputStream openResource(String path) {
        if (path.startsWith("splunk_search:")) {
            path = path.substring("splunk_search:".length());
            
            String[] pathComponents = path.split("/");
            String searchType = pathComponents[0];
            String outputMode = pathComponents[1];
            String search = pathComponents[2];
            
            Args resultsArgs = new Args("output_mode", outputMode);
            if (searchType.equals("blocking")) {
                Job job = service.getJobs().create(
                        search,
                        new Args("exec_mode", "blocking"));
                return job.getResults(resultsArgs);
            }
            else if (searchType.equals("oneshot")) {
                return service.oneshotSearch(search, resultsArgs);
            }
            else {
                throw new IllegalArgumentException(
                        "Unrecognized search type: " + searchType);
            }
        }
        
        InputStream input = getClass().getResourceAsStream(path);
        assertNotNull("Could not open " + path, input);
        return input;
    }

    @Test
        }
    public void testAtomFeed() {
        InputStream input = openResource("jobs.xml");
        AtomFeed feed = AtomFeed.parseStream(input);
        assertEquals(131, feed.entries.size());
        AtomEntry entry = feed.entries.get(0);
        assertEquals("2012-08-22T20:10:28.000-07:00", entry.updated);
        assertTrue(entry.content.containsKey("cursorTime"));
        assertEquals("1969-12-31T16:00:00.000-08:00", entry.content.getString("cursorTime"));
        assertTrue(entry.content.containsKey("diskUsage"));
        assertEquals(90112, entry.content.getInteger("diskUsage"));
        assertEquals(true, entry.content.getBoolean("isDone"));
    }

    @Test
    public void testResults() throws IOException {
        InputStream input = openResource("results.xml");
        ResultsReaderXml reader = new ResultsReaderXml(input);
        Map expected = new HashMap();

        expected.put("series", "twitter");
        expected.put("sum(kb)", "14372242.758775");
        assertNextEventEquals(expected, reader);
        
        expected.put("series", "splunkd");
        expected.put("sum(kb)", "267802.333926");
        assertNextEventEquals(expected, reader);

        expected.put("series", "flurry");
        expected.put("sum(kb)", "12576.454102");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd_access");
        expected.put("sum(kb)", "5979.036338");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunk_web_access");
        expected.put("sum(kb)", "5838.935649");
        assertNextEventEquals(expected, reader);

        assertNull(reader.getNextEvent());
        reader.close();
    }

    @Test
    public void testReadRawField() throws IOException {
        InputStream input = openResource("raw_field.xml");
        ResultsReaderXml reader = new ResultsReaderXml(input);
        Map expected = new HashMap();

        expected.put(
                "_raw",
                "07-13-2012 09:27:27.307 -0700 INFO  Metrics - group=search_concurrency, system total, active_hist_searches=0, active_realtime_searches=0"
        );
        assertNextEventEquals(expected, reader);

        assertNull(reader.getNextEvent());
        reader.close();
    }

    @Test
    public void testReadCsv() throws Exception {
        InputStream input = openResource("results.csv");
        ResultsReaderCsv reader = new ResultsReaderCsv(input);

        String[] fields = new String[0];
        fields = reader.getFields().toArray(fields);
        assertEquals(2, fields.length);
        assertEquals("sum(kb)", fields[0]);
        assertEquals("series", fields[1]);

        Map expected = new HashMap();

        expected.put("series", "twitter");
        expected.put("sum(kb)", "14372242.758775");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd");
        expected.put("sum(kb)", "267802.333926");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd_access");
        expected.put("sum(kb)", "5979.036338");
        assertNextEventEquals(expected, reader);

        assertNull(reader.getNextEvent());
        reader.close();
    }

    @Test
    public void testReadCsvFromOneshot() throws Exception {
        InputStream input = service.oneshotSearch(
                "search index=_internal | head 1 | stats count",
                Args.create("output_mode", "csv"));
        ResultsReaderCsv reader = new ResultsReaderCsv(input);
        Map expected = new HashMap();

        expected.put("count", "1");
        assertNextEventEquals(expected, reader);

        assertNull(reader.getNextEvent());
        reader.close();
    }

    @Test
    public void testReadFromExportJson() throws Exception {
        verifyMultiReader(getExportStreamJson());
    }

    @Test
    public void testReadFromExportXml() throws Exception {
        verifyMultiReader(getExportStreamXml());
    }

    private void verifyMultiReader(
                MultiResultsReader reader)
                throws Exception {

        SearchResults singleResults = null;
        for(SearchResults results : reader) {
            singleResults = results;
            break;
        }

        Event singleEvent = null;
        for(Event event : singleResults) {
            singleEvent = event;
        }

       assertEquals("1", singleEvent.get("count"));
    }

    private MultiResultsReader getExportStreamJson() throws IOException {
        return new MultiResultsReaderJson(
            service.export(
                "search index=_internal | head 1 | stats count",
                Args.create("output_mode", "json")));
    }

    private MultiResultsReader getExportStreamXml() throws IOException {
        return new MultiResultsReaderXml(
            service.export(
                "search index=_internal | head 1 | stats count",
                Args.create("output_mode", "xml")));
    }

    @Test
    public void testReadJsonOnSplunk4() throws Exception {
        InputStream input = openResource("results4.json");
        ResultsReaderJson reader = new ResultsReaderJson(input);
        Map expected = new HashMap();

        expected.put("series", "twitter");
        expected.put("sum(kb)", "14372242.758775");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd");
        expected.put("sum(kb)", "267802.333926");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd_access");
        expected.put("sum(kb)", "5979.036338");
        assertNextEventEquals(expected, reader);

        assertNull(reader.getNextEvent());
        reader.close();
    }

    @Test
    public void testReadJsonOnSplunk5() throws Exception {
        // Splunk 5.0 uses a different format for JSON results
        // from Splunk 4.3.
        InputStream input = openResource("results5.json");
        ResultsReaderJson reader = new ResultsReaderJson(input);
        Map expected = new HashMap();

        expected.put("series", "twitter");
        expected.put("sum(kb)", "14372242.758775");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd");
        expected.put("sum(kb)", "267802.333926");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd_access");
        expected.put("sum(kb)", "5979.036338");
        assertNextEventEquals(expected, reader);

        assertNull(reader.getNextEvent());
        reader.close();
    }
    
    public void testReadMultivalueXmlCsvJson() throws IOException {
        // These results were generated from "search index=_internal | head 1",
        // with the output formats {xml, csv, json}.
        String search = "search index=_internal | head 1";
        
        testReadMultivalue(
                ResultsReaderXml.class, "resultsMV.xml");
        testReadMultivalue(
                ResultsReaderCsv.class, "resultsMV.csv");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMV4.json");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMV5.json");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMVFuture.json", ",");
        
        testReadMultivalue(
                ResultsReaderXml.class, "resultsMVOneshot.xml");
        testReadMultivalue(
                ResultsReaderCsv.class, "resultsMVOneshot.csv");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMVOneshot4.json");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMVOneshot5.json");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMVOneshotFuture.json", ",");
        
        testReadMultivalue(
                ResultsReaderXml.class, "splunk_search:blocking/xml/" + search);
        testReadMultivalue(
                ResultsReaderCsv.class, "splunk_search:blocking/csv/" + search);
        testReadMultivalue(
                ResultsReaderJson.class, "splunk_search:blocking/json/" + search);
        
        testReadMultivalue(
                ResultsReaderXml.class, "splunk_search:oneshot/xml/" + search);
        testReadMultivalue(
                ResultsReaderCsv.class, "splunk_search:oneshot/csv/" + search);
        testReadMultivalue(
                ResultsReaderJson.class, "splunk_search:oneshot/json/" + search);
    }
    
    private void testReadMultivalue(
            Class type,
            String filename) throws IOException {
        
        // For our particular test data, the multi-value delimiter
        // for the "_si" field (which is being checked) is a newline
        // for those ResultsReaders that care about delimiters.
        String delimiter = (type == ResultsReaderXml.class) ? "," : "\n";
        
        testReadMultivalue(type, filename, delimiter);
    }
    
    private void testReadMultivalue(
            Class type,
            String filename,
            String delimiter) throws IOException {
        
        // Test legacy getNextEvent() interface on 2-valued and 1-valued fields
        {
            ResultsReader reader = createResultsReader(type, openResource(filename));
            
            HashMap firstResult = reader.getNextEvent();
            {
                String siDelimited = firstResult.get("_si");
                String[] siArray = siDelimited.split(Pattern.quote(delimiter));
                assertEquals(2, siArray.length);
                // (siArray[0] should be the locally-determined hostname of
                //  splunkd, but there is no good way to test this
                //  consistently.)
                assertEquals("_internal", siArray[1]);
            }
            assertEquals("_internal", firstResult.get("index"));
            
            assertNull("Expected exactly one result.", reader.getNextEvent());
            reader.close();
        }
        
        // Test new getNextEvent() interface on 2-valued and 1-valued fields
        {
            ResultsReader reader = createResultsReader(type, openResource(filename));
            
            Event firstResult = reader.getNextEvent();
            {
                String[] siArray = firstResult.getArray("_si", delimiter);
                assertEquals(2, siArray.length);
                // (siArray[0] should be the locally-determined hostname of
                //  splunkd, but there is no good way to test this
                //  consistently.)
                assertEquals("_internal", siArray[1]);
            }
            assertEquals(
                    new String[] {"_internal"},
                    firstResult.getArray("index", delimiter));
            
            assertNull("Expected exactly one result.", reader.getNextEvent());
            reader.close();
        }
    }
    
    private static ResultsReader createResultsReader(
            Class type, InputStream input) {
        
        try {
            return type.getConstructor(InputStream.class).newInstance(input);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    @Test
    public void testEventIsReadOnly() {
        Event event = new Event();
        
        try {
            event.clear();
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
        
        try {
            event.clone();
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
        
        try {
            event.put(null, null);
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
        
        try {
            event.putAll(null);
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
        
        try {
            event.remove(null);
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
    }

    @Test
    public void testPreviewSingleReaderXmlIter() throws Exception {
        testPreviewSingleReaderXml(true);
    }

    @Test
    public void testPreviewSingleReaderXmlGetNext() throws Exception {
        testPreviewSingleReaderXml(false);
    }

    private void testPreviewSingleReaderXml(boolean useIter) throws Exception {
        ResultsReaderXml reader = new ResultsReaderXml(
            openResource("results-preview.xml"));

        assertTrue(reader.isPreview());

        String[] fieldNameArray = new String[0];
        fieldNameArray = reader.getFields().toArray(fieldNameArray);
        assertEquals(101, fieldNameArray.length);
        assertEquals(fieldNameArray[99], "useragent");

        int index = 0;
        Event lastEvent = null;
        if (useIter){
            for (Event event : reader) {
                lastEvent = event;
                index ++;
            }
        } else {
            Event event;
            while ((event = reader.getNextEvent()) != null) {
                lastEvent = event;
                index ++;
            }
        }
        assertEquals("1355946614", lastEvent.get("_indextime"));
        assertEquals(10, index);

        reader.close();
    }

    final String resultsExportXml = "resultsExport.xml";

    @Test
    public void testExportSingleReaderXml() throws Exception {
        testExportSingleReader(
                new ResultsReaderXml(
                        getExportResultsStream(resultsExportXml)));
    }

    @Test
    public void testExportMultiReaderXml() throws Exception {
        testExportMultiReader(
            new MultiResultsReaderXml(
                getExportResultsStream(resultsExportXml)),
            18);
    }

    final String resultsExportJson = "resultsExport.json";

    @Test
    public void testExportSingleReaderJson() throws Exception {
        testExportSingleReader(
            new ResultsReaderJson(
                getExportResultsStream(resultsExportJson)));
    }

    @Test
    public void testExportMultiReaderJson() throws Exception {
        ExportResultsStream stream = getExportResultsStream(resultsExportJson);
        MultiResultsReaderJson multiReader = new MultiResultsReaderJson(stream);
        testExportMultiReader(multiReader, 15);
    }

    private ExportResultsStream getExportResultsStream(String fileName) {
        return new ExportResultsStream(
            openResource(fileName));
    }

    private void testExportSingleReader(
            ResultsReader reader)
            throws Exception{

        int indexEvent = 0;
        for (Event event : reader){
            if (indexEvent == 0) {
                assertEquals("172.16.35.130", event.get("host"));
                assertEquals("16", event.get("count"));
            }

            if (indexEvent == 4) {
                assertEquals("three.four.com", event.get("host"));
                assertEquals("35994", event.get( "count"));
            }

            indexEvent++;
        }

        assertEquals(5, indexEvent);

        reader.close();
    }

    private void testExportMultiReader(
        MultiResultsReader multiReader,
        int countResultSet)
        throws Exception{
        int indexResultSet = 0;
        SearchResults firstResults = null;
        for(SearchResults results : multiReader) {
            if (firstResults == null)
                firstResults = results;

            if (indexResultSet == countResultSet -1) {
                assertFalse(results.isPreview());
            }

            int indexEvent = 0;
            for (Event event : results) {
                if (indexResultSet == 1 && indexEvent == 1) {
                    assertEquals("andy-pc", event.get("host"));
                    assertEquals("3", event.get("count"));
                }

                if (indexResultSet == countResultSet - 2 && indexEvent == 3) {
                    assertEquals("andy-pc", event.get("host"));
                    assertEquals("135", event.get( "count"));
                }

                indexEvent++;
            }

            switch (indexResultSet) {
                case 0:
                    assertEquals(indexEvent, 1);
                    break;
                case 1:
    @Test
                    assertEquals(indexEvent, 3);
                    break;
                default:
                    assertEquals(indexEvent, 5);
                    break;
            }
            indexResultSet++;
        }

        assertEquals(indexResultSet, countResultSet);

        // firstResults should be empty since the multi-reader has passed it
        // and there should be no exception.
        int count = 0;
        for (Event eventL : firstResults) {
            count++;
        }
        assertEquals(0, count);

        multiReader.close();
    }

    // === Utility ===
    
    private void assertNextEventEquals(
            Map expected,
            ResultsReader reader) throws IOException {
        
        assertEquals(expected, reader.getNextEvent());
        expected.clear();
    }
}
=======
/*
 * Copyright 2012 Splunk, Inc.
 *
 * 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 com.splunk;

import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Pattern;

/**
 * Test aspects of results readers not covered by the atom, results, and export test data.
 *
 * Note: some of these tests predate the introduction of the atom, results, and export test
 * data, and may overlap with tests in that set.
 */
public class ResultsReaderTest extends SDKTestCase {
    @Test
    public void testReadCsv() throws Exception {
        InputStream input = openResource("results.csv");
        ResultsReaderCsv reader = new ResultsReaderCsv(input);
        Map expected = new HashMap();

        expected.put("series", "twitter");
        expected.put("sum(kb)", "14372242.758775");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd");
        expected.put("sum(kb)", "267802.333926");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd_access");
        expected.put("sum(kb)", "5979.036338");
        assertNextEventEquals(expected, reader);

        assertNull(reader.getNextEvent());
        reader.close();
    }

    @Test
    public void testReadCsvFromOneshot() throws Exception {
        InputStream input = service.oneshotSearch(
                "search index=_internal | head 1 | stats count",
                Args.create("output_mode", "csv"));
        ResultsReaderCsv reader = new ResultsReaderCsv(input);
        Map expected = new HashMap();

        expected.put("count", "1");
        assertNextEventEquals(expected, reader);

        assertNull(reader.getNextEvent());
        reader.close();
    }

    public void testReadJsonOnSplunk4() throws Exception {
        InputStream input = openResource("results4.json");
        ResultsReaderJson reader = new ResultsReaderJson(input);
        Map expected = new HashMap();
        expected.put("series", "twitter");
        expected.put("sum(kb)", "14372242.758775");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd");
        expected.put("sum(kb)", "267802.333926");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd_access");
        expected.put("sum(kb)", "5979.036338");
        assertNextEventEquals(expected, reader);

        assertNull(reader.getNextEvent());
        reader.close();
    }

    @Test
    public void testReadJsonOnSplunk5() throws Exception {
        // Splunk 5.0 uses a different format for JSON results
        // from Splunk 4.3.
        InputStream input = openResource("results5.json");
        ResultsReaderJson reader = new ResultsReaderJson(input);
        Map expected = new HashMap();

        expected.put("series", "twitter");
        expected.put("sum(kb)", "14372242.758775");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd");
        expected.put("sum(kb)", "267802.333926");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd_access");
        expected.put("sum(kb)", "5979.036338");
        assertNextEventEquals(expected, reader);

        assertNull(reader.getNextEvent());
        reader.close();
    }
    
    public void testReadMultivalueCsvJson() throws IOException {
        // These results were generated from "search index=_internal | head 1",
        // with the output formats {xml, csv, json}.
        String search = "search index=_internal | head 1";
        
        testReadMultivalue(
                ResultsReaderXml.class, "resultsMV.xml");
        testReadMultivalue(
                ResultsReaderCsv.class, "resultsMV.csv");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMV4.json");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMV5.json");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMVFuture.json", ",");
        
        testReadMultivalue(
                ResultsReaderXml.class, "resultsMVOneshot.xml");
        testReadMultivalue(
                ResultsReaderCsv.class, "resultsMVOneshot.csv");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMVOneshot4.json");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMVOneshot5.json");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMVOneshotFuture.json", ",");
        
        testReadMultivalue(
                ResultsReaderXml.class, "splunk_search:blocking/xml/" + search);
        testReadMultivalue(
                ResultsReaderCsv.class, "splunk_search:blocking/csv/" + search);
        testReadMultivalue(
                ResultsReaderJson.class, "splunk_search:blocking/json/" + search);
        
        testReadMultivalue(
                ResultsReaderXml.class, "splunk_search:oneshot/xml/" + search);
        testReadMultivalue(
                ResultsReaderCsv.class, "splunk_search:oneshot/csv/" + search);
        testReadMultivalue(
                ResultsReaderJson.class, "splunk_search:oneshot/json/" + search);
    }
    
    private void testReadMultivalue(
            Class type,
            String filename) throws IOException {
        
        // For our particular test data, the multi-value delimiter
        // for the "_si" field (which is being checked) is a newline
        // for those ResultsReaders that care about delimiters.
        String delimiter = (type == ResultsReaderXml.class) ? "," : "\n";
        
        testReadMultivalue(type, filename, delimiter);
    }
    
    private void testReadMultivalue(
            Class type,
            String filename,
            String delimiter) throws IOException {
        
        // Test legacy getNextEvent() interface on 2-valued and 1-valued fields
        {
            ResultsReader reader = createResultsReader(type, openResource(filename));
            
            HashMap firstResult = reader.getNextEvent();
            {
                String siDelimited = firstResult.get("_si");
                String[] siArray = siDelimited.split(Pattern.quote(delimiter));
                assertEquals(2, siArray.length);
                // (siArray[0] should be the locally-determined hostname of
                //  splunkd, but there is no good way to test this
                //  consistently.)
                assertEquals("_internal", siArray[1]);
            }
            assertEquals("_internal", firstResult.get("index"));
            
            assertNull("Expected exactly one result.", reader.getNextEvent());
            reader.close();
        }
        
        // Test new getNextEvent() interface on 2-valued and 1-valued fields
        {
            ResultsReader reader = createResultsReader(type, openResource(filename));
            
            Event firstResult = reader.getNextEvent();
            {
                String[] siArray = firstResult.getArray("_si", delimiter);
                assertEquals(2, siArray.length);
                // (siArray[0] should be the locally-determined hostname of
                //  splunkd, but there is no good way to test this
                //  consistently.)
                assertEquals("_internal", siArray[1]);
            }
            assertEquals(
                    new String[] {"_internal"},
                    firstResult.getArray("index", delimiter));
            
            assertNull("Expected exactly one result.", reader.getNextEvent());
            reader.close();
        }
    }
    
    private static ResultsReader createResultsReader(
            Class type, InputStream input) {
        
        try {
            return type.getConstructor(InputStream.class).newInstance(input);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    @Test
    public void testEventIsReadOnly() {
        Event event = new Event();
        
        try {
            event.clear();
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
        
        try {
            event.clone();
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
        
        try {
            event.put(null, null);
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
        
        try {
            event.putAll(null);
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
        
        try {
            event.remove(null);
            fail("Expected UnsupportedOperationException.");
        catch (UnsupportedOperationException e) {
            // Good
        }
    }
    
    // === Utility ===
    
    private void assertNextEventEquals(
            Map expected,
            ResultsReader reader) throws IOException {
        
        assertEquals(expected, reader.getNextEvent());
        expected.clear();
    }
}
>>>>>>> f563e76db159871a759ce6fb1dff30448b6f3800
Solution content
/*
 * Copyright 2012 Splunk, Inc.
 *
 * 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 com.splunk;

import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Pattern;

/**
 * Test aspects of results readers not covered by the atom, results, and export test data.
 *
 * Note: some of these tests predate the introduction of the atom, results, and export test
 * data, and may overlap with tests in that set.
 */
public class ResultsReaderTest extends SDKTestCase {
    @Test
    public void testReadCsv() throws Exception {
        InputStream input = openResource("results.csv");
        ResultsReaderCsv reader = new ResultsReaderCsv(input);

        String[] fields = new String[0];
        fields = reader.getFields().toArray(fields);
        assertEquals(2, fields.length);
        assertEquals("sum(kb)", fields[0]);
        assertEquals("series", fields[1]);

        Map expected = new HashMap();

        expected.put("series", "twitter");
        expected.put("sum(kb)", "14372242.758775");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd");
        expected.put("sum(kb)", "267802.333926");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd_access");
        expected.put("sum(kb)", "5979.036338");
        assertNextEventEquals(expected, reader);

        assertNull(reader.getNextEvent());
        reader.close();
    }

    @Test
    public void testReadCsvFromOneshot() throws Exception {
        InputStream input = service.oneshotSearch(
                "search index=_internal | head 1 | stats count",
                Args.create("output_mode", "csv"));
        ResultsReaderCsv reader = new ResultsReaderCsv(input);
        Map expected = new HashMap();

        expected.put("count", "1");
        assertNextEventEquals(expected, reader);

        assertNull(reader.getNextEvent());
        reader.close();
    }

    @Test
    public void testReadFromExportJson() throws Exception {
        verifyMultiReader(getExportStreamJson());
    }

    @Test
    public void testReadFromExportXml() throws Exception {
        verifyMultiReader(getExportStreamXml());
    }

    private void verifyMultiReader(
        }
                MultiResultsReader reader)
                throws Exception {

        SearchResults singleResults = null;
        for(SearchResults results : reader) {
            singleResults = results;
            break;
        }

        Event singleEvent = null;
        for(Event event : singleResults) {
            singleEvent = event;
        }

       assertEquals("1", singleEvent.get("count"));
    }

    private MultiResultsReader getExportStreamJson() throws IOException {
        return new MultiResultsReaderJson(
            service.export(
                "search index=_internal | head 1 | stats count",
                Args.create("output_mode", "json")));
    }

    private MultiResultsReader getExportStreamXml() throws IOException {
        return new MultiResultsReaderXml(
            service.export(
                "search index=_internal | head 1 | stats count",
                Args.create("output_mode", "xml")));
    }

    @Test
    public void testReadJsonOnSplunk4() throws Exception {
        InputStream input = openResource("results4.json");
        ResultsReaderJson reader = new ResultsReaderJson(input);
        Map expected = new HashMap();

        expected.put("series", "twitter");
        expected.put("sum(kb)", "14372242.758775");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd");
        expected.put("sum(kb)", "267802.333926");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd_access");
        expected.put("sum(kb)", "5979.036338");
        assertNextEventEquals(expected, reader);

        assertNull(reader.getNextEvent());
        reader.close();
    }

    @Test
    public void testReadJsonOnSplunk5() throws Exception {
        // Splunk 5.0 uses a different format for JSON results
        // from Splunk 4.3.
        InputStream input = openResource("results5.json");
        ResultsReaderJson reader = new ResultsReaderJson(input);
        Map expected = new HashMap();

        expected.put("series", "twitter");
        expected.put("sum(kb)", "14372242.758775");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd");
        expected.put("sum(kb)", "267802.333926");
        assertNextEventEquals(expected, reader);

        expected.put("series", "splunkd_access");
        expected.put("sum(kb)", "5979.036338");
        assertNextEventEquals(expected, reader);
    }

        assertNull(reader.getNextEvent());
        reader.close();
    }
    
    public void testReadMultivalueCsvJson() throws IOException {
        // These results were generated from "search index=_internal | head 1",
        // with the output formats {xml, csv, json}.
        String search = "search index=_internal | head 1";
        
        testReadMultivalue(
                ResultsReaderXml.class, "resultsMV.xml");
        testReadMultivalue(
                ResultsReaderCsv.class, "resultsMV.csv");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMV4.json");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMV5.json");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMVFuture.json", ",");
        
        testReadMultivalue(
                ResultsReaderXml.class, "resultsMVOneshot.xml");
    
        testReadMultivalue(
                ResultsReaderCsv.class, "resultsMVOneshot.csv");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMVOneshot4.json");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMVOneshot5.json");
        testReadMultivalue(
                ResultsReaderJson.class, "resultsMVOneshotFuture.json", ",");
        
        testReadMultivalue(
                ResultsReaderXml.class, "splunk_search:blocking/xml/" + search);
        testReadMultivalue(
                ResultsReaderCsv.class, "splunk_search:blocking/csv/" + search);
        testReadMultivalue(
                ResultsReaderJson.class, "splunk_search:blocking/json/" + search);
        
        testReadMultivalue(
                ResultsReaderXml.class, "splunk_search:oneshot/xml/" + search);
        testReadMultivalue(
                ResultsReaderCsv.class, "splunk_search:oneshot/csv/" + search);
        testReadMultivalue(
                ResultsReaderJson.class, "splunk_search:oneshot/json/" + search);
    }
    
    private void testReadMultivalue(
            Class type,
            String filename) throws IOException {
        
        // For our particular test data, the multi-value delimiter
        // for the "_si" field (which is being checked) is a newline
        // for those ResultsReaders that care about delimiters.
        String delimiter = (type == ResultsReaderXml.class) ? "," : "\n";
        
        testReadMultivalue(type, filename, delimiter);
    }
    
    private void testReadMultivalue(
            Class type,
            String filename,
            String delimiter) throws IOException {
        
        // Test legacy getNextEvent() interface on 2-valued and 1-valued fields
        {
            ResultsReader reader = createResultsReader(type, openResource(filename));
            
            HashMap firstResult = reader.getNextEvent();
            {
                String siDelimited = firstResult.get("_si");
                String[] siArray = siDelimited.split(Pattern.quote(delimiter));
                assertEquals(2, siArray.length);
                // (siArray[0] should be the locally-determined hostname of
                //  splunkd, but there is no good way to test this
                //  consistently.)
                assertEquals("_internal", siArray[1]);
            }
            assertEquals("_internal", firstResult.get("index"));
            
            assertNull("Expected exactly one result.", reader.getNextEvent());
            reader.close();
        }
        
        // Test new getNextEvent() interface on 2-valued and 1-valued fields
        {
            ResultsReader reader = createResultsReader(type, openResource(filename));
            
            Event firstResult = reader.getNextEvent();
            {
                String[] siArray = firstResult.getArray("_si", delimiter);
                assertEquals(2, siArray.length);
                // (siArray[0] should be the locally-determined hostname of
                //  splunkd, but there is no good way to test this
                //  consistently.)
                assertEquals("_internal", siArray[1]);
            }
            assertEquals(
                    new String[] {"_internal"},
                    firstResult.getArray("index", delimiter));
            
            assertNull("Expected exactly one result.", reader.getNextEvent());
            reader.close();
        }
    }
    
    private static ResultsReader createResultsReader(
            Class type, InputStream input) {
        
        try {
            return type.getConstructor(InputStream.class).newInstance(input);
        } catch (Exception e) {
            throw new RuntimeException(e);
    @Test
    public void testEventIsReadOnly() {
        Event event = new Event();
        
        try {
            event.clear();
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
        
        try {
            event.clone();
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
        
        try {
            event.put(null, null);
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
        
        try {
            event.putAll(null);
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
        
        try {
            event.remove(null);
            fail("Expected UnsupportedOperationException.");
        }
        catch (UnsupportedOperationException e) {
            // Good
        }
    }

    @Test
    public void testPreviewSingleReaderXmlIter() throws Exception {
        testPreviewSingleReaderXml(true);
    }

    @Test
    public void testPreviewSingleReaderXmlGetNext() throws Exception {
        testPreviewSingleReaderXml(false);
    }

    private void testPreviewSingleReaderXml(boolean useIter) throws Exception {
        ResultsReaderXml reader = new ResultsReaderXml(
            openResource("results-preview.xml"));

        assertTrue(reader.isPreview());

        String[] fieldNameArray = new String[0];
        fieldNameArray = reader.getFields().toArray(fieldNameArray);
        assertEquals(101, fieldNameArray.length);
        assertEquals(fieldNameArray[99], "useragent");

        int index = 0;
        Event lastEvent = null;
        if (useIter){
            for (Event event : reader) {
                lastEvent = event;
                index ++;
            }
        } else {
            Event event;
            while ((event = reader.getNextEvent()) != null) {
                lastEvent = event;
                index ++;
            }
        }
        assertEquals("1355946614", lastEvent.get("_indextime"));
        assertEquals(10, index);

        reader.close();
    }

    final String resultsExportXml = "resultsExport.xml";

    @Test
    public void testExportSingleReaderXml() throws Exception {
        testExportSingleReader(
                new ResultsReaderXml(
                        getExportResultsStream(resultsExportXml)));
    }

    @Test
    public void testExportMultiReaderXml() throws Exception {
        testExportMultiReader(
            new MultiResultsReaderXml(
                getExportResultsStream(resultsExportXml)),
            18);
    }

    final String resultsExportJson = "resultsExport.json";

    @Test
    public void testExportSingleReaderJson() throws Exception {
        testExportSingleReader(
            new ResultsReaderJson(
                getExportResultsStream(resultsExportJson)));
    }

    @Test
    public void testExportMultiReaderJson() throws Exception {
        ExportResultsStream stream = getExportResultsStream(resultsExportJson);
        MultiResultsReaderJson multiReader = new MultiResultsReaderJson(stream);
        testExportMultiReader(multiReader, 15);
    }

    private ExportResultsStream getExportResultsStream(String fileName) {
        return new ExportResultsStream(
            openResource(fileName));
    }

    private void testExportSingleReader(
            ResultsReader reader)
            throws Exception{

        int indexEvent = 0;
        for (Event event : reader){
            if (indexEvent == 0) {
                assertEquals("172.16.35.130", event.get("host"));
                assertEquals("16", event.get("count"));
            }

            if (indexEvent == 4) {
                assertEquals("three.four.com", event.get("host"));
                assertEquals("35994", event.get( "count"));
            }

            indexEvent++;
        }

        assertEquals(5, indexEvent);

        reader.close();
    }

    private void testExportMultiReader(
        MultiResultsReader multiReader,
        int countResultSet)
        throws Exception{
        int indexResultSet = 0;
        SearchResults firstResults = null;
        for(SearchResults results : multiReader) {
            if (firstResults == null)
                firstResults = results;

            if (indexResultSet == countResultSet -1) {
                assertFalse(results.isPreview());
            }

            int indexEvent = 0;
            for (Event event : results) {
                if (indexResultSet == 1 && indexEvent == 1) {
                    assertEquals("andy-pc", event.get("host"));
                    assertEquals("3", event.get("count"));
                }

                if (indexResultSet == countResultSet - 2 && indexEvent == 3) {
                    assertEquals("andy-pc", event.get("host"));
                    assertEquals("135", event.get( "count"));
                }

                indexEvent++;
            }

            switch (indexResultSet) {
                case 0:
                    assertEquals(indexEvent, 1);
                    break;
                case 1:
                    assertEquals(indexEvent, 3);
                    break;
                default:
                    assertEquals(indexEvent, 5);
                    break;
            }
            indexResultSet++;
        }

        assertEquals(indexResultSet, countResultSet);

        // firstResults should be empty since the multi-reader has passed it
        // and there should be no exception.
        int count = 0;
        for (Event eventL : firstResults) {
            count++;
        }
        assertEquals(0, count);

        multiReader.close();
    }

    // === Utility ===
    
    private void assertNextEventEquals(
            Map expected,
            ResultsReader reader) throws IOException {
        
        assertEquals(expected, reader.getNextEvent());
        expected.clear();
    }
}
File
ResultsReaderTest.java
Developer's decision
Combination
Kind of conflict
Class declaration
Comment
Import
Package declaration