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

org.openmuc.jdlms.internal.lnassociation.Association Maven / Gradle / Ivy

Go to download

jDLMS is a library implementing the DLMS/COSEM (IEC 62056) communication standard.

There is a newer version: 1.8.0
Show newest version
package org.openmuc.jdlms.internal.lnassociation;

import java.io.EOFException;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.openmuc.jdlms.ServerConnectionInfo.Status;
import org.openmuc.jdlms.ServerConnectionListener;
import org.openmuc.jdlms.internal.APdu;
import org.openmuc.jdlms.internal.DataDirectory;
import org.openmuc.jdlms.internal.DataDirectory.DlmsLogicalDevice;
import org.openmuc.jdlms.internal.ReleaseReqReason;
import org.openmuc.jdlms.internal.ReleaseRespReason;
import org.openmuc.jdlms.internal.ServerConnectionData;
import org.openmuc.jdlms.internal.ServiceError;
import org.openmuc.jdlms.internal.StateError;
import org.openmuc.jdlms.internal.asn1.cosem.COSEMpdu;
import org.openmuc.jdlms.internal.asn1.iso.acse.ACSEApdu;
import org.openmuc.jdlms.internal.asn1.iso.acse.AssociationInformation;
import org.openmuc.jdlms.internal.asn1.iso.acse.RLREApdu;
import org.openmuc.jdlms.internal.asn1.iso.acse.RLRQApdu;
import org.openmuc.jdlms.internal.asn1.iso.acse.ReleaseResponseReason;
import org.openmuc.jdlms.internal.sessionlayer.ServerSessionLayer;
import org.openmuc.jdlms.internal.settings.ServerSettings;
import org.openmuc.jdlms.internal.transportlayer.ServerConnectionInformationImpl;

public class Association implements Runnable {

    private final DataDirectory directory;
    private final ServerSessionLayer sessionLayer;

    private final Long connectionId;
    private final ServerConnectionData connectionData;
    private final ServerSettings settings;
    private final ServerConnectionInformationImpl serverConnectionInformation;

    public Association(DataDirectory directory, ServerSessionLayer sessionLayer, Long connectionId,
            ServerSettings settings, ServerConnectionInformationImpl serverConnectionInformation) {
        this.directory = directory;
        this.sessionLayer = sessionLayer;
        this.connectionId = connectionId;
        this.settings = settings;
        this.serverConnectionInformation = serverConnectionInformation;

        this.connectionData = new ServerConnectionData();
        this.directory.addConnection(connectionId, this.connectionData);

    }

    @Override
    public void run() {
        AssociationMessenger associationMessenger = new AssociationMessenger(connectionData, directory, sessionLayer,
                connectionId);
        ServerConnectionListener connectionListener = settings.connectionListener;

        try {
            byte[] payload = this.sessionLayer.readNextMessage();
            Status status = Status.OPEN;

            notifyListener(connectionListener, status);

            RequestProcessorData requestProcessorData = new RequestProcessorData(this.sessionLayer.getLogicalDeviceId(),
                    connectionId, directory, connectionData);

            this.connectionData.clientId = this.sessionLayer.getClientId();
            DlmsLogicalDevice dlmsLogicalDevice = this.directory
                    .getLogicalDeviceFor(this.sessionLayer.getLogicalDeviceId());

            APdu aarqAPdu = new InitialmessageProcessor(connectionData, dlmsLogicalDevice)
                    .processInitialMessage(payload);

            associationMessenger.encodeAndSend(aarqAPdu);

            Map requestProcessors = buildRequestProcessors(associationMessenger,
                    requestProcessorData);

            while (true) {

                APdu apdu = associationMessenger.readNextApdu();
                ACSEApdu acseApdu = apdu.getAcseAPdu();
                COSEMpdu cosemPdu = apdu.getCosemPdu();
                if (acseApdu != null && acseApdu.rlrq != null) {
                    sendDisconnectMessage(associationMessenger, acseApdu.rlrq);
                    return;
                }

                if (!this.connectionData.authenticated
                        && cosemPdu.getChoiceIndex() != COSEMpdu.Choices.ACTION_REQUEST) {
                    throw new AssociationException(StateError.SERVICE_NOT_ALLOWED, ServiceError.OPERATION_NOT_POSSIBLE);
                }

                RequestProcessor requestProcessor = requestProcessors.get(cosemPdu.getChoiceIndex());
                if (requestProcessor != null) {
                    requestProcessor.processRequest(cosemPdu);
                }
                else {
                    // TODO handle other requests..
                }

                if (!this.connectionData.authenticated) {
                    throw new IOException("Client failed to authenticate..");
                }

            }
        } catch (GenericAssociationException e) {
            try {
                associationMessenger.encodeAndSend(e.getErrorMessageApdu());
            } catch (IOException e1) {
                // ignore any exception here..
            }
        } catch (IOException e) {
            if (e instanceof EOFException) {
                // client closed the connection..
                return;
            }
            if (e instanceof SocketTimeoutException) {
                // client was too slow
                return;
            }

            e.printStackTrace();
            // TODO ignore??
        } finally {
            this.directory.removeConnection(this.connectionId);
            try {
                sessionLayer.close();
            } catch (IOException e1) {
                // ignore
            }

            notifyListener(connectionListener, Status.CLOSED);
        }

    }

    private void sendDisconnectMessage(AssociationMessenger associationMessenger, RLRQApdu rlrq) throws IOException {
        ReleaseReqReason reqReason = ReleaseReqReason.reasonFor(rlrq.reason.value);

        ReleaseRespReason respReason;
        switch (reqReason) {

        case URGENT:
            respReason = ReleaseRespReason.NOT_FINISHED;
            break;

        case USER_DEFINED:
            respReason = ReleaseRespReason.USER_DEFINED;
            break;

        case NORMAL:
        default:
        case UNKNOWN:
            respReason = ReleaseRespReason.NORMAL;
            break;
        }

        ReleaseResponseReason reason = new ReleaseResponseReason(respReason.getCode());
        AssociationInformation userInformation = null;
        RLREApdu rlre = new RLREApdu(reason, userInformation);
        ACSEApdu reAcse = new ACSEApdu(null, null, null, rlre);
        APdu reponseApdu = new APdu(reAcse, null);

        byte[] buffer = new byte[6];
        int length = reponseApdu.encode(buffer, null);

        associationMessenger.send(Arrays.copyOfRange(buffer, buffer.length - length, buffer.length));
        sessionLayer.close();
    }

    private void notifyListener(ServerConnectionListener connectionListener, Status status) {
        if (connectionListener == null) {
            return;
        }

        serverConnectionInformation.clientId = this.sessionLayer.getClientId();
        serverConnectionInformation.logicalDeviceAddress = this.sessionLayer.getLogicalDeviceId();
        serverConnectionInformation.status = status;
        connectionListener.connectionChanged(serverConnectionInformation);
    }

    private Map buildRequestProcessors(AssociationMessenger associationMessenger,
            RequestProcessorData requestProcessorData) {
        Map requestProcessors = new HashMap<>();
        requestProcessors.put(COSEMpdu.Choices.ACTION_REQUEST,
                new ActionRequestProcessor(associationMessenger, requestProcessorData));
        requestProcessors.put(COSEMpdu.Choices.GET_REQUEST,
                new GetRequestProcessor(associationMessenger, requestProcessorData));
        requestProcessors.put(COSEMpdu.Choices.SET_REQUEST,
                new SetRequestProcessor(associationMessenger, requestProcessorData));
        return requestProcessors;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy