]> git.basschouten.com Git - openhab-addons.git/blob
bc75454f6b99307d745a729a0be4da31b77484c2
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.allplay.internal;
14
15 import static org.openhab.binding.allplay.internal.AllPlayBindingConstants.SPEAKER_THING_TYPE;
16
17 import java.util.Collections;
18 import java.util.Dictionary;
19 import java.util.Hashtable;
20 import java.util.Map;
21 import java.util.Set;
22 import java.util.concurrent.ConcurrentHashMap;
23
24 import org.openhab.binding.allplay.internal.handler.AllPlayHandler;
25 import org.openhab.core.audio.AudioHTTPServer;
26 import org.openhab.core.audio.AudioSink;
27 import org.openhab.core.net.HttpServiceUtil;
28 import org.openhab.core.net.NetworkAddressService;
29 import org.openhab.core.thing.Thing;
30 import org.openhab.core.thing.ThingRegistry;
31 import org.openhab.core.thing.ThingTypeUID;
32 import org.openhab.core.thing.binding.BaseThingHandlerFactory;
33 import org.openhab.core.thing.binding.ThingHandler;
34 import org.openhab.core.thing.binding.ThingHandlerFactory;
35 import org.osgi.framework.ServiceRegistration;
36 import org.osgi.service.component.ComponentContext;
37 import org.osgi.service.component.annotations.Activate;
38 import org.osgi.service.component.annotations.Component;
39 import org.osgi.service.component.annotations.Reference;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 import de.kaizencode.tchaikovsky.AllPlay;
44 import de.kaizencode.tchaikovsky.exception.AllPlayException;
45
46 /**
47  * The {@link AllPlayHandlerFactory} is responsible for creating things and thing
48  * handlers.
49  *
50  * @author Dominic Lerbs - Initial contribution
51  */
52 @Component(service = ThingHandlerFactory.class, configurationPid = "binding.allplay")
53 public class AllPlayHandlerFactory extends BaseThingHandlerFactory {
54
55     private final Logger logger = LoggerFactory.getLogger(AllPlayHandlerFactory.class);
56
57     private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(SPEAKER_THING_TYPE);
58     private final Map<String, ServiceRegistration<AudioSink>> audioSinkRegistrations = new ConcurrentHashMap<>();
59
60     private AllPlay allPlay;
61     private AllPlayBindingProperties bindingProperties;
62
63     // Bindings should not use the ThingRegistry! See https://github.com/openhab/openhab-addons/pull/6080 and
64     // https://github.com/eclipse/smarthome/issues/5182
65     private final ThingRegistry thingRegistry;
66     private final AudioHTTPServer audioHTTPServer;
67     private final NetworkAddressService networkAddressService;
68     private String callbackUrl;
69
70     @Activate
71     public AllPlayHandlerFactory(final @Reference ThingRegistry thingRegistry,
72             final @Reference AudioHTTPServer audioHTTPServer,
73             final @Reference NetworkAddressService networkAddressService) {
74         this.thingRegistry = thingRegistry;
75         this.audioHTTPServer = audioHTTPServer;
76         this.networkAddressService = networkAddressService;
77     }
78
79     @Override
80     public boolean supportsThingType(ThingTypeUID thingTypeUID) {
81         return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
82     }
83
84     @Override
85     protected ThingHandler createHandler(Thing thing) {
86         ThingTypeUID thingTypeUID = thing.getThingTypeUID();
87         if (thingTypeUID.equals(SPEAKER_THING_TYPE)) {
88             logger.debug("Creating AllPlayHandler for thing {}", thing.getUID());
89
90             AllPlayHandler handler = new AllPlayHandler(thingRegistry, thing, allPlay, bindingProperties);
91             registerAudioSink(thing, handler);
92
93             return handler;
94         }
95         return null;
96     }
97
98     private void registerAudioSink(Thing thing, AllPlayHandler handler) {
99         AllPlayAudioSink audioSink = new AllPlayAudioSink(handler, audioHTTPServer, callbackUrl);
100         @SuppressWarnings("unchecked")
101         ServiceRegistration<AudioSink> reg = (ServiceRegistration<AudioSink>) bundleContext
102                 .registerService(AudioSink.class.getName(), audioSink, new Hashtable<>());
103         audioSinkRegistrations.put(thing.getUID().toString(), reg);
104     }
105
106     @Override
107     public void unregisterHandler(Thing thing) {
108         super.unregisterHandler(thing);
109         unregisterAudioSink(thing);
110     }
111
112     private void unregisterAudioSink(Thing thing) {
113         ServiceRegistration<AudioSink> reg = audioSinkRegistrations.get(thing.getUID().toString());
114         if (reg != null) {
115             reg.unregister();
116         }
117     }
118
119     @Override
120     protected void activate(ComponentContext componentContext) {
121         super.activate(componentContext);
122         logger.debug("Activating AllPlayHandlerFactory");
123         allPlay = new AllPlay("openHAB2");
124         try {
125             logger.debug("Connecting to AllPlay");
126             allPlay.connect();
127         } catch (AllPlayException e) {
128             logger.error("Cannot initialize AllPlay", e);
129         }
130         Dictionary<String, Object> properties = componentContext.getProperties();
131         bindingProperties = new AllPlayBindingProperties(properties);
132         callbackUrl = assembleCallbackUrl();
133     }
134
135     @Override
136     protected void deactivate(ComponentContext componentContext) {
137         logger.debug("Deactivating AllPlayHandlerFactory");
138         allPlay.disconnect();
139         allPlay = null;
140         super.deactivate(componentContext);
141     }
142
143     private String assembleCallbackUrl() {
144         String callbackUrl = bindingProperties.getCallbackUrl();
145         if (callbackUrl == null) {
146             String ipAddress = networkAddressService.getPrimaryIpv4HostAddress();
147             if (ipAddress == null) {
148                 logger.warn("No network interface could be found.");
149                 return null;
150             }
151             // we do not use SSL as it can cause certificate validation issues.
152             final int port = HttpServiceUtil.getHttpServicePort(bundleContext);
153             if (port == -1) {
154                 logger.warn("Cannot find port of the http service.");
155                 return null;
156             }
157             callbackUrl = "http://" + ipAddress + ":" + port;
158         }
159         return callbackUrl;
160     }
161 }