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

com.vaadin.server.communication.ClientRpcWriter Maven / Gradle / Ivy

There is a newer version: 8.27.3
Show newest version
/*
 * Copyright (C) 2000-2024 Vaadin Ltd
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See  for the full
 * license.
 */

package com.vaadin.server.communication;

import java.io.IOException;
import java.io.Serializable;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.vaadin.server.ClientConnector;
import com.vaadin.server.ClientMethodInvocation;
import com.vaadin.server.EncodeResult;
import com.vaadin.server.JsonCodec;
import com.vaadin.server.PaintException;
import com.vaadin.shared.communication.ClientRpc;
import com.vaadin.ui.UI;

import elemental.json.Json;
import elemental.json.JsonArray;
import elemental.json.JsonException;
import elemental.json.JsonValue;
import elemental.json.impl.JsonUtil;

/**
 * Serializes {@link ClientRpc client RPC} invocations to JSON.
 *
 * @author Vaadin Ltd
 * @since 7.1
 */
public class ClientRpcWriter implements Serializable {

    /**
     * Writes a JSON object containing all pending client RPC invocations in the
     * given UI.
     *
     * @param ui
     *            The {@link UI} whose RPC calls to write.
     * @param writer
     *            The {@link Writer} used to write the JSON.
     * @throws IOException
     *             If the serialization fails.
     */
    public void write(UI ui, Writer writer) throws IOException {

        Collection pendingInvocations = collectPendingRpcCalls(
                ui.getConnectorTracker().getDirtyVisibleConnectors());

        JsonArray rpcCalls = Json.createArray();
        for (ClientMethodInvocation invocation : pendingInvocations) {
            // add invocation to rpcCalls
            try {
                JsonArray invocationJson = Json.createArray();
                invocationJson.set(0,
                        invocation.getConnector().getConnectorId());
                invocationJson.set(1, invocation.getInterfaceName());
                invocationJson.set(2, invocation.getMethodName());
                JsonArray paramJson = Json.createArray();
                for (int i = 0; i < invocation
                        .getParameterTypes().length; ++i) {
                    Type parameterType = invocation.getParameterTypes()[i];
                    JsonValue referenceParameter = null;
                    // TODO Use default values for RPC parameter types
                    // if (!JsonCodec.isInternalType(parameterType)) {
                    // try {
                    // referenceParameter = parameterType.newInstance();
                    // } catch (Exception e) {
                    // logger.log(Level.WARNING,
                    // "Error creating reference object for parameter of type "
                    // + parameterType.getName());
                    // }
                    // }
                    EncodeResult encodeResult = JsonCodec.encode(
                            invocation.getParameters()[i], referenceParameter,
                            parameterType, ui.getConnectorTracker());
                    paramJson.set(i, encodeResult.getEncodedValue());
                }
                invocationJson.set(3, paramJson);
                rpcCalls.set(rpcCalls.length(), invocationJson);
            } catch (JsonException e) {
                throw new PaintException(
                        "Failed to serialize RPC method call parameters for connector "
                                + invocation.getConnector().getConnectorId()
                                + " method " + invocation.getInterfaceName()
                                + "." + invocation.getMethodName() + ": "
                                + e.getMessage(),
                        e);
            }
        }
        writer.write(JsonUtil.stringify(rpcCalls));
    }

    /**
     * Collects all pending RPC calls from listed {@link ClientConnector}s and
     * clears their RPC queues.
     *
     * @param rpcPendingQueue
     *            list of {@link ClientConnector} of interest
     * @return ordered list of pending RPC calls
     */
    private Collection collectPendingRpcCalls(
            Collection rpcPendingQueue) {
        List pendingInvocations = new ArrayList<>();
        for (ClientConnector connector : rpcPendingQueue) {
            List paintablePendingRpc = connector
                    .retrievePendingRpcCalls();
            if (null != paintablePendingRpc && !paintablePendingRpc.isEmpty()) {
                List oldPendingRpc = pendingInvocations;
                int totalCalls = pendingInvocations.size()
                        + paintablePendingRpc.size();
                pendingInvocations = new ArrayList<>(totalCalls);

                // merge two ordered comparable lists
                for (int destIndex = 0, oldIndex = 0, paintableIndex = 0; destIndex < totalCalls; destIndex++) {
                    if (paintableIndex >= paintablePendingRpc.size()
                            || (oldIndex < oldPendingRpc.size() && oldPendingRpc
                                    .get(oldIndex).compareTo(paintablePendingRpc
                                            .get(paintableIndex)) <= 0)) {
                        pendingInvocations.add(oldPendingRpc.get(oldIndex++));
                    } else {
                        pendingInvocations
                                .add(paintablePendingRpc.get(paintableIndex++));
                    }
                }
            }
        }
        return pendingInvocations;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy