Search in sources :

Example 1 with PServiceCall

use of net.morimekta.providence.PServiceCall in project providence by morimekta.

the class FastBinarySerializer method deserialize.

@Nonnull
@Override
@SuppressWarnings("unchecked")
public <Message extends PMessage<Message, Field>, Field extends PField> PServiceCall<Message, Field> deserialize(@Nonnull InputStream is, @Nonnull PService service) throws SerializerException {
    String methodName = null;
    int sequence = 0;
    PServiceCallType type = null;
    try {
        LittleEndianBinaryReader in = new LittleEndianBinaryReader(is);
        // Max method name length: 255 chars.
        int tag = in.readIntVarint();
        int len = tag >>> 3;
        int typeKey = tag & 0x07;
        methodName = new String(in.expectBytes(len), UTF_8);
        sequence = in.readIntVarint();
        type = PServiceCallType.findById(typeKey);
        if (type == null) {
            throw new SerializerException("Invalid call type " + typeKey).setExceptionType(PApplicationExceptionType.INVALID_MESSAGE_TYPE);
        } else if (type == PServiceCallType.EXCEPTION) {
            PApplicationException ex = readMessage(in, PApplicationException.kDescriptor);
            return (PServiceCall<Message, Field>) new PServiceCall<>(methodName, type, sequence, ex);
        }
        PServiceMethod method = service.getMethod(methodName);
        if (method == null) {
            throw new SerializerException("No such method %s on %s", methodName, service.getQualifiedName()).setExceptionType(PApplicationExceptionType.UNKNOWN_METHOD);
        }
        @SuppressWarnings("unchecked") PMessageDescriptor<Message, Field> descriptor = isRequestCallType(type) ? method.getRequestType() : method.getResponseType();
        if (descriptor == null) {
            throw new SerializerException("No such %s descriptor for %s", isRequestCallType(type) ? "request" : "response", service.getQualifiedName()).setExceptionType(PApplicationExceptionType.UNKNOWN_METHOD);
        }
        Message message = readMessage(in, descriptor);
        return new PServiceCall<>(methodName, type, sequence, message);
    } catch (SerializerException e) {
        throw new SerializerException(e).setCallType(type).setMethodName(methodName).setSequenceNo(sequence);
    } catch (IOException e) {
        throw new SerializerException(e, e.getMessage()).setCallType(type).setMethodName(methodName).setSequenceNo(sequence);
    }
}
Also used : PMessage(net.morimekta.providence.PMessage) PServiceCallType(net.morimekta.providence.PServiceCallType) IOException(java.io.IOException) PField(net.morimekta.providence.descriptor.PField) PApplicationException(net.morimekta.providence.PApplicationException) PServiceCall(net.morimekta.providence.PServiceCall) LittleEndianBinaryReader(net.morimekta.util.io.LittleEndianBinaryReader) PServiceMethod(net.morimekta.providence.descriptor.PServiceMethod) Nonnull(javax.annotation.Nonnull)

Example 2 with PServiceCall

use of net.morimekta.providence.PServiceCall in project providence by morimekta.

the class JsonSerializer method parseServiceCall.

