Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.bidib.jbidibc.netbidib.client.pairingstates.DefaultPairingStateHandler Maven / Gradle / Ivy
package org.bidib.jbidibc.netbidib.client.pairingstates;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.bidib.jbidibc.messages.enums.NetBidibSocketType;
import org.bidib.jbidibc.messages.enums.PairingResult;
import org.bidib.jbidibc.messages.exception.EstablishCommunicationFailedException;
import org.bidib.jbidibc.messages.exception.InvalidConfigurationException;
import org.bidib.jbidibc.messages.exception.ProtocolException;
import org.bidib.jbidibc.messages.helpers.Context;
import org.bidib.jbidibc.messages.helpers.DefaultContext;
import org.bidib.jbidibc.messages.message.BidibCommandMessage;
import org.bidib.jbidibc.messages.message.BidibRequestFactory;
import org.bidib.jbidibc.messages.message.LocalLogoffMessage;
import org.bidib.jbidibc.messages.message.LocalLogonAckMessage;
import org.bidib.jbidibc.messages.message.LocalLogonMessage;
import org.bidib.jbidibc.messages.message.netbidib.BidibLinkData;
import org.bidib.jbidibc.messages.message.netbidib.LocalLinkMessage;
import org.bidib.jbidibc.messages.message.netbidib.LocalProtocolSignatureMessage;
import org.bidib.jbidibc.messages.message.netbidib.NetBidibLinkData.PairingStatus;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.bidib.jbidibc.netbidib.NetBidibContextKeys;
import org.bidib.jbidibc.netbidib.pairingstore.LocalPairingStore.PairingLookupResult;
import org.bidib.jbidibc.netbidib.pairingstore.PairingStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DefaultPairingStateHandler implements PairingStateHandler, PairingStateInteractionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultPairingStateHandler.class);
public static final String PROPERTY_CURRENTPAIRINGSTATE = "currentPairingState";
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private PairingStateEnum currentPairingState = PairingStateEnum.Initial;
private Map pairingStateMap = new HashMap<>();
private ProxyBidibLinkData remotePartnerLinkData;
private ProxyBidibLinkData clientLinkData;
private final NetBidibMessageSender netBidibMessageSender;
private final PairingInteractionPublisher pairingInteractionPublisher;
private final BidibRequestFactory bidibRequestFactory;
private Object pairingStoreLock = new Object();
private PairingStore pairingStore;
public DefaultPairingStateHandler(final NetBidibMessageSender netBidibMessageSender,
final PairingInteractionPublisher pairingInteractionPublisher, final BidibRequestFactory bidibRequestFactory) {
this.netBidibMessageSender = netBidibMessageSender;
this.pairingInteractionPublisher = pairingInteractionPublisher;
this.bidibRequestFactory = bidibRequestFactory;
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
this.pcs.addPropertyChangeListener(propertyName, listener);
}
public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
this.pcs.removePropertyChangeListener(propertyName, listener);
}
private NetBidibSocketType socketType;
@Override
public void setNetBidibSocketType(final NetBidibSocketType socketType) {
this.socketType = socketType;
}
protected NetBidibSocketType getSocketType() {
return this.socketType;
}
@Override
public void initialize(
final BidibLinkData remotePartnerLinkData, final BidibLinkData clientLinkData,
final PairingStore pairingStore) {
this.remotePartnerLinkData = new ProxyBidibLinkData(remotePartnerLinkData);
this.clientLinkData = new ProxyBidibLinkData(clientLinkData);
this.pairingStore = pairingStore;
LOGGER.info("Current pairingStore content: {}", this.pairingStore);
// check if the pairing store is available and valid
this.pairingStore.checkValid();
pairingStateMap
.put(PairingStateEnum.Initial,
new InitialPairingState(this, this.remotePartnerLinkData, this.clientLinkData));
pairingStateMap
.put(PairingStateEnum.Unpaired,
new UnpairedPairingState(this, this.remotePartnerLinkData, this.clientLinkData));
pairingStateMap
.put(PairingStateEnum.MyRequest,
new MyRequestPairingState(this, this.remotePartnerLinkData, this.clientLinkData));
pairingStateMap
.put(PairingStateEnum.TheirRequest,
new TheirRequestPairingState(this, this.remotePartnerLinkData, this.clientLinkData));
pairingStateMap
.put(PairingStateEnum.Paired,
new PairedPairingState(this, this.remotePartnerLinkData, this.clientLinkData));
pairingStateMap
.put(PairingStateEnum.Withdrawn,
new WithdrawnPairingState(this, this.remotePartnerLinkData, this.clientLinkData));
this.addPropertyChangeListener(DefaultPairingStateHandler.PROPERTY_CURRENTPAIRINGSTATE, evt -> {
final PairingStateEnum currentPairingState = getCurrentPairingState();
LOGGER
.info("The pairing state has changed, currentPairingState: {}, clientLinkData.pairingStatus: {}",
currentPairingState, DefaultPairingStateHandler.this.clientLinkData.getPairingStatus());
switch (currentPairingState) {
case Paired:
LOGGER.info("We are in paired state.");
signalPairingFinished(PairingResult.PAIRED, DefaultPairingStateHandler.this.remotePartnerLinkData);
break;
case Unpaired:
LOGGER.info("We are in unpaired state.");
if (DefaultPairingStateHandler.this.clientLinkData
.getPairingStatus() == PairingStatus.PAIRING_REQUESTED) {
LOGGER.info("The remote partner has rejected the pairing.");
signalPairingFinished(PairingResult.UNPAIRED,
DefaultPairingStateHandler.this.remotePartnerLinkData);
}
break;
case Withdrawn:
LOGGER.info("We are in withdrawn state.");
if (DefaultPairingStateHandler.this.clientLinkData
.getPairingStatus() == PairingStatus.PAIRING_REQUESTED
|| DefaultPairingStateHandler.this.clientLinkData.getPairingStatus() == PairingStatus.PAIRED) {
LOGGER.info("The remote partner has withdrawn the pairing.");
signalPairingFinished(PairingResult.UNPAIRED,
DefaultPairingStateHandler.this.remotePartnerLinkData);
}
break;
default:
LOGGER.info("Ignored change of pairing state: {}", currentPairingState);
break;
}
});
this.clientLinkData.addPropertyChangeListener(ProxyBidibLinkData.PROPERTY_PAIRINGSTATUS, evt -> {
final PairingStatus pairingStatus = this.clientLinkData.getPairingStatus();
LOGGER.info("The pairing status of the client has changed, pairingState: {}", pairingStatus);
switch (pairingStatus) {
case PAIRED:
LOGGER.info("The client signalled the paired state.");
// signalPairingState(PairingStateEnum.Paired, DefaultPairingStateHandler.this.clientLinkData,
// DefaultPairingStateHandler.this.remotePartnerLinkData);
break;
case UNPAIRED:
LOGGER.info("The client signalled the unpaired state.");
// signalPairingState(PairingStateEnum.Unpaired, DefaultPairingStateHandler.this.clientLinkData,
// DefaultPairingStateHandler.this.remotePartnerLinkData);
break;
default:
break;
}
});
this.remotePartnerLinkData.addPropertyChangeListener(ProxyBidibLinkData.PROPERTY_PAIRINGSTATUS, evt -> {
final PairingStatus pairingStatus = this.remotePartnerLinkData.getPairingStatus();
LOGGER.info("The pairing status of the remote partner has changed, pairingState: {}", pairingStatus);
switch (pairingStatus) {
case PAIRED:
LOGGER.info("The remote partner signalled the paired state.");
signalPairingState(PairingStateEnum.Paired, DefaultPairingStateHandler.this.remotePartnerLinkData,
DefaultPairingStateHandler.this.clientLinkData);
break;
case UNPAIRED:
LOGGER.info("The remote partner signalled the unpaired state.");
signalPairingState(PairingStateEnum.Unpaired, DefaultPairingStateHandler.this.remotePartnerLinkData,
DefaultPairingStateHandler.this.clientLinkData);
break;
case PAIRING_REQUESTED:
LOGGER.info("The remote partner signalled the pairing requested.");
updatePairingStoreLinkData(DefaultPairingStateHandler.this.remotePartnerLinkData);
break;
case WITHDRAWN:
LOGGER.info("The remote partner signalled the witdrawn state.");
updatePairingStoreLinkData(DefaultPairingStateHandler.this.remotePartnerLinkData);
break;
default:
break;
}
});
}
protected BidibRequestFactory getRequestFactory() {
return bidibRequestFactory;
}
/**
* @return the current pairingState
*/
protected PairingStateEnum getCurrentPairingState() {
return currentPairingState;
}
/**
* @param pairingState
* the pairingState to set
*/
protected void setCurrentPairingState(PairingStateEnum pairingState) {
LOGGER.info("Set the new pairingState: {}", pairingState);
PairingStateEnum oldValue = this.currentPairingState;
this.currentPairingState = pairingState;
this.pcs.firePropertyChange(PROPERTY_CURRENTPAIRINGSTATE, oldValue, this.currentPairingState);
}
/**
* @return the remotePartnerLinkData
*/
public ProxyBidibLinkData getRemotePartnerLinkData() {
return remotePartnerLinkData;
}
/**
* @return the clientLinkData
*/
public ProxyBidibLinkData getClientLinkData() {
return clientLinkData;
}
protected void publishMessage(final BidibCommandMessage message) throws ProtocolException {
LOGGER.info("Publish the message: {}", message);
netBidibMessageSender.publishNetBidibMessage(message);
}
/**
* Signal the pairing request from the remote partner to the UI.
*
* @param remotePartnerLinkData
* the link data
*/
protected void signalPairingRequest(final BidibLinkData remotePartnerLinkData) {
LOGGER.info("Signal the pairing request, remotePartnerLinkData: {}", remotePartnerLinkData);
Integer pairingTimeout = remotePartnerLinkData.getRequestedPairingTimeout();
final Context context = new DefaultContext();
// Prepare the remote partner information
context.register(NetBidibContextKeys.KEY_REQUESTOR_NAME, remotePartnerLinkData.getRequestorName());
context.register(NetBidibContextKeys.KEY_DESCRIPTOR_UID, remotePartnerLinkData.getUniqueId());
context.register(NetBidibContextKeys.KEY_DESCRIPTOR_PROD_STRING, remotePartnerLinkData.getProdString());
context.register(NetBidibContextKeys.KEY_DESCRIPTOR_USER_STRING, remotePartnerLinkData.getUserString());
context.register(NetBidibContextKeys.KEY_PAIRING_TIMEOUT, pairingTimeout);
if (getSocketType() == NetBidibSocketType.clientSocket) {
context.register(NetBidibContextKeys.KEY_CONNECTION_TYPE, NetBidibContextKeys.VALUE_CONNECTION_TYPE_CLIENT);
}
else {
context.register(NetBidibContextKeys.KEY_CONNECTION_TYPE, NetBidibContextKeys.VALUE_CONNECTION_TYPE_SERVER);
}
String actionKey = NetBidibContextKeys.KEY_ACTION_PAIRING_REQUESTED;
LOGGER.info("Publish the user action actionKey: {}, with context: {}", actionKey, context);
this.pairingInteractionPublisher.publishUserAction(actionKey, context);
}
protected void signalPairingFinished(final PairingResult pairingResult, final BidibLinkData remotePartnerLinkData) {
// update the pairing store
updatePairingStore(remotePartnerLinkData.getUniqueId(), pairingResult);
// notify the UI
this.pairingInteractionPublisher.publishPairingFinished(pairingResult);
}
protected void publishLocalLogon(int localNodeAddr, long uniqueId) {
this.pairingInteractionPublisher.publishLocalLogon(localNodeAddr, uniqueId);
}
protected void publishLocalLogoff() {
this.pairingInteractionPublisher.publishLocalLogoff();
}
/**
* Signal the pairing state to the UI.
*
* @param pairingState
* the pairing state
* @param remotePartnerLinkData
* the link data
*/
protected void signalPairingState(
final PairingStateEnum pairingState, final ProxyBidibLinkData remotePartnerLinkData,
final ProxyBidibLinkData clientLinkData) {
LOGGER
.info(
"Signal the pairing state, pairingState: {}, remotePartnerLinkData: {}, final BidibLinkData remotePartnerLinkData: {}",
pairingState, remotePartnerLinkData, clientLinkData);
final Context context = new DefaultContext();
Integer pairingTimeout = clientLinkData.getRequestedPairingTimeout();
// Prepare the remote partner information
context.register(NetBidibContextKeys.KEY_REQUESTOR_NAME, remotePartnerLinkData.getRequestorName());
context.register(NetBidibContextKeys.KEY_DESCRIPTOR_UID, remotePartnerLinkData.getUniqueId());
context.register(NetBidibContextKeys.KEY_DESCRIPTOR_PROD_STRING, remotePartnerLinkData.getProdString());
context.register(NetBidibContextKeys.KEY_DESCRIPTOR_USER_STRING, remotePartnerLinkData.getUserString());
context.register(NetBidibContextKeys.KEY_PAIRING_STATE, pairingState);
context.register(NetBidibContextKeys.KEY_PAIRING_TIMEOUT, pairingTimeout);
if (getSocketType() == NetBidibSocketType.clientSocket) {
context.register(NetBidibContextKeys.KEY_CONNECTION_TYPE, NetBidibContextKeys.VALUE_CONNECTION_TYPE_CLIENT);
}
else {
context.register(NetBidibContextKeys.KEY_CONNECTION_TYPE, NetBidibContextKeys.VALUE_CONNECTION_TYPE_SERVER);
}
String actionKey = NetBidibContextKeys.KEY_ACTION_PAIRING_STATE;
LOGGER.info("Publish the user action actionKey: {}, with context: {}", actionKey, context);
this.pairingInteractionPublisher.publishUserAction(actionKey, context);
}
@Override
public void onLocalProtocolSignature(LocalProtocolSignatureMessage localProtocolSignatureMessage) {
final AbstractPairingState currentState = pairingStateMap.get(currentPairingState);
if (currentState != null) {
if (this.initialResponseLock != null) {
LOGGER.info("The initial localProtocolSignature was received.");
this.initialResponseLock.countDown();
}
currentState.onLocalProtocolSignature(localProtocolSignatureMessage);
}
else {
LOGGER.error("No pairing state configured for current pairing state: {}", currentPairingState);
}
}
@Override
public void onLocalLink(LocalLinkMessage localLinkMessage) {
AbstractPairingState currentState = pairingStateMap.get(currentPairingState);
if (currentState != null) {
currentState.onLocalLink(localLinkMessage);
}
else {
LOGGER.error("No pairing state configured for current pairing state: {}", currentPairingState);
}
}
@Override
public void onLocalLogonAck(LocalLogonAckMessage localLogonAckMessage) {
AbstractPairingState currentState = pairingStateMap.get(currentPairingState);
if (currentState != null) {
currentState.onLocalLogonAck(localLogonAckMessage);
}
else {
LOGGER.error("No pairing state configured for current pairing state: {}", currentPairingState);
}
}
@Override
public void onLocalLogon(LocalLogonMessage localLogonMessage) {
AbstractPairingState currentState = pairingStateMap.get(currentPairingState);
if (currentState != null) {
currentState.onLocalLogon(localLogonMessage);
}
else {
LOGGER.error("No pairing state configured for current pairing state: {}", currentPairingState);
}
}
@Override
public void onLocalLogoff(LocalLogoffMessage localLogoffMessage) {
AbstractPairingState currentState = pairingStateMap.get(currentPairingState);
if (currentState != null) {
currentState.onLocalLogoff(localLogoffMessage);
}
else {
LOGGER.error("No pairing state configured for current pairing state: {}", currentPairingState);
}
}
protected boolean isPaired(final BidibLinkData bidibLinkData) {
LOGGER.info("Check if the remote partner is paired: {}", bidibLinkData);
PairingLookupResult isPaired = PairingLookupResult.UNPAIRED;
if (this.pairingStore != null) {
isPaired = this.pairingStore.isPaired(bidibLinkData.getUniqueId());
if (PairingLookupResult.MISSING == isPaired) {
// create the entry
try {
synchronized (this.pairingStoreLock) {
this.pairingStore
.setPaired(bidibLinkData.getUniqueId(), bidibLinkData.getRequestorName(),
bidibLinkData.getProdString(), bidibLinkData.getUserString(),
bidibLinkData.getProtocolVersion(), false);
this.pairingStore.store();
}
}
catch (InvalidConfigurationException ex) {
LOGGER.warn("Set the pairing result in the pairing store failed.", ex);
// show error in console
this.pairingInteractionPublisher.handleError(ex);
}
catch (Exception ex) {
LOGGER.warn("Set the pairing result in the pairing store failed.", ex);
// show error in console
this.pairingInteractionPublisher
.handleError(new RuntimeException("Set the pairing result in the pairing store failed.", ex));
}
isPaired = PairingLookupResult.UNPAIRED;
}
}
else {
LOGGER.warn("No pairing store configured!");
}
LOGGER.info("isPaired: {}, uniqueId: {}", isPaired, ByteUtils.formatHexUniqueId(bidibLinkData.getUniqueId()));
return PairingLookupResult.PAIRED == isPaired;
}
/**
* Update the pairing result in the pairing store.
*
* @param uniqueId
* the uniqueId
* @param pairingResult
* the pairing result
*/
private void updatePairingStore(Long uniqueId, final PairingResult pairingResult) {
LOGGER
.info("Update the pairing store, uniqueId: {}, pairingResult: {}", ByteUtils.getUniqueIdAsString(uniqueId),
pairingResult);
if (this.pairingStore != null) {
try {
synchronized (this.pairingStoreLock) {
this.pairingStore.setPaired(uniqueId, PairingResult.PAIRED == pairingResult);
this.pairingStore.store();
}
}
catch (InvalidConfigurationException ex) {
LOGGER.warn("Set the pairing result in the pairing store failed.", ex);
// show error in console
this.pairingInteractionPublisher.handleError(ex);
}
catch (Exception ex) {
LOGGER.warn("Set the pairing result in the pairing store failed.", ex);
// show error in console
this.pairingInteractionPublisher
.handleError(new RuntimeException("Set the pairing result in the pairing store failed.", ex));
}
}
else {
LOGGER.warn("No pairing store configured!");
}
}
private void updatePairingStoreLinkData(final BidibLinkData bidibLinkData) {
LOGGER.info("Update the pairing store, bidibLinkData: {}", bidibLinkData);
if (this.pairingStore != null) {
try {
synchronized (this.pairingStoreLock) {
this.pairingStore.updateLinkData(bidibLinkData);
this.pairingStore.store();
}
}
catch (InvalidConfigurationException ex) {
LOGGER.warn("Set the pairing result in the pairing store failed.", ex);
// show error in console
this.pairingInteractionPublisher.handleError(ex);
}
catch (Exception ex) {
LOGGER.warn("Set the pairing result in the pairing store failed.", ex);
// show error in console
this.pairingInteractionPublisher
.handleError(new RuntimeException("Set the pairing result in the pairing store failed.", ex));
}
}
else {
LOGGER.warn("No pairing store configured!");
}
}
@Override
public void initiatePairing() {
AbstractPairingState currentState = pairingStateMap.get(currentPairingState);
if (currentState != null) {
currentState.initiatePairing(this.clientLinkData.getRequestedPairingTimeout());
}
else {
LOGGER.error("No pairing state configured for current pairing state: {}", currentPairingState);
}
}
@Override
public void pairingResult(Long uniqueId, final PairingResult pairingResult) {
AbstractPairingState currentState = pairingStateMap.get(currentPairingState);
if (currentState != null) {
LOGGER
.info("Set the pairing result: {}, uniqueId: {}", pairingResult,
ByteUtils.getUniqueIdAsString(uniqueId));
updatePairingStore(uniqueId, pairingResult);
currentState.pairingResult(pairingResult);
}
else {
LOGGER.error("No pairing state configured for current pairing state: {}", currentPairingState);
}
}
@Override
public void timeoutPairing() {
AbstractPairingState currentState = pairingStateMap.get(currentPairingState);
if (currentState != null) {
currentState.timeoutPairing();
}
else {
LOGGER.error("No pairing state configured for current pairing state: {}", currentPairingState);
}
}
// check if the initial response from the bidib device is received
private CountDownLatch initialResponseLock;
@Override
public void sendNetBidibStartupSequence() throws EstablishCommunicationFailedException {
final AbstractPairingState currentState = pairingStateMap.get(currentPairingState);
if (currentState != null) {
// we must check if the response from the client was received
initialResponseLock = new CountDownLatch(1);
// send the message to the bidib interface
currentState.sendNetBidibStartupSequence();
try {
LOGGER.info("Wait for startup of netBidibPort instance.");
boolean completed = initialResponseLock.await(3000, TimeUnit.MILLISECONDS);
LOGGER.info("Establish communication with bidib interface passed and has completed: {}", completed);
if (!completed) {
throw new EstablishCommunicationFailedException(
"Establish communication with bidib interface did not complete in 3s", "");
}
initialResponseLock = null;
}
catch (InterruptedException ex) {
LOGGER.warn("Wait for establish communication with bidib interface was interrupted.", ex);
throw new EstablishCommunicationFailedException(
"Wait for establish communication with bidib interface was interrupted.", "");
}
}
else {
LOGGER.error("No pairing state configured for current pairing state: {}", currentPairingState);
}
}
}