/**
* Copyright (c) 2014-2017 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.smarthome.binding.digitalstrom.internal.lib.manager.impl;
import java.net.HttpURLConnection;
import org.apache.commons.lang.StringUtils;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.config.Config;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.listener.ConnectionListener;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.manager.ConnectionManager;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.serverConnection.DsAPI;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.serverConnection.HttpTransport;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.serverConnection.impl.DsAPIImpl;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.serverConnection.impl.HttpTransportImpl;
/**
* The {@link ConnectionManagerImpl} is the implementation of the {@link ConnectionManager}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class ConnectionManagerImpl implements ConnectionManager {
private Config config;
private ConnectionListener connListener = null;
private HttpTransport transport;
private String sessionToken;
private Boolean lostConnectionState = false;
private boolean genAppToken = true;
private DsAPI digitalSTROMClient;
public ConnectionManagerImpl(String hostArddress, int connectTimeout, int readTimeout, String username,
String password, String applicationToken) {
init(hostArddress, connectTimeout, readTimeout, username, password, applicationToken, false);
}
public ConnectionManagerImpl(Config config) {
init(config, false);
}
public ConnectionManagerImpl(Config config, ConnectionListener connectionListener) {
this.connListener = connectionListener;
init(config, false);
}
public ConnectionManagerImpl(Config config, ConnectionListener connectionListener, boolean genAppToken) {
this.connListener = connectionListener;
this.genAppToken = genAppToken;
init(config, false);
}
public ConnectionManagerImpl(String hostAddress, String username, String password, String applicationToken) {
init(hostAddress, -1, -1, username, password, applicationToken, false);
}
public ConnectionManagerImpl(String hostAddress, String applicationToken) {
init(hostAddress, -1, -1, null, null, applicationToken, false);
}
public ConnectionManagerImpl(String hostAddress, String username, String password,
ConnectionListener connectionListener) {
this.connListener = connectionListener;
init(hostAddress, -1, -1, username, password, null, false);
}
public ConnectionManagerImpl(String hostAddress, String username, String password, String applicationToken,
ConnectionListener connectionListener) {
this.connListener = connectionListener;
init(hostAddress, -1, -1, username, password, null, false);
}
public ConnectionManagerImpl(String hostAddress, String username, String password, boolean genAppToken) {
this.genAppToken = genAppToken;
init(hostAddress, -1, -1, username, password, null, false);
}
public ConnectionManagerImpl(String hostAddress, String username, String password, String applicationToken,
boolean genAppToken) {
this.genAppToken = genAppToken;
init(hostAddress, -1, -1, username, password, applicationToken, false);
}
public ConnectionManagerImpl(String hostAddress, String username, String password, String applicationToken,
boolean genAppToken, boolean aceptAllCerts) {
this.genAppToken = genAppToken;
init(hostAddress, -1, -1, username, password, applicationToken, aceptAllCerts);
}
public ConnectionManagerImpl(String hostAddress, String username, String password, String applicationToken,
boolean genAppToken, ConnectionListener connectionListener) {
this.connListener = connectionListener;
this.genAppToken = genAppToken;
init(hostAddress, -1, -1, username, password, applicationToken, false);
}
private void init(String hostAddress, int connectionTimeout, int readTimeout, String username, String password,
String applicationToken, boolean aceptAllCerts) {
config = new Config(hostAddress, username, password, applicationToken);
if (connectionTimeout >= 0) {
config.setConnectionTimeout(connectionTimeout);
}
if (readTimeout >= 0) {
config.setReadTimeout(readTimeout);
}
init(config, aceptAllCerts);
}
private void init(Config config, boolean aceptAllCerts) {
this.transport = new HttpTransportImpl(config, aceptAllCerts);
this.digitalSTROMClient = new DsAPIImpl(transport);
this.config = config;
if (this.genAppToken) {
this.onNotAuthenticated();
}
}
@Override
public HttpTransport getHttpTransport() {
return transport;
}
@Override
public DsAPI getDigitalSTROMAPI() {
return this.digitalSTROMClient;
}
@Override
public String getSessionToken() {
return this.sessionToken;
}
@Override
public String checkConnectionAndGetSessionToken() {
if (checkConnection()) {
return this.sessionToken;
}
return null;
}
@Override
public synchronized boolean checkConnection() {
int code = this.digitalSTROMClient.checkConnection(sessionToken);
switch (code) {
case HttpURLConnection.HTTP_OK:
if (!lostConnectionState) {
lostConnectionState = true;
onConnectionResumed();
}
break;
case HttpURLConnection.HTTP_UNAUTHORIZED:
lostConnectionState = false;
break;
case HttpURLConnection.HTTP_FORBIDDEN:
if (this.genAppToken) {
if (StringUtils.isNotBlank(config.getAppToken())) {
sessionToken = this.digitalSTROMClient.loginApplication(config.getAppToken());
} else {
this.onNotAuthenticated();
}
} else {
sessionToken = this.digitalSTROMClient.login(this.config.getUserName(), this.config.getPassword());
}
if (sessionToken != null) {
if (!lostConnectionState) {
onConnectionResumed();
lostConnectionState = true;
}
} else {
if (this.genAppToken) {
onNotAuthenticated();
}
lostConnectionState = false;
}
break;
case -2:
onConnectionLost(ConnectionListener.INVALID_URL);
lostConnectionState = false;
break;
case -3:
case -4:
onConnectionLost(ConnectionListener.CONNECTON_TIMEOUT);
lostConnectionState = false;
break;
case -1:
if (connListener != null) {
connListener.onConnectionStateChange(ConnectionListener.CONNECTION_LOST);
}
break;
case -5:
if (connListener != null) {
onConnectionLost(ConnectionListener.UNKNOWN_HOST);
}
break;
case HttpURLConnection.HTTP_NOT_FOUND:
onConnectionLost(ConnectionListener.HOST_NOT_FOUND);
lostConnectionState = false;
break;
}
return lostConnectionState;
}
/**
* This method is called whenever the connection to the digitalSTROM-Server is available,
* but requests are not allowed due to a missing or invalid authentication.
*/
private void onNotAuthenticated() {
String applicationToken;
boolean isAuthenticated = false;
if (StringUtils.isNotBlank(config.getAppToken())) {
sessionToken = digitalSTROMClient.loginApplication(config.getAppToken());
if (sessionToken != null) {
isAuthenticated = true;
} else {
if (connListener != null) {
connListener.onConnectionStateChange(ConnectionListener.NOT_AUTHENTICATED,
ConnectionListener.WRONG_APP_TOKEN);
if (!checkUserPassword()) {
return;
}
}
}
}
if (checkUserPassword()) {
if (!isAuthenticated) {
// generate applicationToken and test host is reachable
applicationToken = this.digitalSTROMClient.requestAppplicationToken(config.getApplicationName());
if (StringUtils.isNotBlank(applicationToken)) {
// enable applicationToken
if (this.digitalSTROMClient.enableApplicationToken(applicationToken,
this.digitalSTROMClient.login(config.getUserName(), config.getPassword()))) {
config.setAppToken(applicationToken);
// this.applicationToken = applicationToken;
isAuthenticated = true;
} else {
if (connListener != null) {
connListener.onConnectionStateChange(ConnectionListener.NOT_AUTHENTICATED,
ConnectionListener.WRONG_USER_OR_PASSWORD);
}
}
}
}
// remove password and username, to don't store them persistently
if (isAuthenticated) {
config.removeUsernameAndPassword();
if (connListener != null) {
connListener.onConnectionStateChange(ConnectionListener.APPLICATION_TOKEN_GENERATED);
}
}
} else if (!isAuthenticated) {
if (connListener != null) {
connListener.onConnectionStateChange(ConnectionListener.NOT_AUTHENTICATED,
ConnectionListener.NO_USER_PASSWORD);
}
}
}
private boolean checkUserPassword() {
if (StringUtils.isNotBlank(config.getUserName()) && StringUtils.isNotBlank(config.getPassword())) {
return true;
}
return false;
}
/**
* This method is called whenever the connection to the digitalSTROM-Server is lost.
*
* @param reason
*/
private void onConnectionLost(String reason) {
if (connListener != null) {
connListener.onConnectionStateChange(ConnectionListener.CONNECTION_LOST, reason);
}
}
/**
* This method is called whenever the connection to the digitalSTROM-Server is resumed.
*/
private void onConnectionResumed() {
if (connListener != null) {
connListener.onConnectionStateChange(ConnectionListener.CONNECTION_RESUMED);
}
}
@Override
public void registerConnectionListener(ConnectionListener listener) {
this.connListener = listener;
}
@Override
public void unregisterConnectionListener() {
this.connListener = null;
}
@Override
public String getApplicationToken() {
return config.getAppToken();
}
@Override
public boolean removeApplicationToken() {
if (StringUtils.isNotBlank(config.getAppToken())) {
if (checkConnection()) {
return digitalSTROMClient.revokeToken(config.getAppToken(), getSessionToken());
}
return false;
}
return true;
}
@Override
public void updateConfig(String host, String username, String password, String applicationToken) {
init(host, -1, -1, username, password, applicationToken, false);
}
@Override
public void updateConfig(Config config) {
if (this.config != null) {
this.config.updateConfig(config);
} else {
this.config = config;
}
init(this.config, false);
}
@Override
public void configHasBeenUpdated() {
init(this.config, false);
}
@Override
public Config getConfig() {
return this.config;
}
}