@SuppressWarnings("unchecked")
private <T extends PMessage<T, F>, F extends PField> PServiceCall<T, F> parseServiceCall(JsonTokenizer tokenizer, PService service) throws IOException {
    PServiceCallType type = null;
    String methodName = null;
    int sequence = 0;
    try {
        tokenizer.expectSymbol("service call start", JsonToken.kListStart);
        methodName = tokenizer.expectString("method name").rawJsonLiteral();
        tokenizer.expectSymbol("entry sep", JsonToken.kListSep);
        JsonToken callTypeToken = tokenizer.expect("call type");
        if (callTypeToken.isInteger()) {
            int typeKey = callTypeToken.byteValue();
            type = PServiceCallType.findById(typeKey);
            if (type == null) {
                throw new SerializerException("Service call type " + typeKey + " is not valid").setExceptionType(PApplicationExceptionType.INVALID_MESSAGE_TYPE);
            }
        } else if (callTypeToken.isLiteral()) {
            String typeName = callTypeToken.rawJsonLiteral();
            type = PServiceCallType.findByName(typeName.toUpperCase(Locale.US));
            if (type == null) {
                throw new SerializerException("Service call type \"" + Strings.escape(typeName) + "\" is not valid").setExceptionType(PApplicationExceptionType.INVALID_MESSAGE_TYPE);
            }
        } else {
            throw new SerializerException("Invalid service call type token " + callTypeToken.asString()).setExceptionType(PApplicationExceptionType.INVALID_MESSAGE_TYPE);
        }
        tokenizer.expectSymbol("entry sep", JsonToken.kListSep);
        sequence = tokenizer.expectNumber("Service call sequence").intValue();
        tokenizer.expectSymbol("entry sep", JsonToken.kListSep);
        if (type == PServiceCallType.EXCEPTION) {
            PApplicationException ex = (PApplicationException) parseTypedValue(tokenizer.expect("Message start"), tokenizer, PApplicationException.kDescriptor, false);
            tokenizer.expectSymbol("service call end", JsonToken.kListEnd);
            return (PServiceCall<T, F>) new PServiceCall<>(methodName, type, sequence, ex);
        }
        PServiceMethod method = service.getMethod(methodName);
        if (method == null) {
            throw new SerializerException("No such method " + methodName + " on " + service.getQualifiedName()).setExceptionType(PApplicationExceptionType.UNKNOWN_METHOD);
        }
        @SuppressWarnings("unchecked") PMessageDescriptor<T, F> descriptor = isRequestCallType(type) ? method.getRequestType() : method.getResponseType();
        if (descriptor == null) {
            throw new SerializerException("No %s type for %s.%s()", isRequestCallType(type) ? "request" : "response", service.getQualifiedName(), methodName).setExceptionType(PApplicationExceptionType.UNKNOWN_METHOD);
        }
        T message = (T) parseTypedValue(tokenizer.expect("message start"), tokenizer, descriptor, false);
        tokenizer.expectSymbol("service call end", JsonToken.kListEnd);
        return new PServiceCall<>(methodName, type, sequence, message);
    } catch (SerializerException se) {
        throw new SerializerException(se).setMethodName(methodName).setCallType(type).setSequenceNo(sequence);
    } catch (JsonException je) {
        throw new JsonSerializerException(je).setMethodName(methodName).setCallType(type).setSequenceNo(sequence);
    }
}
Also used : JsonException(net.morimekta.util.json.JsonException) PServiceCallType(net.morimekta.providence.PServiceCallType) PApplicationException(net.morimekta.providence.PApplicationException) PServiceCall(net.morimekta.providence.PServiceCall) JsonToken(net.morimekta.util.json.JsonToken) PServiceMethod(net.morimekta.providence.descriptor.PServiceMethod)

Example 3 with PServiceCall

use of net.morimekta.providence.PServiceCall in project providence by morimekta.

the class SerializerTest method setUpData.

