diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/discovery/SqueezeBoxPlayerDiscoveryParticipant.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/discovery/SqueezeBoxPlayerDiscoveryParticipant.java index 265ae2febe01b..ed80853301977 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/discovery/SqueezeBoxPlayerDiscoveryParticipant.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/discovery/SqueezeBoxPlayerDiscoveryParticipant.java @@ -8,7 +8,7 @@ */ package org.openhab.binding.squeezebox.discovery; -import static org.openhab.binding.squeezebox.SqueezeBoxBindingConstants.*; +import static org.openhab.binding.squeezebox.SqueezeBoxBindingConstants.SQUEEZEBOXPLAYER_THING_TYPE; import java.util.HashMap; import java.util.Map; @@ -29,148 +29,160 @@ /** * When a {@link SqueezeBoxServerHandler} finds a new SqueezeBox Player we will * add it to the system. - * + * * @author Dan Cunningham + * @author Mark Hilbush - added method to cancel request player job, and to set thing properties * */ public class SqueezeBoxPlayerDiscoveryParticipant extends AbstractDiscoveryService - implements SqueezeBoxPlayerEventListener { - private final Logger logger = LoggerFactory - .getLogger(SqueezeBoxPlayerDiscoveryParticipant.class); - - private final static int TIMEOUT = 60; - private final static int TTL = 60; - - private SqueezeBoxServerHandler squeezeBoxServerHandler; - private ScheduledFuture requestPlayerJob; - - /** - * Discovers SqueezeBox Players attached to a SqueezeBox Server - * - * @param squeezeBoxServerHandler - */ - public SqueezeBoxPlayerDiscoveryParticipant( - SqueezeBoxServerHandler squeezeBoxServerHandler) { - super(SqueezeBoxPlayerHandler.SUPPORTED_THING_TYPES_UIDS, TIMEOUT, true); - this.squeezeBoxServerHandler = squeezeBoxServerHandler; - setupRequestPlayerJob(); - } - - @Override - protected void startScan() { - this.squeezeBoxServerHandler.requestPlayers(); - } - - @Override - protected void startBackgroundDiscovery() { - this.squeezeBoxServerHandler.requestPlayers(); - }; - - @Override - protected void deactivate() { - super.deactivate(); - if (requestPlayerJob != null) { - requestPlayerJob.cancel(true); - requestPlayerJob = null; - } - } - - @Override - public void playerAdded(SqueezeBoxPlayer player) { - logger.debug("Player added {} {} ", player.getMacAddress(), - player.getName()); - ThingUID bridgeUID = squeezeBoxServerHandler.getThing().getUID(); - ThingUID thingUID = new ThingUID(SQUEEZEBOXPLAYER_THING_TYPE, - bridgeUID, player.getMacAddress().replace(":", "")); - Map properties = new HashMap<>(1); - properties.put("mac", player.getMacAddress()); - DiscoveryResult discoveryResult = DiscoveryResultBuilder - .create(thingUID).withProperties(properties) - .withBridge(bridgeUID) - .withLabel(player.getName()).build(); - thingDiscovered(discoveryResult); - - } - - /** - * Tells the bridge to request a list of players - */ - private void setupRequestPlayerJob() { - Runnable runnable = new Runnable() { - public void run() { - squeezeBoxServerHandler.requestPlayers(); - } - }; - requestPlayerJob = scheduler.scheduleWithFixedDelay(runnable, 10, TTL, - TimeUnit.SECONDS); - } - - // we can ignore the other events - @Override - public void powerChangeEvent(String mac, boolean power) { - } - - @Override - public void modeChangeEvent(String mac, String mode) { - } - - @Override - public void volumeChangeEvent(String mac, int volume) { - } - - @Override - public void muteChangeEvent(String mac, boolean mute) { - } - - @Override - public void currentPlaylistIndexEvent(String mac, int index) { - } - - @Override - public void currentPlayingTimeEvent(String mac, int time) { - } - - @Override - public void numberPlaylistTracksEvent(String mac, int track) { - } - - @Override - public void currentPlaylistShuffleEvent(String mac, int shuffle) { - } - - @Override - public void currentPlaylistRepeatEvent(String mac, int repeat) { - } - - @Override - public void titleChangeEvent(String mac, String title) { - } - - @Override - public void albumChangeEvent(String mac, String album) { - } - - @Override - public void artistChangeEvent(String mac, String artist) { - } - - @Override - public void coverArtChangeEvent(String mac, String coverArtUrl) { - } - - @Override - public void yearChangeEvent(String mac, String year) { - } - - @Override - public void genreChangeEvent(String mac, String genre) { - } - - @Override - public void remoteTitleChangeEvent(String mac, String title) { - } - - @Override - public void irCodeChangeEvent(String mac, String ircode) { - } + implements SqueezeBoxPlayerEventListener { + private final Logger logger = LoggerFactory.getLogger(SqueezeBoxPlayerDiscoveryParticipant.class); + + private final static int TIMEOUT = 60; + private final static int TTL = 60; + + private SqueezeBoxServerHandler squeezeBoxServerHandler; + private ScheduledFuture requestPlayerJob; + + /** + * Discovers SqueezeBox Players attached to a SqueezeBox Server + * + * @param squeezeBoxServerHandler + */ + public SqueezeBoxPlayerDiscoveryParticipant(SqueezeBoxServerHandler squeezeBoxServerHandler) { + super(SqueezeBoxPlayerHandler.SUPPORTED_THING_TYPES_UIDS, TIMEOUT, true); + this.squeezeBoxServerHandler = squeezeBoxServerHandler; + setupRequestPlayerJob(); + } + + @Override + protected void startScan() { + logger.debug("startScan invoked in SqueezeBoxPlayerDiscoveryParticipant"); + this.squeezeBoxServerHandler.requestPlayers(); + } + + /* + * Allows request player job to be canceled when server handler is removed + */ + public void cancelRequestPlayerJob() { + logger.debug("canceling RequestPlayerJob"); + if (requestPlayerJob != null) { + requestPlayerJob.cancel(true); + requestPlayerJob = null; + } + } + + @Override + public void playerAdded(SqueezeBoxPlayer player) { + ThingUID bridgeUID = squeezeBoxServerHandler.getThing().getUID(); + + ThingUID thingUID = new ThingUID(SQUEEZEBOXPLAYER_THING_TYPE, bridgeUID, + player.getMacAddress().replace(":", "")); + + if (!playerThingExists(thingUID)) { + logger.debug("player added {} : {} ", player.getMacAddress(), player.getName()); + + Map properties = new HashMap<>(1); + properties.put("mac", player.getMacAddress()); + + // Added other properties + properties.put("modelId", player.getModel()); + properties.put("name", player.getName()); + properties.put("uid", player.getUuid()); + properties.put("ip", player.getIpAddr()); + + DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties) + .withBridge(bridgeUID).withLabel(player.getName()).build(); + + thingDiscovered(discoveryResult); + } + } + + private boolean playerThingExists(ThingUID newThingUID) { + return squeezeBoxServerHandler.getThingByUID(newThingUID) != null ? true : false; + } + + /** + * Tells the bridge to request a list of players + */ + private void setupRequestPlayerJob() { + Runnable runnable = new Runnable() { + @Override + public void run() { + squeezeBoxServerHandler.requestPlayers(); + } + }; + + logger.debug("request player job scheduled to run every {} seconds", TTL); + requestPlayerJob = scheduler.scheduleWithFixedDelay(runnable, 10, TTL, TimeUnit.SECONDS); + } + + // we can ignore the other events + @Override + public void powerChangeEvent(String mac, boolean power) { + } + + @Override + public void modeChangeEvent(String mac, String mode) { + } + + @Override + public void volumeChangeEvent(String mac, int volume) { + } + + @Override + public void muteChangeEvent(String mac, boolean mute) { + } + + @Override + public void currentPlaylistIndexEvent(String mac, int index) { + } + + @Override + public void currentPlayingTimeEvent(String mac, int time) { + } + + @Override + public void numberPlaylistTracksEvent(String mac, int track) { + } + + @Override + public void currentPlaylistShuffleEvent(String mac, int shuffle) { + } + + @Override + public void currentPlaylistRepeatEvent(String mac, int repeat) { + } + + @Override + public void titleChangeEvent(String mac, String title) { + } + + @Override + public void albumChangeEvent(String mac, String album) { + } + + @Override + public void artistChangeEvent(String mac, String artist) { + } + + @Override + public void coverArtChangeEvent(String mac, String coverArtUrl) { + } + + @Override + public void yearChangeEvent(String mac, String year) { + } + + @Override + public void genreChangeEvent(String mac, String genre) { + } + + @Override + public void remoteTitleChangeEvent(String mac, String title) { + } + + @Override + public void irCodeChangeEvent(String mac, String ircode) { + } } diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java index 2da0bb464ad38..3f52a73f05198 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxPlayerHandler.java @@ -18,7 +18,6 @@ import java.util.concurrent.TimeUnit; import org.apache.commons.lang.StringUtils; -import org.eclipse.smarthome.config.core.Configuration; import org.eclipse.smarthome.core.library.types.DecimalType; import org.eclipse.smarthome.core.library.types.IncreaseDecreaseType; import org.eclipse.smarthome.core.library.types.NextPreviousType; @@ -32,10 +31,12 @@ import org.eclipse.smarthome.core.thing.ChannelUID; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.thing.ThingStatus; +import org.eclipse.smarthome.core.thing.ThingStatusInfo; import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.binding.BaseThingHandler; import org.eclipse.smarthome.core.thing.binding.ThingHandler; import org.eclipse.smarthome.core.types.Command; +import org.eclipse.smarthome.core.types.RefreshType; import org.eclipse.smarthome.core.types.State; import org.openhab.binding.squeezebox.config.SqueezeBoxPlayerConfig; import org.openhab.binding.squeezebox.internal.utils.HttpUtils; @@ -47,6 +48,7 @@ * are sent to/from channels. * * @author Dan Cunningham - Initial contribution + * @author Mark Hilbush - Improved handling of player status, prevent REFRESH from causing exception */ public class SqueezeBoxPlayerHandler extends BaseThingHandler implements SqueezeBoxPlayerEventListener { @@ -106,20 +108,45 @@ public SqueezeBoxPlayerHandler(Thing thing) { public void initialize() { mac = getConfig().as(SqueezeBoxPlayerConfig.class).mac; timeCounter(); - }; + + SqueezeBoxServerHandler bridgeHandler = getBridgeHandler(); + if (bridgeHandler != null) { + logger.debug("updating player status to match server status of {}", bridgeHandler.getThing().getStatus()); + updateStatus(bridgeHandler.getThing().getStatus()); + } + } + + private SqueezeBoxServerHandler getBridgeHandler() { + SqueezeBoxServerHandler bridgeHandler = null; + Thing bridge = getBridge(); + if (bridge != null) { + bridgeHandler = (SqueezeBoxServerHandler) bridge.getHandler(); + } + return bridgeHandler; + } @Override public void bridgeHandlerInitialized(ThingHandler thingHandler, Bridge bridge) { if (thingHandler instanceof SqueezeBoxServerHandler) { this.squeezeBoxServerHandler = (SqueezeBoxServerHandler) thingHandler; updateStatus(ThingStatus.ONLINE); - logger.debug("bridgeHandlerInitialized for player mac {}", mac); + logger.debug("bridgeHandlerInitialized: updating status of player {} to ONLINE", mac); } } @Override public void bridgeHandlerDisposed(ThingHandler thingHandler, Bridge bridge) { + // Mark the player OFFLINE + updateStatus(ThingStatus.OFFLINE); this.squeezeBoxServerHandler = null; + logger.debug("bridgeHandlerDisposed: updating status of player {} to OFFLINE", mac); + } + + @Override + public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { + // Change player status to match the server status + updateStatus(bridgeStatusInfo.getStatus()); + logger.debug("bridgeStatusChanged: updating status of player {} to {}", mac, bridgeStatusInfo.getStatus()); } @Override @@ -134,17 +161,23 @@ public void dispose() { if (squeezeBoxServerHandler != null) { squeezeBoxServerHandler.removePlayerCache(mac); } - logger.debug("Thing {} disposed.", getThing().getUID()); + logger.debug("player thing {} disposed.", getThing().getUID()); super.dispose(); } @Override public void handleCommand(ChannelUID channelUID, Command command) { if (squeezeBoxServerHandler == null) { - logger.warn("Player has no server configured, ignoring command"); + logger.info("player thing {} has no server configured, ignoring command: {}", getThing().getUID(), command); return; } String mac = getConfigAs(SqueezeBoxPlayerConfig.class).mac; + + // Some of the code below is not designed to handle REFRESH + if (command == RefreshType.REFRESH) { + return; + } + switch (channelUID.getIdWithoutGroup()) { case CHANNEL_POWER: if (command.equals(OnOffType.ON)) { @@ -229,6 +262,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { } else { squeezeBoxServerHandler.syncPlayer(mac, command.toString()); } + break; case CHANNEL_UNSYNC: if (command.equals(OnOffType.ON)) { squeezeBoxServerHandler.unSyncPlayer(mac); @@ -253,14 +287,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { @Override public void playerAdded(SqueezeBoxPlayer player) { - if (isMe(player.getMacAddress())) { - Configuration configuration = editConfiguration(); - configuration.put("modelId", player.getModel()); - configuration.put("name", player.getName()); - configuration.put("uid", player.getUuid()); - configuration.put("ip", player.getIpAddr()); - // updateConfiguration(configuration); - } + // Player properties are saved in SqueezeBoxPlayerDiscoveryParticipant } @Override diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java index 674cd29231d8a..869d9906c4316 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/handler/SqueezeBoxServerHandler.java @@ -48,6 +48,7 @@ * @author Ben Jones * @author Dan Cunningham (OH2 Port) * @author Daniel Walters - Fix player discovery when player name contains spaces + * @author Mark Hilbush - Improve reconnect logic. Improve player status updates. */ public class SqueezeBoxServerHandler extends BaseBridgeHandler { private Logger logger = LoggerFactory.getLogger(SqueezeBoxServerHandler.class); @@ -84,6 +85,8 @@ public SqueezeBoxServerHandler(Bridge bridge) { @Override public void initialize() { + logger.debug("initializing server handler for thing {}", getThing()); + scheduler.schedule(new Runnable() { @Override @@ -91,13 +94,14 @@ public void run() { connect(); } }, 0, TimeUnit.SECONDS); - }; + } @Override public void dispose() { + logger.debug("disposing server handler for thing {}", getThing()); cancelReconnect(); disconnect(); - }; + } @Override public void handleCommand(ChannelUID channelUID, Command command) { @@ -267,13 +271,10 @@ private synchronized void sendCommand(String command) { } if (!isConnected()) { - logger.debug("No connection to SqueezeServer, will attempt to reconnect now..."); - connect(); - if (!isConnected()) { - logger.error("Failed to reconnect to SqueezeServer, unable to send command {}", command); - return; - } + logger.debug("no connection to squeeze server when trying to send command, returning..."); + return; } + logger.debug("Sending command: {}", command); try { BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())); @@ -288,6 +289,7 @@ private synchronized void sendCommand(String command) { * Connects to a SqueezeBox Server */ private void connect() { + logger.trace("attempting to get a connection to the server"); disconnect(); SqueezeBoxServerConfig config = getConfigAs(SqueezeBoxServerConfig.class); this.host = config.ipAddress; @@ -301,17 +303,23 @@ private void connect() { try { clientSocket = new Socket(host, cliport); } catch (IOException e) { + logger.debug("unable to open socket to server: {}", e.getMessage()); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage()); + scheduleReconnect(); return; } try { listener = new SqueezeServerListener(); listener.start(); - logger.info("Squeeze Server connection started to server " + this.host); + logger.debug("listener connection started to server {}:{}", host, cliport); } catch (IllegalThreadStateException e) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); } + + // Mark the server ONLINE. bridgeStatusChanged will cause the players to come ONLINE + updateStatus(ThingStatus.ONLINE); + } /** @@ -344,22 +352,25 @@ public SqueezeServerListener() { } public void terminate() { - logger.debug("Squeeze Server listener being terminated"); + logger.debug("setting squeeze server listener terminate flag"); this.terminate = true; } @Override public void run() { BufferedReader reader = null; + boolean endOfStream = false; + try { reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); updateStatus(ThingStatus.ONLINE); requestPlayers(); sendCommand("listen 1"); - String message; + String message = null; while (!terminate && (message = reader.readLine()) != null) { - logger.debug("Message received: {}", message); + // Message is very long and frequent; only show when running at trace level logging + logger.trace("Message received: {}", message); if (message.startsWith("listen 1")) { continue; @@ -371,8 +382,12 @@ public void run() { handlePlayerUpdate(message); } } + if (message == null) { + endOfStream = true; + } } catch (IOException e) { if (!terminate) { + logger.warn("failed to read line from squeeze server socket: {}", e.getMessage()); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); scheduleReconnect(); } @@ -387,6 +402,14 @@ public void run() { } } + // check for end of stream from readLine + if (endOfStream == true && !terminate) { + logger.info("end of stream received from socket during readLine"); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, + "end of stream on socket read"); + scheduleReconnect(); + } + logger.debug("Squeeze Server listener exiting."); } @@ -425,11 +448,6 @@ private void handlePlayersList(String message) { continue; } - // if we already know about it, ignore this set of params - if (players.containsKey(macAddress)) { - continue; - } - final SqueezeBoxPlayer player = new SqueezeBoxPlayer(); player.setMacAddress(macAddress); // populate the player state @@ -445,17 +463,20 @@ private void handlePlayersList(String message) { } } - players.put(macAddress, player); + // Save player if we haven't seen it yet + if (!players.containsKey(macAddress)) { + players.put(macAddress, player); - updatePlayer(new PlayerUpdateEvent() { - @Override - public void updateListener(SqueezeBoxPlayerEventListener listener) { - listener.playerAdded(player); - } - }); + updatePlayer(new PlayerUpdateEvent() { + @Override + public void updateListener(SqueezeBoxPlayerEventListener listener) { + listener.playerAdded(player); + } + }); - // tell the server we want to subscribe to player updates - sendCommand(player.getMacAddress() + " status - 1 subscribe:10 tags:yagJlN"); + // tell the server we want to subscribe to player updates + sendCommand(player.getMacAddress() + " status - 1 subscribe:10 tags:yagJlN"); + } } } @@ -491,8 +512,8 @@ public void updateListener(SqueezeBoxPlayerEventListener listener) { } else if (messageType.equals("play") || messageType.equals("pause") || messageType.equals("stop")) { // ignore these for now // player.setMode(Mode.valueOf(messageType)); - } else - if (messageType.equals("mixer") || messageType.equals("menustatus") || messageType.equals("button")) { + } else if (messageType.equals("mixer") || messageType.equals("menustatus") + || messageType.equals("button")) { // ignore these for now } else { logger.debug("Unhandled message type '{}'. Ignoring.", messageType); @@ -767,6 +788,7 @@ private void updatePlayer(PlayerUpdateEvent event) { * @return */ public boolean registerSqueezeBoxPlayerListener(SqueezeBoxPlayerEventListener squeezeBoxPlayerListener) { + logger.debug("registering player listener"); return squeezeBoxPlayerListeners.add(squeezeBoxPlayerListener); } @@ -777,6 +799,7 @@ public boolean registerSqueezeBoxPlayerListener(SqueezeBoxPlayerEventListener sq * @return */ public boolean unregisterSqueezeBoxPlayerListener(SqueezeBoxPlayerEventListener squeezeBoxPlayerListener) { + logger.debug("unregistering player listener"); return squeezeBoxPlayerListeners.remove(squeezeBoxPlayerListener); } @@ -794,6 +817,7 @@ public void removePlayerCache(String mac) { * Schedule the server to try and reconnect */ private void scheduleReconnect() { + logger.debug("scheduling squeeze server reconnect in {} seconds", RECONNECT_TIME); cancelReconnect(); reconnectFuture = scheduler.schedule(new Runnable() { @Override diff --git a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxHandlerFactory.java b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxHandlerFactory.java index 112d412d1b879..3c575b7f08781 100644 --- a/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxHandlerFactory.java +++ b/addons/binding/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxHandlerFactory.java @@ -15,12 +15,6 @@ import java.util.Map; import java.util.Set; -import org.openhab.binding.squeezebox.discovery.SqueezeBoxPlayerDiscoveryParticipant; -import org.openhab.binding.squeezebox.handler.SqueezeBoxPlayerHandler; -import org.openhab.binding.squeezebox.handler.SqueezeBoxServerHandler; -import org.osgi.framework.ServiceRegistration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.eclipse.smarthome.config.discovery.DiscoveryService; import org.eclipse.smarthome.core.thing.Bridge; import org.eclipse.smarthome.core.thing.Thing; @@ -28,14 +22,22 @@ import org.eclipse.smarthome.core.thing.ThingUID; import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory; import org.eclipse.smarthome.core.thing.binding.ThingHandler; +import org.openhab.binding.squeezebox.discovery.SqueezeBoxPlayerDiscoveryParticipant; +import org.openhab.binding.squeezebox.handler.SqueezeBoxPlayerEventListener; +import org.openhab.binding.squeezebox.handler.SqueezeBoxPlayerHandler; +import org.openhab.binding.squeezebox.handler.SqueezeBoxServerHandler; +import org.osgi.framework.ServiceRegistration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.collect.Sets; /** * The {@link SqueezeBoxHandlerFactory} is responsible for creating things and * thing handlers. - * + * * @author Dan Cunningham - Initial contribution + * @author Mark Hilbush - Cancel request player job when handler removed */ public class SqueezeBoxHandlerFactory extends BaseThingHandlerFactory { @@ -55,15 +57,16 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { protected ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); - if (thingTypeUID.equals(SQUEEZEBOXPLAYER_THING_TYPE)) { - return new SqueezeBoxPlayerHandler(thing); + if (thingTypeUID.equals(SQUEEZEBOXSERVER_THING_TYPE)) { + logger.trace("creating handler for bridge thing {}", thing); + SqueezeBoxServerHandler bridge = new SqueezeBoxServerHandler((Bridge) thing); + registerSqueezeBoxPlayerDiscoveryService(bridge); + return bridge; } - if (thingTypeUID.equals(SQUEEZEBOXSERVER_THING_TYPE)) { - logger.trace("Returning handler for bridge thing {}", thing); - SqueezeBoxServerHandler handler = new SqueezeBoxServerHandler((Bridge) thing); - registerSqueezeBoxPlayerDiscoveryService(handler); - return handler; + if (thingTypeUID.equals(SQUEEZEBOXPLAYER_THING_TYPE)) { + logger.trace("creating handler for player thing {}", thing); + return new SqueezeBoxPlayerHandler(thing); } return null; @@ -72,29 +75,55 @@ protected ThingHandler createHandler(Thing thing) { /** * Adds SqueezeBoxServerHandlers to the discovery service to find SqueezeBox * Players - * + * * @param squeezeBoxServerHandler */ - private synchronized void registerSqueezeBoxPlayerDiscoveryService(SqueezeBoxServerHandler squeezeBoxServerHandler) { + private synchronized void registerSqueezeBoxPlayerDiscoveryService( + SqueezeBoxServerHandler squeezeBoxServerHandler) { + logger.trace("registering player discovery service"); + SqueezeBoxPlayerDiscoveryParticipant discoveryService = new SqueezeBoxPlayerDiscoveryParticipant( squeezeBoxServerHandler); + + // Register the PlayerListener with the SqueezeBoxServerHandler squeezeBoxServerHandler.registerSqueezeBoxPlayerListener(discoveryService); - this.discoveryServiceRegs.put(squeezeBoxServerHandler.getThing().getUID(), bundleContext.registerService( - DiscoveryService.class.getName(), discoveryService, new Hashtable())); + + // Register the service, then add the service to the ServiceRegistration map + discoveryServiceRegs.put(squeezeBoxServerHandler.getThing().getUID(), bundleContext + .registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable())); } @Override protected synchronized void removeHandler(ThingHandler thingHandler) { + if (thingHandler instanceof SqueezeBoxServerHandler) { + logger.trace("removing handler for bridge thing {}", thingHandler.getThing()); + ServiceRegistration serviceReg = this.discoveryServiceRegs.get(thingHandler.getThing().getUID()); if (serviceReg != null) { + logger.trace("unregistering player discovery service"); + + // Get the discovery service object and use it to cancel the RequestPlayerJob + SqueezeBoxPlayerDiscoveryParticipant discoveryService = (SqueezeBoxPlayerDiscoveryParticipant) bundleContext + .getService(serviceReg.getReference()); + discoveryService.cancelRequestPlayerJob(); + + // Unregister the PlayerListener from the SqueezeBoxServerHandler + ((SqueezeBoxServerHandler) thingHandler).unregisterSqueezeBoxPlayerListener( + (SqueezeBoxPlayerEventListener) bundleContext.getService(serviceReg.getReference())); + + // Unregister the PlayerListener service serviceReg.unregister(); + + // Remove the service from the ServiceRegistration map discoveryServiceRegs.remove(thingHandler.getThing().getUID()); } } + if (thingHandler instanceof SqueezeBoxPlayerHandler) { SqueezeBoxServerHandler bridge = ((SqueezeBoxPlayerHandler) thingHandler).getSqueezeBoxServerHandler(); if (bridge != null) { + logger.trace("removing handler for player thing {}", thingHandler.getThing()); bridge.removePlayerCache(((SqueezeBoxPlayerHandler) thingHandler).getMac()); } }