Search in sources :

Example 1 with InvalidResponseException

use of io.smallrye.graphql.client.InvalidResponseException in project smallrye-graphql by smallrye.

the class GraphQLTransportWSSubprotocolHandler method initialize.

private Uni<Void> initialize() {
    return Uni.createFrom().emitter(initializationEmitter -> {
        if (log.isTraceEnabled()) {
            log.trace("Initializing websocket with graphql-transport-ws protocol");
        }
        connectionInitMessage = Json.createObjectBuilder().add("type", "connection_init").build();
        pongMessage = Json.createObjectBuilder().add("type", "pong").add("payload", Json.createObjectBuilder().add("message", "keepalive")).build();
        webSocket.closeHandler((v) -> {
            onClose.run();
            if (webSocket.closeStatusCode() != null) {
                if (webSocket.closeStatusCode() == 1000) {
                    log.debug("WebSocket closed with status code 1000");
                    // even if the status code is OK, any unfinished single-result operation
                    // should be marked as failed
                    uniOperations.forEach((id, emitter) -> emitter.fail(new InvalidResponseException("Connection closed before data was received")));
                    multiOperations.forEach((id, emitter) -> emitter.complete());
                } else {
                    InvalidResponseException exception = new InvalidResponseException("Server closed the websocket connection with code: " + webSocket.closeStatusCode() + " and reason: " + webSocket.closeReason());
                    uniOperations.forEach((id, emitter) -> emitter.fail(exception));
                    multiOperations.forEach((id, emitter) -> emitter.fail(exception));
                }
            } else {
                InvalidResponseException exception = new InvalidResponseException("Connection closed");
                uniOperations.forEach((id, emitter) -> emitter.fail(exception));
                multiOperations.forEach((id, emitter) -> emitter.fail(exception));
            }
        });
        webSocket.exceptionHandler(this::failAllActiveOperationsWith);
        send(webSocket, connectionInitMessage);
        // set up a timeout for subscription initialization
        Cancellable timeoutWaitingForConnectionAckMessage = null;
        if (connectionInitializationTimeout != null) {
            timeoutWaitingForConnectionAckMessage = Uni.createFrom().item(1).onItem().delayIt().by(Duration.ofMillis(connectionInitializationTimeout)).subscribe().with(timeout -> {
                initializationEmitter.fail(new InvalidResponseException("Server did not send a connection_ack message"));
                webSocket.close((short) 1002, "Timeout waiting for a connection_ack message");
            });
        }
        // make an effectively final copy of this value to use it in a lambda expression
        Cancellable finalTimeoutWaitingForConnectionAckMessage = timeoutWaitingForConnectionAckMessage;
        webSocket.handler(text -> {
            if (log.isTraceEnabled()) {
                log.trace("<<< " + text);
            }
            try {
                JsonObject message = parseIncomingMessage(text.toString());
                MessageType messageType = getMessageType(message);
                switch(messageType) {
                    case PING:
                        send(webSocket, pongMessage);
                        break;
                    case CONNECTION_ACK:
                        // TODO: somehow protect against this being invoked multiple times?
                        if (finalTimeoutWaitingForConnectionAckMessage != null) {
                            finalTimeoutWaitingForConnectionAckMessage.cancel();
                        }
                        initializationEmitter.complete(null);
                        break;
                    case NEXT:
                        handleData(message.getString("id"), message.getJsonObject("payload"));
                        break;
                    case ERROR:
                        handleOperationError(message.getString("id"), message.getJsonArray("payload"));
                        break;
                    case COMPLETE:
                        handleComplete(message.getString("id"));
                        break;
                    case CONNECTION_INIT:
                    case PONG:
                    case SUBSCRIBE:
                        break;
                }
            } catch (JsonParsingException | IllegalArgumentException e) {
                log.error("Unexpected message from server: " + text);
            // should we fail the operations here?
            }
        });
    });
}
Also used : WebSocketSubprotocolHandler(io.smallrye.graphql.client.vertx.websocket.WebSocketSubprotocolHandler) Logger(org.jboss.logging.Logger) CompletableFuture(java.util.concurrent.CompletableFuture) Uni(io.smallrye.mutiny.Uni) JsonValue(javax.json.JsonValue) ResponseReader(io.smallrye.graphql.client.impl.ResponseReader) OperationIDGenerator(io.smallrye.graphql.client.vertx.websocket.opid.OperationIDGenerator) Duration(java.time.Duration) Map(java.util.Map) Json(javax.json.Json) InvalidResponseException(io.smallrye.graphql.client.InvalidResponseException) JsonObject(javax.json.JsonObject) GraphQLClientException(io.smallrye.graphql.client.GraphQLClientException) MultiEmitter(io.smallrye.mutiny.subscription.MultiEmitter) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) JsonArray(javax.json.JsonArray) UniEmitter(io.smallrye.mutiny.subscription.UniEmitter) WebSocket(io.vertx.core.http.WebSocket) Collectors(java.util.stream.Collectors) JsonString(javax.json.JsonString) IncrementingNumberOperationIDGenerator(io.smallrye.graphql.client.vertx.websocket.opid.IncrementingNumberOperationIDGenerator) List(java.util.List) StringReader(java.io.StringReader) GraphQLError(io.smallrye.graphql.client.GraphQLError) Cancellable(io.smallrye.mutiny.subscription.Cancellable) JsonParsingException(javax.json.stream.JsonParsingException) JsonObjectBuilder(javax.json.JsonObjectBuilder) Cancellable(io.smallrye.mutiny.subscription.Cancellable) JsonObject(javax.json.JsonObject) InvalidResponseException(io.smallrye.graphql.client.InvalidResponseException) JsonParsingException(javax.json.stream.JsonParsingException)