@BeforeClass
public static void setUpData() throws IOException, ExceptionFields {
    MessageGenerator gen = new MessageGenerator().addFactory(f -> {
        if (f.equals(Operand._Field.OPERATION)) {
            return () -> Operation.builder().setOperator(Operator.ADD).addToOperands(Operand.withNumber(123)).addToOperands(Operand.withNumber(321)).build();
        }
        return null;
    });
    if (operation == null) {
        operation = gen.generate(Operation.kDescriptor);
    }
    if (containers == null) {
        containers = new ArrayList<>();
        for (int i = 0; i < 1; ++i) {
            containers.add(gen.generate(Containers.kDescriptor));
        }
    }
    serviceCalls = new ArrayList<>();
    /**
     * Temporary setup needed to generate
     */
    ContainerService.Iface impl = pC -> {
        if (pC == null) {
            throw new PApplicationException("", PApplicationExceptionType.INTERNAL_ERROR);
        }
        if (pC.mutate().presentFields().isEmpty()) {
            throw gen.generate(ExceptionFields.kDescriptor);
        }
        return CompactFields.builder().setName("" + pC.hashCode()).setId(pC.hashCode()).build();
    };
    PProcessor processor = new ContainerService.Processor(impl);
    PServiceCallHandler handler = new PServiceCallHandler() {

        @Nullable
        @Override
        @SuppressWarnings("unchecked")
        public <Request extends PMessage<Request, RequestField>, Response extends PMessage<Response, ResponseField>, RequestField extends PField, ResponseField extends PField> PServiceCall<Response, ResponseField> handleCall(PServiceCall<Request, RequestField> call, PService service) throws IOException {
            serviceCalls.add(call);
            try {
                PServiceCall response = processor.handleCall(call, service);
                serviceCalls.add(response);
                return response;
            } catch (PApplicationException e) {
                PServiceCall ex = new PServiceCall(call.getMethod(), PServiceCallType.EXCEPTION, call.getSequence(), e);
                serviceCalls.add(ex);
                return ex;
            }
        }
    };
    ContainerService.Client client = new ContainerService.Client(handler);
    client.load(gen.generate(Containers.kDescriptor));
    try {
        client.load(Containers.builder().build());
    } catch (ExceptionFields e) {
    // ignore.
    }
    try {
        // NPE -> PApplicationException
        client.load(null);
    } catch (PApplicationException e) {
    // ignore.
    }
}
Also used : Operand(net.morimekta.test.providence.core.calculator.Operand) CoreMatchers.is(org.hamcrest.CoreMatchers.is) BeforeClass(org.junit.BeforeClass) ByteArrayOutputStream(java.io.ByteArrayOutputStream) PApplicationException(net.morimekta.providence.PApplicationException) MessageCollectors(net.morimekta.providence.streams.MessageCollectors) EqualToMessage(net.morimekta.providence.util_internal.EqualToMessage) Binary(net.morimekta.util.Binary) PServiceCallType(net.morimekta.providence.PServiceCallType) ArrayList(java.util.ArrayList) Assert.assertThat(org.junit.Assert.assertThat) PService(net.morimekta.providence.descriptor.PService) Containers(net.morimekta.test.providence.core.Containers) PProcessor(net.morimekta.providence.PProcessor) ByteArrayInputStream(java.io.ByteArrayInputStream) PApplicationExceptionType(net.morimekta.providence.PApplicationExceptionType) MessageGenerator(net.morimekta.providence.util_internal.MessageGenerator) Assert.fail(org.junit.Assert.fail) Nullable(javax.annotation.Nullable) ExtraMatchers.equalToLines(net.morimekta.testing.ExtraMatchers.equalToLines) Operation(net.morimekta.test.providence.core.calculator.Operation) UTF_8(java.nio.charset.StandardCharsets.UTF_8) PServiceCallHandler(net.morimekta.providence.PServiceCallHandler) Test(org.junit.Test) IOException(java.io.IOException) MessageStreams(net.morimekta.providence.streams.MessageStreams) ContainerService(net.morimekta.test.providence.core.ContainerService) Collectors(java.util.stream.Collectors) File(java.io.File) PMessage(net.morimekta.providence.PMessage) PField(net.morimekta.providence.descriptor.PField) CompactFields(net.morimekta.test.providence.core.CompactFields) List(java.util.List) Rule(org.junit.Rule) PServiceCall(net.morimekta.providence.PServiceCall) ExceptionFields(net.morimekta.test.providence.core.ExceptionFields) TokenizerException(net.morimekta.providence.serializer.pretty.TokenizerException) ConsumeAll(net.morimekta.test.providence.core.ConsumeAll) Assert.assertEquals(org.junit.Assert.assertEquals) Operator(net.morimekta.test.providence.core.calculator.Operator) InputStream(java.io.InputStream) PProcessor(net.morimekta.providence.PProcessor) MessageGenerator(net.morimekta.providence.util_internal.MessageGenerator) PField(net.morimekta.providence.descriptor.PField) PProcessor(net.morimekta.providence.PProcessor) ExceptionFields(net.morimekta.test.providence.core.ExceptionFields) PServiceCallHandler(net.morimekta.providence.PServiceCallHandler) PMessage(net.morimekta.providence.PMessage) PApplicationException(net.morimekta.providence.PApplicationException) PServiceCall(net.morimekta.providence.PServiceCall) ContainerService(net.morimekta.test.providence.core.ContainerService) PService(net.morimekta.providence.descriptor.PService) BeforeClass(org.junit.BeforeClass)

Example 4 with PServiceCall

use of net.morimekta.providence.PServiceCall in project providence by morimekta.

the class NonblockingSocketClientHandler method handleReadResponses.

private void handleReadResponses(SocketChannel channel, PService service) {
    while (this.channel == channel && channel.isOpen()) {
        FramedBufferInputStream in = new FramedBufferInputStream(channel);
        try {
            in.nextFrame();
            PServiceCall reply = serializer.deserialize(in, service);
            if (reply.getType() == PServiceCallType.CALL || reply.getType() == PServiceCallType.ONEWAY) {
                throw new PApplicationException("Reply with invalid call type: " + reply.getType(), PApplicationExceptionType.INVALID_MESSAGE_TYPE);
            }
            CompletableFuture<PServiceCall> future = responseFutures.get(reply.getSequence());
            if (future == null) {
                // The item response timed out.
                LOGGER.debug("No future for sequence ID " + reply.getSequence());
                continue;
            }
            responseFutures.remove(reply.getSequence());
            future.complete(reply);
        } catch (Exception e) {
            if (!channel.isOpen()) {
                // If the channel is closed. Should not trigger on disconnected.
                break;
            }
            LOGGER.error("Exception in channel response reading", e);
        }
    }
    if (responseFutures.size() > 0) {
        LOGGER.warn("Channel closed with {} unfinished calls", responseFutures.size());
        responseFutures.forEach((s, f) -> f.completeExceptionally(new IOException("Channel closed")));
        responseFutures.clear();
    }
}
Also used : PServiceCall(net.morimekta.providence.PServiceCall) PApplicationException(net.morimekta.providence.PApplicationException) FramedBufferInputStream(net.morimekta.providence.thrift.io.FramedBufferInputStream) IOException(java.io.IOException) PApplicationException(net.morimekta.providence.PApplicationException) TimeoutException(java.util.concurrent.TimeoutException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException)

