public void visit(JobInitMessage message) {
   LOGGER.debug("Process JobInitMessage: " + message);
   initSessionContext_.acquireWriteLock();
   try {
     sessionId_ =
         initSessionContext_.tryAllocFreeSlot(
             new InitSessionObject(peerAddress_, localSourceJobId_, data_));
   } catch (SessionRuntimeException e) {
     endWithError(e, ErrorNotificationMethod.REMOTE);
     return;
   } finally {
     initSessionContext_.releaseWriteLock();
   }
   String peerKeyId = networkMonitor_.getPeerPublicKeyId(peerAddress_);
   try {
     Pair<KeyAgreement, DiffieHellmanInitPackage> firstStep =
         DiffieHellmanProtocol.firstStepDHKeyAgreement();
     EncryptedObject encryptedData = encryptionAPI_.encrypt(firstStep.getSecond(), peerKeyId);
     initSessionContext_
         .tryGetInitSessionObject(sessionId_)
         .setKeyAgreement(firstStep.getFirst());
     Message initSessionMessage =
         new InitSessionMessage(myAddress_, peerAddress_, sessionId_, getJobId(), encryptedData);
     networkQueue_.add(initSessionMessage);
   } catch (CryptoException e) {
     endWithErrorAndClear(e, ErrorNotificationMethod.LOCAL);
   }
 }
    public void visit(InitSessionMessage message) {
      LOGGER.debug("Process InitSessionMessage: " + message);
      peerAddress_ = message.getSourceAddress();
      remoteSourceJobId_ = message.getSourceJobId();
      sessionId_ = message.getSessionId();
      if (!peerAddress_.equals(myAddress_)) {
        initSessionContext_.acquireWriteLock();
        try {
          initSessionContext_.allocFreeSlot(sessionId_, new InitSessionObject(peerAddress_));
        } catch (SessionRuntimeException e) {
          endWithError(e, ErrorNotificationMethod.REMOTE);
          return;
        } finally {
          initSessionContext_.releaseWriteLock();
        }
      }
      try {
        DiffieHellmanInitPackage diffieHellmanInitPackage =
            (DiffieHellmanInitPackage)
                encryptionAPI_.decrypt(message.getEncryptedData(), privateKeyPeerId_);

        Pair<KeyAgreement, DiffieHellmanResponsePackage> secondStep =
            DiffieHellmanProtocol.secondStepDHKeyAgreement(diffieHellmanInitPackage);
        initSessionContext_
            .tryGetInitSessionObject(sessionId_)
            .setSessionKey(DiffieHellmanProtocol.fourthStepDHKeyAgreement(secondStep.getFirst()));
        String peerKeyId = networkMonitor_.getPeerPublicKeyId(peerAddress_);
        EncryptedObject encryptedData = encryptionAPI_.encrypt(secondStep.getSecond(), peerKeyId);

        Message initSessionResponseMessage =
            new InitSessionResponseMessage(
                remoteSourceJobId_,
                myAddress_,
                peerAddress_,
                sessionId_,
                getJobId(),
                encryptedData);
        networkQueue_.add(initSessionResponseMessage);
        endWithSuccess();
      } catch (CryptoException e) {
        endWithErrorAndClear(e, ErrorNotificationMethod.REMOTE);
      }
    }
    public void visit(InitSessionResponseMessage message) {
      LOGGER.debug("Process InitSessionResponseMessage: " + message);
      remoteSourceJobId_ = message.getSourceJobId();
      InitSessionObject initSessionObject = null;
      initSessionContext_.acquireReadLock();
      try {
        initSessionObject = initSessionContext_.tryGetInitSessionObject(sessionId_);
      } catch (SessionRuntimeException e) {
        endWithErrorAndClear(e, ErrorNotificationMethod.ALL);
        return;
      } finally {
        initSessionContext_.releaseReadLock();
      }
      try {
        DiffieHellmanResponsePackage diffieHellmanResponsePackage =
            (DiffieHellmanResponsePackage)
                encryptionAPI_.decrypt(message.getEncryptedData(), privateKeyPeerId_);

        KeyAgreement keyAgreement =
            DiffieHellmanProtocol.thirdStepDHKeyAgreement(
                initSessionObject.getKeyAgreement(), diffieHellmanResponsePackage);
        initSessionObject.setSessionKey(
            DiffieHellmanProtocol.fourthStepDHKeyAgreement(keyAgreement));

        InitSessionEndMessage initSessionEndMessage =
            new InitSessionEndMessage(initSessionObject, getJobId());
        outQueue_.add(initSessionEndMessage);
        if (peerAddress_.equals(myAddress_)) {
          endWithSuccess();
        } else {
          endWithSuccessAndClear();
        }
      } catch (CryptoException e) {
        endWithErrorAndClear(e, ErrorNotificationMethod.ALL);
      }
    }