All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hcjf.io.net.NetServiceConsumer Maven / Gradle / Ivy

package org.hcjf.io.net;

import org.hcjf.log.Log;
import org.hcjf.properties.SystemProperties;
import org.hcjf.service.ServiceConsumer;
import org.hcjf.service.ServiceThread;

import javax.net.ssl.SSLEngine;
import java.io.IOException;
import java.net.SocketOption;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * This consumer provide an interface for the net service.
 * @author javaito
 */
public abstract class NetServiceConsumer implements ServiceConsumer {

    private static final String NAME_TEMPLATE = "%s %s %d";

    private final String name;
    private final Integer port;
    private final NetService.TransportLayerProtocol protocol;
    private NetService service;
    private long writeWaitForTimeout;
    private final Map waitForMap;

    public NetServiceConsumer(Integer port, NetService.TransportLayerProtocol protocol) {
        this.port = port;
        this.protocol = protocol;
        writeWaitForTimeout = SystemProperties.getLong(SystemProperties.Net.WRITE_TIMEOUT);
        waitForMap = new HashMap<>();
        name = String.format(NAME_TEMPLATE, getClass().getName(), protocol.toString(), port);
    }

    /**
     * This method return a name to identify the consumer.
     * @return Consumer name.
     */
    public String getName() {
        return name;
    }

    /**
     * Return the waiting time to write a package.
     * @return Waiting time to write a apackage.
     */
    public long getWriteWaitForTimeout() {
        return writeWaitForTimeout;
    }

    /**
     * Set the waiting time to write a package.
     * @param writeWaitForTimeout Waiting time to write a package.
     */
    public void setWriteWaitForTimeout(long writeWaitForTimeout) {
        this.writeWaitForTimeout = writeWaitForTimeout;
    }

    /**
     * This method ser the reference to net service,
     * this method only can be called from the net service
     * that will be associated
     * @param service Net service that will be associated.
     * @throws SecurityException If the method was called from other
     * method that not is NetService.registerConsumer().
     */
    public final void setService(NetService service) {
        StackTraceElement element = Thread.currentThread().getStackTrace()[2];
        if(element.getClassName().equals(NetService.class.getName()) &&
                element.getMethodName().equals("registerConsumer")) {
            this.service = service;
        } else {
            throw new SecurityException("The method 'NetServiceConsumer.setService() only can be called from " +
                    "the net service that will be associated.'");
        }
    }

    /**
     * Returns the net service instance of the consumer.
     * @return Net service instance.
     */
    protected final NetService getService() {
        return service;
    }

    /**
     * Return the port of the consumer.
     * @return Port.
     */
    public final Integer getPort() {
        return port;
    }

    /**
     * This method should create the ssl engine for the consumer.
     * @return SSL engine implementation.
     */
    protected SSLEngine getSSLEngine() {
        throw new  UnsupportedOperationException("Unsupported ssl engine");
    }

    /**
     * Return the transport layer protocol of the consumer.
     * @return Transport layer consumer.
     */
    public final NetService.TransportLayerProtocol getProtocol() {
        return protocol;
    }

    /**
     * Disconnect the specific session.
     * @param session Net session.
     * @param message Disconnection message.
     */
    protected final void disconnect(S session, String message) {
        service.disconnect(session, message);
    }

    /**
     * Returns the shutdown frame to send before the net service shutdown.
     * @param session Session to create the shutdown frame.
     * @return Shutdown frame
     */
    public final byte[] getShutdownFrame(S session) {
        byte[] result = null;
        try {
            D shutdownPackage = getShutdownPackage(session);
            if (shutdownPackage != null) {
                result = encode(shutdownPackage);
            }
        } catch (Exception ex){
            //This exception is totally ignored because the shutdown procedure must be go on
        }
        return result;
    }

    /**
     * Returns the shutdown package to send before the net service shutdown.
     * @param session Session to create the package.
     * @return Shutdown package.
     */
    protected D getShutdownPackage(S session) {
        return null;
    }

    /**
     * This method writes some data over the session indicated,
     * this operation generate a blocking until the net service confirm
     * that the data was written over the communication channel
     * @param session Net session.
     * @param payLoad Data to be written
     * @throws IOException Exception for the io operations
     */
    protected final void write(S session, D payLoad) throws IOException {
        write(session, payLoad, true);
    }