Example 5 with PServiceCall

use of net.morimekta.providence.PServiceCall in project providence by morimekta.

the class NonblockingSocketServer method handleRead.

@SuppressWarnings("unchecked")
private void handleRead(SelectionKey key, Context context) throws IOException {
    long startTime = System.nanoTime();
    // part a: read into the readBuffer.
    if (context.currentFrameSize == 0) {
        // read frame size.
        try {
            if (context.channel.read(context.sizeBuffer) < 0) {
                context.close();
                key.cancel();
                return;
            }
            if (context.sizeBuffer.position() < 4) {
                return;
            }
        } catch (IOException e) {
            // LOGGER.error(e.getMessage(), e);
            context.close();
            key.cancel();
            return;
        }
        context.sizeBuffer.flip();
        try (ByteBufferInputStream in = new ByteBufferInputStream(context.sizeBuffer);
            BigEndianBinaryReader reader = new BigEndianBinaryReader(in)) {
            context.currentFrameSize = reader.expectInt();
        }
        context.sizeBuffer.rewind();
        if (context.currentFrameSize > maxFrameSizeInBytes) {
            LOGGER.warn("Attempting message of " + context.currentFrameSize + " > " + maxFrameSizeInBytes);
            context.close();
            key.cancel();
            return;
        }
        if (context.currentFrameSize < 1) {
            LOGGER.warn("Attempting message of " + context.currentFrameSize);
            context.close();
            key.cancel();
            return;
        }
        context.readBuffer.rewind();
        context.readBuffer.limit(context.currentFrameSize);
    }
    try {
        if (context.channel.read(context.readBuffer) < 0) {
            LOGGER.warn("Closed connection while reading frame");
            context.close();
            key.cancel();
            return;
        }
    } catch (IOException e) {
        LOGGER.warn("Exception reading frame: {}", e.getMessage(), e);
        context.close();
        key.cancel();
        return;
    }
    if (context.readBuffer.position() < context.readBuffer.limit()) {
        // wait until next read, and see if remaining of frame has arrived.
        return;
    }
    // part b: if the read buffer is complete, handle the content.
    PServiceCall call;
    try {
        context.currentFrameSize = 0;
        context.readBuffer.flip();
        call = serializer.deserialize(new ByteBufferInputStream(context.readBuffer), processor.getDescriptor());
        context.readBuffer.clear();
        workerExecutor.submit(() -> {
            PServiceCall reply;
            try {
                reply = processor.handleCall(call);
            } catch (Exception e) {
                reply = new PServiceCall<>(call.getMethod(), PServiceCallType.EXCEPTION, call.getSequence(), PApplicationException.builder().setMessage(e.getMessage()).setId(PApplicationExceptionType.INTERNAL_ERROR).initCause(e).build());
            }
            synchronized (context.writeQueue) {
                context.writeQueue.offer(new WriteEntry(startTime, call, reply));
                key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
                selector.wakeup();
            }
        });
    } catch (IOException e) {
        double duration = ((double) System.nanoTime() - startTime) / NS_IN_MILLIS;
        instrumentation.onTransportException(e, duration, null, null);
    }
}
Also used : PServiceCall(net.morimekta.providence.PServiceCall) ByteBufferInputStream(net.morimekta.util.io.ByteBufferInputStream) BigEndianBinaryReader(net.morimekta.util.io.BigEndianBinaryReader) IOException(java.io.IOException) UncheckedIOException(java.io.UncheckedIOException) PApplicationException(net.morimekta.providence.PApplicationException) IOException(java.io.IOException) UncheckedIOException(java.io.UncheckedIOException)

Aggregations

PServiceCall (net.morimekta.providence.PServiceCall)19 IOException (java.io.IOException)13 PApplicationException (net.morimekta.providence.PApplicationException)12 PServiceCallType (net.morimekta.providence.PServiceCallType)7 PServiceMethod (net.morimekta.providence.descriptor.PServiceMethod)7 Nonnull (javax.annotation.Nonnull)6 PMessage (net.morimekta.providence.PMessage)6 SerializerException (net.morimekta.providence.serializer.SerializerException)6 UncheckedIOException (java.io.UncheckedIOException)5 PField (net.morimekta.providence.descriptor.PField)5 Test (org.junit.Test)5 PProcessor (net.morimekta.providence.PProcessor)4 PService (net.morimekta.providence.descriptor.PService)4 ByteArrayOutputStream (java.io.ByteArrayOutputStream)3 AtomicReference (java.util.concurrent.atomic.AtomicReference)3 ExecutionException (java.util.concurrent.ExecutionException)2 ExecutorService (java.util.concurrent.ExecutorService)2 TimeoutException (java.util.concurrent.TimeoutException)2 Nullable (javax.annotation.Nullable)2 PServiceCallHandler (net.morimekta.providence.PServiceCallHandler)2