Example 2 with InvalidResponseException

use of io.smallrye.graphql.client.InvalidResponseException in project smallrye-graphql by smallrye.

the class GraphQLWSSubprotocolHandler method handleComplete.

private void handleComplete(String operationId) {
    UniEmitter<? super String> emitter = uniOperations.remove(operationId);
    if (emitter != null) {
        // For a uni operation, we should have received a 'next' message before the 'complete' message.
        // If that happened, the emitter was already completed and operation removed from the map.
        // If that didn't happen, then this is an issue with the server, let's fail the operation then.
        emitter.fail(new InvalidResponseException("Protocol error: received a 'complete' message for" + " this operation before the actual data"));
    } else {
        MultiEmitter<? super String> multiEmitter = multiOperations.remove(operationId);
        if (multiEmitter != null) {
            log.debug("Completed operation " + operationId);
            multiEmitter.complete();
        }
    }
}
Also used : InvalidResponseException(io.smallrye.graphql.client.InvalidResponseException)

Example 3 with InvalidResponseException

use of io.smallrye.graphql.client.InvalidResponseException in project smallrye-graphql by smallrye.

the class JsonStringReader method formattedNumber.

private Number formattedNumber(String input) {
    String locale = null;
    String format = null;
    JsonbNumberFormat jsonbNumberFormat = field.getAnnotation(JsonbNumberFormat.class);
    if (jsonbNumberFormat != null) {
        locale = jsonbNumberFormat.locale();
        format = jsonbNumberFormat.value();
    }
    NumberFormat numberFormat = field.getAnnotation(NumberFormat.class);
    if (numberFormat != null) {
        locale = numberFormat.locale();
        format = numberFormat.value();
    }
    java.text.NumberFormat nf;
    if (format != null && !format.isEmpty()) {
        nf = new DecimalFormat(format);
    } else if (locale != null && !locale.isEmpty()) {
        nf = java.text.NumberFormat.getInstance(Locale.forLanguageTag(locale));
    } else {
        nf = new DecimalFormat();
    }
    try {
        return nf.parse(input);
    } catch (ParseException e) {
        throw new InvalidResponseException("Can't parse number", e);
    }
}
Also used : JsonbNumberFormat(javax.json.bind.annotation.JsonbNumberFormat) DecimalFormat(java.text.DecimalFormat) JsonString(javax.json.JsonString) ParseException(java.text.ParseException) InvalidResponseException(io.smallrye.graphql.client.InvalidResponseException) NumberFormat(org.eclipse.microprofile.graphql.NumberFormat) JsonbNumberFormat(javax.json.bind.annotation.JsonbNumberFormat)

Example 4 with InvalidResponseException

use of io.smallrye.graphql.client.InvalidResponseException in project smallrye-graphql by smallrye.

the class NestedBehavior method shouldFailToCallWrappedInvalidByteQuery.

@Test
void shouldFailToCallWrappedInvalidByteQuery() {
    fixture.returnsData("'container':{'code':{'value':1000},'count':3}");
    WrappedByteApi api = fixture.build(WrappedByteApi.class);
    InvalidResponseException thrown = catchThrowableOfType(api::container, InvalidResponseException.class);
    then(thrown).hasMessage("invalid java.lang.Byte value for " + WrappedByteApi.class.getName() + "#container.code.value: 1000");
}
Also used : InvalidResponseException(io.smallrye.graphql.client.InvalidResponseException) Test(org.junit.jupiter.api.Test)

Example 5 with InvalidResponseException

use of io.smallrye.graphql.client.InvalidResponseException in project smallrye-graphql by smallrye.

the class NestedBehavior method shouldFailToSetMissingNonNullField.

@Test
void shouldFailToSetMissingNonNullField() {
    fixture.returnsData("'call':{'foo':'a'}");
    MissingNonNullFieldApi api = fixture.build(MissingNonNullFieldApi.class);
    InvalidResponseException thrown = catchThrowableOfType(api::call, InvalidResponseException.class);
    then(thrown).hasMessage("missing java.lang.String value for " + MissingNonNullFieldApi.class.getName() + "#call.bar");
}
Also used : InvalidResponseException(io.smallrye.graphql.client.InvalidResponseException) Test(org.junit.jupiter.api.Test)

Aggregations

InvalidResponseException (io.smallrye.graphql.client.InvalidResponseException)25 Test (org.junit.jupiter.api.Test)15 WebSocketSubprotocolHandler (io.smallrye.graphql.client.vertx.websocket.WebSocketSubprotocolHandler)4 JsonObject (javax.json.JsonObject)4 JsonValue (javax.json.JsonValue)4 Map (java.util.Map)3 JsonString (javax.json.JsonString)3 GraphQLClientException (io.smallrye.graphql.client.GraphQLClientException)2 GraphQLError (io.smallrye.graphql.client.GraphQLError)2 ResponseReader (io.smallrye.graphql.client.impl.ResponseReader)2 ResultBuilder (io.smallrye.graphql.client.impl.typesafe.ResultBuilder)2 IncrementingNumberOperationIDGenerator (io.smallrye.graphql.client.vertx.websocket.opid.IncrementingNumberOperationIDGenerator)2 OperationIDGenerator (io.smallrye.graphql.client.vertx.websocket.opid.OperationIDGenerator)2 Uni (io.smallrye.mutiny.Uni)2 Cancellable (io.smallrye.mutiny.subscription.Cancellable)2 MultiEmitter (io.smallrye.mutiny.subscription.MultiEmitter)2 UniEmitter (io.smallrye.mutiny.subscription.UniEmitter)2 WebSocket (io.vertx.core.http.WebSocket)2 StringReader (java.io.StringReader)2 Duration (java.time.Duration)2