ProxyIceInvoke.java

// Copyright (c) ZeroC, Inc.

package com.zeroc.Ice;

import java.time.Duration;
import java.util.Map;

class ProxyIceInvoke extends ProxyOutgoingAsyncBase<Object.Ice_invokeResult> {
    public ProxyIceInvoke(ObjectPrx prx, String operation, OperationMode mode, boolean synchronous) {
        super((_ObjectPrxI) prx, operation);
        _mode = mode == null ? OperationMode.Normal : mode;
        _synchronous = synchronous;
        _encoding = _proxy._getReference().getEncoding();
        _is = null;
    }

    public void invoke(byte[] inParams, Map<String, String> ctx) {
        try {
            prepare(ctx);
            writeParamEncaps(inParams);

            if (isBatch()) {
                // NOTE: we don't call sent/completed callbacks for batch AMI requests
                _sentSynchronously = true;
                _proxy._getReference().getBatchRequestQueue().finishBatchRequest(_os, _proxy, _operation);
                finished(true, false);
            } else {
                // invokeImpl can throw and we handle the exception with abort.
                invokeImpl(true); // userThread = true
            }
        } catch (LocalException ex) {
            abort(ex);
        }
    }

    public Object.Ice_invokeResult waitForResponse() {
        if (isBatch()) {
            // The future will not be completed for a batch invocation.
            return new Object.Ice_invokeResult(true, new byte[0]);
        }
        return super.waitForResponse();
    }

    @Override
    public boolean sent() {
        return sent(!_proxy.ice_isTwoway()); // done = true if not a two-way proxy (no response expected)
    }

    @Override
    public int invokeRemote(ConnectionI connection, boolean compress, boolean response)
        throws RetryException {
        _cachedConnection = connection;
        return connection.sendAsyncRequest(this, compress, response, 0);
    }

    @Override
    public int invokeCollocated(CollocatedRequestHandler handler) {
        // The stream cannot be cached if the proxy is not a twoway or there is an invocation timeout set.
        if (!_proxy.ice_isTwoway() || _proxy._getReference().getInvocationTimeout().compareTo(Duration.ZERO) > 0) {
            // Disable caching by marking the streams as cached!
            _state |= StateCachedBuffers;
        }
        return handler.invokeAsyncRequest(this, 0, _synchronous);
    }

    @Override
    public void abort(LocalException ex) {
        if (isBatch()) {
            // If we didn't finish a batch oneway or datagram request, we
            // must notify the connection about that we give up ownership of the batch stream.
            _proxy._getReference().getBatchRequestQueue().abortBatchRequest(_os);
        }

        super.abort(ex);
    }

    @Override
    protected void markCompleted() {
        if (!_proxy.ice_isTwoway()) {
            // For a non-twoway proxy, the invocation is completed after it is sent.
            complete(new Object.Ice_invokeResult(true, new byte[0]));
        } else {
            Object.Ice_invokeResult r = new Object.Ice_invokeResult();
            r.returnValue = (_state & StateOK) > 0;
            r.outParams = readParamEncaps();
            complete(r);
        }
    }

    @Override
    public final boolean completed(InputStream is) {
        // NOTE: this method is called from ConnectionI.parseMessage with the connection locked.
        // Therefore, it must not invoke any user callbacks.

        // _is can already be initialized if the invocation is retried
        if (_is == null) {
            _is = new InputStream(_instance, Protocol.currentProtocolEncoding, _instance.cacheMessageBuffers() > 1);
        }
        _is.swap(is);

        return super.completed(_is);
    }

    private void writeParamEncaps(byte[] encaps) {
        if (encaps == null || encaps.length == 0) {
            _os.writeEmptyEncapsulation(_encoding);
        } else {
            _os.writeEncapsulation(encaps);
        }
    }

    private byte[] readParamEncaps() {
        return _is.readEncapsulation(null);
    }

    private final EncodingVersion _encoding;
    private InputStream _is;

    // True if this AMI request is being used for a generated synchronous invocation.
    private final boolean _synchronous;
}