org.gwtproject.rpc.websockets.shared.impl.AbstractEndpointImpl Maven / Gradle / Ivy
/*
* #%L
* gwt-websockets-api
* %%
* Copyright (C) 2011 - 2018 Vertispan LLC
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.gwtproject.rpc.websockets.shared.impl;
import com.google.gwt.user.client.rpc.SerializationException;
import org.gwtproject.rpc.serialization.api.SerializationStreamReader;
import org.gwtproject.rpc.serialization.api.SerializationStreamWriter;
import org.gwtproject.rpc.serialization.api.TypeSerializer;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* Base class for use in implementing any kind of endpoint, simplifying the code required to have in
* generated concrete implementations.
*/
public abstract class AbstractEndpointImpl {
/**
* Interface describing the constructor of any concrete subclass for use in wrapping these instances.
*/
@FunctionalInterface
public interface EndpointImplConstructor {
E create(
Function writerFactory,
Consumer send,
BiConsumer, TypeSerializer> onMessage
);
}
private final Function writerFactory;
private final Consumer send;
private final TypeSerializer serializer;
// count starts at 1, leaving zero for remote methods
private int nextCallbackId = 1;
private Map> callbacks = new HashMap<>();
protected AbstractEndpointImpl(
Function writerFactory,
Consumer send,
TypeSerializer serializer,
BiConsumer, TypeSerializer> onMessage) {
this.writerFactory = (Function) writerFactory;
this.send = (Consumer) send;
this.serializer = serializer;
onMessage.accept(this::__onMessage, serializer);
}
/**
* Push any errors to the local (non-generated) endpoint implementation.
*/
protected abstract void __onError(Throwable ex);
/**
* Invoke the remote invoked method on the local (non-generated) endpoint implementation.
*/
protected abstract void __invoke(int recipient, SerializationStreamReader reader) throws SerializationException;
public void __onMessage(SerializationStreamReader reader) {
try {
int recipient = reader.readInt();
if (recipient >= 0) {
__invoke(recipient, reader);
} else {
ReadingCallback, ?> callback = callbacks.get(-recipient);
callback.handle(reader);
}
} catch (SerializationException ex) {
__onError(ex);
}
}
private SerializationStreamWriter __startCall() {
return writerFactory.apply(serializer);
}
private void __endCall(SerializationStreamWriter writer) {
send.accept(writer);
}
/**
* Easy lambda to let generated classes run code which might throw within __send()
*/
protected interface Send {
void send(SerializationStreamWriter writer) throws SerializationException;
}
protected void __send(int recipient, Send s) {
SerializationStreamWriter writer = __startCall();
try {
writer.writeInt(recipient);
s.send(writer);
__endCall(writer);
} catch (SerializationException e) {
__onError(e);
throw new RuntimeException(e);
}
}
protected void __send(int recipient, Send s, ReadingCallback, ?> callback) {
SerializationStreamWriter writer = __startCall();
try {
writer.writeInt(recipient);
// add the callbackId to the message to send so the remote end knows it will need a callback
// object when handling the rest of the body
int callbackId = nextCallbackId++;
writer.writeInt(callbackId);
s.send(writer);
__endCall(writer);
//only after we've successfully sent, register the callback
callbacks.put(callbackId, callback);
} catch (SerializationException e) {
//TODO report? can't actually pass to Callback.onFailure, since it might expect something else
throw new RuntimeException(e);
}
}
protected static abstract class ReadingCallback {
public final void handle(SerializationStreamReader reader) throws SerializationException {
boolean success = reader.readBoolean();
if (success) {
success(reader);
} else {
failure(reader);
}
}
public abstract void success(SerializationStreamReader reader) throws org.gwtproject.rpc.serialization.api.SerializationException;
public abstract void failure(SerializationStreamReader reader) throws org.gwtproject.rpc.serialization.api.SerializationException;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy