package com.caringo.client;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpVersion;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.util.IdleConnectionTimeoutThread;
import com.caringo.client.CAStorSDKVersion;
import com.caringo.client.locate.Locator;
import com.caringo.client.locate.StaticLocator;
import com.caringo.client.request.ScspRequestHandler;
import com.caringo.client.request.LocatorRedirectHandler;
/**
* Main interface for initiating a connection to a CAStor cluster and creating or executing SCSP commands. The constructor provides
* initial configuration of the SCSP API.<br>
* <br>
* All command methods should only be called when the factory is running (after a successful <code>start</code> and before a
* <code>stop</code>).<br>
* Example:<br>
*
* <pre>
* {@code
* ScspClient client = new ScspClient("cas.caringo.com", 80, 8, 4);
* client.start();
* ScspNodeInfo command = client.createNodeInfoCommand();
* client.execute();
* //more commands..
* factory.stop();
* }
* </pre>
*
* <br>
* Command object vs. execution method interfaces<br>
* <br>
* ScspClient provides methods for creating command objects that can execute SCSP commands and for direct execution of the same
* commands. For each command object, there is an equivalent ScspClient execution method.
* <p>
* For example, the following two pieces of code are equivalent:
*
* <pre>
* {@code
* void doInfo(ScspClient client, String uuid) {
* ScspResponse response = client.info(uuid);
* System.out.println(response.toString());
* }}
* </pre>
*
* and<br>
*
* <pre>
* {@code
* void doInfo(ScspClient client, String uuid) {
* ScspInfo infoCommand = client.createInfoCommand(uuid);
* ScspResponse response = infoCommand.execute();
* System.out.println(response.toString());
* }
* }
* </pre>
*
* <p>
* Mutable vs. Non-mutable methods<br>
* <br>
* This API provides separate execution interfaces for CAStor anchor streams and regular streams. The anchor stream commands contain
* 'Mutable' in their method names. <br>
* <p>
* Validate mode<br>
* If <code>setValidating(true)</code> is called, all execution methods (<code>write</code>, <code>read</code>, etc.)
* will validate their arguments instead of executing requests to CAStor. <br>
* <p>
* The <code>Path</code> Parameter<br>
* The <code>path</code> parameter to the <code>ScspClient</code> execution methods and the <code>path</code> property in <code>ScspCommand</code>
* can be used to specify the Remote Cluster Name for <code>ScspProxy</code> remote proxy features; for named object names, including bucket
* and object names; and for uuids. Note that the <code>uuid</code> parameter is deprecated in this release and will be removed altogether
* in the next release or the one following - please use the <code>path</code> parameter and property instead.
* <br>
* Copyright (c) 2009 by Caringo, Inc. -- All rights reserved<br>
* This is free software, distributed under the terms of the New BSD license.<br>
* See the LICENSE.txt file included in this archive.<br>
* <br>
*
* @author pray
* @created September 20, 2009
* @id ${Id}
*/
public class ScspClient {
private static final int DEFAULT_MAX_RETRIES = 5;
private static final int DEFAULT_MAX_POOL_SIZE = 50;
private static final String DEFAULT_USER_AGENT = "CAStor Client java/" + CAStorSDKVersion.CAStorSDKVersion;
private static final int CM_IDLE_TIMEOUT = 60 * 1000; // HttpConnectionManager idle timeout - 1 minute
private static final int CM_REAP_PERIOD = 60 * 1000; // HttpConnectionManager reaper retry period - 1 minute
private static final int LOCATOR_RETRY_TIMEOUT = 0; // StaticLocator pool retry timeout - 10 minutes
private static final int CONNECTION_TIMEOUT = 60 * 1000; // Request activity timeout - 1 minute
private static final HttpClientParams CLIENT_PARAMS = new HttpClientParams();
private static final int MAX_REDIRECTS = 10;
public static final int DEFAULT_EXTERNAL_TIMEOUT = 300; // Socket timeout (non-connection) for connections made from a 305 redirect
public static final String CASTOR_ADMIN_AGENT = "CAStorAdminAgent/1.0";
public static final String UserAgent = DEFAULT_USER_AGENT;
static {
CLIENT_PARAMS.setParameter("http.connection.timeout", CONNECTION_TIMEOUT);
CLIENT_PARAMS.setParameter(HttpClientParams.SO_TIMEOUT, CONNECTION_TIMEOUT);
CLIENT_PARAMS.setParameter(HttpClientParams.MAX_REDIRECTS, MAX_REDIRECTS); // this should never be used since we're
// explicitly handling redirects
CLIENT_PARAMS.setParameter(HttpClientParams.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
CLIENT_PARAMS.setParameter(HttpClientParams.USE_EXPECT_CONTINUE, true);
CLIENT_PARAMS.setParameter(HttpClientParams.USER_AGENT, DEFAULT_USER_AGENT);
CLIENT_PARAMS.setParameter(HttpClientParams.WARN_EXTRA_INPUT, true);
CLIENT_PARAMS.setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
}
private HttpConnectionManager connMgr;
private HttpConnectionManager externalConnMgr;
private IdleConnectionTimeoutThread connReaper;
private LocatorRedirectHandler locator;
private boolean validating;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int maxPoolSize = DEFAULT_MAX_POOL_SIZE;
private String userAgent = DEFAULT_USER_AGENT;
private int connectionTimeout;
private int poolTimeout;
private String hostHeaderValue;
private int externalTimeout = DEFAULT_EXTERNAL_TIMEOUT;
/**
* Construct command factory and configure the communication settings.
*
* @param hosts -
* Array of CAStor hosts as IP addressses or host names. Typically this is a single value identifying an initial node
* in the CAStor cluster.
* @param port -
* Port number for talking to CAStor cluter. Typically 80.
* @param maxConnectionPoolSize -
* Size of connection pool. Basically, the connectionPoolSize indicates how many simultaneous open connections should
* be allowed.
* @param maxRetries -
* Maximum number of times to retry a command on communication or server failure.
*/
public ScspClient(String[] hosts, int port, int maxConnectionPoolSize, int maxRetries) {
this.locator = new LocatorRedirectHandler(new StaticLocator(hosts, port, LOCATOR_RETRY_TIMEOUT));
this.maxPoolSize = maxConnectionPoolSize;
this.maxRetries = maxRetries;
this.validating = false;
this.connectionTimeout = CONNECTION_TIMEOUT;
this.poolTimeout = CM_IDLE_TIMEOUT;
}
/**
* Construct command factory and configure the communication settings along with timeouts.
*
* @param hosts -
* Array of CAStor hosts as IP addressses or host names. Typically this is a single value identifying an initial node
* in the CAStor cluster.
* @param port -
* Port number for talking to CAStor cluter. Typically 80.
* @param maxConnectionPoolSize -
* Size of connection pool. Basically, the connectionPoolSize indicates how many simultaneous open connections should
* be allowed.
* @param maxRetries -
* Maximum number of times to retry a command on communication or server failure.
* @param connectionTimeout -
* Idle timeout for a request in seconds.
* @param poolTimeout -
* The amount of time seconds an idle connection will be stored for reuse.
* @param locatorRetryTimeout -
* The number of seconds after a node is found dead that it will be retried.
*/
public ScspClient(String[] hosts, int port, int maxConnectionPoolSize, int maxRetries, int connectionTimeout, int poolTimeout, int locatorRetryTimeout) {
this.locator = new LocatorRedirectHandler(new StaticLocator(hosts, port, locatorRetryTimeout));
this.maxPoolSize = maxConnectionPoolSize;
this.maxRetries = maxRetries;
this.validating = false;
this.connectionTimeout = connectionTimeout * 1000;
this.poolTimeout = poolTimeout * 1000;
CLIENT_PARAMS.setParameter(HttpClientParams.SO_TIMEOUT, this.connectionTimeout);
CLIENT_PARAMS.setParameter("http.connection.timeout", this.connectionTimeout);
}
/**
* Construct command factory and configure the communication settings along with timeouts.
*
* @param locator -
* A host Locator to use for lookup CAStor node addresses.
* @param port -
* Port number for talking to CAStor cluter. Typically 80.
* @param maxConnectionPoolSize -
* Size of connection pool. Basically, the connectionPoolSize indicates how many simultaneous open connections should
* be allowed.
* @param maxRetries -
* Maximum number of times to retry a command on communication or server failure.
* @param connectionTimeout -
* Idle timeout for a request in seconds.
* @param poolTimeout -
* The amount of time seconds an idle connection will be stored for reuse.
*/
public ScspClient(Locator locator, int port, int maxConnectionPoolSize, int maxRetries, int connectionTimeout, int poolTimeout) {
this.locator = new LocatorRedirectHandler(locator);
this.maxPoolSize = maxConnectionPoolSize;
this.maxRetries = maxRetries;
this.validating = false;
this.connectionTimeout = connectionTimeout * 1000;
this.poolTimeout = poolTimeout * 1000;
CLIENT_PARAMS.setParameter(HttpClientParams.SO_TIMEOUT, this.connectionTimeout);
CLIENT_PARAMS.setParameter("http.connection.timeout", this.connectionTimeout);
}
/**
* Start the factory.
*
* @throws IOException -
* Indicates something went wrong when trying to set up connection to CAStor.
*/
public void start() throws IOException {
if (!isStarted()) {
locator.start();
}
if (connMgr == null) {
connMgr = new MultiThreadedHttpConnectionManager();
HttpConnectionManagerParams params = connMgr.getParams();
params.setMaxTotalConnections(maxPoolSize);
params.setDefaultMaxConnectionsPerHost(maxPoolSize); // we don't need to restrict this, like a browser would
connMgr.setParams(params);
}
if (externalConnMgr == null) {
externalConnMgr = new MultiThreadedHttpConnectionManager();
HttpConnectionManagerParams extParams = externalConnMgr.getParams();
extParams.setMaxTotalConnections(maxPoolSize);
extParams.setDefaultMaxConnectionsPerHost(maxPoolSize); // we don't need to restrict this, like a browser would
externalConnMgr.setParams(extParams);
}
if ((connMgr != null) && (externalConnMgr != null)) {
if (connReaper == null) {
connReaper = new IdleConnectionTimeoutThread();
connReaper.setConnectionTimeout(poolTimeout);
connReaper.setTimeoutInterval(CM_REAP_PERIOD);
connReaper.addConnectionManager(connMgr);
connReaper.addConnectionManager(externalConnMgr);
connReaper.start();
}
}
}
/**
* Stop the interface and close all the connections.
*/
public void stop() {
connReaper.shutdown();
connMgr.closeIdleConnections(1);
externalConnMgr.closeIdleConnections(1);
locator.stop();
connReaper = null;
connMgr = null;
externalConnMgr = null;
}
/**
* Create a <code>ScspWrite</code> with an input stream and length.
*
* @param inputStream -
* Stream to read stream data from for writing to CAStor.
* @param inputStreamLength -
* Length of the input stream.
* @return The write command ready to execute.
*/
public ScspWrite createWriteCommand(InputStream inputStream, long inputStreamLength) {
return new ScspWrite(getClient(), inputStream, inputStreamLength);
}
/**
* Create a <code>ScspRead</code> with a CAStor stream UUID and output stream.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor stream to read.
* @param outputStream -
* Stream to write data read from CAStor.
* @return The read command ready to execute.
*/
public ScspRead createReadCommand(String UUID, OutputStream outputStream) {
return new ScspRead(getClient(), UUID, outputStream);
}
/**
* Create a <code>ScspInfo</code> with a CAStor stream UUID.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor stream to retrieve info for.
* @return The read command ready to execute.
*/
public ScspInfo createInfoCommand(String UUID) {
return new ScspInfo(getClient(), UUID);
}
/**
* Create a <code>ScspAggregateInfo</code> with a CAStor stream UUID and output stream.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor stream to read.
* @param outputStream -
* Stream to write data read from CAStor.
* @return The read command ready to execute.
*/
public ScspAggregateInfo createAggregateInfoCommand(String UUID, OutputStream outputStream) {
return new ScspAggregateInfo(getClient(), UUID, outputStream);
}
/**
* Create a <code>ScspDeleteCommand</code> with a CAStor stream UUID.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor stream to delete.
* @return The delete command ready to execute.
*/
public ScspDelete createDeleteCommand(String UUID) {
return new ScspDelete(getClient(), UUID);
}
// Mutable (anchor stream) commands
/**
* Create a <code>ScspCopyCommand</code> with an initial UUID.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor anchor stream to update.
* @return The update command ready to execute.
*/
public ScspCopy createCopyCommand(String UUID) {
return new ScspCopy(getClient(), UUID);
}
/**
* Create a <code>ScspUpdateCommand</code> with an initial UUID, input stream, and length.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor anchor stream to update.
* @param inputStream -
* Stream to read stream data from for writing to CAStor.
* @param inputStreamLength -
* Length of the input stream.
* @return The update command ready to execute.
*/
public ScspUpdate createUpdateCommand(String UUID, InputStream inputStream, long inputStreamLength) {
return new ScspUpdate(getClient(), UUID, inputStream, inputStreamLength);
}
/**
* Create a <code>ScspAppendCommand</code> with an initial UUID, input stream, and length.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor anchor stream to append to.
* @param inputStream -
* Stream to read stream data from for writing to CAStor.
* @param inputStreamLength -
* Length of the input stream.
* @return The update command ready to execute.
*/
public ScspAppend createAppendCommand(String UUID, InputStream inputStream, long inputStreamLength) {
return new ScspAppend(getClient(), UUID, inputStream, inputStreamLength);
}
// Non-stream commands
/**
* Create a <code>ScspNodeInfoCommand</code>.
*
* @return The node info command ready to execute.
*/
public ScspNodeStatus createNodeStatusCommand() {
return new ScspNodeStatus(getClient());
}
// direct execution (non-command) interface
/**
* Execute or validate a normal (non-mutable) SCSP write command with an input stream and length, query args, and headers.
*
* @param path -
* Resource path.
* @param input -
* Stream containing data to to write to CAStor.
* @param inputStreamLength -
* Length of the input stream.
* @param queryArgs -
* queryArgs to pass to execution.
* @param headers -
* headers to pass to execution.
* @return If isValidating, response with <code>ScspResultCode</code> set to ScspRCSuccess if headers and query args are valid
* for this command or ScspRCFailure otherwise. If not isValidating, response returned from CAStor.
* @throws ScspExecutionException
*/
public ScspResponse write(String path, InputStream input, long inputStreamLength, ScspQueryArgs queryArgs, ScspHeaders headers)
throws ScspExecutionException {
ScspWrite wc = createWriteCommand(input, inputStreamLength);
wc.setPath(path);
wc.setQueryArgs(queryArgs);
wc.setHeaders(headers);
if (validating) {
return validateCommand(wc);
} else {
return wc.execute();
}
}
/**
* Execute or validate a normal (non-mutable) SCSP read command with a stream path, an output stream, query args, and headers.
*
* @param UUID -
* (Deprecated) The UUID of CAStor stream to read.
* @param path -
* Resource path.
* @param output -
* Stream to write data read from CAStor.
* @param queryArgs -
* queryArgs to pass to execution.
* @param headers -
* headers to pass to execution.
* @return If isValidating, response with <code>ScspResultCode</code> set to ScspRCSuccess if headers and query args are valid
* for this command or ScspRCFailure otherwise. If not isValidating, response returned from CAStor.
* @throws ScspExecutionException
*/
public ScspResponse read(String UUID, String path, OutputStream output, ScspQueryArgs queryArgs, ScspHeaders headers)
throws ScspExecutionException {
ScspRead rc = createReadCommand(UUID, output);
rc.setPath(path);
rc.setQueryArgs(queryArgs);
rc.setHeaders(headers);
if (validating) {
return validateCommand(rc);
} else {
return rc.execute();
}
}
/**
* Execute or validate a normal (non-mutable) SCSP info command with a stream path, query args, and headers.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor stream to retrieve info for.
* @param path -
* Resource path.
* @param queryArgs -
* queryArgs to pass to execution.
* @param headers -
* headers to pass to execution.
* @return If isValidating, response with <code>ScspResultCode</code> set to ScspRCSuccess if headers and query args are valid
* for this command or ScspRCFailure otherwise. If not isValidating, response returned from CAStor.
* @throws ScspExecutionException
*/
public ScspResponse info(String UUID, String path, ScspQueryArgs queryArgs, ScspHeaders headers) throws ScspExecutionException {
ScspInfo ic = createInfoCommand(UUID);
ic.setPath(path);
ic.setQueryArgs(queryArgs);
ic.setHeaders(headers);
if (validating) {
return validateCommand(ic);
} else {
return ic.execute();
}
}
/**
* Execute or validate a normal (non-mutable) SCSP delete command with a stream path, query args, and headers.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor stream to delete.
* @param path -
* Resource path.
* @param queryArgs -
* queryArgs to pass to execution.
* @param headers -
* headers to pass to execution.
* @return If isValidating, response with <code>ScspResultCode</code> set to ScspRCSuccess if headers and query args are valid
* for this command or ScspRCFailure otherwise. If not isValidating, response returned from CAStor.
* @throws ScspExecutionException
*/
public ScspResponse delete(String UUID, String path, ScspQueryArgs queryArgs, ScspHeaders headers) throws ScspExecutionException {
ScspDelete dc = createDeleteCommand(UUID);
dc.setPath(path);
dc.setQueryArgs(queryArgs);
dc.setHeaders(headers);
if (validating) {
return validateCommand(dc);
} else {
return dc.execute();
}
}
/**
* Execute or validate an anchor (mutable) stream SCSP write command with an input stream and length, query args, and headers.
*
* @param path -
* Resource path.
* @param input -
* Stream containing the data to write to CAStor.
* @param inputStreamLength -
* Length of the input stream.
* @param queryArgs -
* queryArgs to pass to execution
* @param headers -
* headers to pass to execution
* @return If isValidating, response with <code>ScspResultCode</code> set to ScspRCSuccess if headers and query args are valid
* for this command or ScspRCFailure otherwise. If not isValidating, response returned from CAStor.
* @throws ScspExecutionException
*/
public ScspResponse writeMutable(String path, InputStream input, long inputStreamLength, ScspQueryArgs queryArgs, ScspHeaders headers)
throws ScspExecutionException {
ScspWrite wc = createWriteCommand(input, inputStreamLength);
wc.setPath(path);
wc.setHeaders(headers);
if (validating) {
return validateMutable(wc, queryArgs);
} else {
return executeMutable(wc, queryArgs);
}
}
/**
* Execute or validate an anchor (mutable) SCSP read command with a stream path, an output stream, query args, and headers.
*
* @param UUID -
* (Deprecated) The UUID of CAStor stream to read.
* @param path -
* Resource path.
* @param output -
* Stream to write data read from CAStor.
* @param queryArgs -
* queryArgs to pass to execution.
* @param headers -
* headers to pass to execution.
* @return If isValidating, response with <code>ScspResultCode</code> set to ScspRCSuccess if headers and query args are valid
* for this command or ScspRCFailure otherwise. If not isValidating, response returned from CAStor.
* @throws ScspExecutionException
*/
public ScspResponse readMutable(String UUID, String path, OutputStream output, ScspQueryArgs queryArgs, ScspHeaders headers)
throws ScspExecutionException {
ScspRead rc = createReadCommand(UUID, output);
rc.setPath(path);
rc.setHeaders(headers);
if (validating) {
return validateMutable(rc, queryArgs);
} else {
return executeMutable(rc, queryArgs);
}
}
/**
* Execute or validate an anchor (mutable) stream SCSP info command with a stream path, query args, and headers.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor stream to retrieve info for.
* @param path -
* Resource path.
* @param queryArgs -
* queryArgs to pass to execution.
* @param headers -
* headers to pass to execution.
* @return If isValidating, response with <code>ScspResultCode</code> set to ScspRCSuccess if headers and query args are valid
* for this command or ScspRCFailure otherwise. If not isValidating, response returned from CAStor.
* @throws ScspExecutionException
*/
public ScspResponse infoMutable(String UUID, String path, ScspQueryArgs queryArgs, ScspHeaders headers) throws ScspExecutionException {
ScspInfo ic = createInfoCommand(UUID);
ic.setPath(path);
ic.setHeaders(headers);
if (validating) {
return validateMutable(ic, queryArgs);
} else {
return executeMutable(ic, queryArgs);
}
}
/**
* Execute or validate an anchor (mutable) stream SCSP delete command with a stream path, query args, and headers.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor stream to delete.
* @param path -
* Resource path.
* @param queryArgs -
* queryArgs to pass to execution.
* @param headers -
* headers to pass to execution.
* @return If isValidating, response with <code>ScspResultCode</code> set to ScspRCSuccess if headers and query args are valid
* for this command or ScspRCFailure otherwise. If not isValidating, response returned from CAStor.
* @throws ScspExecutionException
*/
public ScspResponse deleteMutable(String UUID, String path, ScspQueryArgs queryArgs, ScspHeaders headers) throws ScspExecutionException {
ScspDelete dc = createDeleteCommand(UUID);
dc.setPath(path);
dc.setHeaders(headers);
if (validating) {
return validateMutable(dc, queryArgs);
} else {
return executeMutable(dc, queryArgs);
}
}
/**
* Execute or validate a SCSP append command with a stream path, an input stream and length, query args, and headers.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor stream to append to.
* @param path -
* Resource path.
* @param inputStream -
* Stream containing the data to write to CAStor.
* @param inputStreamLength -
* Length of the input stream.
* @param queryArgs -
* queryArgs to pass to execution
* @param headers -
* headers to pass to execution
* @return If isValidating, response with <code>ScspResultCode</code> set to ScspRCSuccess if headers and query args are valid
* for this command or ScspRCFailure otherwise. If not isValidating, response returned from CAStor.
* @throws ScspExecutionException
*/
public ScspResponse appendMutable(String UUID, String path, InputStream inputStream, long inputStreamLength, ScspQueryArgs queryArgs,
ScspHeaders headers) throws ScspExecutionException {
ScspAppend ac = createAppendCommand(UUID, inputStream, inputStreamLength);
ac.setPath(path);
ac.setHeaders(headers);
if (validating) {
return validateMutable(ac, queryArgs);
} else {
return executeMutable(ac, queryArgs);
}
}
/**
* Execute or validate a SCSP update command with a stream path, an input stream and length, query args, and headers.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor stream to udpate.
* @param path -
* Resource path.
* @param inputStream -
* Stream containing the data to write to CAStor.
* @param inputStreamLength -
* Length of the input stream.
* @param queryArgs -
* queryArgs to pass to execution
* @param headers -
* headers to pass to execution
* @return If isValidating, response with <code>ScspResultCode</code> set to ScspRCSuccess if headers and query args are valid
* for this command or ScspRCFailure otherwise. If not isValidating, response returned from CAStor.
* @throws ScspExecutionException
*/
public ScspResponse updateMutable(String UUID, String path, InputStream inputStream, long inputStreamLength, ScspQueryArgs queryArgs,
ScspHeaders headers) throws ScspExecutionException {
ScspUpdate uc = createUpdateCommand(UUID, inputStream, inputStreamLength);
uc.setPath(path);
uc.setHeaders(headers);
if (validating) {
return validateMutable(uc, queryArgs);
} else {
return executeMutable(uc, queryArgs);
}
}
/**
* Execute or validate a SCSP copy command with a stream path, query args, and headers.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor stream to copy.
* @param path -
* Resource path.
* @param queryArgs -
* queryArgs to pass to execution.
* @param headers -
* headers to pass to execution.
* @return If isValidating, response with <code>ScspResultCode</code> set to ScspRCSuccess if headers and query args are valid
* for this command or ScspRCFailure otherwise. If not isValidating, response returned from CAStor.
* @throws ScspExecutionException
*/
public ScspResponse copyMutable(String UUID, String path, ScspQueryArgs queryArgs, ScspHeaders headers) throws ScspExecutionException {
ScspCopy cc = createCopyCommand(UUID);
cc.setPath(path);
cc.setHeaders(headers);
if (validating) {
return validateMutable(cc, queryArgs);
} else {
return executeMutable(cc, queryArgs);
}
}
/**
* Execute or validate an SCSP info command to retrieve cluster status with query args and headers.
*
* @param queryArgs -
* queryArgs to pass to execution.
* @param headers -
* headers to pass to execution.
* @return If isValidating, response with <code>ScspResultCode</code> set to ScspRCSuccess if headers and query args are valid
* for this command or ScspRCFailure otherwise. If not isValidating, response returned from CAStor.
* @throws ScspExecutionException
*/
public ScspResponse nodeStatus(ScspQueryArgs queryArgs, ScspHeaders headers) throws ScspExecutionException {
ScspNodeStatus nsc = createNodeStatusCommand();
nsc.setQueryArgs(queryArgs);
nsc.setHeaders(headers);
if (validating) {
return validateCommand(nsc);
} else {
return nsc.execute();
}
}
/**
* Execute or validate an SCSP GET command for a manifest stream with a stream path, query args, and headers.
*
* @param UUID -
* (Deprecated) The UUID of the CAStor stream to retrieve info for.
* @param path -
* Resource path.
* @param output -
* Stream to write data read from CAStor.
* @param queryArgs -
* queryArgs to pass to execution.
* @param headers -
* headers to pass to execution.
* @return If isValidating, response with <code>ScspResultCode</code> set to ScspRCSuccess if headers and query args are valid
* for this command or ScspRCFailure otherwise. If not isValidating, response returned from CAStor.
* @throws ScspExecutionException
*/
public ScspResponse aggregateInfo(String UUID, String path, OutputStream output, ScspQueryArgs queryArgs, ScspHeaders headers) throws ScspExecutionException {
ScspAggregateInfo ic = createAggregateInfoCommand(UUID, output);
ic.setPath(path);
ic.setQueryArgs(queryArgs);
ic.setHeaders(headers);
if (validating) {
return validateCommand(ic);
} else {
return ic.execute();
}
}
/**
* Set the user agent to pass in HTTP requests to CAStor.
*
* @param userAgent -
* the user agent to pass to CAStor.
*/
public void setUserAgent(String userAgent) {
this.userAgent = userAgent;
CLIENT_PARAMS.setParameter(HttpClientParams.USER_AGENT, userAgent);
}
/**
* Get the user agent.
*
* @return the user agent.
*/
public String getUserAgent() {
return userAgent;
}
/**
* Set the default Host header value to pass in HTTP requests to CAStor.
* This value will be used only if no other Host header has been specified.
*
* @param hostHeaderValue -
* the Host header value to pass to CAStor.
*/
public void setHostHeaderValue(String hostHeaderValue) {
this.hostHeaderValue = hostHeaderValue;
CLIENT_PARAMS.setVirtualHost(hostHeaderValue);
}
/**
* Get the default value of the Host header (if previously specified)
*
* @return the defaul value of the Host header
*/
public String getHostHeaderValue() {
return hostHeaderValue;
}
/**
* Set the idle timeout for requests resulting from a 305, in seconds.
*
* @param externalTimeout -
* the post-305 idle timeout
*/
public void setExternalTimeout(int externalTimeout) {
this.externalTimeout = externalTimeout;
}
/**
* Get idle timeout for requests resulting from a 305, in seconds.
*
* @return the post-305 idle timeout
*/
public int getExternalTimeout() {
return this.externalTimeout;
}
/**
* Has <code>start</code> been successfully called without an intervening <code>stop</code>?
*
* @return - Whether <code>start</code> has been called.
*/
public boolean isStarted() {
return (connMgr != null) && (externalConnMgr != null) && (connReaper != null);
}
/**
* Return whether this is in Validation mode.
*
* @return - validating
*/
public boolean isValidating() {
return validating;
}
/**
* Set validation mode
*
* @param validating -
* Turn on validation if true.
*/
public void setValidating(boolean validating) {
this.validating = validating;
}
// validate a command and build the correct result code
//
private ScspResponse validateCommand(ScspCommand command) {
boolean valid = command.validate();
return new ScspResponse(valid ? ScspResponse.ScspResultCode.ScspRCSuccess : ScspResponse.ScspResultCode.ScspRCFailure, 0,
"", new ScspHeaders(), "",0);
}
// build an HttpClient and request handler for executing a command. This glues the underlying HttpClient and request handler
// interface to the Scsp interfaces.
private ScspRequestHandler getClient() {
if (!this.isStarted()) {
throw new IllegalStateException("ClientFactory " + this + " has not been started.");
}
HttpClient client = new HttpClient(new HttpClientParams(CLIENT_PARAMS));
client.setHttpConnectionManager(connMgr);
return new ScspRequestHandler(client, locator, maxRetries, this.externalTimeout, externalConnMgr);
}
// Execute one of the Mutable commands, automatically supplying the required alias query argument
// while not polluting the ScspQueryArgs passed into the command
//
private ScspResponse executeMutable(ScspCommand command, ScspQueryArgs queryArgs) throws ScspExecutionException {
if (null == queryArgs) {
queryArgs = new ScspQueryArgs();
}
HashMap<String,String> argsMap = queryArgs.getArgList();
ScspQueryArgs commandArgs = new ScspQueryArgs();
commandArgs.setValue("alias", "yes");
commandArgs.addAll(argsMap);
command.setQueryArgs(commandArgs);
return command.execute();
}
// Validate one of the Mutable commands, automatically supplying the required alias query argument
// while not polluting the ScspQueryArgs passed into the command
//
private ScspResponse validateMutable(ScspCommand command, ScspQueryArgs queryArgs) {
if (null == queryArgs) {
queryArgs = new ScspQueryArgs();
}
HashMap<String,String> argsMap = queryArgs.getArgList();
ScspQueryArgs commandArgs = new ScspQueryArgs();
commandArgs.setValue("alias", "yes");
commandArgs.addAll(argsMap);
command.setQueryArgs(commandArgs);
return validateCommand(command);
}
}