    /**
     * This method writes some data over the session indicated.
     * @param session Net session.
     * @param payLoad Data to be written.
     * @param waitFor If this parameter is true then the operation generate
     *                a blocking over the communication channel.
     * @throws IOException Exception for io operations
     */
    protected final void write(S session, D payLoad, boolean waitFor) throws IOException {
        if(waitFor) {
            NetPackage netPackage = service.writeData(session, encode(payLoad));
            synchronized (netPackage) {
                try {
                    netPackage.wait(getWriteWaitForTimeout());
                } catch (InterruptedException e) {
                    Log.w(SystemProperties.get(SystemProperties.Net.LOG_TAG), "Write wait for interrupted", e);
                }
            }

            switch (netPackage.getPackageStatus()) {
                case CONNECTION_CLOSE: {
                    throw new IOException("Connection Close");
                }
                case IO_ERROR: {
                    throw new IOException("IO Error");
                }
                case REJECTED_SESSION_LOCK: {
                    throw new IOException("Session locked");
                }
                case UNKNOWN_SESSION: {
                    throw new IOException("Unknown session");
                }
            }
        } else {
            NetPackage netPackage = service.writeData(session, encode(payLoad));
        }
    }

    /**
     * This method abstracts the connection event to use the entities of the domain's implementation.
     * @param netPackage Connection package.
     */
    public final void onConnect(NetPackage netPackage) {
        onConnect((S) netPackage.getSession(), decode(netPackage), netPackage);
    }

    /**
     * Method that must be implemented by the custom implementation to know when a session is connected
     * @param session Connected session.
     * @param payLoad Decoded package payload.
     * @param netPackage Original package.
     */
    protected void onConnect(S session, D payLoad, NetPackage netPackage) {}

    /**
     * This method abstracts the disconnection event to use the entities of the domain's implementation.
     * @param netPackage Disconnection package.
     */
    public final void onDisconnect(NetPackage netPackage) {
        synchronized (netPackage) {
            netPackage.notify();
        }

        onDisconnect((S) netPackage.getSession(), netPackage);
    }

    /**
     * Method must be implemented by the custom implementation to known when a session is disconnected
     * @param session Disconnected session.
     * @param netPackage Original package.
     */
    protected void onDisconnect(S session, NetPackage netPackage) {}

    /**
     * When the net service receive data call this method to process the package
     * @param netPackage Net package.
     */
    public final void onRead(NetPackage netPackage) {
        S session = (S) netPackage.getSession();
        D decodedPackage = decode(netPackage);
        try {
            session = checkSession(session, decodedPackage, netPackage);
            session.setChecked(true);

            try {
                onRead(session, decodedPackage, netPackage);
            } catch (Exception ex) {
                Log.w(SystemProperties.get(SystemProperties.Net.LOG_TAG), "On read method fail", ex);
            }
        } catch (Exception ex){
            Log.w(SystemProperties.get(SystemProperties.Net.LOG_TAG), "Check session fail", ex);
            session.setChecked(false);
            onCheckSessionError(session, decodedPackage, netPackage, ex);
        }
    }

    /**
     * When the net service receive data, this method is called to process the package.
     * @param session Net session.
     * @param payLoad Net package decoded
     * @param netPackage Net package.
     */
    protected void onRead(S session, D payLoad, NetPackage netPackage) {}


    /**
     * When an exception is occurred while checking session,
     * this method is called to process the package according the exception information.
     * @param session Net session.
     * @param payLoad Net package decoded
     * @param netPackage Net package.
     * @param cause Error cause.
     */
    protected void onCheckSessionError(S session, D payLoad, NetPackage netPackage, Throwable cause) {}

    /**
     * When the net service write data then call this method to process the package.
     * @param netPackage Net package.
     */
    public final void onWrite(NetPackage netPackage) {
        synchronized (netPackage) {
            netPackage.notify();
        }
        onWrite((S)netPackage.getSession(), netPackage);
    }

    /**
     * When the net service write data then call this method to process the package.
     * @param session Net session.
     * @param netPackage Net package.
     */
    protected void onWrite(S session, NetPackage netPackage){}

    /**
     * This method decode the implementation data.
     * @param payLoad Implementation data.
     * @return Implementation data encoded.
     */
    protected abstract byte[] encode(D payLoad);

    /**
     * This method decode the net package to obtain the implementation data
     * @param netPackage Net package.
     * @return Return the implementation data.
     */
    protected abstract D decode(NetPackage netPackage);

    /**
     * Destroy the session.
     * @param session Net session to be destroyed
     */
    public abstract void destroySession(NetSession session);

    /**
     * Check the channel session.
     * @param session Created session.
     * @param payLoad Decoded package.
     * @param netPackage Net package.
     * @return Updated session.
     */
    public abstract S checkSession(S session, D payLoad, NetPackage netPackage);

    /**
     * Return the socket options of the implementation.
     * @return Socket options.
     */
    public Map getSocketOptions() {
        return null;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy