/*
* Copyright (c) 2015-2016, Christoph Engelbert (aka noctarius) and
* contributors. All rights reserved.
*
* 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.
*/
package com.noctarius.tengi.spi.connection;
import com.noctarius.tengi.core.connection.Connection;
import com.noctarius.tengi.core.connection.Transport;
import com.noctarius.tengi.core.model.Identifier;
import com.noctarius.tengi.core.model.Message;
import com.noctarius.tengi.spi.buffer.MemoryBuffer;
import com.noctarius.tengi.spi.connection.packets.PollingRequest;
import com.noctarius.tengi.spi.serialization.Protocol;
import com.noctarius.tengi.spi.serialization.Serializer;
import com.noctarius.tengi.spi.serialization.codec.AutoClosableEncoder;
import java.util.concurrent.CompletableFuture;
/**
* The <tt>ConnectionContext</tt> is an abstract base class for binding protocol processors
* and {@link com.noctarius.tengi.core.connection.Connection} representations. It is capable
* of forwarding write-requests to an underlying transport as well as implements some protocol
* basics such as a common protocol header.
*
* @param <S> the socket type
*/
public abstract class ConnectionContext<S> {
private final Identifier connectionId;
private final Transport transport;
private final Serializer serializer;
/**
* Constructs a new <tt>ConnectionContext</tt> instance using the given parameters.
*
* @param connectionId the connection's connectionId
* @param serializer the <tt>Serializer</tt> to bind
* @param transport the <tt>Transport</tt> that received the connection request
*/
protected ConnectionContext(Identifier connectionId, Serializer serializer, Transport transport) {
this.connectionId = connectionId;
this.serializer = serializer;
this.transport = transport;
}
/**
* Returns the connectionId of the corresponding {@link com.noctarius.tengi.core.connection.Connection}.
*
* @return the connectionId for the bound <tt>Connection</tt>
*/
public Identifier getConnectionId() {
return connectionId;
}
/**
* Returns the <tt>Transport</tt> instance that received the initial connection request and that handles
* the connection itself.
*
* @return the underlying <tt>Transport</tt>
*/
public Transport getTransport() {
return transport;
}
/**
* Returns the bound <tt>Protocol</tt> instance.
*
* @return the bound <tt>Protocol</tt>
*/
public Protocol getProtocol() {
return serializer.getProtocol();
}
/**
* Returns the bound <tt>Serializer</tt> instance.
*
* @return the bound <tt>Serializer</tt>
*/
public Serializer getSerializer() {
return serializer;
}
/**
* This method is called when a non-streaming {@link com.noctarius.tengi.core.connection.Transport}
* receives a long-polling or polling request for all cached elements since the last retrieval.
*
* @param socket the socket to send the response to
* @param connection the bound connection of this context
* @param request the request itself
*/
public void processPollingRequest(S socket, Connection connection, PollingRequest request) {
}
/**
* Writes the given <tt>MemoryBuffer</tt> to the internally bound socket or, in case of non-streaming
* transports, caches the buffer for later retrieval. The message passed in is meant for the
* {@link java.util.concurrent.CompletableFuture} to return whenever the operation is done successfully.
* It is not required to keep the message and a <tt>null</tt> return value must be expected as a legally
* returned value from the future instance.
*
* @param memoryBuffer the buffer to write
* @param message the message that is represented inside the buffer
* @return a <tt>CompletableFuture</tt> representing the sending process
* @throws java.lang.Exception whenever an unexpected situation occurs while sending the object
*/
public abstract CompletableFuture<Message> writeMemoryBuffer(MemoryBuffer memoryBuffer, Message message)
throws Exception;
/**
* Writes the given <tt>MemoryBuffer</tt> to the given socket. Even in case of a non-streaming transport
* this write operation cannot be delayed and must be executed immediately.
*
* @param socket the socket to write to
* @param connection the connection to be returned from the future
* @param memoryBuffer the buffer to write to the socket
* @return a <tt>CompletableFuture</tt> representing the sending process
* @throws java.lang.Exception whenever an unexpected situation occurs while sending the object
*/
public abstract CompletableFuture<Connection> writeSocket(S socket, Connection connection, MemoryBuffer memoryBuffer)
throws Exception;
/**
* Closes the <tt>ConnectionContext</tt> itself and must free all internal resources.
*
* @param connection the connection to be returned from the future
* @return a <tt>CompletableFuture</tt> representing the close process
*/
public abstract CompletableFuture<Connection> close(Connection connection);
/**
* Writes all required packet header information to the given <tt>MemoryBuffer</tt>.
*
* @param memoryBuffer the <tt>MemoryBuffer</tt> to write the header to
* @return the given <tt>MemoryBuffer</tt> instance for fluent usage
* @throws java.lang.Exception whenever an unexpected situation occurs while sending the object
*/
protected MemoryBuffer preparePacket(MemoryBuffer memoryBuffer)
throws Exception {
try (AutoClosableEncoder encoder = serializer.retrieveEncoder(memoryBuffer)) {
encoder.writeBoolean("loggedIn", true);
encoder.writeObject("connectionId", getConnectionId());
return memoryBuffer;
}
}
}