require_relative 'abstract/abstract_invocation_context' require_relative '../../core/interpreter/interpreter' require_relative '../../core/exceptions/exception_thrower' require_relative 'invocation_context_iterator' # InvocationContext is a class that represents a context for invoking commands. # It implements several interfaces for different types of interactions. # This class is used to construct chains of invocations, representing expressions of interaction that have not yet been executed. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/foundations/invocation-context article on Javonet Guides} class InvocationContext < AbstractInvocationContext include Enumerable def initialize(runtime_name, connection_type, tcp_ip_address, command, is_executed = false) @is_executed = is_executed @runtime_name = runtime_name @connection_type = connection_type @tcp_ip_address = tcp_ip_address @current_command = command @response_command = nil @interpreter = Interpreter.new # generates error: ruby/lib/javonet-ruby-sdk/sdk/internal/invocation_context.rb:17: warning: finalizer references object to be finalized #ObjectSpace.define_finalizer(self, self.finalize(@current_command, @is_executed, @interpreter, @connection_type, @tcp_ip_address)) end def finalize(command, is_executed, interpreter, connection_type, tcp_ip_address) proc do if command.command_type == CommandType::REFERENCE && is_executed == true destruct_command = Command.new(@runtime_name, CommandType::DESTRUCT_REFERENCE, command.payload) interpreter.execute(destruct_command, connection_type, tcp_ip_address) end end end def iterator if not [CommandType::REFERENCE, CommandType::ARRAY_GET_ITEM, CommandType::ARRAY_SET_ITEM].include? @current_command.command_type raise "Object is not iterable" else InvocationContextIterator.new(self) end end def [](i) if not [CommandType::REFERENCE, CommandType::ARRAY_GET_ITEM].include? @current_command.command_type raise "Object is not iterable" else invocation_context_iterator = InvocationContextIterator.new(self) invocation_context_iterator[i] end end def []=(i, value) if not [CommandType::REFERENCE, CommandType::ARRAY_SET_ITEM, CommandType::ARRAY_GET_ITEM].include? @current_command.command_type raise "Object is not iterable" else invocation_context_iterator = InvocationContextIterator.new(self) invocation_context_iterator[i] = value end end # Executes the current command. # Because invocation context is building the intent of executing particular expression on target environment, we call the initial state of invocation context as non-materialized. # The non-materialized context wraps either single command or chain of recursively nested commands. # Commands are becoming nested through each invocation of methods on Invocation Context. # Each invocation triggers the creation of new Invocation Context instance wrapping the current command with new parent command valid for invoked method. # Developer can decide on any moment of the materialization for the context taking full control of the chunks of the expression being transferred and processed on target runtime. # @return [InvocationContext] the InvocationContext after executing the command. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/foundations/execute-method article on Javonet Guides} def execute @response_command = @interpreter.execute(@current_command, @connection_type, @tcp_ip_address) if @response_command.command_type == CommandType::EXCEPTION raise ExceptionThrower.throw_exception(@response_command) end if @response_command.command_type == CommandType::CREATE_CLASS_INSTANCE @current_command = @response_command @is_executed = true return self end InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, @response_command, true) end # Invokes a static method on the target runtime. # @param method_name [String] The name of the static method to invoke. # @param args [Array] The arguments to pass to the static method. # @return [InvocationContext] A new InvocationContext instance that wraps the command to invoke the static method. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/calling-methods/invoking-static-method article on Javonet Guides} def invoke_static_method(method_name, *args) local_command = Command.new(@runtime_name, CommandType::INVOKE_STATIC_METHOD, [method_name, *args]) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Invokes an instance method on the target runtime. # @param method_name [String] The name of the instance method to invoke. # @param args [Array] The arguments to pass to the instance method. # @return [InvocationContext] A new InvocationContext instance that wraps the command to invoke the instance method. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/calling-methods/creating-instance-and-calling-instance-methods article on Javonet Guides} def invoke_instance_method(method_name, *args) local_command = Command.new(@runtime_name, CommandType::INVOKE_INSTANCE_METHOD, [method_name, *args]) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Creates a new instance of a class in the target runtime. # @param args [Array] The arguments to class constructor # @return [InvocationContext] A new InvocationContext instance that wraps the command to create the instance. # @see https://www.javonet.com/guides/v2/ruby/calling-methods/creating-instance-and-calling-instance-methods def create_instance(*args) local_command = Command.new(@runtime_name, CommandType::CREATE_CLASS_INSTANCE, [*args]) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Retrieves the value of a static field from the target runtime. # @param field_name [String] The name of the static field to get. # @return [InvocationContext] A new InvocationContext instance that wraps the command to get the static field. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/fields-and-properties/getting-and-setting-values-for-static-fields-and-properties article on Javonet Guides} def get_static_field(field_name) local_command = Command.new(@runtime_name, CommandType::GET_STATIC_FIELD, [field_name]) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Sets the value of a static field in the target runtime. # @param field_name [String] The name of the static field to set. # @param value [Object] The new value of the static field. # @return [InvocationContext] A new InvocationContext instance that wraps the command to set the static field. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/fields-and-properties/getting-and-setting-values-for-static-fields-and-properties article on Javonet Guides} def set_static_field(field_name, value) local_command = Command.new(@runtime_name, CommandType::SET_STATIC_FIELD, [field_name, value]) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Retrieves the value of an instance field from the target runtime. # @param field_name [String] The name of the instance field to get. # @return [InvocationContext] A new InvocationContext instance that wraps the command to get the instance field. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/fields-and-properties/getting-and-setting-values-for-instance-fields-and-properties article on Javonet Guides} def get_instance_field(field_name) local_command = Command.new(@runtime_name, CommandType::GET_INSTANCE_FIELD, [field_name]) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Sets the value of an instance field in the target runtime. # @param field_name [String] The name of the instance field to set. # @param value [Object] The new value of the instance field. # @return [InvocationContext] A new InvocationContext instance that wraps the command to set the instance field. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/fields-and-properties/getting-and-setting-values-for-instance-fields-and-properties article on Javonet Guides} def set_instance_field(field_name, value) local_command = Command.new(@runtime_name, CommandType::SET_INSTANCE_FIELD, [field_name, value]) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Retrieves the value at a specific indexes in an array from the target runtime. # @param indexes [Array] The indexes to pass to the get index command. # @return [InvocationContext] A new InvocationContext instance that wraps the command to get the index. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/arrays-and-collections/one-dimensional-arrays article on Javonet Guides} def get_index(*indexes) local_command = Command.new(@runtime_name, CommandType::ARRAY_GET_ITEM, [*indexes]) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Sets the value at a specific index in an array in the target runtime. # @param indexes [Array] The indexes where new value should be set # @param value [Object] The new value to set at the indexes. # @return [InvocationContext] A new InvocationContext instance that wraps the command to set the index. # @see https://www.javonet.com/guides/v2/ruby/arrays-and-collections/one-dimensional-arrays Setting Array Element Guide def set_index(indexes, value) local_command = Command.new(@runtime_name, CommandType::ARRAY_SET_ITEM, [indexes, value]) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Retrieves the number of elements from the target runtime. # @return [InvocationContext] A new InvocationContext instance that wraps the command to get the size. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/arrays-and-collections/one-dimensional-arrays article on Javonet Guides} def get_size local_command = Command.new(@runtime_name, CommandType::ARRAY_GET_SIZE, []) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Retrieves the rank of an array from the target runtime. # @return [InvocationContext] A new InvocationContext instance that wraps the command to get the rank. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/arrays-and-collections/multidimensional-arrays article on Javonet Guides} def get_rank local_command = Command.new(@runtime_name, CommandType::ARRAY_GET_RANK, []) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Invokes a generic static method on the target runtime. # @param method_name [String] The name of the generic static method to invoke. # @param args [Array] The arguments to pass to the generic static method. # @return [InvocationContext] A new InvocationContext instance that wraps the command to invoke the generic static method. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/generics/calling-generic-static-method article on Javonet Guides} def invoke_generic_static_method(method_name, *args) local_command = Command.new(@runtime_name, CommandType::INVOKE_GENERIC_STATIC_METHOD, [method_name, *args]) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Invokes a generic method on the target runtime. # @param method_name [String] The name of the generic method to invoke. # @param args [Array] The arguments to pass to the generic method. # @return [InvocationContext] A new InvocationContext instance that wraps the command to invoke the generic method. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/generics/calling-generic-instance-method article on Javonet Guides} def invoke_generic_method(method_name, *args) local_command = Command.new(@runtime_name, CommandType::INVOKE_GENERIC_METHOD, [method_name, *args]) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Retrieves the name of an enum from the target runtime. # @return [InvocationContext] A new InvocationContext instance that wraps the command to get the enum name. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/enums/using-enum-type article on Javonet Guides} def get_enum_name local_command = Command.new(@runtime_name, CommandType::GET_ENUM_NAME, []) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Retrieves the value of an enum from the target runtime. # @return [InvocationContext] A new InvocationContext instance that wraps the command to get the enum value. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/enums/using-enum-type article on Javonet Guides} def get_enum_value local_command = Command.new(@runtime_name, CommandType::GET_ENUM_VALUE, []) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Retrieves the value of a reference from the target runtime. # @return [InvocationContext] A new InvocationContext instance that wraps the command to get the ref value. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/methods-arguments/passing-arguments-by-reference-with-ref-keyword article on Javonet Guides} def get_ref_value local_command = Command.new(@runtime_name, CommandType::GET_REF_VALUE, []) InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) end # Retrieves an array from the target runtime. # @return [Object] A new InvocationContext instance that wraps the command to retrieve the array. # @see Refer to this {https://www.javonet.com/guides/v2/ruby/arrays-and-collections/one-dimensional-arrays article on Javonet Guides} def retrieve_array local_command = Command.new(@runtime_name, CommandType::RETRIEVE_ARRAY, []) local_inv_ctx = InvocationContext.new(@runtime_name, @connection_type, @tcp_ip_address, build_command(local_command)) local_inv_ctx.execute local_inv_ctx.response_command.payload end # Retrieves the value of the current command from the target runtime. # @return [Object] The value of the current command. # @see https://www.javonet.com/guides/v2/ruby/foundations/execute-method Getting Command Value Guide def get_value @current_command.payload[0] end def build_command(command) command.payload.each_index { |i| command.payload[i] = encapsulate_payload_item(command.payload[i]) } command.prepend_arg_to_payload(@current_command) end def encapsulate_payload_item(payload_item) if payload_item.is_a? Command payload_item.payload.each_index { |i| payload_item.payload[i] = encapsulate_payload_item(payload_item.payload[i]) } return payload_item elsif payload_item.is_a? InvocationContext return payload_item.current_command elsif payload_item.is_a? Array payload_item.each_index { |i| payload_item[i] = encapsulate_payload_item(payload_item[i]) } return Command.new(@runtime_name, CommandType::ARRAY, [*payload_item]) else return Command.new(@runtime_name, CommandType::VALUE, [*payload_item]) end end def current_command @current_command end def response_command @response_command end end