Skip to content

Commit

Permalink
[sonyprojector] Allow translation of exception messages that can be d…
Browse files Browse the repository at this point in the history
…isplayed in MainUI

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
  • Loading branch information
lolodomo committed Nov 11, 2021
1 parent c6a89be commit 5d57908
Show file tree
Hide file tree
Showing 13 changed files with 149 additions and 137 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,22 @@
package org.openhab.binding.sonyprojector.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

/**
* The {@link SonyProjectorException} class is used for any exception thrown by the binding
*
* @author Markus Wehrle - Initial contribution
*/
@NonNullByDefault
public class SonyProjectorException extends Exception {
public class SonyProjectorException extends RuntimeException {

private static final long serialVersionUID = 1L;

// Parameterless Constructor
public SonyProjectorException() {
public SonyProjectorException(String message) {
super(message);
}

// Constructor that accepts a message
public SonyProjectorException(@Nullable String message) {
super(message);
public SonyProjectorException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.sonyprojector.internal.handler.SonyProjectorHandler;
import org.openhab.core.i18n.TranslationProvider;
import org.openhab.core.io.transport.serial.SerialPortManager;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
Expand Down Expand Up @@ -49,12 +50,15 @@ public class SonyProjectorHandlerFactory extends BaseThingHandlerFactory {
private final SerialPortManager serialPortManager;

private final SonyProjectorStateDescriptionOptionProvider stateDescriptionProvider;
private final TranslationProvider i18nProvider;

@Activate
public SonyProjectorHandlerFactory(final @Reference SerialPortManager serialPortManager,
final @Reference SonyProjectorStateDescriptionOptionProvider stateDescriptionProvider) {
final @Reference SonyProjectorStateDescriptionOptionProvider stateDescriptionProvider,
final @Reference TranslationProvider i18nProvider) {
this.serialPortManager = serialPortManager;
this.stateDescriptionProvider = stateDescriptionProvider;
this.i18nProvider = i18nProvider;
}

@Override
Expand All @@ -67,7 +71,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();

if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
return new SonyProjectorHandler(thing, stateDescriptionProvider, serialPortManager);
return new SonyProjectorHandler(thing, stateDescriptionProvider, serialPortManager, i18nProvider);
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.sonyprojector.internal.SonyProjectorException;
import org.openhab.binding.sonyprojector.internal.SonyProjectorModel;
import org.openhab.core.i18n.CommunicationException;
import org.openhab.core.i18n.ConnectionException;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.util.HexUtils;
import org.slf4j.Logger;
Expand Down Expand Up @@ -897,9 +899,8 @@ protected byte[] getSetting(SonyProjectorItem item) throws SonyProjectorExceptio
logger.debug("Get setting {} succeeded: result data: {}", item.getName(), HexUtils.bytesToHex(result));

return result;
} catch (SonyProjectorException e) {
logger.debug("Get setting {} failed: {}", item.getName(), e.getMessage());
throw new SonyProjectorException("Get setting " + item.getName() + " failed: " + e.getMessage());
} catch (CommunicationException e) {
throw new SonyProjectorException("Get setting " + item.getName() + " failed", e);
}
}

Expand All @@ -916,9 +917,8 @@ private void setSetting(SonyProjectorItem item, byte[] data) throws SonyProjecto

try {
executeCommand(item, false, data);
} catch (SonyProjectorException e) {
logger.debug("Set setting {} failed: {}", item.getName(), e.getMessage());
throw new SonyProjectorException("Set setting " + item.getName() + " failed: " + e.getMessage());
} catch (CommunicationException e) {
throw new SonyProjectorException("Set setting " + item.getName() + " failed", e);
}

logger.debug("Set setting {} succeeded", item.getName());
Expand Down Expand Up @@ -950,13 +950,11 @@ private synchronized void sendIR(SonyProjectorItem item) throws SonyProjectorExc
if (!runningSession) {
close();
}
} catch (SonyProjectorException e) {
logger.debug("Send IR {} failed: {}", item.getName(), e.getMessage());
throw new SonyProjectorException("Send IR " + item.getName() + " failed: " + e.getMessage());
} catch (CommunicationException e) {
throw new SonyProjectorException("Send IR " + item.getName() + " failed", e);
} catch (InterruptedException e) {
logger.debug("Send IR {} interrupted: {}", item.getName(), e.getMessage());
Thread.currentThread().interrupt();
throw new SonyProjectorException("Send IR " + item.getName() + " interrupted: " + e.getMessage());
throw new SonyProjectorException("Send IR " + item.getName() + " interrupted", e);
}

logger.debug("Send IR {} succeeded", item.getName());
Expand All @@ -971,40 +969,37 @@ private synchronized void sendIR(SonyProjectorItem item) throws SonyProjectorExc
*
* @return the buffer containing the returned message
*
* @throws SonyProjectorException - In case of any problem
* @throws ConnectionException - In case of any connection problem
* @throws CommunicationException - In case of any communication problem
*/
private synchronized byte[] executeCommand(SonyProjectorItem item, boolean getCommand, byte[] data)
throws SonyProjectorException {
try {
boolean runningSession = connected;
throws ConnectionException, CommunicationException {
boolean runningSession = connected;

open();
open();

// Build the message and send it
writeCommand(buildMessage(item, getCommand, data));
// Build the message and send it
writeCommand(buildMessage(item, getCommand, data));

// Read the response
byte[] responseMessage = readResponse();
// Read the response
byte[] responseMessage = readResponse();

if (!runningSession) {
close();
}
if (!runningSession) {
close();
}

// Validate the content of the response
validateResponse(responseMessage, item);
// Validate the content of the response
validateResponse(responseMessage, item);

return responseMessage;
} catch (SonyProjectorException e) {
throw new SonyProjectorException(e.getMessage());
}
return responseMessage;
}

/**
* Open the connection with the projector if not yet opened
*
* @throws SonyProjectorException - In case of any problem
* @throws ConnectionException - In case of any problem
*/
public abstract void open() throws SonyProjectorException;
public abstract void open() throws ConnectionException;

/**
* Close the connection with the projector
Expand Down Expand Up @@ -1049,23 +1044,23 @@ public void close() {
* @param dataBuffer the buffer into which the data is read.
* @return the total number of bytes read into the buffer, or -1 if there is no more data because the end of the
* stream has been reached.
* @throws SonyProjectorException - If the input stream is null, if the first byte cannot be read for any reason
* @throws CommunicationException - If the input stream is null, if the first byte cannot be read for any reason
* other than the end of the file, if the input stream has been closed, or if some other I/O error
* occurs.
*/
protected int readInput(byte[] dataBuffer) throws SonyProjectorException {
protected int readInput(byte[] dataBuffer) throws CommunicationException {
if (simu) {
throw new SonyProjectorException("readInput failed: should not be called in simu mode");
throw new CommunicationException("readInput failed: should not be called in simu mode");
}
InputStream dataIn = this.dataIn;
if (dataIn == null) {
throw new SonyProjectorException("readInput failed: input stream is null");
throw new CommunicationException("readInput failed: input stream is null");
}
try {
return dataIn.read(dataBuffer);
} catch (IOException e) {
logger.debug("readInput failed: {}", e.getMessage());
throw new SonyProjectorException("readInput failed: " + e.getMessage());
throw new CommunicationException("readInput failed", e);
}
}

Expand All @@ -1074,23 +1069,23 @@ protected int readInput(byte[] dataBuffer) throws SonyProjectorException {
*
* @param message the buffer containing the message to be sent
*
* @throws SonyProjectorException - In case of any communication problem
* @throws CommunicationException - In case of any communication problem
*/
protected void writeCommand(byte[] message) throws SonyProjectorException {
protected void writeCommand(byte[] message) throws CommunicationException {
logger.debug("writeCommand: {}", HexUtils.bytesToHex(message));
if (simu) {
return;
}
OutputStream dataOut = this.dataOut;
if (dataOut == null) {
throw new SonyProjectorException("writeCommand failed: output stream is null");
throw new CommunicationException("writeCommand failed: output stream is null");
}
try {
dataOut.write(message);
dataOut.flush();
} catch (IOException e) {
logger.debug("writeCommand failed: {}", e.getMessage());
throw new SonyProjectorException("writeCommand failed: " + e.getMessage());
throw new CommunicationException("writeCommand failed", e);
}
}

Expand All @@ -1099,20 +1094,20 @@ protected void writeCommand(byte[] message) throws SonyProjectorException {
*
* @return the buffer containing the returned message
*
* @throws SonyProjectorException - In case of any communication problem
* @throws CommunicationException - In case of any communication problem
*/
protected abstract byte[] readResponse() throws SonyProjectorException;
protected abstract byte[] readResponse() throws CommunicationException;

/**
* Validate the content of a returned message
*
* @param responseMessage the buffer containing the returned message
* @param the projector setting to get or set
*
* @throws SonyProjectorException - If the message has unexpected content
* @throws CommunicationException - If the message has unexpected content
*/
protected abstract void validateResponse(byte[] responseMessage, SonyProjectorItem item)
throws SonyProjectorException;
throws CommunicationException;

/**
* Extract the value from the returned message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.openhab.binding.sonyprojector.internal.SonyProjectorModel;
import org.openhab.binding.sonyprojector.internal.communication.SonyProjectorConnector;
import org.openhab.binding.sonyprojector.internal.communication.SonyProjectorItem;
import org.openhab.core.i18n.CommunicationException;
import org.openhab.core.i18n.ConnectionException;
import org.openhab.core.util.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -114,7 +116,7 @@ public String getCommunity() {
}

@Override
public synchronized void open() throws SonyProjectorException {
public synchronized void open() throws ConnectionException {
if (!connected) {
logger.debug("Opening SDCP connection IP {} port {}", this.address, this.port);
try {
Expand All @@ -130,8 +132,7 @@ public synchronized void open() throws SonyProjectorException {

logger.debug("SDCP connection opened");
} catch (IOException | SecurityException | IllegalArgumentException e) {
logger.debug("Opening SDCP connection failed: {}", e.getMessage());
throw new SonyProjectorException("Opening SDCP connection failed: " + e.getMessage());
throw new ConnectionException("@text/exception.opening-sdcp-connection-failed", e);
}
}
}
Expand Down Expand Up @@ -181,28 +182,28 @@ protected byte[] buildMessage(SonyProjectorItem item, boolean getCommand, byte[]
* @param dataBuffer the buffer into which the data is read.
* @return the total number of bytes read into the buffer, or -1 if there is no more data because the end of the
* stream has been reached.
* @throws SonyProjectorException - If the input stream is null, if the first byte cannot be read for any reason
* @throws CommunicationException - If the input stream is null, if the first byte cannot be read for any reason
* other than the end of the file, if the input stream has been closed, or if some other I/O error
* occurs.
*/
@Override
protected int readInput(byte[] dataBuffer) throws SonyProjectorException {
protected int readInput(byte[] dataBuffer) throws CommunicationException {
InputStream dataIn = this.dataIn;
if (dataIn == null) {
throw new SonyProjectorException("readInput failed: input stream is null");
throw new CommunicationException("readInput failed: input stream is null");
}
try {
return dataIn.read(dataBuffer);
} catch (SocketTimeoutException e) {
return 0;
} catch (IOException e) {
logger.debug("readInput failed: {}", e.getMessage());
throw new SonyProjectorException("readInput failed: " + e.getMessage());
throw new CommunicationException("readInput failed", e);
}
}

@Override
protected synchronized byte[] readResponse() throws SonyProjectorException {
protected synchronized byte[] readResponse() throws CommunicationException {
logger.debug("readResponse (timeout = {} ms)...", READ_TIMEOUT_MS);
byte[] message = new byte[MSG_MAX_SIZE];
boolean timeout = false;
Expand All @@ -222,53 +223,53 @@ protected synchronized byte[] readResponse() throws SonyProjectorException {
}
if ((count < MSG_MIN_SIZE) && timeout) {
logger.debug("readResponse timeout: only {} bytes read after {} ms", count, READ_TIMEOUT_MS);
throw new SonyProjectorException("readResponse failed: timeout");
throw new CommunicationException("readResponse failed: timeout");
}
logger.debug("readResponse: {}", HexUtils.bytesToHex(message));
if (count < MSG_MIN_SIZE) {
logger.debug("readResponse: unexpected response data length: {}", count);
throw new SonyProjectorException("Unexpected response data length");
throw new CommunicationException("Unexpected response data length");
}
return message;
}

@Override
protected void validateResponse(byte[] responseMessage, SonyProjectorItem item) throws SonyProjectorException {
protected void validateResponse(byte[] responseMessage, SonyProjectorItem item) throws CommunicationException {
// Check response size
if (responseMessage.length < MSG_MIN_SIZE) {
logger.debug("Unexpected response data length: {}", responseMessage.length);
throw new SonyProjectorException("Unexpected response data length");
throw new CommunicationException("Unexpected response data length");
}

// Header should be a sony projector header
byte[] headerMsg = Arrays.copyOf(responseMessage, HEADER.length);
if (!Arrays.equals(headerMsg, HEADER)) {
logger.debug("Unexpected HEADER in response: {} rather than {}", HexUtils.bytesToHex(headerMsg),
HexUtils.bytesToHex(HEADER));
throw new SonyProjectorException("Unexpected HEADER in response");
throw new CommunicationException("Unexpected HEADER in response");
}

// Community should be the same as used for sending
byte[] communityResponseMsg = Arrays.copyOfRange(responseMessage, 2, 6);
if (!Arrays.equals(communityResponseMsg, community.getBytes())) {
logger.debug("Unexpected community in response: {} rather than {}",
HexUtils.bytesToHex(communityResponseMsg), HexUtils.bytesToHex(community.getBytes()));
throw new SonyProjectorException("Unexpected community in response");
throw new CommunicationException("Unexpected community in response");
}

// Item number should be the same as used for sending
byte[] itemResponseMsg = Arrays.copyOfRange(responseMessage, 7, 9);
if (!Arrays.equals(itemResponseMsg, item.getCode())) {
logger.debug("Unexpected item number in response: {} rather than {}", HexUtils.bytesToHex(itemResponseMsg),
HexUtils.bytesToHex(item.getCode()));
throw new SonyProjectorException("Unexpected item number in response");
throw new CommunicationException("Unexpected item number in response");
}

// Check response size
int dataLength = responseMessage[9] & 0x000000FF;
if (responseMessage.length < (10 + dataLength)) {
logger.debug("Unexpected response data length: {}", dataLength);
throw new SonyProjectorException("Unexpected response data length");
throw new CommunicationException("Unexpected response data length");
}

// byte 7 is expected to be 1, which indicates that the request was successful
Expand All @@ -279,11 +280,11 @@ protected void validateResponse(byte[] responseMessage, SonyProjectorItem item)
try {
SonyProjectorSdcpError error = SonyProjectorSdcpError.getFromDataCode(errorCode);
msg = error.getMessage();
} catch (SonyProjectorException e) {
} catch (CommunicationException e) {
}
}
logger.debug("{} received in response", msg);
throw new SonyProjectorException(msg + " received in response");
throw new CommunicationException(msg + " received in response");
}
}

Expand Down
Loading

0 comments on commit 5d57908

Please sign in to comment.