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 = Protocol.getCompatibleEncoding(_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;
}