use of net.morimekta.providence.PServiceCall in project providence by morimekta.
the class QueuedFileMessageWriterTest method testAFewWrites_serviceCalls.
@Test
@SuppressWarnings("unchecked")
public void testAFewWrites_serviceCalls() throws IOException, InterruptedException {
setDefaultPollDelay(new Duration(10, TimeUnit.MILLISECONDS));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOMessageWriter target = new IOMessageWriter(baos, new BinarySerializer());
QueuedMessageWriter writer = new QueuedMessageWriter(target);
ExecutorService executorService = Executors.newFixedThreadPool(11);
for (int i = 0; i < 10; ++i) {
executorService.submit(() -> {
MessageGenerator generator = new MessageGenerator();
for (int j = 0; j < 10; ++j) {
try {
if (j > 0)
sleep(1L);
PServiceCall tmp = new PServiceCall("test", PServiceCallType.CALL, j, generator.generate(CompactFields.kDescriptor));
writer.write(tmp);
} catch (IOException e) {
throw new UncheckedIOException(e.getMessage(), e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
}
sleep(10L);
executorService.shutdown();
assertTrue(executorService.awaitTermination(10, TimeUnit.SECONDS));
sleep(1L);
writer.close();
}
use of net.morimekta.providence.PServiceCall in project providence by morimekta.
the class BinarySerializerTest method testService.
@Test
public void testService() throws IOException, CalculateException {
PServiceCall call = decode("[\"calculate\", \"call\", 44, {\"1\": {\"1\": 2}}]".getBytes(UTF_8), json);
PServiceCall result = decode(encode(call, unversioned), lenient);
assertThat(result, is(call));
result = decode(encode(call, strict), strict);
assertThat(result, is(call));
}
use of net.morimekta.providence.PServiceCall in project providence by morimekta.
the class WrappedProcessorTest method testWrapper.
@Test
public void testWrapper() throws IOException {
PProcessor processor = mock(PProcessor.class);
WrappedProcessor wrap = new WrappedProcessor(processor, (call, p) -> {
// before call
PServiceCall reply = p.handleCall(call, p.getDescriptor());
// after call
return reply;
});
PApplicationException c = new PApplicationException("call", PApplicationExceptionType.INTERNAL_ERROR);
PApplicationException r = new PApplicationException("call", PApplicationExceptionType.INTERNAL_ERROR);
AtomicReference<PService> service = new AtomicReference<>();
service.set(new PService("test", "Service", service::get, new PServiceMethod[] {}) {
@Nullable
@Override
public PServiceMethod getMethod(String name) {
for (PServiceMethod method : getMethods()) {
if (method.getName().equals(name)) {
return method;
}
}
return null;
}
});
PServiceCall call = new PServiceCall<>("test", PServiceCallType.CALL, 44, c);
PServiceCall reply = new PServiceCall<>("reply", PServiceCallType.REPLY, 44, r);
when(processor.getDescriptor()).thenReturn(service.get());
when(processor.handleCall(call, service.get())).thenReturn(reply);
assertThat(wrap.handleCall(call), sameInstance(reply));
verify(processor, atLeastOnce()).getDescriptor();
verify(processor).handleCall(call, service.get());
verifyNoMoreInteractions(processor);
}
use of net.morimekta.providence.PServiceCall in project providence by morimekta.
the class BinarySerializer 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 IOException {
BigEndianBinaryReader in = new BigEndianBinaryReader(is);
String methodName = null;
int sequence = 0;
PServiceCallType type = null;
try {
int methodNameLen = in.expectInt();
int typeKey;
// versioned
if (methodNameLen <= 0) {
int version = methodNameLen & VERSION_MASK;
if (version == VERSION_1) {
typeKey = methodNameLen & 0xFF;
methodNameLen = in.expectInt();
if (methodNameLen > MAX_METHOD_NAME_LEN) {
throw new SerializerException("Exceptionally long method name of %s bytes", methodNameLen).setExceptionType(PApplicationExceptionType.PROTOCOL_ERROR);
}
if (methodNameLen < 1) {
throw new SerializerException("Exceptionally short method name of %s bytes", methodNameLen).setExceptionType(PApplicationExceptionType.PROTOCOL_ERROR);
}
methodName = new String(in.expectBytes(methodNameLen), UTF_8);
} else {
throw new SerializerException("Bad protocol version: %08x", version >>> 16).setExceptionType(PApplicationExceptionType.INVALID_PROTOCOL);
}
} else {
if (strict && versioned) {
throw new SerializerException("Missing protocol version").setExceptionType(PApplicationExceptionType.INVALID_PROTOCOL);
}
if (methodNameLen > MAX_METHOD_NAME_LEN) {
if (methodNameLen >>> 24 == '<') {
throw new SerializerException("Received HTML in service call").setExceptionType(PApplicationExceptionType.PROTOCOL_ERROR);
}
if (methodNameLen >>> 24 == '{' || methodNameLen >>> 24 == '[') {
throw new SerializerException("Received JSON in service call").setExceptionType(PApplicationExceptionType.PROTOCOL_ERROR);
}
throw new SerializerException("Exceptionally long method name of %s bytes", methodNameLen).setExceptionType(PApplicationExceptionType.PROTOCOL_ERROR);
}
methodName = new String(in.expectBytes(methodNameLen), UTF_8);
typeKey = in.expectByte();
}
sequence = in.expectInt();
type = PServiceCallType.findById(typeKey);
PServiceMethod method = service.getMethod(methodName);
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, strict);
return (PServiceCall<Message, Field>) new PServiceCall<>(methodName, type, sequence, ex);
} else if (method == null) {
throw new SerializerException("No such method " + methodName + " on " + service.getQualifiedName()).setExceptionType(PApplicationExceptionType.UNKNOWN_METHOD);
}
@SuppressWarnings("unchecked") PMessageDescriptor<Message, Field> descriptor = isRequestCallType(type) ? method.getRequestType() : method.getResponseType();
Message message = readMessage(in, descriptor, strict);
return new PServiceCall<>(methodName, type, sequence, message);
} catch (SerializerException se) {
throw new SerializerException(se).setMethodName(methodName).setCallType(type).setSequenceNo(sequence);
} catch (IOException e) {
throw new SerializerException(e, e.getMessage()).setMethodName(methodName).setCallType(type).setSequenceNo(sequence);
}
}
use of net.morimekta.providence.PServiceCall in project providence by morimekta.
the class NonblockingSocketClientHandler method handleCall.
@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 {
if (call.getType() == PServiceCallType.EXCEPTION || call.getType() == PServiceCallType.REPLY) {
throw new PApplicationException("Request with invalid call type: " + call.getType(), PApplicationExceptionType.INVALID_MESSAGE_TYPE);
}
long startTime = System.nanoTime();
PServiceCall<Response, ResponseField> response = null;
CompletableFuture<PServiceCall> responseFuture = null;
if (call.getType() == PServiceCallType.CALL) {
responseFuture = new CompletableFuture<>();
// Each sequence No must be unique for the client, otherwise this will be messed up.
responseFutures.put(call.getSequence(), responseFuture);
}
try {
synchronized (this) {
try {
ensureConnected(service);
if (out == null) {
throw new IOException("Closed channel");
}
serializer.serialize(out, call);
out.flush();
} finally {
if (out != null) {
out.completeFrame();
}
}
}
if (responseFuture != null) {
try {
if (response_timeout > 0) {
response = (PServiceCall<Response, ResponseField>) responseFuture.get(response_timeout, TimeUnit.MILLISECONDS);
} else {
response = (PServiceCall<Response, ResponseField>) responseFuture.get();
}
long endTime = System.nanoTime();
double duration = ((double) (endTime - startTime)) / NS_IN_MILLIS;
try {
instrumentation.onComplete(duration, call, response);
} catch (Exception ignore) {
}
return response;
} catch (TimeoutException | InterruptedException e) {
responseFuture.completeExceptionally(e);
throw new IOException(e.getMessage(), e);
} catch (ExecutionException e) {
throw new IOException(e.getMessage(), e);
} finally {
responseFutures.remove(call.getSequence());
}
}
} catch (Exception e) {
long endTime = System.nanoTime();
double duration = ((double) (endTime - startTime)) / NS_IN_MILLIS;
try {
instrumentation.onTransportException(e, duration, call, response);
} catch (Exception ie) {
e.addSuppressed(ie);
}
throw e;
}
return null;
}
Aggregations