All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.crankuptheamps.client.Command Maven / Gradle / Ivy

////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2010-2024 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; } /** * Retrieves the State of the World (SOW) key associated with this instance. * * @return A string representing 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 only used to publish to a SOW topic and if * the user wants to restrict the command to a set of messages identified * by key, SowKeys is used instead. 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 * @see Command#setSowKeys(String) * @see Command#getSowKeys() */ public Command setSowKey(String sowKey) { _sowKey = sowKey; return this; } /** * Returns the SOW keys on this command. * * @return the sow key * @since 5.0.0.0 */ public String getSowKeys() { return _sowKeys; } /** * Returns the SOW keys on this command. * * @return the sow key * @since 4.3.0.0 * @deprecated Use getSowKeys() instead */ @Deprecated public String getSOWKeys() { return _sowKeys; } /** * Sets the SowKeys for this command. * * SowKeys are a comma-separated list of unique keys assigned by AMPS to * SOW messages to be deleted. AMPS uses these ids to locate and remove * the specified records. The SOW key for a message is available through * the {@link Message#getSowKey} method on a message. This method specifies * that the command is only intended to apply to the keys provided.You * cannot perform bulk updates by including multiple SOW keys in a single * publish operation. It also works to limit queiries. * * @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; } /** * Checks if the current command represents a subscription. * * @return {@code true} if this command is a subscription command, * otherwise {@code false}. * @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; } /** * Checks if the current command represents a State of the World (SOW) * operation. * * @return {@code true} if this command queries a SOW, otherwise * {@code false}. * @since 4.0.0.0 */ public final boolean isSow() { return _command == Message.Command.SOW || _command == Message.Command.SOWAndDeltaSubscribe || _command == Message.Command.SOWAndSubscribe; } /** * Checks whether a sequence number is needed for this message based on the * message command. * * @return {@code true} if this command can be associated with a client * sequence number, {@code false} otherwise. * @since 4.0.0.0 */ public boolean needsSequenceNumber() { return _command == Message.Command.Publish || _command == Message.Command.DeltaPublish || _command == Message.Command.SOWDelete; } /** * This method converts the input command into bytes using ISO-8859-1 encoding, * checks its validity, and returns an integer representation of the command. * If the command is unknown, it raises an IllegalArgumentException. * * @param command_ A string value command to be translated. * @return An integer representation of the command. * @throws IllegalArgumentException If the provided command cannot be * recognized. * @since 4.0.0.0 */ 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. * Provides a starting point for creating 'Command' objects. * * @since 4.0.0.0 */ public Command() { } /** * Create a new `Command` object with the specified command code. * * This constructor creates a new `Command` object, initializing it with an * integer value representing a specific command code. The initialization * process is handled internally by the constructor. * * @param command A {@link Message.Command} value indicating the AMPS command. * @since 4.0.0.0 */ public Command(final String command) { init(translateCommand(command)); } public Command(final int command) { init(command); } /** * Resets this 'Command' object with a new Command type and re-initializes all * other fields altering its purpose. This method allows the reusability of the * current `Command` object by changing its state to represent a different * command type. * * @param command A {@link Message.Command} value indicating the AMPS command. * @return This `Command` object with its state reset to the new command type, * supporting method chaining. * @since 4.0.0.0 */ public Command reset(final int command) { init(command); return this; } /** * Resets the current 'Command' object with a new command type specified as * a string value and re-initializes all associated fields. Translates the * string into a command type using `translateCommand` and alters the object's * purpose. * * @param command A string representing the new command type. * @return This current 'Command' object with its state reset to the new type, * allowing method chaining. * * @since 4.0.0.0 */ public Command reset(final String command) { init(translateCommand(command)); return this; } /** * Gets the automatically generated command ID associated with this command. * * @return The commandId, which is automatically generated for some command * types. * @since 4.0.0.0 */ public CommandId getCommandId() { return _commandId; } /** * Sets a unique command identifier 'CommandId' for this `Command` object. * * @param commandId A unique command identifier to be associated with this * `Command`. * @return Returns This `Command` object with the specified identifier. * @since 4.0.0.0 */ public Command setCommandId(CommandId commandId) { _commandId = commandId; return this; } /** * Retrieve the query identifier associated with the 'Command' object. This * method is used to access the identifier set by the 'setQueryId' method when * needed. It allows you to read or obtain the QueryId for tracking, monitoring, * or correlating messages within the messaging system. * * @return The query identifier ('CommandId') previously set using the * 'setQueryId' method, or 'null' if not set. * @since 4.0.0.0 */ public CommandId getQueryId() { return _queryId; } /** * Set a custom QueryId for this Command. * The QueryId is a unique identifier that you can assign to this command. * You have the option to set this independently of the Command so customizing * the QueryId provides flexibility as you can assign QueryIds based on * application-specific logic. When the QueryId is independent of the Command in * AMPS, it means you are not bound by the CommandId for assigning QueryIds. * Instead, you have the freedom to create custom identifiers for queries and * messages, which can be valuable when you have scenarios when you need to * correlate responses from different types of queries based on shared * attributes other than the CommandId. * * @param queryId A unique query identifier to be associated with this * `Command`. * @return This `Command` object with the specified query identifier. * @since 4.0.0.0 */ public Command setQueryId(CommandId queryId) { _queryId = queryId; return this; } /** * Retrieves the command type associated with this `Command` object. * * @return The command type integer associated with this `Command`. * @since 4.0.0.0 */ public int getCommand() { return _command; } /** * Set the command type for this 'Command' object. * * @param command An integer representing the command type to be associated with * this `Command`. * @return This `Command` object with the specified command type. * @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 of Command. * @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, offset, and length. * * @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 of Command. * @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 of the Command. * @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 of Command. * @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; } /** * Sets the subId for this command using a string representation. * * @param subId The subId to set. * @return Returns this instance of Command. * @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 The current instance of Command. * @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 The current instance of Command. * @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 The current instance of Command. * @since 4.0.0.0 */ public Command setData(String data) { _dataString = data; _data = null; return this; } /** * Set the raw 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 The current instance of Command. * @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 The current instance of Command. */ public Command setData(CompositeMessageBuilder builder) { _dataString = null; _data = builder._bytes; _dataOffset = 0; _dataLength = builder._position; return this; } /** * Gets the timeout set on this command. * * @return The timeout value. * @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 The current instance of Command. * @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; } /** * Sets the top_n header for this command. This parameter sets a maximum number * of records returned by a SOW query. This should usually be set as part of the * command's options string, rather than using this method. * * @param topN The topN to set. * @return The current instance of Command. * @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 The current instance of Command. * @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 The current instance of Command. * @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 The current instance of Command. * @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 The current instance of Command. * @since 4.0.0.0 */ public Command setCorrelationId(String correlationId_) { _correlationId = correlationId_; return this; } /** * Gets the correlation Id set with this command. * * @return The correlation id. * @since 4.0.0.0 */ public String getCorrelationId() { return _correlationId; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy