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.ogema.drivers.homematic.xmlrpc.hl.HmConnection Maven / Gradle / Ivy
/**
* Copyright 2011-2019 Fraunhofer-Gesellschaft zur Förderung der angewandten Wissenschaften e.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ogema.drivers.homematic.xmlrpc.hl;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.MalformedURLException;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.apache.xmlrpc.XmlRpcException;
import org.ogema.core.application.ApplicationManager;
import org.ogema.core.model.Resource;
import org.ogema.core.model.ResourceList;
import org.ogema.core.model.simple.BooleanResource;
import org.ogema.core.model.simple.StringResource;
import org.ogema.core.resourcemanager.ResourceDemandListener;
import org.ogema.core.resourcemanager.ResourceValueListener;
import org.ogema.drivers.homematic.xmlrpc.hl.api.DeviceHandler;
import org.ogema.drivers.homematic.xmlrpc.hl.api.DeviceHandlerFactory;
import org.ogema.drivers.homematic.xmlrpc.hl.api.HomeMaticConnection;
import org.ogema.drivers.homematic.xmlrpc.hl.channels.KeyChannel;
import org.ogema.drivers.homematic.xmlrpc.hl.channels.MaintenanceChannel;
import org.ogema.drivers.homematic.xmlrpc.hl.channels.MotionDetectorChannel;
import org.ogema.drivers.homematic.xmlrpc.hl.channels.PMSwitchDevice;
import org.ogema.drivers.homematic.xmlrpc.hl.channels.PowerMeterChannel;
import org.ogema.drivers.homematic.xmlrpc.hl.channels.ShutterContactChannel;
import org.ogema.drivers.homematic.xmlrpc.hl.channels.SwitchChannel;
import org.ogema.drivers.homematic.xmlrpc.hl.channels.ThermostatChannel;
import org.ogema.drivers.homematic.xmlrpc.hl.channels.WeatherChannel;
import org.ogema.drivers.homematic.xmlrpc.hl.discovery.Ccu;
import org.ogema.drivers.homematic.xmlrpc.hl.discovery.UdpDiscovery;
import org.ogema.drivers.homematic.xmlrpc.hl.types.HmDevice;
import org.ogema.drivers.homematic.xmlrpc.hl.types.HmLogicInterface;
import org.ogema.drivers.homematic.xmlrpc.ll.HomeMaticClient;
import org.ogema.drivers.homematic.xmlrpc.ll.HomeMaticClientCli;
import org.ogema.drivers.homematic.xmlrpc.ll.HomeMaticService;
import org.ogema.drivers.homematic.xmlrpc.ll.api.HmEvent;
import org.ogema.drivers.homematic.xmlrpc.ll.api.HmEventListener;
import org.ogema.drivers.homematic.xmlrpc.ll.api.HomeMatic;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.event.EventAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HmConnection implements HomeMaticConnection {
private final ApplicationManager appman;
// private final EventAdmin eventAdmin;
private final ComponentContext ctx;
public static final Logger logger = LoggerFactory.getLogger(HomeMaticDriver.class);
private final HomeMaticDriver hmDriver;
final int MAX_RETRIES = 5;
// private final Runnable initTask;
protected long reInitTryTime = 2 * 60000;
public static final long MAX_REINITTRYTIME = 24 * 60 * 60000;
private Thread connectionThread;
// quasi-final: not changed after init() call
HomeMaticService hm;
// quasi-final: not changed after init() call
HomeMatic client;
final HmLogicInterface baseResource;
// quasi-final: not changed after init() call
ServiceRegistration commandLine;
private final ScheduledExecutorService t = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture> installModePoller;
ScheduledFuture> pingCheck;
final WriteScheduler writer;
/*
* Chain of responsibility for handling HomeMatic devices, the first handler
* that accepts a DeviceDescription will control that device (=> register more
* specific handlers first; not actually useful for standard homematic device
* types)
*/
final List handlers;
public static Resource getToplevelResource(Resource r) {
Resource res = r.getLocationResource();
while (!res.isTopLevel()) {
res = res.getParent();
if (res == null) {
throw new IllegalStateException("This should never occur!");
}
}
return res;
}
private final ResourceDemandListener devResourceListener = new ResourceDemandListener() {
@Override
public void resourceAvailable(HmDevice t) {
if (!getToplevelResource(t).equalsLocation(baseResource)) {
return;
}
hmDriver.setupDevice(t);
}
@Override
public void resourceUnavailable(HmDevice t) {
// TODO
}
};
public HmConnection(List handlerFactories, final ApplicationManager appman,
EventAdmin eventAdmin, ComponentContext ctx, HomeMaticDriver hmDriver,
final HmLogicInterface baseResource) {
this.appman = appman;
this.baseResource = baseResource;
// this.eventAdmin = eventAdmin;
this.ctx = ctx;
this.hmDriver = hmDriver;
writer = new WriteScheduler(appman, eventAdmin);
this.handlers = new ArrayList<>();
for (DeviceHandlerFactory fac : handlerFactories) {
this.handlers.add(fac.createHandler(this));
}
this.handlers.add(new PMSwitchDevice(this));
this.handlers.add(new MaintenanceChannel(this));
this.handlers.add(new ThermostatChannel(this));
this.handlers.add(new SwitchChannel(this));
this.handlers.add(new PowerMeterChannel(this));
this.handlers.add(new WeatherChannel(this));
this.handlers.add(new ShutterContactChannel(this));
this.handlers.add(new MotionDetectorChannel(this));
this.handlers.add(new KeyChannel(this));
writer.start();
}
private void connect() {
logger.debug("Starting Homematic init for ogema-" + baseResource.getName() + ", may block for 20sec");
try { // blocks for ca. 20s if no connection can be established
hm.init(client, "ogema-" + baseResource.getName());
} catch (XmlRpcException e) {
if (Thread.interrupted()) {
Thread.currentThread().interrupt();
return;
}
logger.error("could not start HomeMatic driver for config {}", baseResource.getPath());
logger.debug("Exception details:", e);
retryConnect();
return;
}
if (Thread.interrupted()) {
Thread.currentThread().interrupt();
logger.error("Thread interrupted for config {}", baseResource.getPath());
return;
}
appman.getResourceAccess().addResourceDemand(HmDevice.class, devResourceListener);
if (installModePoller == null) {
installModePoller = t.scheduleWithFixedDelay(installModePolling, 0, 60, TimeUnit.SECONDS);
}
if (pingCheck == null) {
pingCheck = t.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
checkPing();
}
}, 10, 60, TimeUnit.SECONDS);
}
logger.info("HomeMatic driver configured and registered according to config {}", baseResource.getPath());
}
@Override
public void addEventListener(HmEventListener l) {
hm.addEventListener(l);
}
@Override
public void removeEventListener(HmEventListener l) {
hm.removeEventListener(l);
}
final ResourceValueListener installModeListener = new ResourceValueListener() {
@Override
public void resourceChanged(BooleanResource t) {
if (t.equals(baseResource.installationMode().stateControl())) {
try {
boolean onOff = t.getValue();
client.setInstallMode(onOff, 900, 1);
int secondsRemaining = client.getInstallMode();
baseResource.installationMode().stateFeedback().setValue(secondsRemaining > 0);
} catch (XmlRpcException ex) {
logger.error("could not activate install mode", ex);
}
} else if (t.equals(baseResource.installationMode().stateFeedback())) {
boolean installModeOn = baseResource.installationMode().stateFeedback().getValue();
logger.info("installation mode {}", installModeOn ? "on" : "off");
}
}
};
final Runnable installModePolling = new Runnable() {
@Override
public void run() {
try {
int secondsRemaining = client.getInstallMode();
logger.debug("polled installation mode: {}s", secondsRemaining);
baseResource.installationMode().stateFeedback().setValue(secondsRemaining > 0);
} catch (XmlRpcException ex) {
logger.error("could not poll HomeMatic client for installation mode state", ex);
}
}
};
Future checkPing() {
final String callerId = "ogema" + System.currentTimeMillis();
final CountDownLatch pongReceived = new CountDownLatch(1);
final long pingTimeoutSec = 10;
final HmEventListener pong = new HmEventListener() {
@Override
public void event(List events) {
if (events.size() == 1) {
HmEvent e = events.get(0);
if ("PONG".equals(e.getValueKey())) {
// BidCos vs IP
if ("CENTRAL".equals(e.getAddress()) || "CENTRAL:0".equals(e.getAddress())) {
if (callerId.equals(e.getValueString())) {
pongReceived.countDown();
}
}
}
}
}
};
addEventListener(pong);
return t.submit(new Callable() {
@Override
public Boolean call() throws Exception {
try {
client.ping(callerId);
if (pongReceived.await(pingTimeoutSec, TimeUnit.SECONDS)) {
logger.debug("ping OK");
return true;
} else {
logger.warn("Homematic service does not respond, registering again...");
performConnect();
return false;
}
} catch (XmlRpcException ex) {
// TODO
logger.warn("PING failed", ex);
return false;
} finally {
removeEventListener(pong);
}
}
});
}
@Override
public T getValue(String address, String value_key) throws IOException {
try {
return client.getValue(address, value_key);
} catch (XmlRpcException e) {
throw new IOException(e.getMessage());
}
}
@Override
public void performSetValue(String address, String valueKey, Object value) {
writer.addWriteAction(WriteAction.createSetValue(client, address, valueKey, value));
}
@Override
public void performPutParamset(String address, String set, Map values) {
writer.addWriteAction(WriteAction.createPutParamset(client, address, set, values));
}
@Override
public void performAddLink(String sender, String receiver, String name, String description) {
WriteAction writeAction = WriteAction.createAddLink(client, sender, receiver, name, description);
writer.addWriteAction(writeAction);
}
@Override
public void performRemoveLink(String sender, String receiver) {
writer.addWriteAction(WriteAction.createRemoveLink(client, sender, receiver));
}
@Override
public List> performGetLinks(String address, int flags) {
try {
logger.debug("get links for {}", address);
return client.getLinks(address, flags);
} catch (XmlRpcException ex) {
logger.error("getLinks failed for {}", address, ex);
return null;
}
}
/**
* Returns the HmDevice element controlling the given OGEMA resource, or null if
* the resource is not controlled by the HomeMatic driver.
*
* @param ogemaDevice
* @return HomeMatic device resource controlling the given resource or null.
*/
@SuppressWarnings("rawtypes")
@Override
public HmDevice findControllingDevice(Resource ogemaDevice) {
// XXX: review this mess
for (ResourceList l : ogemaDevice.getReferencingResources(ResourceList.class)) {
if (l.getParent() != null && l.getParent() instanceof HmDevice) {
return l.getParent();
}
}
for (Resource ref : ogemaDevice.getLocationResource().getReferencingNodes(true)) {
if (ref.getParent() != null && ref.getParent().getParent() instanceof HmDevice) {
return ref.getParent().getParent();
}
for (ResourceList l : ref.getReferencingResources(ResourceList.class)) {
if (l.getParent() != null && l.getParent() instanceof HmDevice) {
return l.getParent();
}
}
}
return null;
}
@Override
public HmDevice getToplevelDevice(HmDevice channel) {
if (channel.getParent() != null && channel.getParent().getParent() instanceof HmDevice) {
return channel.getParent().getParent();
} else {
return channel;
}
}
@Override
public HmDevice getChannel(HmDevice device, String channelAddress) {
Objects.requireNonNull(device);
Objects.requireNonNull(channelAddress);
for (HmDevice channel : device.channels().getAllElements()) {
if (channelAddress.equalsIgnoreCase(channel.address().getValue())) {
return channel;
}
}
return null;
}
@Override
public void registerControlledResource(HmDevice channel, Resource ogemaDevice) {
Objects.requireNonNull(channel);
Objects.requireNonNull(ogemaDevice);
for (Resource entry : channel.controlledResources().getAllElements()) {
if (entry.equalsLocation(ogemaDevice)) {
return;
}
}
channel.controlledResources().create().activate(false);
channel.controlledResources().add(ogemaDevice);
}
/*
* TODO: error handling. If this fails (e.g. CCU not available) then we should retry later.
*/
public void init() {
try {
final HmLogicInterface config = baseResource;
final String serverUrl; // driver servlet url
String xmlRpcServiceUrl = null; // homematic gateway XML-RPC interface URL
final List interfaces = new ArrayList<>();
if (config.networkInterface().isActive() ||
config.baseUrl().isActive() ||
config.clientUrl().isActive()) {
serverUrl = getServerUrl(config, interfaces, xmlRpcServiceUrl);
if (config.clientUrl().isActive())
xmlRpcServiceUrl = config.clientUrl().getValue();
else
xmlRpcServiceUrl = getXmlRpcInterface(config, interfaces);
} else {
if (!config.clientPort().isActive())
throw new IllegalStateException("Neither client port nor client URL set for config " + config);
xmlRpcServiceUrl = getXmlRpcInterface(config, interfaces);
serverUrl = getServerUrl(config, interfaces, xmlRpcServiceUrl);
}
if (serverUrl == null || serverUrl.isEmpty()) {
throw new IllegalStateException("Invalid server or client address " + serverUrl + ", " + xmlRpcServiceUrl);
}
if (xmlRpcServiceUrl == null || xmlRpcServiceUrl.isEmpty()) {
throw new IllegalStateException("CCU XML-RPC service not found. Serial number: " + config.serialNumber().getValue());
}
final String alias = getServletAlias(config);
logger.info("New Homematic XML_RPC connection to {}, servlet URL {}{}", xmlRpcServiceUrl, serverUrl, alias);
client = new HomeMaticClient(xmlRpcServiceUrl, config.ccuUser().isActive() ? config.ccuUser().getValue() : null, config.ccuPw().isActive() ? config.ccuPw().getValue() : null);
commandLine = new HomeMaticClientCli(client).register(ctx.getBundleContext(), config.getName());
hm = new HomeMaticService(ctx.getBundleContext(), serverUrl, alias);
config.installationMode().stateControl().create();
config.installationMode().stateFeedback().create();
config.installationMode().activate(true);
config.installationMode().stateControl().addValueListener(installModeListener, true);
config.installationMode().stateFeedback().addValueListener(installModeListener, false);
Persistence persistence = new Persistence(appman, config);
hm.setBackend(persistence);
hm.addDeviceListener(persistence);
performConnect();
} catch (IOException ex) {
logger.error("could not start HomeMatic driver for config {} (2)", baseResource.getPath());
logger.debug("Exception details:", ex);
// throw new IllegalStateException(ex);
}
}
private static String getServletAlias(final HmLogicInterface config) {
if (config.alias().isActive())
return config.alias().getValue();
final int port;
try {
port = config.clientPort().isActive() ? config.clientPort().getValue() : new URL(config.clientUrl().getValue()).getPort();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
switch (port) {
case 2010:
case 42010:
return HmLogicInterface.ALIAS + "ip";
case 2001:
case 42001:
return HmLogicInterface.ALIAS;
case 2000:
case 42000:
return HmLogicInterface.ALIAS + "wired";
default:
return HmLogicInterface.ALIAS + port;
}
}
private String getServerUrl(final HmLogicInterface config,
final List interfaces, final String clientUrl) throws SocketException, UnknownHostException, MalformedURLException {
String urlPattern = config.baseUrl().getValue();
if (urlPattern == null || urlPattern.isEmpty()) {
urlPattern = "http://%s:%d";
}
if(Boolean.getBoolean("org.ogema.drivers.homematic.xmlrpc.hl.testwithoutconnection")) {
String address = String.format(urlPattern, "localhost", 9999);
return address;
}
String iface = config.networkInterface().getValue();
if (interfaces.isEmpty()) {
if (config.networkInterface().isActive()) {
final NetworkInterface nif = NetworkInterface.getByName(iface);
if (nif != null)
interfaces.add(nif);
} else if (config.baseUrl().isActive()) {
final NetworkInterface nif = NetworkInterface.getByInetAddress(Inet4Address.getByName(new URL(config.baseUrl().getValue()).getHost()));
if (nif != null)
interfaces.add(nif);
} else {
interfaces.addAll(getBestMatchingInterfaces(clientUrl == null ? null : clientUrl.toLowerCase()));
}
if (interfaces.isEmpty()) {
throw new IllegalArgumentException(
"Bad configuration: Network interface or base url not set and failed to determine interface automatically");
} else {
logger.debug("network interfaces selected: {}", interfaces);
}
}
String address;
if (config.baseUrl().isActive())
address = config.baseUrl().getValue();
else {
Inet4Address i4address = null;
for (NetworkInterface nif : interfaces) {
i4address = getAddressFromInterface(nif);
if (i4address != null) {
break;
}
}
if (i4address == null) {
throw new IllegalArgumentException("could not determine IP address for interface " + iface);
}
logger.info("Selected IPv4 address for own network interface {}", i4address);
final String ipAddrString = i4address.getHostAddress();
int port;
if (config.port().isActive()) {
port = config.port().getValue();
} else {
port = 8080; // default jetty port
try {
port = Integer.parseInt(ctx.getBundleContext().getProperty("org.osgi.service.http.port"));
} catch (NumberFormatException ok) {
} catch (SecurityException e) {
logger.warn("Failed to determine Jetty port",e);
}
}
address = String.format(urlPattern, ipAddrString, port);
}
return address;
}
private static String getXmlRpcInterface(final HmLogicInterface config, final List interfaces) throws SocketException {
final Collection ccus = runCcuDiscovery(config, interfaces);
if (ccus.isEmpty()) {
logger.warn("No CCU found");
return null;
}
if (ccus.size() > 1)
logger.warn("More than one matching CCU found: {}", ccus);
else
logger.debug("CCUs found: {}", ccus);
final Ccu ccu = ccus.iterator().next();
if (!config.serialNumber().isActive()) {
config.serialNumber(). create().setValue(ccu.getSerialNumber());
config.serialNumber().activate(false);
}
if (interfaces.isEmpty())
interfaces.add(ccu.getNetworkInterface());
final int port = config.clientPort().getValue();
// by default, ports 42001 and 42010 are used for BidCos and IP with https, ports 2001 and 2010 with http
// see https://homematic-forum.de/forum/viewtopic.php?p=465022#p465022
final String scheme = port > 40000 ? "https" : "http";
return scheme + "://" + ccu.getAddress().getHostAddress() + ":" + port;
}
/**
* @param interfaces may be empty, in which case it is to be filled
* @return
* @throws SocketException
*/
private static Collection runCcuDiscovery(final HmLogicInterface config, final List interfaces) throws SocketException {
final List ifs;
if (!interfaces.isEmpty())
ifs = interfaces;
else {
ifs = new ArrayList<>();
final Enumeration en = NetworkInterface.getNetworkInterfaces();
while (en.hasMoreElements()) {
ifs.add(en.nextElement());
}
}
// UDP discovery
final String serialNr = config.serialNumber().isActive() ? config.serialNumber().getValue() : UdpDiscovery.DEFAULT_SERIAL_NR;
Collection results = null;
try (final UdpDiscovery udp = new UdpDiscovery()) {
outer: for (NetworkInterface nif : ifs) {
for (InterfaceAddress ia : nif.getInterfaceAddresses()) {
final InetAddress brdc = ia.getBroadcast();
if (brdc == null)
continue;
udp.submit(brdc, nif, serialNr);
results = udp.getIntermediateResults(0);
if (results != null)
break outer; // closes UDP
}
}
if (results == null)
results = udp.getIntermediateResults(2 * UdpDiscovery.LISTEN_TIMEOUT);
}
// determine client url from broadcast to xxx.xxx.xxx.255:43439
if (results != null && !results.isEmpty()) {
final Collection ccus;
if (!serialNr.equals(UdpDiscovery.DEFAULT_SERIAL_NR)) {
ccus = new ArrayList<>(results.size());
for (Ccu ccu : results) {
if (serialNr.equalsIgnoreCase(ccu.getSerialNumber()))
ccus.add(ccu);
}
} else {
ccus = results;
}
return ccus;
} else
return Collections.emptyList();
}
protected void retryConnect() {
logger.info("Will retry init for config {} after " + (reInitTryTime / 1000) + " seconds.",
baseResource.getPath());
t.schedule(new Runnable() {
@Override
public void run() {
performConnect();
}
}, reInitTryTime, TimeUnit.MILLISECONDS);
reInitTryTime *= 2;
if (reInitTryTime > MAX_REINITTRYTIME) {
reInitTryTime = MAX_REINITTRYTIME;
}
}
// no synchronization for connectionThread because it is only executed in the
// single-threaded scheduler (after init())
protected void performConnect() {
if (connectionThread == null || !connectionThread.isAlive()) {
connectionThread = new Thread(new Runnable() {
@Override
public void run() {
if(Boolean.getBoolean("org.ogema.drivers.homematic.xmlrpc.hl.testwithoutconnection"))
return;
connect();
}
}, "homematic-xmlrpc-init");
connectionThread.start();
}
}
protected void close() {
HmLogicInterface config = baseResource;
try {
t.shutdownNow();
if (appman != null) {
appman.getResourceAccess().removeResourceDemand(HmDevice.class, devResourceListener);
}
config.installationMode().stateControl().removeValueListener(installModeListener);
config.installationMode().stateFeedback().removeValueListener(installModeListener);
if (client != null) {
// service unregistration in stop method may block(?)
new Thread(new Runnable() {
@Override
public void run() {
if (hm != null) {
hm.close();
}
if (commandLine != null) {
commandLine.unregister();
}
}
}).start();
}
if (connectionThread != null && connectionThread.isAlive()) {
connectionThread.interrupt();
}
writer.close();
if (logger != null) {
logger.info("HomeMatic configuration removed: {}", config);
}
} catch (Exception e) {
if (logger != null) {
logger.error("HomeMatic XmlRpc driver shutdown failed", e);
}
}
}
private static Inet4Address getAddressFromInterface(final NetworkInterface nif) {
final Enumeration addresses = nif.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress a = addresses.nextElement();
if (a instanceof Inet4Address) {
return (Inet4Address) a;
}
}
return null;
}
// TODO: cover case that clientUrl is not an IP address but a domain name;
// probably not too relevant, though
private static List getBestMatchingInterfaces(final String clientUrl) throws SocketException {
if (isOwnLoopbackAddress(clientUrl)) {
return Collections.singletonList(NetworkInterface.getByName("lo"));
}
String targetAddress = clientUrl;
try {
targetAddress = new URL(clientUrl).getHost();
} catch (MalformedURLException | NullPointerException ignore) {
}
final Enumeration> e = NetworkInterface.getNetworkInterfaces();
// the higher the key, the better the interfaces match the clientUrl
final NavigableMap> matches = new TreeMap<>();
while (e.hasMoreElements()) {
NetworkInterface n = (NetworkInterface) e.nextElement();
final Enumeration> ee = n.getInetAddresses();
int cnt = -1;
while (ee.hasMoreElements()) {
InetAddress i = (InetAddress) ee.nextElement();
if (!(i instanceof Inet4Address) && !(i instanceof Inet6Address)) {
continue;
}
final int level = targetAddress == null ? 1 :
getAgreementLevel(i.getHostAddress().toLowerCase(), targetAddress);
if (level > cnt) {
cnt = level;
}
}
if (cnt >= 0) {
List ifs = matches.get(cnt);
if (ifs == null) {
ifs = new ArrayList<>();
matches.put(cnt, ifs);
}
ifs.add(n);
}
}
final Logger logger = LoggerFactory.getLogger(HomeMaticDriver.class);
if (matches.isEmpty()) {
logger.error("No network interfaces found, cannot start driver");
return null;
}
final Iterator> it = matches.descendingMap().values().iterator();
final List list = new ArrayList<>();
while (it.hasNext()) {
list.addAll(it.next());
}
return list;
}
private static int getAgreementLevel(String address, String targetAddress) {
final int sz = Math.min(address.length(), targetAddress.length());
for (int i = 0; i < sz; i++) {
if (address.charAt(i) != targetAddress.charAt(i)) {
return i;
}
}
return sz;
}
private static boolean isOwnLoopbackAddress(final String clientUrl) {
if (clientUrl == null)
return false;
return clientUrl.contains("localhost") || clientUrl.contains("127.0.0.1")
|| clientUrl.contains("0:0:0:0:0:0:0:1") || clientUrl.contains("::1");
}
}