com.crankuptheamps.client.Command Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of amps-client Show documentation
Show all versions of amps-client Show documentation
AMPS Java client by 60East Technologies, Inc.
////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2010-2022 60East Technologies Inc., All Rights Reserved.
//
// This computer software is owned by 60East Technologies Inc. and is
// protected by U.S. copyright laws and other laws and by international
// treaties. This computer software is furnished by 60East Technologies
// Inc. pursuant to a written license agreement and may be used, copied,
// transmitted, and stored only in accordance with the terms of such
// license agreement and with the inclusion of the above copyright notice.
// This computer software or any other copies thereof may not be provided
// or otherwise made available to any other person.
//
// U.S. Government Restricted Rights. This computer software: (a) was
// developed at private expense and is in all respects the proprietary
// information of 60East Technologies Inc.; (b) was not developed with
// government funds; (c) is a trade secret of 60East Technologies Inc.
// for all purposes of the Freedom of Information Act; and (d) is a
// commercial item and thus, pursuant to Section 12.212 of the Federal
// Acquisition Regulations (FAR) and DFAR Supplement Section 227.7202,
// Government's use, duplication or disclosure of the computer software
// is subject to the restrictions set forth by 60East Technologies Inc..
//
////////////////////////////////////////////////////////////////////////////
package com.crankuptheamps.client;
import com.crankuptheamps.client.fields.CommandField;
import com.crankuptheamps.client.exception.AMPSException;
import java.nio.charset.StandardCharsets;
/**
*
* Command is an encapsulation of a single AMPS command sent by the client.
* Using Command you can build commands to be executed by the client,
* with message processing happening either synchronously via the
* {@link Client} execute() method or asynchronously via the executeAsync()
* methods.
*
* Command is designed to be used as a "builder" enabling AMPS commands
* to be built easily, for example:
*
*
* Client client = new Client(...);
* for(Message m : client.execute(new Command("sow").setTopic("topic"))) { ... }
*
*
* Notice that the {@link Message} class can represent both command messages
* to AMPS and response messages from AMPS. In contrast, Command represents
* only commands to AMPS, so the class includes only properties that
* are valid on outgoing commands.
*
* @since 4.0.0.0
*/
public class Command
{
Message _message;
private boolean _expiration_isSet;
private byte[] _data;
private byte[] _topic;
private CommandId _commandId;
private CommandId _queryId;
private CommandId _subId;
private int _dataLength;
private int _dataOffset;
private int _topicLength;
private int _topicOffset;
private int _ackType;
private int _batchSize = 10;
private int _command;
private int _expiration;
private int _topN = -1;
private long _clientSequenceNumber;
private long _timeout = 0;
private String _bookmark;
private String _correlationId;
private String _dataString;
private String _filter;
private String _options;
private String _orderBy;
private String _sowKey;
private String _sowKeys;
private String _topicString;
/**
* Set the command and reinitialize all other fields to their default
* on-construction values.
* @param command
*/
private void init(final int command)
{
_command = command;
_bookmark = null;
_commandId = null;
_correlationId = null;
_data = null;
_dataString = null;
_filter = null;
_options = null;
_orderBy = null;
_queryId = null;
_sowKey = null;
_sowKeys = null;
_subId = null;
_topic = null;
_topicString = null;
_ackType = Message.AckType.None;
_batchSize = 10;
_clientSequenceNumber = 0;
_expiration = 0;
_timeout = 0;
_topN = -1;
_expiration_isSet = false;
if((_command & Message.Command.NoDataCommands) == 0
|| _command == Message.Command.SOWDelete)
{
_commandId = com.crankuptheamps.client.CommandId.nextIdentifier();
if(isSow())
{
_queryId = _commandId;
}
if(isSubscribe())
{
_subId = _commandId;
}
}
}
/**
* Returns the SOW key on this command.
* @return the sow key
* @since 4.0.0.0
* @deprecated Use getSowKey() instead.
*/
@Deprecated
public String getSOWKey()
{
return _sowKey;
}
/**
* Returns the SOW key on this command.
* @return the sow key
* @since 5.0.0.0
*/
public String getSowKey()
{
return _sowKey;
}
/**
* The SowKey for a command is used to publish to a SOW topic with
* explicit keys set by the user rather than AMPS. The SOW key for a
* message is available through the {@link Message#getSowKey} method
* on a message.
* @param sowKey the sow key to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.3.0.0
* @deprecated Use setSowKey() instead.
*/
@Deprecated
public Command setSOWKey(String sowKey)
{
_sowKey = sowKey;
return this;
}
/**
* The SowKey for a command is used to publish to a SOW topic with
* explicit keys set by the user rather than AMPS. The SOW key for a
* message is available through the {@link Message#getSowKey} method
* on a message.
* @param sowKey the sow key to set
* @return Returns this instance so that various operations can be chained together.
* @since 5.0.0.0
*/
public Command setSowKey(String sowKey)
{
_sowKey = sowKey;
return this;
}
/**
* Returns the SOW key on this command.
* @return the sow key
* @since 5.0.0.0
*/
public String getSowKeys()
{
return _sowKeys;
}
/**
* Returns the SOW key on this command.
* @return the sow key
* @since 4.3.0.0
* @deprecated Use getSowKeys() instead
*/
@Deprecated
public String getSOWKeys()
{
return _sowKeys;
}
/**
* The SowKeys for a command are a comma-separated list
* of the keys that AMPS assigns to SOW messages. The SOW key for a
* message is available through the {@link Message#getSowKey} method
* on a message.
* @param sowKeys the sow keys to set
* @return Returns this instance so that various operations can be chained together.
* @since 5.0.0.0
*/
public Command setSowKeys(String sowKeys)
{
_sowKeys = sowKeys;
return this;
}
/**
* The SowKeys for a command are a comma-separated list
* of the keys that AMPS assigns to SOW messages. The SOW key for a
* message is available through the {@link Message#getSowKey} method
* on a message.
* @param sowKeys the sow keys to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
* @deprecated Use setSowKeys() instead.
*/
@Deprecated
public Command setSOWKeys(String sowKeys)
{
_sowKeys = sowKeys;
return this;
}
/**
* Returns true if this command creates a subscription.
* @return true if this command creates a subscription.
* @since 4.0.0.0
*/
public final boolean isSubscribe()
{
return _command == Message.Command.DeltaSubscribe
|| _command == Message.Command.SOWAndDeltaSubscribe
|| _command == Message.Command.SOWAndSubscribe
|| _command == Message.Command.Subscribe;
}
/**
* Returns true if this command queries a SOW.
* @return true if this command queries a SOW.
* @since 4.0.0.0
*/
public final boolean isSow()
{
return _command == Message.Command.SOW
|| _command == Message.Command.SOWAndDeltaSubscribe
|| _command == Message.Command.SOWAndSubscribe;
}
/**
* Returns true if this command can be associated with a client sequence number.
*
* @return true if this command can be associated with a client sequence number.
* @since 4.0.0.0
*/
public boolean needsSequenceNumber()
{
return _command == Message.Command.Publish
|| _command == Message.Command.DeltaPublish
|| _command == Message.Command.SOWDelete;
}
private int translateCommand(String command_)
{
CommandField cf = new CommandField();
cf.set(command_.getBytes(StandardCharsets.ISO_8859_1));
if(!CommandField.encodeCommand(cf.getValue()).equals(command_))
{
throw new IllegalArgumentException("unknown command type " + command_);
}
return cf.getValue();
}
/**
* Create a new Command with no command type or arguments set.
* @since 4.0.0.0
*/
public Command()
{
}
/**
* Create a Command with the Command field set.
* @param command A {@link Message.Command} value indicating the AMPS command.
* @since 4.0.0.0
*/
public Command(final int command)
{
init(command);
}
/**
* Create a Command with the Command field set.
* @param command A string indicating the AMPS command.
* @since 4.0.0.0
*/
public Command(final String command)
{
init(translateCommand(command));
}
/**
* Resets this command with a new Command type and re-initializes all other fields.
* @param command A {@link Message.Command} value indicating the AMPS command.
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command reset(final int command)
{
init(command);
return this;
}
/**
* Resets this command with a new Command type and re-initializes all other fields.
* @param command A string value indicating the AMPS command.
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command reset(final String command)
{
init(translateCommand(command));
return this;
}
/**
* @return the commandId, which is automatically generated for some command types.
* @since 4.0.0.0
*/
public CommandId getCommandId()
{
return _commandId;
}
/**
* Set the commandId for this command.
* @param commandId the commandId to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setCommandId(CommandId commandId)
{
_commandId = commandId;
return this;
}
/**
* Get the queryId for this command.
* @return the queryId
* @since 4.0.0.0
*/
public CommandId getQueryId()
{
return _queryId;
}
/**
* Set the queryId for this command.
* @param queryId the queryId to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setQueryId(CommandId queryId)
{
_queryId = queryId;
return this;
}
/**
* Return the command type for this command.
* @return the command
* @since 4.0.0.0
*/
public int getCommand()
{
return _command;
}
/**
* Set the command type for this command.
* @param command the command to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setCommand(int command)
{
_command = command;
return this;
}
/**
* Get the topic set on this command.
* @return the topic
* @since 4.0.0.0
*/
public String getTopic()
{
if (_topic == null)
return _topicString;
if (_message == null)
return new String(_topic,_topicOffset,_topicLength, StandardCharsets.ISO_8859_1);
else
return new String(_topic,_topicOffset,_topicLength, _message.getDecoder().charset());
}
/**
* Set the topic for this command.
* @param topic the topic to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setTopic(String topic)
{
_topicString = topic;
_topic = null;
return this;
}
/**
* Set the topic for this command from raw bytes.
* @param topic The raw bytes to be used for the topic.
* @param offset The offset into topic where the topic data begins
* @param length The length of the topic.
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setTopic(byte[] topic, int offset, int length)
{
_topic = topic;
_topicString = null;
_topicLength = length;
_topicOffset = 0;
return this;
}
/**
* Get the filter for this command.
* @return the filter
* @since 4.0.0.0
*/
public String getFilter()
{
return _filter;
}
/**
* Set the filter for this command.
* @param filter the filter to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setFilter(String filter)
{
_filter = filter;
return this;
}
/**
* Get the orderBy clause for this command.
* @return the orderBy
* @since 4.0.0.0
*/
public String getOrderBy()
{
return _orderBy;
}
/**
* Set the orderBy clause for this command.
* @param orderBy the orderBy to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setOrderBy(String orderBy)
{
_orderBy = orderBy;
return this;
}
/**
* Get the subId set on this command.
* @return the subId
* @since 4.0.0.0
*/
public CommandId getSubId()
{
return _subId;
}
/**
* Set the subId for this command.
* @param subId the subId to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setSubId(CommandId subId)
{
if(subId != null) _subId = subId;
return this;
}
/**
* Set the subId for this command.
* @param subId the subId to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setSubId(String subId)
{
if(subId != null) _subId = new CommandId(subId);
return this;
}
/**
* Get the bookmark for this command.
* @return the bookmark
* @since 4.0.0.0
*/
public String getBookmark()
{
return _bookmark;
}
/**
* Set the bookmark for this command.
* @param bookmark the bookmark to set
* @return Returns the instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setBookmark(String bookmark)
{
_bookmark = bookmark;
return this;
}
/**
* Get the options for this command.
* @return the options
* @since 4.0.0.0
*/
public String getOptions()
{
return _options;
}
/**
* Set the options for this command. Options are a comma-delimited list.
* @param options the options to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setOptions(String options)
{
_options = options;
return this;
}
/**
* Get the ackType for this command.
* @return the ackType
* @since 4.0.0.0
*/
public int getAckType()
{
return _ackType;
}
/**
* Set the ackType for this command. Different ackTypes are supported
* for each command. See the Command Reference for details.
* @param ackType the ackType to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setAckType(int ackType)
{
if (ackType == Message.AckType.None
|| ackType == Message.AckType.Persisted) {
if (_commandId != null
&& (_command & Message.Command.NoDataCommands) != 0) {
_commandId = null;
}
}
else if (_commandId == null) {
_commandId = CommandId.nextIdentifier();
}
_ackType = ackType;
return this;
}
/**
* Adds an additional ackType to the ackTypes already set
* for this Command.
* @param ackType the ackType to add
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command addAckType(int ackType)
{
_ackType |= ackType;
return this;
}
/**
* Get the data set on this command.
* @return the data
* @since 4.0.0.0
*/
public String getData()
{
if (_data == null)
return _dataString;
if (_message == null)
return new String(_data,_dataOffset,_dataLength, StandardCharsets.ISO_8859_1);
else
return new String(_data,_dataOffset,_dataLength, _message.getDecoder().charset());
}
/**
* Set the data for this command.
* @param data the data to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setData(String data)
{
_dataString = data;
_data = null;
return this;
}
/**
* Set the data for this command.
* @param data The raw bytes to be used for the data.
* @param offset The offset into data where the data begins.
* @param length The length of the data.
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setData(byte[] data, int offset, int length)
{
_dataString = null;
_data = data;
_dataOffset = offset;
_dataLength = length;
return this;
}
/**
* Set the data for this command.
* @param builder a {@link CompositeMessageBuilder} to set self's data from.
* @return Returns this instance so that various operations can be chained together.
*/
public Command setData(CompositeMessageBuilder builder)
{
_dataString = null;
_data = builder._bytes;
_dataOffset = 0;
_dataLength = builder._position;
return this;
}
/**
* Get the timeout set on this command.
* @return the timeout
* @since 4.0.0.0
*/
public long getTimeout()
{
return _timeout;
}
/**
* Set the timeout for this command (in milliseconds). If the client does
* not receive and consume a processed ack within the specified timeout,
* this method throws an exception. Notice that the timeout is monitored
* in the AMPS client, not on the server, and the client receive thread
* receives and consumes the ack from the server.
* @param timeout the timeout to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setTimeout(long timeout)
{
_timeout = timeout;
return this;
}
/**
* Get the topN value for this command.
* @return the topN
* @since 4.0.0.0
*/
public int getTopN()
{
return _topN;
}
/**
* Set the topN value for this command. This parameter sets a maximum
* number of records returned by a SOW query.
* @param topN the topN to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setTopN(int topN)
{
_topN = topN;
return this;
}
/**
* Get the batchSize set on this command.
* @return the batchSize
* @since 4.0.0.0
*/
public int getBatchSize()
{
return _batchSize;
}
/**
* Set the batchSize for this command. This sets the number of records
* returned in a batch during a SOW query.
* @param batchSize the batchSize to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setBatchSize(int batchSize)
{
_batchSize = batchSize;
return this;
}
/**
* Get the expiration set on this command. This method returns 0 if
* no expiration is set. Use {@link Command#hasExpiration() } to check if an
* expiration is set.
* @return the expiration
* @since 4.0.0.0
*/
public int getExpiration()
{
if(!_expiration_isSet) return 0;
return _expiration;
}
/**
* Returns true if this command has an expiration set.
* @return true if an expiration is set.
* @since 4.0.0.0
*/
public boolean hasExpiration()
{
return _expiration_isSet;
}
/**
* Set the expiration for this command. For a publish command to a
* SOW topic or a queue, the expiration sets the amount of time
* to retain the message in the SOW or the queue.
* @param expiration the expiration to set
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setExpiration(int expiration)
{
_expiration = expiration;
_expiration_isSet = true;
return this;
}
/**
* Clears any expiration value set on self.
* @since 4.0.0.0
*/
public void unsetExpiration()
{
_expiration_isSet = false;
}
/**
* Binds self to a given client, preparing a message from that client to be sent.
* @param client_ The client to bind against
* @return The CommandId for this command, if one is set, or null.
* @throws AMPSException Thrown when preparing the command fails.
* @since 4.0.0.0
*/
protected CommandId prepare(Client client_) throws AMPSException
{
if(_message == null)
{
_message = client_.allocateMessage();
}
else
{
_message.reset();
}
_message.setCommand(_command);
if(_commandId !=null) _message.setCommandId(_commandId);
_message.setAckType(_ackType);
if(_bookmark != null) _message.setBookmark(_bookmark);
if(_data != null)
_message.setData(_data,_dataOffset,_dataLength);
else if(_dataString != null)
_message.setData(_dataString);
if(_filter !=null) _message.setFilter(_filter);
if(_options !=null) _message.setOptions(_options);
if(_orderBy !=null) _message.setOrderBy(_orderBy);
if(_queryId !=null) _message.setQueryId(_queryId);
if(_subId !=null) _message.setSubId(_subId);
if(_topic !=null)
_message.setTopic(_topic,_topicOffset,_topicLength);
else if(_topicString != null)
_message.setTopic(_topicString);
if(_expiration_isSet) _message.setExpiration(_expiration);
if(_sowKey !=null) _message.setSowKey(_sowKey);
if(_sowKeys !=null) _message.setSowKeys(_sowKeys);
if(_batchSize > 1
&& (_command == Message.Command.SOW
|| _command == Message.Command.SOWAndSubscribe
|| _command == Message.Command.SOWAndDeltaSubscribe))
{
_message.setBatchSize(_batchSize);
}
if(_topN != -1) _message.setTopN(_topN);
if(_correlationId != null) _message.setCorrelationId(_correlationId);
if(_clientSequenceNumber > 0 && needsSequenceNumber()) {
_message.setSequence(_clientSequenceNumber);
}
return _commandId;
}
/**
* Sets the client sequence number for this command.
* @param seqNumber Sequence number for this command
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setClientSequenceNumber(long seqNumber)
{
_clientSequenceNumber = seqNumber;
return this;
}
/**
* Get the client sequence number set on this command.
* @return the client sequence number generated for this command, or 0 if none was generated.
* @since 4.0.0.0
*/
public long getClientSequenceNumber()
{
return _clientSequenceNumber;
}
/**
* Sets the correlation Id for this command. The correlation ID
* is an arbitrary string that can be used for whatever purpose the
* application needs. It is not interpreted or used by AMPS. However,
* the correlation ID must only contain characters that are valid base64
* encoded characters.
* @param correlationId_ The CorrelationId is a user provided string included in the log message for a logon.
* AMPS does not interpret or use this string for any other purpose.
* @return Returns this instance so that various operations can be chained together.
* @since 4.0.0.0
*/
public Command setCorrelationId(String correlationId_)
{
_correlationId = correlationId_;
return this;
}
/**
* Returns the correlation Id set on this command
* @return Returns the correlation id
* @since 4.0.0.0
*/
public String getCorrelationId()
{
return _correlationId;
}
}