/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.wso2.carbon.inbound.endpoint.protocol.mqtt;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.SynapseException;
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
import java.util.concurrent.ConcurrentHashMap;
/**
* Reference Holder for MQTT clients in existence per ESB Server instance
*/
public class MqttClientManager {
private static MqttClientManager instance;
private static final Log log = LogFactory.getLog(MqttClientManager.class);
private ConcurrentHashMap<String, MqttAsyncClient> mqttClientMap;
private ConcurrentHashMap<String, MqttAsyncCallback> mqttCallbackMap;
//keep a flag to indicate the cases where manually load the tenant
private ConcurrentHashMap<String, Boolean> tenantLoadingFlagMap;
private ConcurrentHashMap<String, String> inboundNameToIdentifierMap;
private ConcurrentHashMap<String, MqttDefaultFilePersistence> mqttClientDataStoreMap;
private MqttClientManager() {
mqttClientMap = new ConcurrentHashMap<>();
mqttCallbackMap = new ConcurrentHashMap<>();
tenantLoadingFlagMap = new ConcurrentHashMap<>();
inboundNameToIdentifierMap = new ConcurrentHashMap<>();
mqttClientDataStoreMap = new ConcurrentHashMap<>();
}
public static synchronized MqttClientManager getInstance() {
if (instance == null) {
log.info("Initializing.. MQTT Client Manager");
instance = new MqttClientManager();
}
return instance;
}
public void registerMqttClient(String identifier, MqttAsyncClient mqttClient) {
mqttClientMap.put(identifier, mqttClient);
}
public void unregisterMqttClient(String identifier, String name) {
mqttClientMap.remove(identifier);
mqttCallbackMap.remove(identifier);
tenantLoadingFlagMap.remove(identifier);
inboundNameToIdentifierMap.remove(name);
mqttClientDataStoreMap.remove(identifier);
}
public boolean hasMqttClient(String identifier) {
return mqttClientMap.containsKey(identifier);
}
public MqttAsyncClient getMqttClient(String identifier) {
if (tenantLoadingFlagMap.containsKey(identifier)) {
//this is manually tenant loading case should return the client
return mqttClientMap.get(identifier);
} else {
MqttAsyncCallback callback = mqttCallbackMap.get(identifier);
//this is the case where recreation of same bounded inbound endpoint for server host
//server port, client id
String msg = "Client ID: " +
callback.getMqttConnectionConsumer().getMqttAsyncClient().getClientId() +
" Server Host: " + callback.getMqttConnectionConsumer()
.getMqttConnectionFactory().getServerHost() +
" Server Port: " + callback.getMqttConnectionConsumer()
.getMqttConnectionFactory().getServerPort() +
" is bound to existing MQTT Inbound Endpoint.";
log.error(msg);
throw new SynapseException(msg);
}
}
public void registerMqttCallback(String identifier, MqttAsyncCallback mqttCallback) {
mqttCallbackMap.put(identifier, mqttCallback);
}
public boolean hasMqttCallback(String identifier) {
return mqttCallbackMap.containsKey(identifier);
}
public MqttAsyncCallback getMqttCallback(String identifier) {
return mqttCallbackMap.get(identifier);
}
public void registerInboundTenantLoadingFlag(String identifier) {
tenantLoadingFlagMap.put(identifier, true);
}
public void unRegisterInboundTenantLoadingFlag(String identifier) {
tenantLoadingFlagMap.remove(identifier);
}
public boolean isInboundTenantLoadingFlagSet(String identifier) {
return tenantLoadingFlagMap.containsKey(identifier);
}
public String buildIdentifier(String clientId, String host, String port) {
//this identifier is unique per Mqtt connection
return clientId + "." + host + "." + port;
}
public void registerInboundEndpoint(String name, String identifier) {
inboundNameToIdentifierMap.put(name, identifier);
}
public String getInboundEndpointIdentifier(String name) {
return inboundNameToIdentifierMap.get(name);
}
public boolean hasInboundEndpoint(String name) {
return inboundNameToIdentifierMap.containsKey(name);
}
public String buildNameIdentifier(String name, String tenantId) {
//this identifier is unique per inbound deployment existing among multiple tenants
return name + "." + tenantId;
}
public void registerClientDataStore(String identifier, MqttDefaultFilePersistence dataStore) {
mqttClientDataStoreMap.put(identifier, dataStore);
}
public boolean hasClientDataStore(String identifier) {
return mqttClientDataStoreMap.containsKey(identifier);
}
public MqttDefaultFilePersistence getMqttClientDataStore(String identifier) {
return mqttClientDataStoreMap.get(identifier);
}
}