added xmpp, mqtt input/output adapters

merge-requests/1/head
ayyoob 9 years ago
parent d6bb9e766f
commit 2b6816d7ed

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>iot-base-plugin</artifactId>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<version>2.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.device.mgt.iot.input.adapter</artifactId>
<packaging>bundle</packaging>
<name>WSO2 Carbon - Device Mgt Input Adaptor Module</name>
<description>Provides the back-end functionality of Input adaptor</description>
<url>http://wso2.org</url>
<dependencies>
<dependency>
<groupId>org.wso2.carbon.analytics-common</groupId>
<artifactId>org.wso2.carbon.event.input.adapter.core</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.logging</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.wso2</groupId>
<artifactId>httpcore</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.orbit.org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple.wso2</groupId>
<artifactId>json-simple</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.identity.jwt.client.extension</artifactId>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity</groupId>
<artifactId>org.wso2.carbon.identity.oauth.stub</artifactId>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack.wso2</groupId>
<artifactId>smack</artifactId>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack.wso2</groupId>
<artifactId>smackx</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<executions>
<execution>
<id>generate-scr-descriptor</id>
<goals>
<goal>scr</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Bundle-Name>${project.artifactId}</Bundle-Name>
<Private-Package>
org.wso2.carbon.device.mgt.iot.input.adapter.internal,
org.wso2.carbon.device.mgt.iot.input.adapter.internal.*
</Private-Package>
<Export-Package>
!org.wso2.carbon.device.mgt.iot.input.adapter.internal,
!org.wso2.carbon.device.mgt.iot.input.adapter.internal.*,
org.wso2.carbon.device.mgt.iot.input.adapter.*
</Export-Package>
<Import-Package>
org.wso2.carbon.event.input.adapter.core,
org.wso2.carbon.event.input.adapter.core.*,
javax.xml.namespace; version=0.0.0,
org.eclipse.paho.client.mqttv3.*,
org.apache.http;version="${httpclient.version.range}",
org.apache.http.message;version="${httpclient.version.range}",
org.apache.http.client;version="${httpclient.version.range}",
org.apache.http.impl;version="${httpclient.version.range}",
org.apache.http.conn.*;version="${httpclient.version.range}",
org.apache.http.util;version="${httpclient.version.range}",
org.apache.http.client.entity;version="${httpclient.version.range}",
org.apache.http.client.methods;version="${httpclient.version.range}",
org.apache.http.impl.client;version="${httpclient.version.range}",
org.json.simple.*,
org.wso2.carbon.identity.jwt.client.extension.*,
com.jayway.jsonpath.*,
javax.net.ssl,
org.apache.commons.logging,
org.apache.http.entity,
org.osgi.framework,
org.osgi.service.component,
org.wso2.carbon.context,
org.wso2.carbon.core,
javax.servlet,
javax.servlet.http,
org.apache.axiom.om.util,
org.osgi.service.http,
org.wso2.carbon.user.api,
org.wso2.carbon.user.core.service,
org.wso2.carbon.user.core.tenant,
org.wso2.carbon.utils,
org.wso2.carbon.utils.multitenancy,
org.wso2.carbon.identity.oauth2.stub;version="${carbon.identity.version.range}",
org.wso2.carbon.identity.oauth2.stub.dto;version="${carbon.identity.version.range}",
org.apache.axis2,
org.apache.axis2.client,
org.apache.axis2.context,
org.apache.axis2.transport.http,
org.apache.commons.httpclient,
org.apache.commons.httpclient.contrib.ssl,
org.apache.commons.httpclient.params,
org.apache.commons.httpclient.protocol,
org.apache.commons.pool,
org.apache.commons.pool.impl,
org.jivesoftware.smack.*,
org.apache.log4j,
org.wso2.carbon.base,
org.wso2.carbon.core.util
</Import-Package>
<DynamicImport-Package>*</DynamicImport-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,55 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.input.adapter;
/**
* This is the return type of the ContentValidator.
*/
public class ContentInfo {
/**
* true if the content is valid if not when false then content will not be published.
*/
private boolean isValidContent;
/**
* msgText to be returned. eg: if the content is encrypted then we can decrypt the content and then validate and
* return it.
*/
private String msgText;
public ContentInfo(boolean isValidContent, String msgText) {
this.isValidContent = isValidContent;
this.msgText = msgText;
}
public boolean isValidContent() {
return isValidContent;
}
public void setIsValidContent(boolean isValidContent) {
this.isValidContent = isValidContent;
}
public String getMsgText() {
return msgText;
}
public void setMsgText(String msgText) {
this.msgText = msgText;
}
}

@ -0,0 +1,8 @@
package org.wso2.carbon.device.mgt.iot.input.adapter;
import java.util.Map;
public interface ContentTransformer {
String transform(String message, Map<String, String> dynamicProperties);
}

@ -0,0 +1,33 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.input.adapter;
import java.util.Map;
/**
* This interface will be triggered to validate the stream content before publishing.
*/
public interface ContentValidator {
/**
* @param contentValidationParams that related to input adapter.
* @param dynamicParameter that message.
* @return ContentInfo.
*/
ContentInfo validate(String msgPayload, Map<String, String> contentValidationParams, Map<String, String> dynamicParameter);
}

@ -0,0 +1,14 @@
package org.wso2.carbon.device.mgt.iot.input.adapter;
import java.util.Map;
/**
* This holds the default implementation of ContentTransformer
*/
public class DefaultContentTransformer implements ContentTransformer{
@Override
public String transform(String message, Map<String, String> dynamicProperties) {
return message;
}
}

@ -0,0 +1,11 @@
package org.wso2.carbon.device.mgt.iot.input.adapter;
import java.util.Map;
public class DefaultContentValidator implements ContentValidator {
@Override
public ContentInfo validate(String msgPayload, Map<String, String> params, Map<String, String> dynamicPaarams) {
return new ContentInfo(true, msgPayload);
}
}

@ -0,0 +1,213 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* 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.wso2.carbon.device.mgt.iot.input.adapter.http;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.iot.input.adapter.internal.EventAdapterServiceDataHolder;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapter;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterConfiguration;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterListener;
import org.wso2.carbon.event.input.adapter.core.exception.InputEventAdapterException;
import org.wso2.carbon.event.input.adapter.core.exception.InputEventAdapterRuntimeException;
import org.wso2.carbon.event.input.adapter.core.exception.TestConnectionNotSupportedException;
import org.wso2.carbon.device.mgt.iot.input.adapter.http.util.HTTPEventAdapterConstants;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import javax.servlet.ServletException;
import java.util.Hashtable;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public final class HTTPEventAdapter implements InputEventAdapter {
private final InputEventAdapterConfiguration eventAdapterConfiguration;
private final Map<String, String> globalProperties;
private InputEventAdapterListener eventAdaptorListener;
private final String id = UUID.randomUUID().toString();
public static ExecutorService executorService;
private static final Log log = LogFactory.getLog(HTTPEventAdapter.class);
private boolean isConnected = false;
public HTTPEventAdapter(InputEventAdapterConfiguration eventAdapterConfiguration,
Map<String, String> globalProperties) {
this.eventAdapterConfiguration = eventAdapterConfiguration;
this.globalProperties = globalProperties;
}
@Override
public void init(InputEventAdapterListener eventAdaptorListener) throws InputEventAdapterException {
this.eventAdaptorListener = eventAdaptorListener;
//ThreadPoolExecutor will be assigned if it is null
if (executorService == null) {
int minThread;
int maxThread;
long defaultKeepAliveTime;
int jobQueueSize;
//If global properties are available those will be assigned else constant values will be assigned
if (globalProperties.get(HTTPEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE_NAME) != null) {
minThread = Integer
.parseInt(globalProperties.get(HTTPEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE_NAME));
} else {
minThread = HTTPEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE;
}
if (globalProperties.get(HTTPEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME) != null) {
maxThread = Integer
.parseInt(globalProperties.get(HTTPEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME));
} else {
maxThread = HTTPEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE;
}
if (globalProperties.get(HTTPEventAdapterConstants.ADAPTER_KEEP_ALIVE_TIME_NAME) != null) {
defaultKeepAliveTime = Integer
.parseInt(globalProperties.get(HTTPEventAdapterConstants.ADAPTER_KEEP_ALIVE_TIME_NAME));
} else {
defaultKeepAliveTime = HTTPEventAdapterConstants.DEFAULT_KEEP_ALIVE_TIME_IN_MILLS;
}
if (globalProperties.get(HTTPEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME) != null) {
jobQueueSize = Integer
.parseInt(globalProperties.get(HTTPEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME));
} else {
jobQueueSize = HTTPEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE;
}
RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
executor.getQueue().put(r);
} catch (InterruptedException e) {
log.error("Exception while adding event to executor queue : " + e.getMessage(), e);
}
}
};
executorService = new ThreadPoolExecutor(minThread, maxThread, defaultKeepAliveTime, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(jobQueueSize), rejectedExecutionHandler);
}
}
@Override
public void testConnect() throws TestConnectionNotSupportedException {
throw new TestConnectionNotSupportedException("not-supported");
}
@Override
public void connect() {
registerDynamicEndpoint(eventAdapterConfiguration.getName());
isConnected = true;
}
@Override
public void disconnect() {
if (isConnected){
isConnected = false;
unregisterDynamicEndpoint(eventAdapterConfiguration.getName());
}
}
@Override
public void destroy() {
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof HTTPEventAdapter))
return false;
HTTPEventAdapter that = (HTTPEventAdapter) o;
return id.equals(that.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean isEventDuplicatedInCluster() {
return false;
}
@Override
public boolean isPolling() {
return false;
}
private void registerDynamicEndpoint(String adapterName) {
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
String endpoint;
if (MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
endpoint = HTTPEventAdapterConstants.ENDPOINT_PREFIX + adapterName;
} else {
endpoint = HTTPEventAdapterConstants.ENDPOINT_PREFIX + HTTPEventAdapterConstants.ENDPOINT_TENANT_KEY
+ HTTPEventAdapterConstants.ENDPOINT_URL_SEPARATOR + tenantDomain
+ HTTPEventAdapterConstants.ENDPOINT_URL_SEPARATOR + adapterName;
}
try {
HttpService httpService = EventAdapterServiceDataHolder.getHTTPService();
if (httpService == null) {
throw new InputEventAdapterRuntimeException(
"HttpService not available, Error in registering endpoint " + endpoint);
}
httpService.registerServlet(endpoint, new HTTPMessageServlet(eventAdaptorListener, tenantId,
eventAdapterConfiguration),
new Hashtable(), httpService.createDefaultHttpContext());
} catch (ServletException | NamespaceException e) {
throw new InputEventAdapterRuntimeException("Error in registering endpoint " + endpoint, e);
}
}
private void unregisterDynamicEndpoint(String adapterName) {
HttpService httpService = EventAdapterServiceDataHolder.getHTTPService();
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
String endpoint;
if (MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
endpoint = HTTPEventAdapterConstants.ENDPOINT_PREFIX + adapterName;
} else {
endpoint = HTTPEventAdapterConstants.ENDPOINT_PREFIX + HTTPEventAdapterConstants.ENDPOINT_TENANT_KEY
+ HTTPEventAdapterConstants.ENDPOINT_URL_SEPARATOR + tenantDomain
+ HTTPEventAdapterConstants.ENDPOINT_URL_SEPARATOR + adapterName;
}
if (httpService != null) {
httpService.unregister(endpoint);
}
}
}

@ -0,0 +1,171 @@
/*
* Copyright (c) 2005 - 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* 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.wso2.carbon.device.mgt.iot.input.adapter.http;
import org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.Constants;
import org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.util.MQTTEventAdapterConstants;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapter;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterConfiguration;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterFactory;
import org.wso2.carbon.event.input.adapter.core.MessageType;
import org.wso2.carbon.event.input.adapter.core.Property;
import org.wso2.carbon.device.mgt.iot.input.adapter.http.util.HTTPEventAdapterConstants;
import org.wso2.carbon.utils.CarbonUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
/**
* The http event adapter factory class to create a http input adapter
*/
public class HTTPEventAdapterFactory extends InputEventAdapterFactory {
private ResourceBundle resourceBundle =
ResourceBundle.getBundle("org.wso2.carbon.device.mgt.iot.input.adapter.http.i18n.Resources", Locale.getDefault());
private int httpPort;
private int httpsPort;
private int portOffset;
public HTTPEventAdapterFactory() {
portOffset = getPortOffset();
httpPort = HTTPEventAdapterConstants.DEFAULT_HTTP_PORT + portOffset;
httpsPort = HTTPEventAdapterConstants.DEFAULT_HTTPS_PORT + portOffset;
}
@Override
public String getType() {
return HTTPEventAdapterConstants.ADAPTER_TYPE_HTTP;
}
@Override
public List<String> getSupportedMessageFormats() {
List<String> supportInputMessageTypes = new ArrayList<String>();
supportInputMessageTypes.add(MessageType.JSON);
supportInputMessageTypes.add(MessageType.TEXT);
supportInputMessageTypes.add(MessageType.XML);
supportInputMessageTypes.add(MessageType.WSO2EVENT);
return supportInputMessageTypes;
}
@Override
public List<Property> getPropertyList() {
List<Property> propertyList = new ArrayList<Property>();
// Transport Exposed
Property exposedTransportsProperty = new Property(HTTPEventAdapterConstants.EXPOSED_TRANSPORTS);
exposedTransportsProperty.setRequired(true);
exposedTransportsProperty.setDisplayName(
resourceBundle.getString(HTTPEventAdapterConstants.EXPOSED_TRANSPORTS));
exposedTransportsProperty.setOptions(
new String[]{HTTPEventAdapterConstants.HTTPS, HTTPEventAdapterConstants.HTTP,
HTTPEventAdapterConstants.LOCAL, HTTPEventAdapterConstants.ALL});
exposedTransportsProperty.setDefaultValue(HTTPEventAdapterConstants.ALL);
propertyList.add(exposedTransportsProperty);
// OAUTH validation endpoint admin service username
Property username = new Property(HTTPEventAdapterConstants.USERNAME);
username.setRequired(true);
username.setDisplayName(resourceBundle.getString(HTTPEventAdapterConstants.USERNAME));
username.setHint(resourceBundle.getString(HTTPEventAdapterConstants.USERNAME_HINT));
propertyList.add(username);
// OAUTH validation endpoint admin service password
Property password = new Property(HTTPEventAdapterConstants.PASSWORD);
password.setRequired(true);
password.setDisplayName(resourceBundle.getString(HTTPEventAdapterConstants.PASSWORD));
password.setHint(resourceBundle.getString(HTTPEventAdapterConstants.PASSWORD_HINT));
propertyList.add(password);
// OAUTH validation endpoint
Property tokenValidationEndpoint = new Property(HTTPEventAdapterConstants.TOKEN_VALIDATION_ENDPOINT_URL);
tokenValidationEndpoint.setRequired(true);
tokenValidationEndpoint.setDisplayName(resourceBundle.getString(HTTPEventAdapterConstants.TOKEN_VALIDATION_ENDPOINT_URL));
tokenValidationEndpoint.setHint(resourceBundle.getString(HTTPEventAdapterConstants.TOKEN_VALIDATION_ENDPOINT_URL_HINT));
propertyList.add(tokenValidationEndpoint);
Property maximumHttpConnectionPerHost = new Property(HTTPEventAdapterConstants.MAXIMUM_HTTP_CONNECTION_PER_HOST);
maximumHttpConnectionPerHost.setRequired(true);
maximumHttpConnectionPerHost.setDisplayName(resourceBundle.getString(
HTTPEventAdapterConstants.MAXIMUM_HTTP_CONNECTION_PER_HOST));
maximumHttpConnectionPerHost.setHint(resourceBundle.getString(
HTTPEventAdapterConstants.MAXIMUM_HTTP_CONNECTION_PER_HOST_HINT));
maximumHttpConnectionPerHost.setDefaultValue(HTTPEventAdapterConstants.MAX_HTTP_CONNECTION);
propertyList.add(maximumHttpConnectionPerHost);
Property maxTotalHttpConnection = new Property(HTTPEventAdapterConstants.MAXIMUM_TOTAL_HTTP_CONNECTION);
maxTotalHttpConnection.setRequired(true);
maxTotalHttpConnection.setDisplayName(resourceBundle.getString(
HTTPEventAdapterConstants.MAXIMUM_TOTAL_HTTP_CONNECTION));
maxTotalHttpConnection.setHint(resourceBundle.getString(
HTTPEventAdapterConstants.MAXIMUM_TOTAL_HTTP_CONNECTION_HINT));
maxTotalHttpConnection.setDefaultValue(HTTPEventAdapterConstants.MAX_TOTAL_HTTP_CONNECTION);
propertyList.add(maxTotalHttpConnection);
//Content Validator details
Property contentValidator = new Property(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME);
contentValidator.setDisplayName(
resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME));
contentValidator.setRequired(false);
contentValidator.setHint(
resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME_HINT));
contentValidator.setDefaultValue(HTTPEventAdapterConstants.DEFAULT);
propertyList.add(contentValidator);
//Content Validator Params details
Property contentValidatorParams = new Property(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS);
contentValidatorParams.setDisplayName(
resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS));
contentValidatorParams.setRequired(false);
contentValidatorParams.setHint(
resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS_HINT));
contentValidatorParams.setDefaultValue(HTTPEventAdapterConstants.MQTT_CONTENT_VALIDATION_DEFAULT_PARAMETERS);
propertyList.add(contentValidatorParams);
//Content Transformer details
Property contentTransformer = new Property(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME);
contentTransformer.setDisplayName(
resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME));
contentTransformer.setRequired(false);
contentTransformer.setHint(
resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME_HINT));
contentTransformer.setDefaultValue(Constants.DEFAULT);
propertyList.add(contentTransformer);
return propertyList;
}
@Override
public String getUsageTips() {
return resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_USAGE_TIPS_PREFIX) + httpPort +
resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_USAGE_TIPS_MID1) + httpsPort +
resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_USAGE_TIPS_MID2) + httpPort +
resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_USAGE_TIPS_MID3) + httpsPort +
resourceBundle.getString(HTTPEventAdapterConstants.ADAPTER_USAGE_TIPS_POSTFIX);
}
@Override
public InputEventAdapter createEventAdapter(InputEventAdapterConfiguration eventAdapterConfiguration,
Map<String, String> globalProperties) {
return new HTTPEventAdapter(eventAdapterConfiguration, globalProperties);
}
private int getPortOffset() {
return CarbonUtils.getPortFromServerConfig(HTTPEventAdapterConstants.CARBON_CONFIG_PORT_OFFSET_NODE) + 1;
}
}

@ -0,0 +1,394 @@
/*
* Copyright (c) 2005 - 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* 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.wso2.carbon.device.mgt.iot.input.adapter.http;
import org.apache.axis2.context.ServiceContext;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.iot.input.adapter.ContentInfo;
import org.wso2.carbon.device.mgt.iot.input.adapter.ContentTransformer;
import org.wso2.carbon.device.mgt.iot.input.adapter.DefaultContentTransformer;
import org.wso2.carbon.device.mgt.iot.input.adapter.DefaultContentValidator;
import org.wso2.carbon.device.mgt.iot.input.adapter.http.exception.HTTPContentInitializationException;
import org.wso2.carbon.device.mgt.iot.input.adapter.http.oauth.OAuthTokenValidaterStubFactory;
import org.wso2.carbon.device.mgt.iot.input.adapter.http.util.AuthenticationInfo;
import org.wso2.carbon.device.mgt.iot.input.adapter.http.util.HTTPEventAdapterConstants;
import org.wso2.carbon.device.mgt.iot.input.adapter.internal.EventAdapterServiceDataHolder;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterConfiguration;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterListener;
import org.wso2.carbon.device.mgt.iot.input.adapter.ContentValidator;
import org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.exception.MQTTContentInitializationException;
import org.wso2.carbon.identity.oauth2.stub.OAuth2TokenValidationServiceStub;
import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO;
import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO_OAuth2AccessToken;
import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationResponseDTO;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.rmi.RemoteException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* This will act as the event reciver.
*/
public class HTTPMessageServlet extends HttpServlet {
private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String AUTH_MESSAGE_STORE_AUTHENTICATION_INFO = "AUTH_MESSAGE_STORE_AUTHENTICATION_INFO";
private static final String AUTH_FAILURE_RESPONSE = "_AUTH_FAILURE_";
private static final Pattern PATTERN = Pattern.compile("[B|b]earer\\s");
private static final String TOKEN_TYPE = "bearer";
private static String cookie;
private static Log log = LogFactory.getLog(HTTPMessageServlet.class);
private GenericObjectPool stubs;
private static Map<String, String> contentValidationProperties;
private static ContentValidator contentValidator;
private static ContentTransformer contentTransformer;
private InputEventAdapterListener eventAdaptorListener;
private int tenantId;
private String exposedTransports;
public HTTPMessageServlet(InputEventAdapterListener eventAdaptorListener, int tenantId,
InputEventAdapterConfiguration eventAdapterConfiguration) {
this.eventAdaptorListener = eventAdaptorListener;
this.tenantId = tenantId;
this.exposedTransports = eventAdapterConfiguration.getProperties().get(
HTTPEventAdapterConstants.EXPOSED_TRANSPORTS);
this.stubs = new GenericObjectPool(new OAuthTokenValidaterStubFactory(eventAdapterConfiguration));
HTTPMessageServlet.contentValidationProperties = new HashMap<>();
String contentValidationParams = eventAdapterConfiguration.getProperties().get(
HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS);
if (contentValidationParams != null && !contentValidationParams.isEmpty()) {
String validationParams[] = contentValidationParams.split(",");
for (String validationParam : validationParams) {
String[] validationProperty = validationParam.split(":");
if (validationProperty.length == 2) {
contentValidationProperties.put(validationProperty[0], validationProperty[1]);
}
}
}
String className = eventAdapterConfiguration.getProperties().get(
HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME);
if (HTTPEventAdapterConstants.DEFAULT.equals(className)) {
contentValidator = new DefaultContentValidator();
} else {
try {
Class<? extends ContentValidator> contentValidatorClass = Class.forName(className)
.asSubclass(ContentValidator.class);
contentValidator = contentValidatorClass.newInstance();
} catch (ClassNotFoundException e) {
throw new HTTPContentInitializationException(
"Unable to find the class validator: " + className, e);
} catch (InstantiationException e) {
throw new HTTPContentInitializationException(
"Unable to create an instance of :" + className, e);
} catch (IllegalAccessException e) {
throw new HTTPContentInitializationException("Access of the instance in not allowed.", e);
}
}
String contentTransformerClassName = eventAdapterConfiguration.getProperties().get(
HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME);
if (contentTransformerClassName != null && contentTransformerClassName.equals(HTTPEventAdapterConstants.DEFAULT)) {
contentTransformer = new DefaultContentTransformer();
} else if (contentTransformerClassName != null && !contentTransformerClassName.isEmpty()) {
try {
Class<? extends ContentTransformer> contentTransformerClass = Class.forName(contentTransformerClassName)
.asSubclass(ContentTransformer.class);
contentTransformer = contentTransformerClass.newInstance();
} catch (ClassNotFoundException e) {
throw new HTTPContentInitializationException(
"Unable to find the class transformer: " + contentTransformerClassName, e);
} catch (InstantiationException e) {
throw new HTTPContentInitializationException(
"Unable to create an instance of :" + contentTransformerClassName, e);
} catch (IllegalAccessException e) {
throw new HTTPContentInitializationException("Access of the instance in not allowed.", e);
}
}
}
private String getBearerToken(HttpServletRequest request) {
String authorizationHeader = request.getHeader(AUTHORIZATION_HEADER);
if (authorizationHeader != null) {
Matcher matcher = PATTERN.matcher(authorizationHeader);
if (matcher.find()) {
authorizationHeader = authorizationHeader.substring(matcher.end());
}
}
return authorizationHeader;
}
private AuthenticationInfo checkAuthentication(HttpServletRequest req) {
AuthenticationInfo authenticationInfo = (AuthenticationInfo) req.getSession().getAttribute(
AUTH_MESSAGE_STORE_AUTHENTICATION_INFO);
if (authenticationInfo != null) {
return authenticationInfo;
}
String bearerToken = getBearerToken(req);
if (bearerToken == null) {
return authenticationInfo;
}
try {
authenticationInfo = validateToken(bearerToken);
boolean success = authenticationInfo.isAuthenticated();
if (success) {
req.getSession().setAttribute(AUTH_MESSAGE_STORE_AUTHENTICATION_INFO, authenticationInfo);
}
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug("checkAuthentication() fail: " + e.getMessage(), e);
}
}
return authenticationInfo;
}
/**
* This method gets a string accessToken and validates it
*
* @param token which need to be validated.
* @return AuthenticationInfo with the validated results.
*/
private AuthenticationInfo validateToken(String token) {
OAuth2TokenValidationServiceStub tokenValidationServiceStub = null;
try {
Object stub = this.stubs.borrowObject();
if (stub != null) {
tokenValidationServiceStub = (OAuth2TokenValidationServiceStub) stub;
if (cookie != null) {
tokenValidationServiceStub._getServiceClient().getOptions().setProperty(
HTTPConstants.COOKIE_STRING, cookie);
}
return getAuthenticationInfo(token, tokenValidationServiceStub);
} else {
log.warn("Stub initialization failed.");
}
} catch (RemoteException e) {
log.error("Error on connecting with the validation endpoint.", e);
} catch (Exception e) {
log.error("Error occurred in borrowing an validation stub from the pool.", e);
} finally {
try {
if (tokenValidationServiceStub != null) {
this.stubs.returnObject(tokenValidationServiceStub);
}
} catch (Exception e) {
log.warn("Error occurred while returning the object back to the oauth token validation service " +
"stub pool.", e);
}
}
AuthenticationInfo authenticationInfo = new AuthenticationInfo();
authenticationInfo.setAuthenticated(false);
authenticationInfo.setTenantId(-1);
return authenticationInfo;
}
/**
* This creates an AuthenticationInfo object that is used for authorization. This method will validate the token
* and
* sets the required parameters to the object.
*
* @param token that needs to be validated.
* @param tokenValidationServiceStub stub that is used to call the external service.
* @return AuthenticationInfo This contains the information related to authenticated client.
* @throws RemoteException that triggers when failing to call the external service..
*/
private AuthenticationInfo getAuthenticationInfo(String token,
OAuth2TokenValidationServiceStub tokenValidationServiceStub)
throws RemoteException, UserStoreException {
AuthenticationInfo authenticationInfo = new AuthenticationInfo();
OAuth2TokenValidationRequestDTO validationRequest = new OAuth2TokenValidationRequestDTO();
OAuth2TokenValidationRequestDTO_OAuth2AccessToken accessToken =
new OAuth2TokenValidationRequestDTO_OAuth2AccessToken();
accessToken.setTokenType(TOKEN_TYPE);
accessToken.setIdentifier(token);
validationRequest.setAccessToken(accessToken);
boolean authenticated;
OAuth2TokenValidationResponseDTO tokenValidationResponse;
tokenValidationResponse = tokenValidationServiceStub.validate(validationRequest);
if (tokenValidationResponse == null) {
authenticationInfo.setAuthenticated(false);
return authenticationInfo;
}
authenticated = tokenValidationResponse.getValid();
if (authenticated) {
String authorizedUser = tokenValidationResponse.getAuthorizedUser();
String username = MultitenantUtils.getTenantAwareUsername(authorizedUser);
String tenantDomain = MultitenantUtils.getTenantDomain(authorizedUser);
authenticationInfo.setUsername(username);
authenticationInfo.setTenantDomain(tenantDomain);
RealmService realmService = EventAdapterServiceDataHolder.getRealmService();
int tenantId = realmService.getTenantManager().getTenantId(authenticationInfo.getTenantDomain());
authenticationInfo.setTenantId(tenantId);
} else {
if (log.isDebugEnabled()) {
log.debug("Token validation failed for token: " + token);
}
}
ServiceContext serviceContext = tokenValidationServiceStub._getServiceClient()
.getLastOperationContext().getServiceContext();
cookie = (String) serviceContext.getProperty(HTTPConstants.COOKIE_STRING);
authenticationInfo.setAuthenticated(authenticated);
return authenticationInfo;
}
private String inputStreamToString(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int i;
while ((i = in.read(buff)) > 0) {
out.write(buff, 0, i);
}
out.close();
return out.toString();
}
@Override
protected void doPost(HttpServletRequest req,
HttpServletResponse res) throws IOException {
String data = this.inputStreamToString(req.getInputStream());
if (data == null) {
log.warn("Event Object is empty/null");
return;
}
AuthenticationInfo authenticationInfo = null;
if (exposedTransports.equalsIgnoreCase(HTTPEventAdapterConstants.HTTPS)) {
if (!req.isSecure()) {
res.setStatus(403);
log.error("Only Secured endpoint is enabled for requests");
return;
} else {
authenticationInfo = this.checkAuthentication(req);
int tenantId = authenticationInfo != null ? authenticationInfo.getTenantId() : -1;
if (tenantId == -1) {
res.getOutputStream().write(AUTH_FAILURE_RESPONSE.getBytes());
res.setStatus(401);
log.error("Authentication failed for the request");
return;
} else if (tenantId != this.tenantId) {
res.getOutputStream().write(AUTH_FAILURE_RESPONSE.getBytes());
res.setStatus(401);
log.error("Authentication failed for the request");
return;
}
}
} else if (exposedTransports.equalsIgnoreCase(HTTPEventAdapterConstants.HTTP)) {
if (req.isSecure()) {
res.setStatus(403);
log.error("Only unsecured endpoint is enabled for requests");
return;
}
} else {
authenticationInfo = this.checkAuthentication(req);
int tenantId = authenticationInfo != null ? authenticationInfo.getTenantId() : -1;
if (tenantId == -1) {
res.getOutputStream().write(AUTH_FAILURE_RESPONSE.getBytes());
res.setStatus(401);
log.error("Authentication failed for the request");
return;
} else if (tenantId != this.tenantId) {
res.getOutputStream().write(AUTH_FAILURE_RESPONSE.getBytes());
res.setStatus(401);
log.error("Authentication failed for the request");
return;
}
}
if (log.isDebugEnabled()) {
log.debug("Message : " + data);
}
if (authenticationInfo != null) {
Map<String, String> paramMap = new HashMap<>();
Enumeration<String> reqParameterNames = req.getParameterNames();
while (reqParameterNames.hasMoreElements()) {
String paramterName = reqParameterNames.nextElement();
paramMap.put(paramterName, req.getParameter(paramterName));
}
paramMap.put(HTTPEventAdapterConstants.USERNAME_TAG, authenticationInfo.getUsername());
paramMap.put(HTTPEventAdapterConstants.TENANT_DOMAIN_TAG, authenticationInfo.getTenantDomain());
if (contentValidator != null && contentTransformer != null) {
data = contentTransformer.transform(data, paramMap);
ContentInfo contentInfo = contentValidator.validate(data, contentValidationProperties, paramMap);
if (contentInfo != null && contentInfo.isValidContent()) {
HTTPEventAdapter.executorService.submit(new HTTPRequestProcessor(eventAdaptorListener,
contentInfo.getMsgText(), tenantId));
}
}
}
}
@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse res) throws IOException {
doPost(req, res);
}
public class HTTPRequestProcessor implements Runnable {
private InputEventAdapterListener inputEventAdapterListener;
private String payload;
private int tenantId;
public HTTPRequestProcessor(InputEventAdapterListener inputEventAdapterListener,
String payload, int tenantId) {
this.inputEventAdapterListener = inputEventAdapterListener;
this.payload = payload;
this.tenantId = tenantId;
}
public void run() {
try {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId);
if (log.isDebugEnabled()) {
log.debug("Event received in HTTP Event Adapter - " + payload);
}
if (payload.trim() != null) {
inputEventAdapterListener.onEvent(payload);
} else {
log.warn("Dropping the empty/null event received through http adapter");
}
} catch (Exception e) {
log.error("Error while parsing http request for processing: " + e.getMessage(), e);
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
}
}

@ -0,0 +1,56 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.input.adapter.http.exception;
/**
* This exception will thrown when content validator is failed to intialiaze.
*/
public class HTTPContentInitializationException extends RuntimeException {
private String errMessage;
public HTTPContentInitializationException(String msg, Exception nestedEx) {
super(msg, nestedEx);
setErrorMessage(msg);
}
public HTTPContentInitializationException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
public HTTPContentInitializationException(String msg) {
super(msg);
setErrorMessage(msg);
}
public HTTPContentInitializationException() {
super();
}
public HTTPContentInitializationException(Throwable cause) {
super(cause);
}
public String getErrorMessage() {
return errMessage;
}
public void setErrorMessage(String errMessage) {
this.errMessage = errMessage;
}
}

@ -0,0 +1,181 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.input.adapter.http.oauth;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.transport.http.HttpTransportProperties;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.log4j.Logger;
import org.wso2.carbon.core.util.Utils;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterConfiguration;
import org.wso2.carbon.device.mgt.iot.input.adapter.http.oauth.exception.OAuthTokenValidationException;
import org.wso2.carbon.device.mgt.iot.input.adapter.http.util.HTTPEventAdapterConstants;
import org.wso2.carbon.identity.oauth2.stub.OAuth2TokenValidationServiceStub;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.GeneralSecurityException;
/**
* This follows object pool pattern to manage the stub for oauth validation service.
*/
public class OAuthTokenValidaterStubFactory extends BasePoolableObjectFactory {
private static final Logger log = Logger.getLogger(OAuthTokenValidaterStubFactory.class);
private HttpClient httpClient;
InputEventAdapterConfiguration eventAdapterConfiguration;
public OAuthTokenValidaterStubFactory(InputEventAdapterConfiguration eventAdapterConfiguration) {
this.eventAdapterConfiguration = eventAdapterConfiguration;
this.httpClient = createHttpClient();
}
/**
* This creates a OAuth2TokenValidationServiceStub object to the pool.
*
* @return an OAuthValidationStub object
* @throws Exception thrown when creating the object.
*/
@Override
public Object makeObject() throws Exception {
return this.generateStub();
}
/**
* This is used to clean up the OAuth validation stub and releases to the object pool.
*
* @param o object that needs to be released.
* @throws Exception throws when failed to release to the pool
*/
@Override
public void passivateObject(Object o) throws Exception {
if (o instanceof OAuth2TokenValidationServiceStub) {
OAuth2TokenValidationServiceStub stub = (OAuth2TokenValidationServiceStub) o;
stub._getServiceClient().cleanupTransport();
}
}
/**
* This is used to create a stub which will be triggered through object pool factory, which will create an
* instance of it.
*
* @return OAuth2TokenValidationServiceStub stub that is used to call an external service.
* @throws OAuthTokenValidationException will be thrown when initialization failed.
*/
private OAuth2TokenValidationServiceStub generateStub() throws OAuthTokenValidationException {
OAuth2TokenValidationServiceStub stub;
try {
URL hostURL = new URL(Utils.replaceSystemProperty(eventAdapterConfiguration.getProperties().get(
HTTPEventAdapterConstants.TOKEN_VALIDATION_ENDPOINT_URL)));
if (hostURL != null) {
stub = new OAuth2TokenValidationServiceStub(hostURL.toString());
if (stub != null) {
ServiceClient client = stub._getServiceClient();
client.getServiceContext().getConfigurationContext().setProperty(
HTTPConstants.CACHED_HTTP_CLIENT, httpClient);
HttpTransportProperties.Authenticator auth =
new HttpTransportProperties.Authenticator();
auth.setPreemptiveAuthentication(true);
String username = eventAdapterConfiguration.getProperties().get(HTTPEventAdapterConstants
.USERNAME);
String password = eventAdapterConfiguration.getProperties().get(HTTPEventAdapterConstants
.PASSWORD);
auth.setPassword(username);
auth.setUsername(password);
Options options = client.getOptions();
options.setProperty(HTTPConstants.AUTHENTICATE, auth);
options.setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Constants.VALUE_TRUE);
client.setOptions(options);
if (hostURL.getProtocol().equals("https")) {
// set up ssl factory since axis2 https transport is used.
EasySSLProtocolSocketFactory sslProtocolSocketFactory =
createProtocolSocketFactory();
Protocol authhttps = new Protocol(hostURL.getProtocol(),
(ProtocolSocketFactory) sslProtocolSocketFactory,
hostURL.getPort());
Protocol.registerProtocol(hostURL.getProtocol(), authhttps);
options.setProperty(HTTPConstants.CUSTOM_PROTOCOL_HANDLER, authhttps);
}
} else {
String errorMsg = "OAuth Validation instanization failed.";
throw new OAuthTokenValidationException(errorMsg);
}
} else {
String errorMsg = "host url is invalid";
throw new OAuthTokenValidationException(errorMsg);
}
} catch (AxisFault axisFault) {
throw new OAuthTokenValidationException(
"Error occurred while creating the OAuth2TokenValidationServiceStub.", axisFault);
} catch (MalformedURLException e) {
throw new OAuthTokenValidationException(
"Error occurred while parsing token endpoint URL", e);
}
return stub;
}
/**
* This is required to create a trusted connection with the external entity.
* Have to manually configure it since we use CommonHTTPTransport(axis2 transport) in axis2.
*
* @return an EasySSLProtocolSocketFactory for SSL communication.
*/
private EasySSLProtocolSocketFactory createProtocolSocketFactory() throws OAuthTokenValidationException {
try {
EasySSLProtocolSocketFactory easySSLPSFactory = new EasySSLProtocolSocketFactory();
return easySSLPSFactory;
} catch (IOException e) {
String errorMsg = "Failed to initiate EasySSLProtocolSocketFactory.";
throw new OAuthTokenValidationException(errorMsg, e);
} catch (GeneralSecurityException e) {
String errorMsg = "Failed to set the key material in easy ssl factory.";
throw new OAuthTokenValidationException(errorMsg, e);
}
}
/**
* This created httpclient pool that can be used to connect to external entity. This connection can be configured
* via broker.xml by setting up the required http connection parameters.
*
* @return an instance of HttpClient that is configured with MultiThreadedHttpConnectionManager
*/
private HttpClient createHttpClient() {
HttpConnectionManagerParams params = new HttpConnectionManagerParams();
params.setDefaultMaxConnectionsPerHost(Integer.parseInt(eventAdapterConfiguration.getProperties().get(
HTTPEventAdapterConstants.MAXIMUM_HTTP_CONNECTION_PER_HOST)));
params.setMaxTotalConnections(Integer.parseInt(eventAdapterConfiguration.getProperties().get(
HTTPEventAdapterConstants.MAXIMUM_TOTAL_HTTP_CONNECTION)));
HttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
connectionManager.setParams(params);
return new HttpClient(connectionManager);
}
}

@ -0,0 +1,56 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.input.adapter.http.oauth.exception;
/**
* This Exception will be thrown, when there any interference with token validation flow.
*/
public class OAuthTokenValidationException extends Exception {
private String errMessage;
public OAuthTokenValidationException(String msg, Exception nestedEx) {
super(msg, nestedEx);
setErrorMessage(msg);
}
public OAuthTokenValidationException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
public OAuthTokenValidationException(String msg) {
super(msg);
setErrorMessage(msg);
}
public OAuthTokenValidationException() {
super();
}
public OAuthTokenValidationException(Throwable cause) {
super(cause);
}
public String getErrorMessage() {
return errMessage;
}
public void setErrorMessage(String errMessage) {
this.errMessage = errMessage;
}
}

@ -0,0 +1,69 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* 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.wso2.carbon.device.mgt.iot.input.adapter.http.util;
/**
* This will be return after authentication and this will consist of the authenticated user info.
*/
public class AuthenticationInfo {
/**
* this variable is used to check whether the client is authenticated.
*/
private boolean authenticated;
private String username;
private String tenantDomain;
private int tenantId;
/**
* returns whether the client is authenticated
*/
public boolean isAuthenticated() {
return authenticated;
}
public void setAuthenticated(boolean authenticated) {
this.authenticated = authenticated;
}
/**
* returns the authenticated client username
*/
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
/**
* return the authenticated client tenant domain
*/
public String getTenantDomain() {
return tenantDomain;
}
public void setTenantDomain(String tenantDomain) {
this.tenantDomain = tenantDomain;
}
public int getTenantId() {
return tenantId;
}
public void setTenantId(int tenantId) {
this.tenantId = tenantId;
}
}

@ -0,0 +1,77 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.input.adapter.http.util;
import com.jayway.jsonpath.JsonPath;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.simple.JSONArray;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.wso2.carbon.device.mgt.iot.input.adapter.ContentInfo;
import org.wso2.carbon.device.mgt.iot.input.adapter.ContentValidator;
import java.util.Map;
public class HTTPContentValidator implements ContentValidator {
private static final Log log = LogFactory.getLog(HTTPContentValidator.class);
private static String JSON_ARRAY_START_CHAR = "[";
@Override
public ContentInfo validate(String msgPayload, Map<String, String> contentValidationParams,
Map<String, String> dynamicParams) {
String deviceId = dynamicParams.get("deviceId");
String msg = msgPayload;
String deviceIdJsonPath = contentValidationParams.get(HTTPEventAdapterConstants.DEVICE_ID_JSON_PATH);
boolean status;
if (msg.startsWith(JSON_ARRAY_START_CHAR)) {
status = processMultipleEvents(msg, deviceId, deviceIdJsonPath);
} else {
status = processSingleEvent(msg, deviceId, deviceIdJsonPath);
}
return new ContentInfo(status, msg);
}
private boolean processSingleEvent(String msg, String deviceIdFromTopic, String deviceIdJsonPath) {
Object res = JsonPath.read(msg, deviceIdJsonPath);
String deviceIdFromContent = (res != null) ? res.toString() : "";
if (deviceIdFromContent.equals(deviceIdFromTopic)) {
return true;
}
return false;
}
private boolean processMultipleEvents(String msg, String deviceIdFromTopic, String deviceIdJsonPath) {
try {
JSONParser jsonParser = new JSONParser();
JSONArray jsonArray = (JSONArray) jsonParser.parse(msg);
boolean status = false;
for (int i = 0; i < jsonArray.size(); i++) {
status = processSingleEvent(jsonArray.get(i).toString(), deviceIdFromTopic, deviceIdJsonPath);
if (!status) {
return status;
}
}
return status;
} catch (ParseException e) {
log.error("Invalid input " + msg, e);
return false;
}
}
}

@ -0,0 +1,76 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* 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.wso2.carbon.device.mgt.iot.input.adapter.http.util;
/**
* This holds the constants related to HTTP event adapter.
*/
public final class HTTPEventAdapterConstants {
private HTTPEventAdapterConstants() {
}
public static final String ADAPTER_TYPE_HTTP = "oauth-http";
public static final String ADAPTER_USAGE_TIPS_PREFIX = "http.usage.tips_prefix";
public static final String ADAPTER_USAGE_TIPS_MID1 = "http.usage.tips_mid1";
public static final String ADAPTER_USAGE_TIPS_MID2 = "http.usage.tips_mid2";
public static final String ADAPTER_USAGE_TIPS_MID3 = "http.usage.tips_mid3";
public static final String ADAPTER_USAGE_TIPS_POSTFIX = "http.usage.tips_postfix";
public static final int ADAPTER_MIN_THREAD_POOL_SIZE = 8;
public static final int ADAPTER_MAX_THREAD_POOL_SIZE = 100;
public static final int ADAPTER_EXECUTOR_JOB_QUEUE_SIZE = 10000;
public static final long DEFAULT_KEEP_ALIVE_TIME_IN_MILLS = 20000;
public static final String ENDPOINT_PREFIX = "/endpoints/";
public static final String ENDPOINT_URL_SEPARATOR = "/";
public static final String ENDPOINT_TENANT_KEY = "t";
public static final String ADAPTER_MIN_THREAD_POOL_SIZE_NAME = "minThread";
public static final String ADAPTER_MAX_THREAD_POOL_SIZE_NAME = "maxThread";
public static final String ADAPTER_KEEP_ALIVE_TIME_NAME = "keepAliveTimeInMillis";
public static final String ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME = "jobQueueSize";
public static final String EXPOSED_TRANSPORTS = "transports";
public static final String HTTPS = "https";
public static final String HTTP = "http";
public static final String LOCAL = "local";
public static final String ALL = "all";
public static final String CARBON_CONFIG_PORT_OFFSET_NODE = "Ports.Offset";
public static final int DEFAULT_HTTP_PORT = 9763;
public static final int DEFAULT_HTTPS_PORT = 9443;
public static final String MAXIMUM_TOTAL_HTTP_CONNECTION = "maximumTotalHttpConnection";
public static final String MAXIMUM_TOTAL_HTTP_CONNECTION_HINT = "maximumTotalHttpConnection.hint";
public static final String MAXIMUM_HTTP_CONNECTION_PER_HOST = "maximumHttpConnectionPerHost";
public static final String MAXIMUM_HTTP_CONNECTION_PER_HOST_HINT = "maximumHttpConnectionPerHost.hint";
public static final String TOKEN_VALIDATION_ENDPOINT_URL = "tokenValidationEndpointUrl";
public static final String TOKEN_VALIDATION_ENDPOINT_URL_HINT = "tokenValidationEndpointUrl.hint";
public static final String USERNAME = "username";
public static final String USERNAME_HINT = "username.hint";
public static final String PASSWORD = "password";
public static final String PASSWORD_HINT = "password.hint";
public static final String DEFAULT_STRING = "default";
public static final String MAX_HTTP_CONNECTION = "2";
public static final String MAX_TOTAL_HTTP_CONNECTION = "100";
public static final String TENANT_DOMAIN_TAG = "tenantDomain";
public static final String USERNAME_TAG = "username";
public static final String PAYLOAD_TAG = "payload";
public static final String DEVICE_ID_JSON_PATH = "device_id_json_path";
public static final String ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME = "contentValidation";
public static final String ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME_HINT = "contentValidation.hint";
public static final String ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS = "contentValidationParams";
public static final String ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS_HINT = "contentValidationParams.hint";
public static final String DEFAULT = "default";
public static final String MQTT_CONTENT_VALIDATION_DEFAULT_PARAMETERS =
"device_id_json_path:meta_deviceId";
public static final String ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME = "contentTransformer";
public static final String ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME_HINT = "contentTransformer.hint";
}

@ -0,0 +1,81 @@
/*
* 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.device.mgt.iot.input.adapter.internal;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.http.HttpService;
import org.wso2.carbon.device.mgt.iot.input.adapter.http.HTTPEventAdapterFactory;
import org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.MQTTEventAdapterFactory;
import org.wso2.carbon.device.mgt.iot.input.adapter.xmpp.XMPPEventAdapterFactory;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterFactory;
import org.wso2.carbon.user.core.service.RealmService;
/**
* @scr.component component.name="input.iot.Mqtt.AdapterService.component" immediate="true"
*/
/**
* @scr.component name="org.wso2.carbon.event.input.adapter.extension.EventAdapterServiceComponent" immediate="true"
* @scr.reference name="user.realmservice.default"
* interface="org.wso2.carbon.user.core.service.RealmService" cardinality="1..1"
* policy="dynamic" bind="setRealmService" unbind="unsetRealmService"
* @scr.reference name="http.service" interface="org.osgi.service.http.HttpService"
* cardinality="1..1" policy="dynamic" bind="setHttpService" unbind="unsetHttpService"
*/
public class EventAdapterServiceComponent {
private static final Log log = LogFactory.getLog(EventAdapterServiceComponent.class);
protected void activate(ComponentContext context) {
try {
InputEventAdapterFactory mqttEventAdapterFactory = new MQTTEventAdapterFactory();
context.getBundleContext().registerService(InputEventAdapterFactory.class.getName(),
mqttEventAdapterFactory, null);
InputEventAdapterFactory httpEventEventAdapterFactory = new HTTPEventAdapterFactory();
context.getBundleContext().registerService(InputEventAdapterFactory.class.getName(),
httpEventEventAdapterFactory, null);
InputEventAdapterFactory xmppEventEventAdapterFactory = new XMPPEventAdapterFactory();
context.getBundleContext().registerService(InputEventAdapterFactory.class.getName(),
xmppEventEventAdapterFactory, null);
if (log.isDebugEnabled()) {
log.debug("Successfully deployed the input adapter service");
}
} catch (RuntimeException e) {
log.error("Can not create the input adapter service ", e);
}
}
protected void setRealmService(RealmService realmService) {
EventAdapterServiceDataHolder.registerRealmService(realmService);
}
protected void unsetRealmService(RealmService realmService) {
EventAdapterServiceDataHolder.registerRealmService(null);
}
protected void setHttpService(HttpService httpService) {
EventAdapterServiceDataHolder.registerHTTPService(httpService);
}
protected void unsetHttpService(HttpService httpService) {
EventAdapterServiceDataHolder.registerHTTPService(null);
}
}

@ -0,0 +1,50 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* 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.wso2.carbon.device.mgt.iot.input.adapter.internal;
import org.osgi.service.http.HttpService;
import org.wso2.carbon.user.core.service.RealmService;
/**
* common place to hold some OSGI service references.
*/
public final class EventAdapterServiceDataHolder {
private static RealmService realmService;
private static HttpService httpService;
private EventAdapterServiceDataHolder() {
}
public static void registerRealmService(
RealmService realmService) {
EventAdapterServiceDataHolder.realmService = realmService;
}
public static RealmService getRealmService() {
return realmService;
}
public static void registerHTTPService(
HttpService httpService) {
EventAdapterServiceDataHolder.httpService = httpService;
}
public static HttpService getHTTPService() {
return httpService;
}
}

@ -0,0 +1,38 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.input.adapter.mqtt;
/**
* This holds the constants related to MQTT input adapter.
*/
public class Constants {
public static final String EMPTY_STRING = "";
public static final String GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer refresh_token";
public static final String TOKEN_SCOPE = "production";
public static final String APPLICATION_TYPE = "device";
public static final String CLIENT_ID = "client_id";
public static final String CLIENT_SECRET = "client_secret";
public static final String CLIENT_NAME = "client_name";
public static final String DEFAULT = "default";
public static final String MQTT_CONTENT_VALIDATION_DEFAULT_PARAMETERS =
"device_id_json_path:event.metaData.deviceId,device_id_topic_hierarchy_index:2";
public static final String TOPIC = "topic";
public static final String PAYLOAD = "payload";
public static final String DEVICE_ID_JSON_PATH = "device_id_json_path";
public static final String DEVICE_ID_TOPIC_HIERARCHY_INDEX = "device_id_topic_hierarchy_index";
}

@ -0,0 +1,165 @@
/*
* 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.device.mgt.iot.input.adapter.mqtt;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.util.MQTTBrokerConnectionConfiguration;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapter;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterConfiguration;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterListener;
import org.wso2.carbon.event.input.adapter.core.exception.InputEventAdapterException;
import org.wso2.carbon.event.input.adapter.core.exception.TestConnectionNotSupportedException;
import org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.util.MQTTAdapterListener;
import org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.util.MQTTEventAdapterConstants;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Input XMPPEventAdapter will be used to receive events with MQTT protocol using specified broker and topic.
*/
public class MQTTEventAdapter implements InputEventAdapter {
private final InputEventAdapterConfiguration eventAdapterConfiguration;
private final Map<String, String> globalProperties;
private InputEventAdapterListener eventAdapterListener;
private final String id = UUID.randomUUID().toString();
private MQTTAdapterListener mqttAdapterListener;
private MQTTBrokerConnectionConfiguration mqttBrokerConnectionConfiguration;
public MQTTEventAdapter(InputEventAdapterConfiguration eventAdapterConfiguration,
Map<String, String> globalProperties) {
this.eventAdapterConfiguration = eventAdapterConfiguration;
this.globalProperties = globalProperties;
}
@Override
public void init(InputEventAdapterListener eventAdapterListener) throws InputEventAdapterException {
this.eventAdapterListener = eventAdapterListener;
try {
int keepAlive;
//If global properties are available those will be assigned else constant values will be assigned
if (globalProperties.get(MQTTEventAdapterConstants.ADAPTER_CONF_KEEP_ALIVE) != null) {
keepAlive = Integer.parseInt((globalProperties.get(MQTTEventAdapterConstants.ADAPTER_CONF_KEEP_ALIVE)));
} else {
keepAlive = MQTTEventAdapterConstants.ADAPTER_CONF_DEFAULT_KEEP_ALIVE;
}
String contentValidationParams = eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS);
String params[] = contentValidationParams.split(",");
Map<String, String> paramsMap = new HashMap<>();
for (String param: params) {
String paramsKeyAndValue[] = splitOnFirst(param, ':');
if (paramsKeyAndValue.length != 2) {
throw new InputEventAdapterException("Invalid parameters for content validation - " + param);
}
paramsMap.put(paramsKeyAndValue[0], paramsKeyAndValue[1]);
}
mqttBrokerConnectionConfiguration = new MQTTBrokerConnectionConfiguration(
eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_URL),
eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_USERNAME),
eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_SCOPES),
eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_DCR_URL),
eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_CLEAN_SESSION),
keepAlive,
eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME),
paramsMap,
eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME)
);
mqttAdapterListener = new MQTTAdapterListener(mqttBrokerConnectionConfiguration,
eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_MESSAGE_TOPIC),
eventAdapterConfiguration.getProperties().get(MQTTEventAdapterConstants.ADAPTER_CONF_CLIENTID),
eventAdapterListener, PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId());
} catch (Throwable t) {
throw new InputEventAdapterException(t.getMessage(), t);
}
}
private String[] splitOnFirst(String str, char c) {
int idx = str.indexOf(c);
String head = str.substring(0, idx);
String tail = str.substring(idx + 1);
return new String[] { head, tail} ;
}
@Override
public void testConnect() throws TestConnectionNotSupportedException {
throw new TestConnectionNotSupportedException("not-supported");
}
@Override
public void connect() {
mqttAdapterListener.createConnection();
}
@Override
public void disconnect() {
//when mqtt and this feature both together then this method becomes a blocking method, Therefore
// have used a thread to skip it.
try {
Thread thread = new Thread(new Runnable() {
public void run() {
if (mqttAdapterListener != null) {
mqttAdapterListener.stopListener(eventAdapterConfiguration.getName());
}
}
});
thread.start();
thread.join(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@Override
public void destroy() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MQTTEventAdapter)) return false;
MQTTEventAdapter that = (MQTTEventAdapter) o;
if (!id.equals(that.id)) return false;
return true;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean isEventDuplicatedInCluster() {
return true;
}
@Override
public boolean isPolling() {
return true;
}
}

@ -0,0 +1,149 @@
/*
* 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.device.mgt.iot.input.adapter.mqtt;
import org.wso2.carbon.device.mgt.iot.input.adapter.xmpp.util.XMPPEventAdapterConstants;
import org.wso2.carbon.event.input.adapter.core.*;
import org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.util.MQTTEventAdapterConstants;
import java.util.*;
/**
* The mqtt event adapter factory class to create a mqtt input adapter
*/
public class MQTTEventAdapterFactory extends InputEventAdapterFactory {
private ResourceBundle resourceBundle = ResourceBundle.getBundle
("org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.i18n.Resources", Locale.getDefault());
@Override
public String getType() {
return MQTTEventAdapterConstants.ADAPTER_TYPE_MQTT;
}
@Override
public List<String> getSupportedMessageFormats() {
List<String> supportInputMessageTypes = new ArrayList<String>();
supportInputMessageTypes.add(MessageType.JSON);
supportInputMessageTypes.add(MessageType.TEXT);
supportInputMessageTypes.add(MessageType.XML);
supportInputMessageTypes.add(MessageType.WSO2EVENT);
return supportInputMessageTypes;
}
@Override
public List<Property> getPropertyList() {
List<Property> propertyList = new ArrayList<Property>();
// set topic
Property topicProperty = new Property(MQTTEventAdapterConstants.ADAPTER_MESSAGE_TOPIC);
topicProperty.setDisplayName(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_MESSAGE_TOPIC));
topicProperty.setRequired(true);
topicProperty.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_MESSAGE_TOPIC_HINT));
propertyList.add(topicProperty);
//Broker Url
Property brokerUrl = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_URL);
brokerUrl.setDisplayName(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_URL));
brokerUrl.setRequired(true);
brokerUrl.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_URL_HINT));
propertyList.add(brokerUrl);
//DCR endpoint details
Property dcrUrl = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_DCR_URL);
dcrUrl.setDisplayName(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_DCR_URL));
dcrUrl.setRequired(false);
dcrUrl.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_DCR_URL_HINT));
propertyList.add(dcrUrl);
//Content Validator details
Property contentValidator = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME);
contentValidator.setDisplayName(
resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME));
contentValidator.setRequired(false);
contentValidator.setHint(
resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME_HINT));
contentValidator.setDefaultValue(Constants.DEFAULT);
propertyList.add(contentValidator);
//Content Validator Params details
Property contentValidatorParams = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS);
contentValidatorParams.setDisplayName(
resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS));
contentValidatorParams.setRequired(false);
contentValidatorParams.setHint(
resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS_HINT));
contentValidatorParams.setDefaultValue(Constants.MQTT_CONTENT_VALIDATION_DEFAULT_PARAMETERS);
propertyList.add(contentValidatorParams);
//Broker Username
Property userName = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_USERNAME);
userName.setDisplayName(
resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_USERNAME));
userName.setRequired(false);
userName.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_USERNAME_HINT));
propertyList.add(userName);
//Broker Required Scopes.
Property scopes = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_SCOPES);
scopes.setDisplayName(
resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_SCOPES));
scopes.setRequired(false);
scopes.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_SCOPES_HINT));
propertyList.add(scopes);
//Broker clear session
Property clearSession = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_CLEAN_SESSION);
clearSession.setDisplayName(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CLEAN_SESSION));
clearSession.setRequired(false);
clearSession.setOptions(new String[]{"true", "false"});
clearSession.setDefaultValue("true");
clearSession.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CLEAN_SESSION_HINT));
propertyList.add(clearSession);
//Content Transformer details
Property contentTransformer = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME);
contentTransformer.setDisplayName(
resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME));
contentTransformer.setRequired(false);
contentTransformer.setHint(
resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME_HINT));
contentTransformer.setDefaultValue(Constants.DEFAULT);
propertyList.add(contentTransformer);
// set clientId
Property clientId = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_CLIENTID);
clientId.setDisplayName(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CLIENTID));
clientId.setRequired(false);
clientId.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CLIENTID_HINT));
propertyList.add(clientId);
return propertyList;
}
@Override
public String getUsageTips() {
return null;
}
@Override
public InputEventAdapter createEventAdapter(InputEventAdapterConfiguration eventAdapterConfiguration,
Map<String, String> globalProperties) {
return new MQTTEventAdapter(eventAdapterConfiguration, globalProperties);
}
}

@ -0,0 +1,56 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.input.adapter.mqtt.exception;
/**
* This exception will thrown when content validator is failed to intialiaze.
*/
public class MQTTContentInitializationException extends RuntimeException {
private String errMessage;
public MQTTContentInitializationException(String msg, Exception nestedEx) {
super(msg, nestedEx);
setErrorMessage(msg);
}
public MQTTContentInitializationException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
public MQTTContentInitializationException(String msg) {
super(msg);
setErrorMessage(msg);
}
public MQTTContentInitializationException() {
super();
}
public MQTTContentInitializationException(Throwable cause) {
super(cause);
}
public String getErrorMessage() {
return errMessage;
}
public void setErrorMessage(String errMessage) {
this.errMessage = errMessage;
}
}

@ -0,0 +1,305 @@
/*
* 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.device.mgt.iot.input.adapter.mqtt.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.core.ServerStatus;
import org.wso2.carbon.device.mgt.iot.input.adapter.ContentInfo;
import org.wso2.carbon.device.mgt.iot.input.adapter.ContentTransformer;
import org.wso2.carbon.device.mgt.iot.input.adapter.DefaultContentTransformer;
import org.wso2.carbon.device.mgt.iot.input.adapter.DefaultContentValidator;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterListener;
import org.wso2.carbon.event.input.adapter.core.exception.InputEventAdapterRuntimeException;
import org.wso2.carbon.device.mgt.iot.input.adapter.ContentValidator;
import org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.Constants;
import org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.exception.MQTTContentInitializationException;
import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo;
import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException;
import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
public class MQTTAdapterListener implements MqttCallback, Runnable {
private static final Log log = LogFactory.getLog(MQTTAdapterListener.class);
private MqttClient mqttClient;
private MqttConnectOptions connectionOptions;
private boolean cleanSession;
private int keepAlive;
private MQTTBrokerConnectionConfiguration mqttBrokerConnectionConfiguration;
private String mqttClientId;
private String topic;
private int tenantId;
private boolean connectionSucceeded = false;
ContentValidator contentValidator;
Map<String, String> contentValidationParams;
ContentTransformer contentTransformer;
private InputEventAdapterListener eventAdapterListener = null;
public MQTTAdapterListener(MQTTBrokerConnectionConfiguration mqttBrokerConnectionConfiguration,
String topic, String mqttClientId,
InputEventAdapterListener inputEventAdapterListener, int tenantId) {
if(mqttClientId == null || mqttClientId.trim().isEmpty()){
mqttClientId = MqttClient.generateClientId();
}
this.mqttClientId = mqttClientId;
this.mqttBrokerConnectionConfiguration = mqttBrokerConnectionConfiguration;
this.cleanSession = mqttBrokerConnectionConfiguration.isCleanSession();
this.keepAlive = mqttBrokerConnectionConfiguration.getKeepAlive();
this.topic = topic;
this.eventAdapterListener = inputEventAdapterListener;
this.tenantId = tenantId;
//SORTING messages until the server fetches them
String temp_directory = System.getProperty("java.io.tmpdir");
MqttDefaultFilePersistence dataStore = new MqttDefaultFilePersistence(temp_directory);
try {
// Construct the connection options object that contains connection parameters
// such as cleanSession and LWT
connectionOptions = new MqttConnectOptions();
connectionOptions.setCleanSession(cleanSession);
connectionOptions.setKeepAliveInterval(keepAlive);
// Construct an MQTT blocking mode client
mqttClient = new MqttClient(this.mqttBrokerConnectionConfiguration.getBrokerUrl(), this.mqttClientId,
dataStore);
// Set this wrapper as the callback handler
mqttClient.setCallback(this);
String contentValidatorClassName = this.mqttBrokerConnectionConfiguration.getContentValidatorClassName();
if (contentValidatorClassName != null && contentValidatorClassName.equals(Constants.DEFAULT)) {
contentValidator = new DefaultContentValidator();
} else if (contentValidatorClassName != null && !contentValidatorClassName.isEmpty()) {
try {
Class<? extends ContentValidator> contentValidatorClass = Class.forName(contentValidatorClassName)
.asSubclass(ContentValidator.class);
contentValidator = contentValidatorClass.newInstance();
} catch (ClassNotFoundException e) {
throw new MQTTContentInitializationException(
"Unable to find the class validator: " + contentValidatorClassName, e);
} catch (InstantiationException e) {
throw new MQTTContentInitializationException(
"Unable to create an instance of :" + contentValidatorClassName, e);
} catch (IllegalAccessException e) {
throw new MQTTContentInitializationException("Access of the instance in not allowed.", e);
}
}
contentValidationParams = mqttBrokerConnectionConfiguration.getContentValidatorParams();
String contentTransformerClassName = this.mqttBrokerConnectionConfiguration.getContentTransformerClassName();
if (contentTransformerClassName != null && contentTransformerClassName.equals(Constants.DEFAULT)) {
contentTransformer = new DefaultContentTransformer();
} else if (contentTransformerClassName != null && !contentTransformerClassName.isEmpty()) {
try {
Class<? extends ContentTransformer> contentTransformerClass = Class.forName(contentTransformerClassName)
.asSubclass(ContentTransformer.class);
contentTransformer = contentTransformerClass.newInstance();
} catch (ClassNotFoundException e) {
throw new MQTTContentInitializationException(
"Unable to find the class transfoer: " + contentTransformerClassName, e);
} catch (InstantiationException e) {
throw new MQTTContentInitializationException(
"Unable to create an instance of :" + contentTransformerClassName, e);
} catch (IllegalAccessException e) {
throw new MQTTContentInitializationException("Access of the instance in not allowed.", e);
}
}
} catch (MqttException e) {
log.error("Exception occurred while subscribing to MQTT broker at "
+ mqttBrokerConnectionConfiguration.getBrokerUrl());
throw new InputEventAdapterRuntimeException(e);
} catch (Throwable e) {
log.error("Exception occurred while subscribing to MQTT broker at "
+ mqttBrokerConnectionConfiguration.getBrokerUrl());
throw new InputEventAdapterRuntimeException(e);
}
}
public void startListener() throws MqttException {
if (this.mqttBrokerConnectionConfiguration.getBrokerUsername() != null && this.mqttBrokerConnectionConfiguration.getDcrUrl() != null) {
String username = this.mqttBrokerConnectionConfiguration.getBrokerUsername();
String dcrUrlString = this.mqttBrokerConnectionConfiguration.getDcrUrl();
String scopes = this.mqttBrokerConnectionConfiguration.getBrokerScopes();
//getJWT Client Parameters.
if (dcrUrlString != null && !dcrUrlString.isEmpty()) {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId, true);
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(username);
try {
URL dcrUrl = new URL(dcrUrlString);
HttpClient httpClient = MQTTUtil.getHttpClient(dcrUrl.getProtocol());
HttpPost postMethod = new HttpPost(dcrUrlString);
RegistrationProfile registrationProfile = new RegistrationProfile();
registrationProfile.setCallbackUrl(Constants.EMPTY_STRING);
registrationProfile.setGrantType(Constants.GRANT_TYPE);
registrationProfile.setOwner(username);
registrationProfile.setTokenScope(Constants.TOKEN_SCOPE);
registrationProfile.setApplicationType(Constants.APPLICATION_TYPE);
registrationProfile.setClientName(username + "_" + tenantId);
String jsonString = registrationProfile.toJSON();
StringEntity requestEntity = new StringEntity(jsonString, ContentType.APPLICATION_JSON);
postMethod.setEntity(requestEntity);
HttpResponse httpResponse = httpClient.execute(postMethod);
String response = MQTTUtil.getResponseString(httpResponse);
try {
JSONParser jsonParser = new JSONParser();
JSONObject jsonPayload = (JSONObject) jsonParser.parse(response);
String clientId = (String) jsonPayload.get(Constants.CLIENT_ID);
String clientSecret = (String) jsonPayload.get(Constants.CLIENT_SECRET);
JWTClientManagerService jwtClientManagerService = MQTTUtil.getJWTClientManagerService();
AccessTokenInfo accessTokenInfo = jwtClientManagerService.getJWTClient().getAccessToken(
clientId, clientSecret, username, scopes);
connectionOptions.setUserName(accessTokenInfo.getAccessToken());
} catch (ParseException e) {
String msg = "error occurred while parsing client credential payload";
log.error(msg, e);
} catch (JWTClientException e) {
String msg = "error occurred while parsing the response from JWT Client";
log.error(msg, e);
}
} catch (MalformedURLException e) {
log.error("Invalid dcrUrl : " + dcrUrlString);
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException | IOException e) {
log.error("Failed to create an https connection.", e);
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
}
// Connect to the MQTT server
mqttClient.connect(connectionOptions);
// Subscribe to the requested topic
// The QoS specified is the maximum level that messages will be sent to the client at.
// For instance if QoS 1 is specified, any messages originally published at QoS 2 will
// be downgraded to 1 when delivering to the client but messages published at 1 and 0
// will be received at the same level they were published at.
mqttClient.subscribe(topic);
}
public void stopListener(String adapterName) {
if (connectionSucceeded) {
try {
// Un-subscribe accordingly and disconnect from the MQTT server.
if (!ServerStatus.getCurrentStatus().equals(ServerStatus.STATUS_SHUTTING_DOWN) || cleanSession) {
mqttClient.unsubscribe(topic);
}
mqttClient.disconnect(3000);
} catch (MqttException e) {
log.error("Can not unsubscribe from the destination " + topic
+ " with the event adapter " + adapterName, e);
}
}
//This is to stop all running reconnection threads
connectionSucceeded = true;
}
@Override
public void connectionLost(Throwable throwable) {
log.warn("MQTT connection not reachable " + throwable);
connectionSucceeded = false;
new Thread(this).start();
}
@Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
try {
String msgText = mqttMessage.toString();
if (log.isDebugEnabled()) {
log.debug(msgText);
}
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId);
if (log.isDebugEnabled()) {
log.debug("Event received in MQTT Event Adapter - " + msgText);
}
if (contentValidator != null && contentTransformer != null) {
ContentInfo contentInfo;
Map<String, String> dynamicProperties = new HashMap<>();
dynamicProperties.put(Constants.TOPIC, topic);
msgText = contentTransformer.transform(msgText, dynamicProperties);
contentInfo = contentValidator.validate(msgText,contentValidationParams, dynamicProperties);
if (contentInfo != null && contentInfo.isValidContent()) {
eventAdapterListener.onEvent(contentInfo.getMsgText());
}
} else {
eventAdapterListener.onEvent(msgText);
}
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
}
@Override
public void run() {
while (!connectionSucceeded) {
try {
MQTTEventAdapterConstants.initialReconnectDuration = MQTTEventAdapterConstants.initialReconnectDuration
* MQTTEventAdapterConstants.reconnectionProgressionFactor;
Thread.sleep(MQTTEventAdapterConstants.initialReconnectDuration);
startListener();
connectionSucceeded = true;
log.info("MQTT Connection successful");
} catch (InterruptedException e) {
log.error("Interruption occurred while waiting for reconnection", e);
} catch (MqttException e) {
log.error("MQTT Exception occurred when starting listener", e);
}
}
}
public void createConnection() {
new Thread(this).start();
}
}

@ -0,0 +1,131 @@
/*
* 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.device.mgt.iot.input.adapter.mqtt.util;
import org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.Constants;
import org.wso2.carbon.device.mgt.iot.input.adapter.util.PropertyUtils;
import java.util.Map;
/**
* This holds the configurations related to MQTT Broker.
*/
public class MQTTBrokerConnectionConfiguration {
private String brokerUsername = null;
private String brokerScopes = null;
private boolean cleanSession = true;
private int keepAlive;
private String brokerUrl;
private String dcrUrl;
private String contentValidatorClassName;
private Map<String, String> contentValidatorParams;
private String contentTransformerClassName;
public String getBrokerScopes() {
return brokerScopes;
}
public void setBrokerScopes(String brokerScopes) {
this.brokerScopes = brokerScopes;
}
public String getBrokerUsername() {
return brokerUsername;
}
public void setBrokerUsername(String brokerUsername) {
this.brokerUsername = brokerUsername;
}
public void setCleanSession(boolean cleanSession) {
this.cleanSession = cleanSession;
}
public boolean isCleanSession() {
return cleanSession;
}
public String getBrokerUrl() {
return brokerUrl;
}
public void setBrokerUrl(String brokerUrl) {
this.brokerUrl = brokerUrl;
}
public String getDcrUrl() {
return dcrUrl;
}
public void setDcrUrl(String dcrUrl) {
this.dcrUrl = dcrUrl;
}
public int getKeepAlive() {
return keepAlive;
}
public void setKeepAlive(int keepAlive) {
this.keepAlive = keepAlive;
}
public String getContentValidatorClassName() {
return contentValidatorClassName;
}
public void setContentValidatorClassName(String contentValidatorClassName) {
this.contentValidatorClassName = contentValidatorClassName;
}
public Map<String, String> getContentValidatorParams() {
return contentValidatorParams;
}
public void setContentValidatorParams(Map<String, String> contentValidatorParams) {
this.contentValidatorParams = contentValidatorParams;
}
public String getContentTransformerClassName() {
return contentTransformerClassName;
}
public MQTTBrokerConnectionConfiguration(String brokerUrl, String brokerUsername, String brokerScopes,
String dcrUrl, String cleanSession, int keepAlive,
String contentValidatorClassName, Map<String, String> contentValidatorParams,
String contentTransformerClassName) {
this.brokerUsername = brokerUsername;
this.brokerScopes = brokerScopes;
if (brokerScopes == null) {
this.brokerScopes = Constants.EMPTY_STRING;
}
this.brokerUrl = PropertyUtils.replaceMqttProperty(brokerUrl);
this.dcrUrl = PropertyUtils.replaceMqttProperty(dcrUrl);
this.contentValidatorClassName = contentValidatorClassName;
if (cleanSession != null) {
this.cleanSession = Boolean.parseBoolean(cleanSession);
}
this.keepAlive = keepAlive;
if (contentValidatorParams != null) {
this.contentValidatorParams = contentValidatorParams;
}
this.contentTransformerClassName = contentTransformerClassName;
}
}

@ -0,0 +1,87 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.input.adapter.mqtt.util;
import com.jayway.jsonpath.JsonPath;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.wso2.carbon.device.mgt.iot.input.adapter.ContentInfo;
import org.wso2.carbon.device.mgt.iot.input.adapter.ContentValidator;
import org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.Constants;
import java.util.Map;
public class MQTTContentValidator implements ContentValidator {
private static String JSON_ARRAY_START_CHAR = "[";
private static final Log log = LogFactory.getLog(MQTTContentValidator.class);
@Override
public ContentInfo validate(String msgPayload, Map<String, String> contentValidationParams,
Map<String, String> dynamicParams) {
String topic = dynamicParams.get(Constants.TOPIC);
String topics[] = topic.split("/");
String msg = msgPayload;
String deviceIdJsonPath = contentValidationParams.get(Constants.DEVICE_ID_JSON_PATH);
String deviceIdInTopicHierarchyLevel = contentValidationParams.get(Constants.DEVICE_ID_TOPIC_HIERARCHY_INDEX);
int deviceIdInTopicHierarchyLevelIndex = 0;
if (deviceIdInTopicHierarchyLevel != null && !deviceIdInTopicHierarchyLevel.isEmpty()) {
deviceIdInTopicHierarchyLevelIndex = Integer.parseInt(deviceIdInTopicHierarchyLevel);
}
String deviceIdFromTopic = topics[deviceIdInTopicHierarchyLevelIndex];
boolean status;
if (msg.startsWith(JSON_ARRAY_START_CHAR)) {
status = processMultipleEvents(msg, deviceIdFromTopic, deviceIdJsonPath);
} else {
status = processSingleEvent(msg, deviceIdFromTopic, deviceIdJsonPath);
}
return new ContentInfo(status, msg);
}
private boolean processSingleEvent(String msg, String deviceIdFromTopic, String deviceIdJsonPath) {
Object res = JsonPath.read(msg, deviceIdJsonPath);
String deviceIdFromContent = (res != null) ? res.toString() : "";
if (deviceIdFromContent.equals(deviceIdFromTopic)) {
return true;
}
return false;
}
private boolean processMultipleEvents(String msg, String deviceIdFromTopic, String deviceIdJsonPath) {
try {
JSONParser jsonParser = new JSONParser();
JSONArray jsonArray = (JSONArray) jsonParser.parse(msg);
boolean status = false;
for (int i = 0; i < jsonArray.size(); i++) {
status = processSingleEvent(jsonArray.get(i).toString(), deviceIdFromTopic, deviceIdJsonPath);
if (!status) {
return status;
}
}
return status;
} catch (ParseException e) {
log.error("Invalid input " + msg, e);
return false;
}
}
}

@ -0,0 +1,52 @@
/*
* 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.device.mgt.iot.input.adapter.mqtt.util;
/**
* This holds the constants related to mqtt event adapter.
*/
public class MQTTEventAdapterConstants {
public static final String ADAPTER_TYPE_MQTT = "oauth-mqtt";
public static final String ADAPTER_CONF_URL = "url";
public static final String ADAPTER_CONF_USERNAME = "username";
public static final String ADAPTER_CONF_USERNAME_HINT = "username.hint";
public static final String ADAPTER_CONF_SCOPES = "scopes";
public static final String ADAPTER_CONF_SCOPES_HINT = "scopes.hint";
public static final String ADAPTER_CONF_URL_HINT = "url.hint";
public static final String ADAPTER_CONF_DCR_URL = "dcrUrl";
public static final String ADAPTER_CONF_DCR_URL_HINT = "dcrUrl.hint";
public static final String ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME = "contentValidation";
public static final String ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME_HINT = "contentValidation.hint";
public static final String ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS = "contentValidationParams";
public static final String ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS_HINT = "contentValidationParams.hint";
public static final String ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME = "contentTransformer";
public static final String ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME_HINT = "contentTransformer.hint";
public static final String ADAPTER_MESSAGE_TOPIC = "topic";
public static final String ADAPTER_MESSAGE_TOPIC_HINT = "topic.hint";
public static final String ADAPTER_CONF_CLIENTID = "clientId";
public static final String ADAPTER_CONF_CLIENTID_HINT = "clientId.hint";
public static final String ADAPTER_CONF_CLEAN_SESSION = "cleanSession";
public static final String ADAPTER_CONF_CLEAN_SESSION_HINT = "cleanSession.hint";
public static final String ADAPTER_CONF_KEEP_ALIVE = "keepAlive";
public static final int ADAPTER_CONF_DEFAULT_KEEP_ALIVE = 60000;
public static int initialReconnectDuration = 10000;
public static final int reconnectionProgressionFactor = 2;
}

@ -0,0 +1,99 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.input.adapter.mqtt.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
/**
* This is the utility class that is used for MQTT input adapater.
*/
public class MQTTUtil {
private static final String HTTPS_PROTOCOL = "https";
private static final Log log = LogFactory.getLog(MQTTUtil.class);
/**
* Return a http client instance
*
* @param protocol- service endpoint protocol http/https
* @return
*/
public static HttpClient getHttpClient(String protocol)
throws IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
HttpClient httpclient;
if (HTTPS_PROTOCOL.equals(protocol)) {
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
} else {
httpclient = HttpClients.createDefault();
}
return httpclient;
}
public static String getResponseString(HttpResponse httpResponse) throws IOException {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
String readLine;
String response = "";
while (((readLine = br.readLine()) != null)) {
response += readLine;
}
return response;
} finally {
EntityUtils.consumeQuietly(httpResponse.getEntity());
if (br != null) {
try {
br.close();
} catch (IOException e) {
log.warn("Error while closing the connection! " + e.getMessage());
}
}
}
}
public static JWTClientManagerService getJWTClientManagerService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
JWTClientManagerService jwtClientManagerService =
(JWTClientManagerService) ctx.getOSGiService(JWTClientManagerService.class, null);
if (jwtClientManagerService == null) {
String msg = "JWT management service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return jwtClientManagerService;
}
}

@ -0,0 +1,73 @@
package org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.util;
/**
* This class represents the data that are required to register
* the oauth application.
*/
public class RegistrationProfile {
private String callbackUrl;
private String clientName;
private String tokenScope;
private String owner;
private String grantType;
private String applicationType;
private static final String TAG = RegistrationProfile.class.getSimpleName();
public String getCallbackUrl() {
return callbackUrl;
}
public void setCallbackUrl(String callBackUrl) {
this.callbackUrl = callBackUrl;
}
public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public String getTokenScope() {
return tokenScope;
}
public void setTokenScope(String tokenScope) {
this.tokenScope = tokenScope;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getGrantType() {
return grantType;
}
public void setGrantType(String grantType) {
this.grantType = grantType;
}
public String getApplicationType() {
return applicationType;
}
public void setApplicationType(String applicationType) {
this.applicationType = applicationType;
}
public String toJSON() {
String jsonString =
"{\"callbackUrl\": \"" + callbackUrl + "\",\"clientName\": \"" + clientName + "\", \"tokenScope\": " +
"\"" + tokenScope + "\", \"owner\": \"" + owner + "\"," + "\"grantType\": \"" + grantType +
"\", \"saasApp\" :false }\n";
return jsonString;
}
}

@ -0,0 +1,54 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.input.adapter.util;
import org.wso2.carbon.base.ServerConfiguration;
import org.wso2.carbon.core.util.Utils;
public class PropertyUtils {
private static final String MQTT_PORT = "\\$\\{mqtt.broker.port\\}";
private static final String MQTT_BROKER_HOST = "\\$\\{mqtt.broker.host\\}";
private static final String CARBON_CONFIG_PORT_OFFSET = "Ports.Offset";
private static final String DEFAULT_CARBON_SERVER_HOST_PROPERTY = "server.host";
private static final int CARBON_DEFAULT_PORT_OFFSET = 0;
private static final int DEFAULT_MQTT_PORT = 1883;
//This method is only used if the mb features are within DAS.
public static String replaceMqttProperty (String urlWithPlaceholders) {
urlWithPlaceholders = Utils.replaceSystemProperty(urlWithPlaceholders);
urlWithPlaceholders = urlWithPlaceholders.replaceAll(MQTT_PORT, "" + (DEFAULT_MQTT_PORT + getPortOffset()));
urlWithPlaceholders = urlWithPlaceholders.replaceAll(MQTT_BROKER_HOST, System.getProperty(DEFAULT_CARBON_SERVER_HOST_PROPERTY,
"localhost"));
return urlWithPlaceholders;
}
private static int getPortOffset() {
ServerConfiguration carbonConfig = ServerConfiguration.getInstance();
String portOffset = System.getProperty("portOffset", carbonConfig.getFirstProperty(CARBON_CONFIG_PORT_OFFSET));
try {
if ((portOffset != null)) {
return Integer.parseInt(portOffset.trim());
} else {
return CARBON_DEFAULT_PORT_OFFSET;
}
} catch (NumberFormatException e) {
return CARBON_DEFAULT_PORT_OFFSET;
}
}
}

@ -0,0 +1,32 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.input.adapter.xmpp;
/**
* This holds the constants related to MQTT input adapter.
*/
public class Constants {
public static final String DEFAULT = "default";
public static final String XMPP_CONTENT_VALIDATION_DEFAULT_PARAMETERS =
"device_id_json_path:event.metaData.deviceId,device_id_topic_hierarchy_index:2";
public static final String FROM_KEY = "from";
public static final String SUBJECT_KEY = "subject";
public static final String DEVICE_ID_JSON_PATH = "device_id_json_path";
public static final String DEVICE_ID_TOPIC_HIERARCHY_INDEX = "device_id_topic_hierarchy_index";
}

@ -0,0 +1,161 @@
/*
* 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.device.mgt.iot.input.adapter.xmpp;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.iot.input.adapter.xmpp.util.XMPPAdapterListener;
import org.wso2.carbon.device.mgt.iot.input.adapter.xmpp.util.XMPPServerConnectionConfiguration;
import org.wso2.carbon.device.mgt.iot.input.adapter.xmpp.util.XMPPEventAdapterConstants;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapter;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterConfiguration;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterListener;
import org.wso2.carbon.event.input.adapter.core.exception.InputEventAdapterException;
import org.wso2.carbon.event.input.adapter.core.exception.TestConnectionNotSupportedException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Input XMPPEventAdapter will be used to receive events with XMPP protocol using specified broker and topic.
*/
public class XMPPEventAdapter implements InputEventAdapter {
private final InputEventAdapterConfiguration eventAdapterConfiguration;
private final Map<String, String> globalProperties;
private InputEventAdapterListener eventAdapterListener;
private final String id = UUID.randomUUID().toString();
private XMPPAdapterListener xmppAdapterListener;
private XMPPServerConnectionConfiguration xmppServerConnectionConfiguration;
public XMPPEventAdapter(InputEventAdapterConfiguration eventAdapterConfiguration,
Map<String, String> globalProperties) {
this.eventAdapterConfiguration = eventAdapterConfiguration;
this.globalProperties = globalProperties;
}
@Override
public void init(InputEventAdapterListener eventAdapterListener) throws InputEventAdapterException {
this.eventAdapterListener = eventAdapterListener;
try {
String contentValidationParams = eventAdapterConfiguration.getProperties().get(
XMPPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS);
String params[] = contentValidationParams.split(",");
Map<String, String> paramsMap = new HashMap<>();
for (String param : params) {
String paramsKeyAndValue[] = splitOnFirst(param, ':');
if (paramsKeyAndValue.length != 2) {
throw new InputEventAdapterException("Invalid parameters for content validation - " + param);
}
paramsMap.put(paramsKeyAndValue[0], paramsKeyAndValue[1]);
}
int xmppPort = XMPPEventAdapterConstants.DEFAULT_XMPP_PORT;
String xmppPortString = eventAdapterConfiguration.getProperties()
.get(XMPPEventAdapterConstants.ADAPTER_CONF_PORT);
if (xmppPortString != null && !xmppPortString.trim().isEmpty()) {
xmppPort = Integer.parseInt(xmppPortString);
}
int timeoutInterval = XMPPEventAdapterConstants.DEFAULT_TIMEOUT_INTERVAL;
String timeoutIntervalString = eventAdapterConfiguration.getProperties().get(
XMPPEventAdapterConstants.ADAPTER_CONF_TIMEOUT_INTERVAL);
if (timeoutIntervalString != null && !timeoutIntervalString.trim().isEmpty()) {
timeoutInterval = Integer.parseInt(timeoutIntervalString);
}
xmppServerConnectionConfiguration =
new XMPPServerConnectionConfiguration(eventAdapterConfiguration.getProperties()
.get(XMPPEventAdapterConstants.ADAPTER_CONF_HOST),
xmppPort,
eventAdapterConfiguration.getProperties().get(XMPPEventAdapterConstants.ADAPTER_CONF_USERNAME),
eventAdapterConfiguration.getProperties().get(XMPPEventAdapterConstants.ADAPTER_CONF_PASSWORD),
timeoutInterval,
eventAdapterConfiguration.getProperties().get(XMPPEventAdapterConstants.ADAPTER_CONF_RESOURCE),
eventAdapterConfiguration.getProperties().get(XMPPEventAdapterConstants
.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME),
paramsMap,
eventAdapterConfiguration.getProperties().get(XMPPEventAdapterConstants.ADAPTER_CONF_RECIEVER_JID),
eventAdapterConfiguration.getProperties().get(XMPPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME)
);
xmppAdapterListener = new XMPPAdapterListener(xmppServerConnectionConfiguration,
eventAdapterListener, PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId());
} catch (Throwable t) {
throw new InputEventAdapterException(t.getMessage(), t);
}
}
private String[] splitOnFirst(String str, char c) {
int idx = str.indexOf(c);
String head = str.substring(0, idx);
String tail = str.substring(idx + 1);
return new String[] { head, tail} ;
}
@Override
public void testConnect() throws TestConnectionNotSupportedException {
throw new TestConnectionNotSupportedException("not-supported");
}
@Override
public void connect() {
xmppAdapterListener.createConnection();
}
@Override
public void disconnect() {
if (xmppAdapterListener != null) {
xmppAdapterListener.stopListener(eventAdapterConfiguration.getName());
}
}
@Override
public void destroy() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof XMPPEventAdapter)) return false;
XMPPEventAdapter that = (XMPPEventAdapter) o;
if (!id.equals(that.id)) return false;
return true;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean isEventDuplicatedInCluster() {
return true;
}
@Override
public boolean isPolling() {
return true;
}
}

@ -0,0 +1,151 @@
/*
* 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.device.mgt.iot.input.adapter.xmpp;
import org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.util.MQTTEventAdapterConstants;
import org.wso2.carbon.device.mgt.iot.input.adapter.xmpp.util.XMPPEventAdapterConstants;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapter;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterConfiguration;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterFactory;
import org.wso2.carbon.event.input.adapter.core.MessageType;
import org.wso2.carbon.event.input.adapter.core.Property;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
/**
* The xmpp event adapter factory class to create a xmpp input adapter
*/
public class XMPPEventAdapterFactory extends InputEventAdapterFactory {
private ResourceBundle resourceBundle = ResourceBundle.getBundle
("org.wso2.carbon.device.mgt.iot.input.adapter.xmpp.i18n.Resources", Locale.getDefault());
@Override
public String getType() {
return XMPPEventAdapterConstants.ADAPTER_TYPE_XMPP;
}
@Override
public List<String> getSupportedMessageFormats() {
List<String> supportInputMessageTypes = new ArrayList<String>();
supportInputMessageTypes.add(MessageType.JSON);
supportInputMessageTypes.add(MessageType.TEXT);
supportInputMessageTypes.add(MessageType.XML);
supportInputMessageTypes.add(MessageType.WSO2EVENT);
return supportInputMessageTypes;
}
@Override
public List<Property> getPropertyList() {
List<Property> propertyList = new ArrayList<Property>();
// Url
Property host = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_HOST);
host.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_HOST));
host.setRequired(true);
host.setHint(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_HOST_HINT));
// Host Port
Property port = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_PORT);
port.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_PORT));
port.setRequired(true);
port.setHint(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_PORT_HINT));
//Broker Username
Property userName = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_USERNAME);
userName.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_USERNAME));
userName.setRequired(true);
userName.setHint(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_USERNAME_HINT));
//Broker Password
Property password = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_PASSWORD);
password.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_PASSWORD));
password.setRequired(true);
password.setHint(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_PASSWORD_HINT));
//Timeout Interval
Property timooutInterval = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_TIMEOUT_INTERVAL);
timooutInterval.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_TIMEOUT_INTERVAL_HINT));
timooutInterval.setRequired(false);
timooutInterval.setHint(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_TIMEOUT_INTERVAL_HINT));
//Resource
Property resource = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_RESOURCE);
resource.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_RESOURCE));
resource.setRequired(true);
resource.setHint(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_RESOURCE_HINT));
//Content Validator details
Property contentValidator = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME);
contentValidator.setDisplayName(
resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME));
contentValidator.setRequired(false);
contentValidator.setHint(
resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME_HINT));
contentValidator.setDefaultValue(org.wso2.carbon.device.mgt.iot.input.adapter.mqtt.Constants.DEFAULT);
//Content Validator Params details
Property contentValidatorParams = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS);
contentValidatorParams.setDisplayName(
resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS));
contentValidatorParams.setRequired(false);
contentValidatorParams.setHint(
resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS_HINT));
contentValidatorParams.setDefaultValue(Constants.XMPP_CONTENT_VALIDATION_DEFAULT_PARAMETERS);
Property jid = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_RECIEVER_JID);
jid.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_RECIEVER_JID));
jid.setRequired(true);
jid.setHint(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_RECIEVER_JID_HINT));
//Content Transformer details
Property contentTransformer = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME);
contentTransformer.setDisplayName(
resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME));
contentTransformer.setRequired(false);
contentTransformer.setHint(
resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME_HINT));
contentTransformer.setDefaultValue(Constants.DEFAULT);
propertyList.add(host);
propertyList.add(port);
propertyList.add(userName);
propertyList.add(password);
propertyList.add(timooutInterval);
propertyList.add(resource);
propertyList.add(contentValidator);
propertyList.add(contentValidatorParams);
propertyList.add(jid);
propertyList.add(contentTransformer);
return propertyList;
}
@Override
public String getUsageTips() {
return null;
}
@Override
public InputEventAdapter createEventAdapter(InputEventAdapterConfiguration eventAdapterConfiguration,
Map<String, String> globalProperties) {
return new XMPPEventAdapter(eventAdapterConfiguration, globalProperties);
}
}

@ -0,0 +1,56 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.input.adapter.xmpp.exception;
/**
* This exception will thrown when content validator is failed to intialiaze.
*/
public class XMPPContentInitializationException extends RuntimeException {
private String errMessage;
public XMPPContentInitializationException(String msg, Exception nestedEx) {
super(msg, nestedEx);
setErrorMessage(msg);
}
public XMPPContentInitializationException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
public XMPPContentInitializationException(String msg) {
super(msg);
setErrorMessage(msg);
}
public XMPPContentInitializationException() {
super();
}
public XMPPContentInitializationException(Throwable cause) {
super(cause);
}
public String getErrorMessage() {
return errMessage;
}
public void setErrorMessage(String errMessage) {
this.errMessage = errMessage;
}
}

@ -0,0 +1,226 @@
/*
* 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.device.mgt.iot.input.adapter.xmpp.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.filter.ToContainsFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.core.ServerStatus;
import org.wso2.carbon.device.mgt.iot.input.adapter.ContentInfo;
import org.wso2.carbon.device.mgt.iot.input.adapter.ContentTransformer;
import org.wso2.carbon.device.mgt.iot.input.adapter.ContentValidator;
import org.wso2.carbon.device.mgt.iot.input.adapter.DefaultContentTransformer;
import org.wso2.carbon.device.mgt.iot.input.adapter.DefaultContentValidator;
import org.wso2.carbon.device.mgt.iot.input.adapter.xmpp.Constants;
import org.wso2.carbon.device.mgt.iot.input.adapter.xmpp.exception.XMPPContentInitializationException;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterListener;
import org.wso2.carbon.event.input.adapter.core.exception.InputEventAdapterRuntimeException;
import java.util.HashMap;
import java.util.Map;
public class XMPPAdapterListener implements Runnable {
private static final Log log = LogFactory.getLog(XMPPAdapterListener.class);
private XMPPConnection xmppConnection;
private XMPPServerConnectionConfiguration xmppServerConnectionConfiguration;
private int tenantId;
private boolean connectionSucceeded = false;
private ContentValidator contentValidator;
private Map<String, String> contentValidationParams;
private ContentTransformer contentTransformer;
private PacketFilter packetFilter;
private PacketListener packetListener;
private InputEventAdapterListener eventAdapterListener = null;
public XMPPAdapterListener(XMPPServerConnectionConfiguration xmppServerConnectionConfiguration,
InputEventAdapterListener inputEventAdapterListener, int tenantId) {
this.xmppServerConnectionConfiguration = xmppServerConnectionConfiguration;
this.eventAdapterListener = inputEventAdapterListener;
this.tenantId = tenantId;
try {
String contentValidatorClassName = this.xmppServerConnectionConfiguration.getContentValidatorClassName();
if (contentValidatorClassName != null && contentValidatorClassName.equals(Constants.DEFAULT)) {
contentValidator = new DefaultContentValidator();
} else if (contentValidatorClassName != null && !contentValidatorClassName.isEmpty()) {
try {
Class<? extends ContentValidator> contentValidatorClass = Class.forName(contentValidatorClassName)
.asSubclass(ContentValidator.class);
contentValidator = contentValidatorClass.newInstance();
} catch (ClassNotFoundException e) {
throw new XMPPContentInitializationException(
"Unable to find the class validator: " + contentValidatorClassName, e);
} catch (InstantiationException e) {
throw new XMPPContentInitializationException(
"Unable to create an instance of :" + contentValidatorClassName, e);
} catch (IllegalAccessException e) {
throw new XMPPContentInitializationException("Access of the instance in not allowed.", e);
}
}
contentValidationParams = xmppServerConnectionConfiguration.getContentValidatorParams();
String contentTransformerClassName = this.xmppServerConnectionConfiguration.getContentTransformerClassName();
if (contentTransformerClassName != null && contentTransformerClassName.equals(Constants.DEFAULT)) {
contentTransformer = new DefaultContentTransformer();
} else if (contentTransformerClassName != null && !contentTransformerClassName.isEmpty()) {
try {
Class<? extends ContentTransformer> contentTransformerClass = Class.forName(contentTransformerClassName)
.asSubclass(ContentTransformer.class);
contentTransformer = contentTransformerClass.newInstance();
} catch (ClassNotFoundException e) {
throw new XMPPContentInitializationException(
"Unable to find the class transformer: " + contentTransformerClassName, e);
} catch (InstantiationException e) {
throw new XMPPContentInitializationException(
"Unable to create an instance of :" + contentTransformerClassName, e);
} catch (IllegalAccessException e) {
throw new XMPPContentInitializationException("Access of the instance in not allowed.", e);
}
}
} catch (Throwable e) {
log.error("Exception occurred while subscribing to MQTT broker at "
+ xmppServerConnectionConfiguration.getHost());
throw new InputEventAdapterRuntimeException(e);
}
}
public void startListener() throws XMPPException {
SmackConfiguration.setPacketReplyTimeout(xmppServerConnectionConfiguration.getTimeoutInterval());
ConnectionConfiguration config = new ConnectionConfiguration(xmppServerConnectionConfiguration.getHost(),
xmppServerConnectionConfiguration.getPort());
config.setSASLAuthenticationEnabled(false);
config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
xmppConnection = new XMPPConnection(config);
xmppConnection.connect();
String resource = xmppServerConnectionConfiguration.getResource();
String username = xmppServerConnectionConfiguration.getUsername();
String password = xmppServerConnectionConfiguration.getPassword();
try {
if (resource == null || resource.trim().isEmpty()) {
xmppConnection.login(username, password);
} else {
xmppConnection.login(username, password, resource);
}
setFilterOnReceiver(xmppServerConnectionConfiguration.getJid());
} catch (XMPPException e) {
String errorMsg = "Login attempt to the XMPP Server with username - " + username + " failed.";
log.info(errorMsg);
throw new InputEventAdapterRuntimeException(errorMsg, e);
}
}
public void stopListener(String adapterName) {
if (connectionSucceeded) {
// Un-subscribe accordingly and disconnect from the MQTT server.
if (!ServerStatus.getCurrentStatus().equals(ServerStatus.STATUS_SHUTTING_DOWN)) {
xmppConnection.removePacketListener(packetListener);
}
xmppConnection.disconnect();
}
//This is to stop all running reconnection threads
connectionSucceeded = true;
}
protected void setFilterOnReceiver(String receiverJID) {
packetFilter = new AndFilter(new PacketTypeFilter(Message.class), new ToContainsFilter(
receiverJID));
packetListener = new PacketListener() {
@Override
public void processPacket(Packet packet) {
if (packet instanceof Message) {
final Message xmppMessage = (Message) packet;
Thread msgProcessThread = new Thread() {
public void run() {
processIncomingMessage(xmppMessage);
}
};
msgProcessThread.start();
}
}
};
xmppConnection.addPacketListener(packetListener, packetFilter);
}
public void processIncomingMessage(Message xmppMessage) {
try {
String from = xmppMessage.getFrom();
String subject = xmppMessage.getSubject();
String message = xmppMessage.getBody();
if (log.isDebugEnabled()) {
log.debug(message);
}
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId);
if (log.isDebugEnabled()) {
log.debug("Event received in MQTT Event Adapter - " + message);
}
if (contentValidator != null && contentTransformer != null) {
Map<String, String> dynamicParmaters = new HashMap<>();
dynamicParmaters.put(Constants.FROM_KEY, from);
dynamicParmaters.put(Constants.SUBJECT_KEY, subject);
message = contentTransformer.transform(message, dynamicParmaters);
ContentInfo contentInfo = contentValidator.validate(message, contentValidationParams, dynamicParmaters);
if (contentInfo != null && contentInfo.isValidContent()) {
eventAdapterListener.onEvent(contentInfo.getMsgText());
}
} else {
eventAdapterListener.onEvent(message);
}
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
@Override
public void run() {
while (!connectionSucceeded) {
try {
XMPPEventAdapterConstants.initialReconnectDuration = XMPPEventAdapterConstants.initialReconnectDuration
* XMPPEventAdapterConstants.reconnectionProgressionFactor;
Thread.sleep(XMPPEventAdapterConstants.initialReconnectDuration);
startListener();
connectionSucceeded = true;
log.info("XMPP Connection successful");
} catch (InterruptedException e) {
log.error("Interruption occurred while waiting for reconnection", e);
} catch (XMPPException e) {
log.error("XMPP Exception occurred when starting listener", e);
}
}
}
public void createConnection() {
new Thread(this).start();
}
}

@ -0,0 +1,54 @@
/*
* 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.device.mgt.iot.input.adapter.xmpp.util;
/**
* This holds the constants related to xmpp event adapter.
*/
public class XMPPEventAdapterConstants {
public static final String ADAPTER_TYPE_XMPP = "xmpp";
//static properties
public static final String ADAPTER_CONF_HOST = "host";
public static final String ADAPTER_CONF_HOST_HINT = "host.hint";
public static final String ADAPTER_CONF_PORT = "port";
public static final String ADAPTER_CONF_PORT_HINT = "port.hint";
public static final String ADAPTER_CONF_USERNAME = "username";
public static final String ADAPTER_CONF_USERNAME_HINT = "username.hint";
public static final String ADAPTER_CONF_PASSWORD = "password";
public static final String ADAPTER_CONF_PASSWORD_HINT = "password.hint";
public static final String ADAPTER_CONF_RESOURCE = "resource";
public static final String ADAPTER_CONF_RESOURCE_HINT = "resource.hint";
public static final String ADAPTER_CONF_TIMEOUT_INTERVAL = "timeoutInterval";
public static final String ADAPTER_CONF_TIMEOUT_INTERVAL_HINT = "timeoutInterval.hint";
public static final String ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME = "contentValidation";
public static final String ADAPTER_CONF_CONTENT_VALIDATOR_CLASSNAME_HINT = "contentValidation.hint";
public static final String ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS = "contentValidationParams";
public static final String ADAPTER_CONF_CONTENT_VALIDATOR_PARAMS_HINT = "contentValidationParams.hint";
public static final String ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME = "contentTransformer";
public static final String ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME_HINT = "contentTransformer.hint";
public static final String ADAPTER_CONF_RECIEVER_JID = "jid";
public static final String ADAPTER_CONF_RECIEVER_JID_HINT = "jid.hint";
public static final int DEFAULT_XMPP_PORT = 5222;
public static final int DEFAULT_TIMEOUT_INTERVAL = 5000;
public static int initialReconnectDuration = 10000;
public static final int reconnectionProgressionFactor = 2;
}

@ -0,0 +1,99 @@
/*
* 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.device.mgt.iot.input.adapter.xmpp.util;
import org.wso2.carbon.device.mgt.iot.input.adapter.util.PropertyUtils;
import org.wso2.carbon.device.mgt.iot.input.adapter.xmpp.Constants;
import java.util.Map;
/**
* This holds the configurations related to MQTT Broker.
*/
public class XMPPServerConnectionConfiguration {
private String host;
private int port;
private String username;
private String password;
private int timeoutInterval;
private String resource;
private String jid;
private String contentValidatorClassName;
private Map<String, String> contentValidatorParams;
private String contentTransformerClassName;
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public int getTimeoutInterval() {
return timeoutInterval;
}
public String getResource() {
return resource;
}
public String getContentValidatorClassName() {
return contentValidatorClassName;
}
public Map<String, String> getContentValidatorParams() {
return contentValidatorParams;
}
public String getJid() {
return jid;
}
public String getContentTransformerClassName() {
return contentTransformerClassName;
}
public XMPPServerConnectionConfiguration(String host, int port, String username, String password,
int timeoutInterval, String resource, String contentValidatorClassName,
Map<String, String> contentValidatorParams, String jid,
String contentTransformerClassName) {
this.host = host;
this.port = port;
this.username = username;
this.password = password;
this.timeoutInterval = timeoutInterval;
this.resource = resource;
this.contentValidatorClassName = contentValidatorClassName;
if (contentValidatorParams != null) {
this.contentValidatorParams = contentValidatorParams;
}
this.contentTransformerClassName = contentTransformerClassName;
this.jid = jid;
}
}

@ -0,0 +1,40 @@
#
# Copyright (c) 2005-2014, 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.
#
transports=Transport(s)
http.usage.tips_prefix=Following url formats are used to receive events</br>For super tenants:</br>&nbsp;&nbsp;<i>http://localhost:
http.usage.tips_mid1=/endpoints/&lt;event_receiver_name&gt</i></br>&nbsp;&nbsp;<i>https://localhost:
http.usage.tips_mid2=/endpoints/&lt;event_receiver_name&gt;</i></br></br>For other tenants:</br>&nbsp;&nbsp;<i>http://localhost:
http.usage.tips_mid3=/endpoints/t/&lt;tenant_domain&gt;/&lt;event_receiver_name&gt;</i></br>&nbsp;&nbsp;<i>https://localhost:
http.usage.tips_postfix=/endpoints/t/&lt;tenant_domain&gt;/&lt;event_receiver_name&gt;</i>
tokenValidationEndpointUrl=tokenEndpointUrl
tokenValidationEndpointUrl.hint=OAUTH Token Validation Endpoint
username=username
username.hint=username of the user to connect to the admin services
password=password
password.hint=password of the user to connect to the admin services.
maximumTotalHttpConnection=maximumTotalHttpConnection
maximumTotalHttpConnection.hint=Maximum Total connection to be made with the endpoint
maximumHttpConnectionPerHost=maximumHttpConnectionPerHost
maximumHttpConnectionPerHost.hint=Maximum Http connection per host.
contentValidation=contentValidation
contentValidation.hint=Class Name of the content Validation or 'default' to set default class, required to implement (if required)
contentValidationParams=contentValidationParams
contentValidationParams.hint=ContentValidationParams, comma seperated. (if required)
contentTransformer=contentTransformer
contentTransformer.hint=Class Name of the content transformer or 'default' to set default class, required to implement (if required)

@ -0,0 +1,40 @@
#
# 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.
#
topic=Topic
topic.hint=Topic subscribed
clientId=Client Id
clientId.hint=client identifier is used by the server to identify a client when it reconnects, It used for durable subscriptions or reliable delivery of messages is required.
url=Broker Url
username=Username
username.hint=Username of the broker (if required)
scopes=Scopes
scopes.hint=Scopes required to connect to broker (if required)
dcrUrl=dcrUrl
dcrUrl.hint=dynamic client registration endpoint URL to create application (if required) eg: https://localhost:9443/dynamic-client-web/register
contentValidation=contentValidation
contentValidation.hint=Class Name of the content Validation or 'default' to set default class, required to implement (if required)
contentValidationParams=contentValidationParams
contentValidationParams.hint=ContentValidationParams, comma seperated. (if required)
url.hint=MQTT broker url tcp://localhost:1883
cleanSession=Clean Session
cleanSession.hint=Persist topic subscriptions and ack positions across client sessions
keepAlive=Keep Alive (In seconds)
events.duplicated.in.cluster=Is events duplicated in cluster
contentTransformer=contentTransformer
contentTransformer.hint=Class Name of the content transformer or 'default' to set default class, required to implement (if required)

@ -0,0 +1,38 @@
#
# 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.
#
host=Server Url
host.hint=XMPP Server url
port=Server Port
port.hint=Server Port Number
username=Username
username.hint=Username of the broker
password=Password
password.hint=Password to connect to the server.
timeoutInterval=Time out Interval
timeoutInterval.hint=used by listeners to the server and for reconnection schedules.
resource=Resource
resource.hint=specific to the XMPP-Account to which the login is made to.
contentValidation=contentValidation
contentValidation.hint=Class Name of the content Validation or 'default' to set default class, required to implement (if required)
contentValidationParams=contentValidationParams
contentValidationParams.hint=ContentValidationParams, comma seperated. (if required)
jid=jid
jid.hint=JID - XMPP Account Name.
contentTransformer=contentTransformer
contentTransformer.hint=Class Name of the content transformer or 'default' to set default class, required to implement (if required)

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>iot-base-plugin</artifactId>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<version>2.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.device.mgt.iot.output.adapter.mqtt</artifactId>
<packaging>bundle</packaging>
<name>WSO2 Carbon - Device Mgt Output MQTT Adaptor Module</name>
<description>org.wso2.carbon.device.mgt.iot.output.adapter.xmpp provides the back-end functionality of mqtt adaptor
</description>
<url>http://wso2.org</url>
<dependencies>
<dependency>
<groupId>org.wso2.carbon.analytics-common</groupId>
<artifactId>org.wso2.carbon.event.output.adapter.core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.core</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.logging</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.wso2</groupId>
<artifactId>httpcore</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.orbit.org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple.wso2</groupId>
<artifactId>json-simple</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.identity.jwt.client.extension</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<executions>
<execution>
<id>generate-scr-descriptor</id>
<goals>
<goal>scr</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Bundle-Name>${project.artifactId}</Bundle-Name>
<Private-Package>
org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.internal,
org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.internal.*
</Private-Package>
<Export-Package>
!org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.internal,
!org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.internal.*,
org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.*,
</Export-Package>
<Import-Package>
org.wso2.carbon.event.output.adapter.core,
org.wso2.carbon.event.output.adapter.core.*,
javax.net.ssl,
org.apache.commons.logging,
org.apache.http,
org.apache.http.client,
org.apache.http.client.methods,
org.apache.http.conn.socket,
org.apache.http.conn.ssl,
org.apache.http.entity,
org.apache.http.impl.client,
org.apache.http.util,
org.eclipse.paho.client.mqttv3,
org.eclipse.paho.client.mqttv3.persist,
org.json.simple,
org.json.simple.parser,
org.osgi.framework,
org.osgi.service.component,
org.wso2.carbon.context,
org.wso2.carbon.identity.jwt.client.extension.*
</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,204 @@
/*
* 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.device.mgt.iot.output.adapter.xmpp;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.util.MQTTAdapterPublisher;
import org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.util.MQTTBrokerConnectionConfiguration;
import org.wso2.carbon.event.output.adapter.core.EventAdapterUtil;
import org.wso2.carbon.event.output.adapter.core.OutputEventAdapter;
import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterConfiguration;
import org.wso2.carbon.event.output.adapter.core.exception.OutputEventAdapterException;
import org.wso2.carbon.event.output.adapter.core.exception.TestConnectionNotSupportedException;
import org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.util.MQTTEventAdapterConstants;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Output MQTTEventAdapter will be used to publish events with MQTT protocol to specified broker and topic.
*/
public class MQTTEventAdapter implements OutputEventAdapter {
private OutputEventAdapterConfiguration eventAdapterConfiguration;
private Map<String, String> globalProperties;
private MQTTAdapterPublisher mqttAdapterPublisher;
private int connectionKeepAliveInterval;
private String qos;
private static ThreadPoolExecutor threadPoolExecutor;
private static final Log log = LogFactory.getLog(MQTTEventAdapter.class);
private int tenantId;
public MQTTEventAdapter(OutputEventAdapterConfiguration eventAdapterConfiguration,
Map<String, String> globalProperties) {
this.eventAdapterConfiguration = eventAdapterConfiguration;
this.globalProperties = globalProperties;
Object keeAliveInternal = globalProperties.get(MQTTEventAdapterConstants.CONNECTION_KEEP_ALIVE_INTERVAL);
if (keeAliveInternal != null) {
try {
connectionKeepAliveInterval = Integer.parseInt(keeAliveInternal.toString());
} catch (NumberFormatException e) {
log.error("Error when configuring user specified connection keep alive time, using default value", e);
connectionKeepAliveInterval = MQTTEventAdapterConstants.DEFAULT_CONNECTION_KEEP_ALIVE_INTERVAL;
}
} else {
connectionKeepAliveInterval = MQTTEventAdapterConstants.DEFAULT_CONNECTION_KEEP_ALIVE_INTERVAL;
}
}
@Override
public void init() throws OutputEventAdapterException {
tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
//ThreadPoolExecutor will be assigned if it is null
if (threadPoolExecutor == null) {
int minThread;
int maxThread;
int jobQueSize;
long defaultKeepAliveTime;
//If global properties are available those will be assigned else constant values will be assigned
if (globalProperties.get(MQTTEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE_NAME) != null) {
minThread = Integer.parseInt(globalProperties.get(
MQTTEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE_NAME));
} else {
minThread = MQTTEventAdapterConstants.DEFAULT_MIN_THREAD_POOL_SIZE;
}
if (globalProperties.get(MQTTEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME) != null) {
maxThread = Integer.parseInt(globalProperties.get(
MQTTEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME));
} else {
maxThread = MQTTEventAdapterConstants.DEFAULT_MAX_THREAD_POOL_SIZE;
}
if (globalProperties.get(MQTTEventAdapterConstants.ADAPTER_KEEP_ALIVE_TIME_NAME) != null) {
defaultKeepAliveTime = Integer.parseInt(globalProperties.get(
MQTTEventAdapterConstants.ADAPTER_KEEP_ALIVE_TIME_NAME));
} else {
defaultKeepAliveTime = MQTTEventAdapterConstants.DEFAULT_KEEP_ALIVE_TIME_IN_MILLIS;
}
if (globalProperties.get(MQTTEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME) != null) {
jobQueSize = Integer.parseInt(globalProperties.get(
MQTTEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME));
} else {
jobQueSize = MQTTEventAdapterConstants.DEFAULT_EXECUTOR_JOB_QUEUE_SIZE;
}
threadPoolExecutor = new ThreadPoolExecutor(minThread, maxThread, defaultKeepAliveTime,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(
jobQueSize));
}
}
@Override
public void testConnect() throws TestConnectionNotSupportedException {
throw new TestConnectionNotSupportedException("Test connection is not available");
}
@Override
public void connect() {
MQTTBrokerConnectionConfiguration mqttBrokerConnectionConfiguration =
new MQTTBrokerConnectionConfiguration(eventAdapterConfiguration.getStaticProperties()
.get(MQTTEventAdapterConstants.ADAPTER_CONF_URL),
eventAdapterConfiguration.getStaticProperties()
.get(MQTTEventAdapterConstants.ADAPTER_CONF_USERNAME),
eventAdapterConfiguration.getStaticProperties()
.get(MQTTEventAdapterConstants.ADAPTER_CONF_DCR_URL),
eventAdapterConfiguration.getStaticProperties()
.get(MQTTEventAdapterConstants.ADAPTER_CONF_SCOPES),
connectionKeepAliveInterval,
eventAdapterConfiguration.getStaticProperties()
.get(MQTTEventAdapterConstants.ADAPTER_CONF_CLEAN_SESSION)
);
String clientId = eventAdapterConfiguration.getStaticProperties().get(
MQTTEventAdapterConstants.ADAPTER_CONF_CLIENTID);
qos = eventAdapterConfiguration.getStaticProperties().get(MQTTEventAdapterConstants.ADAPTER_MESSAGE_QOS);
mqttAdapterPublisher = new MQTTAdapterPublisher(mqttBrokerConnectionConfiguration, clientId);
}
@Override
public void publish(Object message, Map<String, String> dynamicProperties) {
String topic = dynamicProperties.get(MQTTEventAdapterConstants.ADAPTER_MESSAGE_TOPIC);
try {
threadPoolExecutor.submit(new MQTTSender(topic, message));
} catch (RejectedExecutionException e) {
EventAdapterUtil.logAndDrop(eventAdapterConfiguration.getName(), message, "Job queue is full", e, log,
tenantId);
}
}
@Override
public void disconnect() {
try {
if (mqttAdapterPublisher != null) {
mqttAdapterPublisher.close();
mqttAdapterPublisher = null;
}
} catch (OutputEventAdapterException e) {
log.error("Exception when closing the mqtt publisher connection on Output MQTT Adapter '" +
eventAdapterConfiguration.getName() + "'", e);
}
}
@Override
public void destroy() {
//not required
}
@Override
public boolean isPolled() {
return false;
}
class MQTTSender implements Runnable {
String topic;
Object message;
MQTTSender(String topic, Object message) {
this.topic = topic;
this.message = message;
}
@Override
public void run() {
try {
if (!mqttAdapterPublisher.isConnected()) {
synchronized (MQTTEventAdapter.class) {
if (!mqttAdapterPublisher.isConnected()) {
mqttAdapterPublisher.connect();
}
}
}
if (qos == null) {
mqttAdapterPublisher.publish(message.toString(), topic);
} else {
mqttAdapterPublisher.publish(Integer.parseInt(qos), message.toString(), topic);
}
} catch (Throwable t) {
EventAdapterUtil.logAndDrop(eventAdapterConfiguration.getName(), message, null, t, log, tenantId);
}
}
}
}

@ -0,0 +1,126 @@
/*
* 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.device.mgt.iot.output.adapter.xmpp;
import org.wso2.carbon.event.output.adapter.core.*;
import org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.util.MQTTEventAdapterConstants;
import java.util.*;
/**
* The mqtt event adapter factory class to create a mqtt output adapter
*/
public class MQTTEventAdapterFactory extends OutputEventAdapterFactory {
private ResourceBundle resourceBundle =
ResourceBundle.getBundle("org.wso2.carbon.device.mgt.iot.output.adapter.mqtt.i18n.Resources", Locale.getDefault());
@Override
public String getType() {
return MQTTEventAdapterConstants.ADAPTER_TYPE_MQTT;
}
@Override
public List<String> getSupportedMessageFormats() {
List<String> supportedMessageFormats = new ArrayList<String>();
supportedMessageFormats.add(MessageType.XML);
supportedMessageFormats.add(MessageType.JSON);
supportedMessageFormats.add(MessageType.TEXT);
return supportedMessageFormats;
}
@Override
public List<Property> getStaticPropertyList() {
List<Property> staticPropertyList = new ArrayList<Property>();
//Broker Url
Property brokerUrl = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_URL);
brokerUrl.setDisplayName(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_URL));
brokerUrl.setRequired(true);
brokerUrl.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_URL_HINT));
//Broker Username
Property userName = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_USERNAME);
userName.setDisplayName(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_USERNAME));
userName.setRequired(true);
userName.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_USERNAME_HINT));
//Broker dcr URL
Property dcrUrl = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_DCR_URL);
dcrUrl.setDisplayName(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_DCR_URL));
dcrUrl.setRequired(true);
dcrUrl.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_DCR_URL_HINT));
//Broker Connection Scopes
Property scopes = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_SCOPES);
scopes.setDisplayName(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_SCOPES));
scopes.setRequired(true);
scopes.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_SCOPES_HINT));
// set clientId
Property clientId = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_CLIENTID);
clientId.setDisplayName(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CLIENTID));
clientId.setRequired(false);
clientId.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CLIENTID_HINT));
staticPropertyList.add(clientId);
//Broker clear session
Property clearSession = new Property(MQTTEventAdapterConstants.ADAPTER_CONF_CLEAN_SESSION);
clearSession.setDisplayName(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CLEAN_SESSION));
clearSession.setRequired(false);
clearSession.setOptions(new String[]{"true", "false"});
clearSession.setDefaultValue("true");
clearSession.setHint(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_CONF_CLEAN_SESSION_HINT));
// set Quality of Service
Property qos = new Property(MQTTEventAdapterConstants.ADAPTER_MESSAGE_QOS);
qos.setDisplayName(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_MESSAGE_QOS));
qos.setRequired(true);
qos.setOptions(new String[]{"0", "1", "2"});
qos.setDefaultValue("1");
staticPropertyList.add(brokerUrl);
staticPropertyList.add(userName);
staticPropertyList.add(dcrUrl);
staticPropertyList.add(scopes);
staticPropertyList.add(clearSession);
staticPropertyList.add(qos);
return staticPropertyList;
}
@Override
public List<Property> getDynamicPropertyList() {
List<Property> dynamicPropertyList = new ArrayList<Property>();
// set topic
Property topicProperty = new Property(MQTTEventAdapterConstants.ADAPTER_MESSAGE_TOPIC);
topicProperty.setDisplayName(resourceBundle.getString(MQTTEventAdapterConstants.ADAPTER_MESSAGE_TOPIC));
topicProperty.setRequired(true);
dynamicPropertyList.add(topicProperty);
return dynamicPropertyList;
}
@Override
public String getUsageTips() {
return null;
}
@Override
public OutputEventAdapter createEventAdapter(OutputEventAdapterConfiguration eventAdapterConfiguration,
Map<String, String> globalProperties) {
return new MQTTEventAdapter(eventAdapterConfiguration, globalProperties);
}
}

@ -0,0 +1,51 @@
/*
* 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.device.mgt.iot.output.adapter.xmpp.internal;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.service.component.ComponentContext;
import org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.MQTTEventAdapterFactory;
import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterFactory;
/**
* @scr.component component.name="output.Mqtt.AdapterService.component" immediate="true"
*/
public class MQTTEventAdapterServiceComponent {
private static final Log log = LogFactory.getLog(MQTTEventAdapterServiceComponent.class);
/**
* Deployment of the MQTT event adapter service will be done.
* @param context bundle context where service is registered
*/
protected void activate(ComponentContext context) {
try {
OutputEventAdapterFactory mqttEventAdapterFactory = new MQTTEventAdapterFactory();
context.getBundleContext().registerService(OutputEventAdapterFactory.class.getName(),
mqttEventAdapterFactory, null);
if (log.isDebugEnabled()) {
log.debug("The MQTT publisher service has been deployed successfully");
}
} catch (RuntimeException e) {
log.error("Exception occurred when deploying MQTT publisher service", e);
}
}
}

@ -0,0 +1,32 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.output.adapter.xmpp.util;
/**
* This holds the constants related to MQTT input adapter.
*/
public class Constants {
public static final String DEFAULT_CALLBACK = "";
public static final String DEFAULT_PASSWORD = "";
public static final String GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer refresh_token";
public static final String TOKEN_SCOPE = "production";
public static final String APPLICATION_TYPE = "device";
public static final String CLIENT_ID = "client_id";
public static final String CLIENT_SECRET = "client_secret";
}

@ -0,0 +1,191 @@
/*
* 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.device.mgt.iot.output.adapter.xmpp.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.event.output.adapter.core.exception.ConnectionUnavailableException;
import org.wso2.carbon.event.output.adapter.core.exception.OutputEventAdapterException;
import org.wso2.carbon.event.output.adapter.core.exception.OutputEventAdapterRuntimeException;
import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo;
import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException;
import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
/**
* MQTT publisher related configuration initialization and publishing capabilties are implemented here.
*/
public class MQTTAdapterPublisher {
private static final Log log = LogFactory.getLog(MQTTAdapterPublisher.class);
private MqttClient mqttClient;
private MQTTBrokerConnectionConfiguration mqttBrokerConnectionConfiguration;
String clientId;
public MQTTAdapterPublisher(MQTTBrokerConnectionConfiguration mqttBrokerConnectionConfiguration, String clientId) {
if (clientId == null || clientId.trim().isEmpty()) {
this.clientId = MqttClient.generateClientId();
}
this.mqttBrokerConnectionConfiguration = mqttBrokerConnectionConfiguration;
connect();
}
public void connect() {
if (clientId == null || clientId.trim().isEmpty()) {
clientId = MqttClient.generateClientId();
}
boolean cleanSession = mqttBrokerConnectionConfiguration.isCleanSession();
int keepAlive = mqttBrokerConnectionConfiguration.getKeepAlive();
String temp_directory = System.getProperty(MQTTEventAdapterConstants.ADAPTER_TEMP_DIRECTORY_NAME);
MqttDefaultFilePersistence dataStore = new MqttDefaultFilePersistence(temp_directory);
try {
MqttConnectOptions connectionOptions = new MqttConnectOptions();
connectionOptions.setCleanSession(cleanSession);
connectionOptions.setKeepAliveInterval(keepAlive);
if (mqttBrokerConnectionConfiguration.getBrokerUsername() != null) {
connectionOptions.setUserName(getToken(mqttBrokerConnectionConfiguration.getBrokerUsername(),
mqttBrokerConnectionConfiguration.getDcrUrl(),
mqttBrokerConnectionConfiguration.getScopes()));
connectionOptions.setPassword(Constants.DEFAULT_PASSWORD.toCharArray());
}
// Construct an MQTT blocking mode client
mqttClient = new MqttClient(mqttBrokerConnectionConfiguration.getBrokerUrl(), clientId, dataStore);
mqttClient.connect(connectionOptions);
} catch (MqttException e) {
log.error("Error occurred when constructing MQTT client for broker url : "
+ mqttBrokerConnectionConfiguration.getBrokerUrl(), e);
handleException(e);
}
}
public boolean isConnected() {
return mqttClient.isConnected();
}
public void publish(int qos, String payload, String topic) {
try {
// Create and configure a message
MqttMessage message = new MqttMessage(payload.getBytes());
message.setQos(qos);
mqttClient.publish(topic, message);
} catch (MqttException e) {
log.error("Error occurred when publishing message for MQTT server : " + mqttClient.getServerURI(), e);
handleException(e);
}
}
public void publish(String payload, String topic) {
try {
// Create and configure a message
MqttMessage message = new MqttMessage(payload.getBytes());
mqttClient.publish(topic, message);
} catch (MqttException e) {
log.error("Error occurred when publishing message for MQTT server : " + mqttClient.getServerURI(), e);
handleException(e);
}
}
public void close() throws OutputEventAdapterException {
try {
mqttClient.disconnect(1000);
mqttClient.close();
} catch (MqttException e) {
throw new OutputEventAdapterException(e);
}
}
private void handleException(MqttException e) {
//Check for Client not connected exception code and throw ConnectionUnavailableException
if (e.getReasonCode() == 32104) {
throw new ConnectionUnavailableException(e);
} else {
throw new OutputEventAdapterRuntimeException(e);
}
}
private String getToken(String username, String dcrUrlString, String scopes) {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
if (dcrUrlString != null && !dcrUrlString.isEmpty()) {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId, true);
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(username);
try {
URL dcrUrl = new URL(dcrUrlString);
HttpClient httpClient = MQTTUtil.getHttpClient(dcrUrl.getProtocol());
HttpPost postMethod = new HttpPost(dcrUrlString);
RegistrationProfile registrationProfile = new RegistrationProfile();
registrationProfile.setCallbackUrl(Constants.DEFAULT_CALLBACK);
registrationProfile.setGrantType(Constants.GRANT_TYPE);
registrationProfile.setOwner(username);
registrationProfile.setTokenScope(Constants.TOKEN_SCOPE);
registrationProfile.setApplicationType(Constants.APPLICATION_TYPE);
registrationProfile.setClientName(username + "_" + tenantId);
String jsonString = registrationProfile.toJSON();
StringEntity requestEntity = new StringEntity(jsonString, ContentType.APPLICATION_JSON);
postMethod.setEntity(requestEntity);
HttpResponse httpResponse = httpClient.execute(postMethod);
String response = MQTTUtil.getResponseString(httpResponse);
try {
JSONParser jsonParser = new JSONParser();
JSONObject jsonPayload = (JSONObject) jsonParser.parse(response);
String clientId = (String) jsonPayload.get(Constants.CLIENT_ID);
String clientSecret = (String) jsonPayload.get(Constants.CLIENT_SECRET);
JWTClientManagerService jwtClientManagerService = MQTTUtil.getJWTClientManagerService();
AccessTokenInfo accessTokenInfo = jwtClientManagerService.getJWTClient().getAccessToken(
clientId, clientSecret, username, scopes);
return accessTokenInfo.getAccessToken();
} catch (ParseException e) {
String msg = "error occurred while parsing client credential payload";
throw new OutputEventAdapterRuntimeException(msg, e);
} catch (JWTClientException e) {
String msg = "error occurred while parsing the response from JWT Client";
throw new OutputEventAdapterRuntimeException(msg, e);
}
} catch (MalformedURLException e) {
throw new OutputEventAdapterRuntimeException("Invalid dcrUrl : " + dcrUrlString);
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException | IOException e) {
throw new OutputEventAdapterRuntimeException("Failed to create an https connection.", e);
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
throw new OutputEventAdapterRuntimeException("Invalid configuration for mqtt publisher");
}
}

@ -0,0 +1,65 @@
/*
* 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.device.mgt.iot.output.adapter.xmpp.util;
public class MQTTBrokerConnectionConfiguration {
private String brokerUsername;
private String dcrUrl;
private String scopes;
private String brokerUrl;
private boolean cleanSession = true;
private int keepAlive;
public String getDcrUrl() {
return dcrUrl;
}
public String getScopes() {
return scopes;
}
public String getBrokerUsername() {
return brokerUsername;
}
public boolean isCleanSession() {
return cleanSession;
}
public String getBrokerUrl() {
return brokerUrl;
}
public int getKeepAlive() {
return keepAlive;
}
public MQTTBrokerConnectionConfiguration(String brokerUrl, String brokerUsername,
String dcrUrl, String scopes, int keepAlive, String cleanSession) {
this.brokerUsername = brokerUsername;
this.dcrUrl = dcrUrl;
this.scopes = scopes;
this.brokerUrl = brokerUrl;
this.keepAlive = keepAlive;
if (cleanSession != null) {
this.cleanSession = Boolean.parseBoolean(cleanSession);
}
}
}

@ -0,0 +1,54 @@
/*
* 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.device.mgt.iot.output.adapter.xmpp.util;
public final class MQTTEventAdapterConstants {
private MQTTEventAdapterConstants() {
}
public static final String ADAPTER_TYPE_MQTT = "oauth-mqtt";
public static final String ADAPTER_CONF_URL = "url";
public static final String ADAPTER_CONF_USERNAME = "username";
public static final String ADAPTER_CONF_USERNAME_HINT = "username.hint";
public static final String ADAPTER_CONF_DCR_URL = "dcrUrl";
public static final String ADAPTER_CONF_DCR_URL_HINT = "dcrUrl.hint";
public static final String ADAPTER_CONF_SCOPES = "scopes";
public static final String ADAPTER_CONF_SCOPES_HINT = "scopes.hint";
public static final String ADAPTER_CONF_URL_HINT = "url.hint";
public static final String ADAPTER_MESSAGE_TOPIC = "topic";
public static final String ADAPTER_MESSAGE_QOS = "qos";
public static final String ADAPTER_CONF_CLEAN_SESSION = "cleanSession";
public static final String ADAPTER_CONF_CLEAN_SESSION_HINT = "cleanSession.hint";
public static final String CONNECTION_KEEP_ALIVE_INTERVAL = "connectionKeepAliveInterval";
public static final int DEFAULT_CONNECTION_KEEP_ALIVE_INTERVAL = 60;
public static final String ADAPTER_TEMP_DIRECTORY_NAME = "java.io.tmpdir";
public static final String ADAPTER_CONF_CLIENTID = "clientId";
public static final String ADAPTER_CONF_CLIENTID_HINT = "clientId.hint";
public static final int DEFAULT_MIN_THREAD_POOL_SIZE = 8;
public static final int DEFAULT_MAX_THREAD_POOL_SIZE = 100;
public static final int DEFAULT_EXECUTOR_JOB_QUEUE_SIZE = 2000;
public static final long DEFAULT_KEEP_ALIVE_TIME_IN_MILLIS = 20000;
public static final String ADAPTER_MIN_THREAD_POOL_SIZE_NAME = "minThread";
public static final String ADAPTER_MAX_THREAD_POOL_SIZE_NAME = "maxThread";
public static final String ADAPTER_KEEP_ALIVE_TIME_NAME = "keepAliveTimeInMillis";
public static final String ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME = "jobQueueSize";
}

@ -0,0 +1,98 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.output.adapter.xmpp.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
/**
* This is the utility class that is used for MQTT input adapater.
*/
public class MQTTUtil {
private static final String HTTPS_PROTOCOL = "https";
private static final Log log = LogFactory.getLog(MQTTUtil.class);
/**
* Return a http client instance
* @param protocol- service endpoint protocol http/https
* @return
*/
public static HttpClient getHttpClient(String protocol)
throws IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
HttpClient httpclient;
if (HTTPS_PROTOCOL.equals(protocol)) {
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
} else {
httpclient = HttpClients.createDefault();
}
return httpclient;
}
public static String getResponseString(HttpResponse httpResponse) throws IOException {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
String readLine;
String response = "";
while (((readLine = br.readLine()) != null)) {
response += readLine;
}
return response;
} finally {
EntityUtils.consumeQuietly(httpResponse.getEntity());
if (br != null) {
try {
br.close();
} catch (IOException e) {
log.warn("Error while closing the connection! " + e.getMessage());
}
}
}
}
public static JWTClientManagerService getJWTClientManagerService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
JWTClientManagerService jwtClientManagerService =
(JWTClientManagerService) ctx.getOSGiService(JWTClientManagerService.class, null);
if (jwtClientManagerService == null) {
String msg = "JWT management service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return jwtClientManagerService;
}
}

@ -0,0 +1,73 @@
package org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.util;
/**
* This class represents the data that are required to register
* the oauth application.
*/
public class RegistrationProfile {
private String callbackUrl;
private String clientName;
private String tokenScope;
private String owner;
private String grantType;
private String applicationType;
private static final String TAG = RegistrationProfile.class.getSimpleName();
public String getCallbackUrl() {
return callbackUrl;
}
public void setCallbackUrl(String callBackUrl) {
this.callbackUrl = callBackUrl;
}
public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public String getTokenScope() {
return tokenScope;
}
public void setTokenScope(String tokenScope) {
this.tokenScope = tokenScope;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getGrantType() {
return grantType;
}
public void setGrantType(String grantType) {
this.grantType = grantType;
}
public String getApplicationType() {
return applicationType;
}
public void setApplicationType(String applicationType) {
this.applicationType = applicationType;
}
public String toJSON() {
String jsonString =
"{\"callbackUrl\": \"" + callbackUrl + "\",\"clientName\": \"" + clientName + "\", \"tokenScope\": " +
"\"" + tokenScope + "\", \"owner\": \"" + owner + "\"," + "\"grantType\": \"" + grantType +
"\", \"saasApp\" :false }\n";
return jsonString;
}
}

@ -0,0 +1,33 @@
#
# 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.
#
topic=Topic
url=Broker Url
username=Username
username.hint=Username of the broker
dcrUrl=dcrUrl
dcrUrl.hint=Dynamic Client Registration Url
scopes=scopes
scopes.hint=Scopes that required to connect with the broker.
url.hint=MQTT broker url
cleanSession=Clean Session
cleanSession.hint=Persist topic subscriptions and ack positions across client sessions
keepAlive=Keep Alive (In seconds)
qos=Quality of Service
clientId=Client Id
clientId.hint=client identifier is used by the server to identify a client when it reconnects, It used for durable subscriptions or reliable delivery of messages is required.

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>iot-base-plugin</artifactId>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<version>2.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.device.mgt.iot.output.adapter.xmpp</artifactId>
<packaging>bundle</packaging>
<name>WSO2 Carbon - Device Mgt Output MQTT Adaptor Module</name>
<description>org.wso2.carbon.device.mgt.iot.output.adapter.xmpp provides the back-end functionality of xmpp adaptor
</description>
<url>http://wso2.org</url>
<dependencies>
<dependency>
<groupId>org.wso2.carbon.analytics-common</groupId>
<artifactId>org.wso2.carbon.event.output.adapter.core</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.core</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.logging</artifactId>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack.wso2</groupId>
<artifactId>smack</artifactId>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack.wso2</groupId>
<artifactId>smackx</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<executions>
<execution>
<id>generate-scr-descriptor</id>
<goals>
<goal>scr</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Bundle-Name>${project.artifactId}</Bundle-Name>
<Private-Package>
org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.internal,
org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.internal.*
</Private-Package>
<Export-Package>
!org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.internal,
!org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.internal.*,
org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.*,
</Export-Package>
<Import-Package>
org.wso2.carbon.event.output.adapter.core,
org.wso2.carbon.event.output.adapter.core.*,
org.jivesoftware.smack.*,
org.apache.commons.logging,
org.osgi.framework,
org.osgi.service.component,
org.wso2.carbon.context
</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,200 @@
/*
* 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.device.mgt.iot.output.adapter.xmpp;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.util.XMPPAdapterPublisher;
import org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.util.XMPPServerConnectionConfiguration;
import org.wso2.carbon.event.output.adapter.core.EventAdapterUtil;
import org.wso2.carbon.event.output.adapter.core.OutputEventAdapter;
import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterConfiguration;
import org.wso2.carbon.event.output.adapter.core.exception.OutputEventAdapterException;
import org.wso2.carbon.event.output.adapter.core.exception.TestConnectionNotSupportedException;
import org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.util.XMPPEventAdapterConstants;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Output XMPPEventAdapter will be used to publish events with MQTT protocol to specified broker and topic.
*/
public class XMPPEventAdapter implements OutputEventAdapter {
private OutputEventAdapterConfiguration eventAdapterConfiguration;
private Map<String, String> globalProperties;
private XMPPAdapterPublisher xmppAdapterPublisher;
private static ThreadPoolExecutor threadPoolExecutor;
private static final Log log = LogFactory.getLog(XMPPEventAdapter.class);
private int tenantId;
public XMPPEventAdapter(OutputEventAdapterConfiguration eventAdapterConfiguration,
Map<String, String> globalProperties) {
this.eventAdapterConfiguration = eventAdapterConfiguration;
this.globalProperties = globalProperties;
}
@Override
public void init() throws OutputEventAdapterException {
tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
//ThreadPoolExecutor will be assigned if it is null
if (threadPoolExecutor == null) {
int minThread;
int maxThread;
int jobQueSize;
long defaultKeepAliveTime;
//If global properties are available those will be assigned else constant values will be assigned
if (globalProperties.get(XMPPEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE_NAME) != null) {
minThread = Integer.parseInt(globalProperties.get(
XMPPEventAdapterConstants.ADAPTER_MIN_THREAD_POOL_SIZE_NAME));
} else {
minThread = XMPPEventAdapterConstants.DEFAULT_MIN_THREAD_POOL_SIZE;
}
if (globalProperties.get(XMPPEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME) != null) {
maxThread = Integer.parseInt(globalProperties.get(
XMPPEventAdapterConstants.ADAPTER_MAX_THREAD_POOL_SIZE_NAME));
} else {
maxThread = XMPPEventAdapterConstants.DEFAULT_MAX_THREAD_POOL_SIZE;
}
if (globalProperties.get(XMPPEventAdapterConstants.ADAPTER_KEEP_ALIVE_TIME_NAME) != null) {
defaultKeepAliveTime = Integer.parseInt(globalProperties.get(
XMPPEventAdapterConstants.ADAPTER_KEEP_ALIVE_TIME_NAME));
} else {
defaultKeepAliveTime = XMPPEventAdapterConstants.DEFAULT_KEEP_ALIVE_TIME_IN_MILLIS;
}
if (globalProperties.get(XMPPEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME) != null) {
jobQueSize = Integer.parseInt(globalProperties.get(
XMPPEventAdapterConstants.ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME));
} else {
jobQueSize = XMPPEventAdapterConstants.DEFAULT_EXECUTOR_JOB_QUEUE_SIZE;
}
threadPoolExecutor = new ThreadPoolExecutor(minThread, maxThread, defaultKeepAliveTime,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(
jobQueSize));
}
}
@Override
public void testConnect() throws TestConnectionNotSupportedException {
throw new TestConnectionNotSupportedException("Test connection is not available");
}
@Override
public void connect() {
int xmppPort = XMPPEventAdapterConstants.DEFAULT_XMPP_PORT;
String xmppPortString = eventAdapterConfiguration.getStaticProperties()
.get(XMPPEventAdapterConstants.ADAPTER_CONF_PORT);
if (xmppPortString != null && !xmppPortString.trim().isEmpty()) {
xmppPort = Integer.parseInt(xmppPortString);
}
int timeoutInterval = XMPPEventAdapterConstants.DEFAULT_TIMEOUT_INTERVAL;
String timeoutIntervalString = eventAdapterConfiguration.getStaticProperties().get(
XMPPEventAdapterConstants.ADAPTER_CONF_TIMEOUT_INTERVAL);
if (timeoutIntervalString != null && !timeoutIntervalString.trim().isEmpty()) {
timeoutInterval = Integer.parseInt(timeoutIntervalString);
}
XMPPServerConnectionConfiguration xmppServerConnectionConfiguration =
new XMPPServerConnectionConfiguration(eventAdapterConfiguration.getStaticProperties()
.get(XMPPEventAdapterConstants.ADAPTER_CONF_HOST),
xmppPort,
eventAdapterConfiguration.getStaticProperties()
.get(XMPPEventAdapterConstants.ADAPTER_CONF_USERNAME),
eventAdapterConfiguration.getStaticProperties()
.get(XMPPEventAdapterConstants.ADAPTER_CONF_PASSWORD),
timeoutInterval,
eventAdapterConfiguration.getStaticProperties()
.get(XMPPEventAdapterConstants.ADAPTER_CONF_RESOURCE)
);
xmppAdapterPublisher = new XMPPAdapterPublisher(xmppServerConnectionConfiguration);
}
@Override
public void publish(Object message, Map<String, String> dynamicProperties) {
String jid = dynamicProperties.get(XMPPEventAdapterConstants.ADAPTER_CONF_JID);
String subject = dynamicProperties.get(XMPPEventAdapterConstants.ADAPTER_CONF_SUBJECT);
String messageType = dynamicProperties.get(XMPPEventAdapterConstants.ADAPTER_CONF_MESSAGETYPE);
try {
threadPoolExecutor.submit(new XMPPSender(jid, subject, (String)message, messageType));
} catch (RejectedExecutionException e) {
EventAdapterUtil.logAndDrop(eventAdapterConfiguration.getName(), message, "Job queue is full", e, log,
tenantId);
}
}
@Override
public void disconnect() {
try {
if (xmppAdapterPublisher != null) {
xmppAdapterPublisher.close();
xmppAdapterPublisher = null;
}
} catch (OutputEventAdapterException e) {
log.error("Exception when closing the mqtt publisher connection on Output MQTT Adapter '" +
eventAdapterConfiguration.getName() + "'", e);
}
}
@Override
public void destroy() {
//not required
}
@Override
public boolean isPolled() {
return false;
}
class XMPPSender implements Runnable {
String jid;
String subject;
String message;
String messageType;
XMPPSender(String jid, String subject, String message, String messageType) {
this.jid = jid;
this.message = message;
this.subject = subject;
this.messageType = messageType;
}
@Override
public void run() {
try {
if (!xmppAdapterPublisher.isConnected()) {
synchronized (XMPPEventAdapter.class) {
if (!xmppAdapterPublisher.isConnected()) {
xmppAdapterPublisher.connect();
}
}
}
xmppAdapterPublisher.publish(jid, subject, message, messageType);
} catch (Throwable t) {
EventAdapterUtil.logAndDrop(eventAdapterConfiguration.getName(), message, null, t, log, tenantId);
}
}
}
}

@ -0,0 +1,132 @@
/*
* 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.device.mgt.iot.output.adapter.xmpp;
import org.wso2.carbon.event.output.adapter.core.*;
import org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.util.XMPPEventAdapterConstants;
import java.util.*;
/**
* The xmpp event adapter factory class to create a xmpp output adapter
*/
public class XMPPEventAdapterFactory extends OutputEventAdapterFactory {
private ResourceBundle resourceBundle =
ResourceBundle.getBundle("org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.i18n.Resources", Locale.getDefault());
@Override
public String getType() {
return XMPPEventAdapterConstants.ADAPTER_TYPE_XMPP;
}
@Override
public List<String> getSupportedMessageFormats() {
List<String> supportedMessageFormats = new ArrayList<String>();
supportedMessageFormats.add(MessageType.XML);
supportedMessageFormats.add(MessageType.JSON);
supportedMessageFormats.add(MessageType.TEXT);
return supportedMessageFormats;
}
@Override
public List<Property> getStaticPropertyList() {
List<Property> staticPropertyList = new ArrayList<Property>();
// Url
Property host = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_HOST);
host.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_HOST));
host.setRequired(true);
host.setHint(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_HOST_HINT));
// Host Port
Property port = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_PORT);
port.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_PORT));
port.setRequired(true);
port.setHint(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_PORT_HINT));
//Broker Username
Property userName = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_USERNAME);
userName.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_USERNAME));
userName.setRequired(true);
userName.setHint(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_USERNAME_HINT));
//Broker Password
Property password = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_PASSWORD);
password.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_PASSWORD));
password.setRequired(true);
password.setHint(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_PASSWORD_HINT));
//Timeout Interval
Property timooutInterval = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_TIMEOUT_INTERVAL);
timooutInterval.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_TIMEOUT_INTERVAL_HINT));
timooutInterval.setRequired(false);
timooutInterval.setHint(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_TIMEOUT_INTERVAL_HINT));
//Resource
Property resource = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_RESOURCE);
resource.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_RESOURCE));
resource.setRequired(true);
resource.setHint(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_RESOURCE_HINT));
staticPropertyList.add(host);
staticPropertyList.add(port);
staticPropertyList.add(userName);
staticPropertyList.add(password);
staticPropertyList.add(timooutInterval);
staticPropertyList.add(resource);
return staticPropertyList;
}
@Override
public List<Property> getDynamicPropertyList() {
List<Property> dynamicPropertyList = new ArrayList<Property>();
// set topic
Property jidProperty = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_JID);
jidProperty.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_JID_HINT));
jidProperty.setRequired(true);
Property subjectProperty = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_SUBJECT);
subjectProperty.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_SUBJECT_HINT));
subjectProperty.setRequired(false);
Property messageType = new Property(XMPPEventAdapterConstants.ADAPTER_CONF_MESSAGETYPE);
messageType.setDisplayName(resourceBundle.getString(XMPPEventAdapterConstants.ADAPTER_CONF_MESSAGETYPE_HINT));
messageType.setRequired(true);
messageType.setOptions(
new String[]{XMPPEventAdapterConstants.MessageType.CHAT, XMPPEventAdapterConstants.MessageType.ERROR,
XMPPEventAdapterConstants.MessageType.GROUP_CHAT, XMPPEventAdapterConstants.MessageType.NORMAL,
XMPPEventAdapterConstants.MessageType.HEADLINE});
messageType.setDefaultValue(XMPPEventAdapterConstants.MessageType.NORMAL);
dynamicPropertyList.add(jidProperty);
dynamicPropertyList.add(subjectProperty);
dynamicPropertyList.add(messageType);
return dynamicPropertyList;
}
@Override
public String getUsageTips() {
return null;
}
@Override
public OutputEventAdapter createEventAdapter(OutputEventAdapterConfiguration eventAdapterConfiguration,
Map<String, String> globalProperties) {
return new XMPPEventAdapter(eventAdapterConfiguration, globalProperties);
}
}

@ -0,0 +1,51 @@
/*
* 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.device.mgt.iot.output.adapter.xmpp.internal;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.service.component.ComponentContext;
import org.wso2.carbon.device.mgt.iot.output.adapter.xmpp.XMPPEventAdapterFactory;
import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterFactory;
/**
* @scr.component component.name="output.XMPP.AdapterService.component" immediate="true"
*/
public class XMPPEventAdapterServiceComponent {
private static final Log log = LogFactory.getLog(XMPPEventAdapterServiceComponent.class);
/**
* Deployment of the XMPP event adapter service will be done.
* @param context bundle context where service is registered
*/
protected void activate(ComponentContext context) {
try {
OutputEventAdapterFactory xmppEventAdapterFactory = new XMPPEventAdapterFactory();
context.getBundleContext().registerService(OutputEventAdapterFactory.class.getName(),
xmppEventAdapterFactory, null);
if (log.isDebugEnabled()) {
log.debug("The XMPP publisher service has been deployed successfully");
}
} catch (RuntimeException e) {
log.error("Exception occurred when deploying XMPP publisher service", e);
}
}
}

@ -0,0 +1,106 @@
/*
* 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.device.mgt.iot.output.adapter.xmpp.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.wso2.carbon.event.output.adapter.core.exception.OutputEventAdapterException;
import org.wso2.carbon.event.output.adapter.core.exception.OutputEventAdapterRuntimeException;
/**
* XMPP publisher related configuration initialization and publishing capabilties are implemented here.
*/
public class XMPPAdapterPublisher {
private static final Log log = LogFactory.getLog(XMPPAdapterPublisher.class);
private XMPPServerConnectionConfiguration xmppServerConnectionConfiguration;
XMPPConnection xmppConnection;
public XMPPAdapterPublisher(XMPPServerConnectionConfiguration xmppServerConnectionConfiguration) {
this.xmppServerConnectionConfiguration = xmppServerConnectionConfiguration;
connect();
}
public void connect() {
SmackConfiguration.setPacketReplyTimeout(xmppServerConnectionConfiguration.getTimeoutInterval());
ConnectionConfiguration config = new ConnectionConfiguration(xmppServerConnectionConfiguration.getHost(),
xmppServerConnectionConfiguration.getPort());
config.setSASLAuthenticationEnabled(false);
config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
xmppConnection = new XMPPConnection(config);
String resource = xmppServerConnectionConfiguration.getResource();
String username = xmppServerConnectionConfiguration.getUsername();
String password = xmppServerConnectionConfiguration.getPassword();
try {
xmppConnection.connect();
if (resource == null || resource.trim().isEmpty()) {
xmppConnection.login(username, password);
} else {
xmppConnection.login(username, password, resource);
}
} catch (XMPPException e) {
String errorMsg = "Login attempt to the XMPP Server with username - " + username + " failed.";
log.info(errorMsg);
throw new OutputEventAdapterRuntimeException(errorMsg, e);
}
}
public boolean isConnected() {
return xmppConnection.isConnected();
}
public void publish(String JID, String subject, String message, String messageType) {
Message xmppMessage = new Message();
xmppMessage.setTo(JID);
xmppMessage.setSubject(subject);
xmppMessage.setBody(message);
if (messageType != null) {
switch (messageType) {
case XMPPEventAdapterConstants.MessageType.CHAT:
xmppMessage.setType(Message.Type.chat);
break;
case XMPPEventAdapterConstants.MessageType.GROUP_CHAT:
xmppMessage.setType(Message.Type.groupchat);
break;
case XMPPEventAdapterConstants.MessageType.ERROR:
xmppMessage.setType(Message.Type.error);
break;
case XMPPEventAdapterConstants.MessageType.HEADLINE:
xmppMessage.setType(Message.Type.headline);
break;
default:
xmppMessage.setType(Message.Type.normal);
}
} else {
xmppMessage.setType(Message.Type.normal);
}
xmppConnection.sendPacket(xmppMessage);
}
public void close() throws OutputEventAdapterException {
if (xmppConnection != null && isConnected()) {
xmppConnection.disconnect();
}
}
}

@ -0,0 +1,71 @@
/*
* 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.device.mgt.iot.output.adapter.xmpp.util;
public final class XMPPEventAdapterConstants {
private XMPPEventAdapterConstants() {
}
public static final String ADAPTER_TYPE_XMPP = "xmpp";
//dynamic properties
public static final String ADAPTER_CONF_JID = "jid";
public static final String ADAPTER_CONF_JID_HINT = "jid.hint";
public static final String ADAPTER_CONF_SUBJECT = "subject";
public static final String ADAPTER_CONF_SUBJECT_HINT = "subject.hint";
public static final String ADAPTER_CONF_MESSAGETYPE = "messageType";
public static final String ADAPTER_CONF_MESSAGETYPE_HINT = "messageType.hint";
//static properties
public static final String ADAPTER_CONF_HOST = "host";
public static final String ADAPTER_CONF_HOST_HINT = "host.hint";
public static final String ADAPTER_CONF_PORT = "port";
public static final String ADAPTER_CONF_PORT_HINT = "port.hint";
public static final String ADAPTER_CONF_USERNAME = "username";
public static final String ADAPTER_CONF_USERNAME_HINT = "username.hint";
public static final String ADAPTER_CONF_PASSWORD = "password";
public static final String ADAPTER_CONF_PASSWORD_HINT = "password.hint";
public static final String ADAPTER_CONF_RESOURCE = "resource";
public static final String ADAPTER_CONF_RESOURCE_HINT = "resource.hint";
public static final String ADAPTER_CONF_TIMEOUT_INTERVAL = "timeoutInterval";
public static final String ADAPTER_CONF_TIMEOUT_INTERVAL_HINT = "timeoutInterval.hint";
public static final int DEFAULT_XMPP_PORT = 5222;
public static final int DEFAULT_TIMEOUT_INTERVAL = 5000;
//global properties
public static final int DEFAULT_MIN_THREAD_POOL_SIZE = 8;
public static final int DEFAULT_MAX_THREAD_POOL_SIZE = 100;
public static final int DEFAULT_EXECUTOR_JOB_QUEUE_SIZE = 2000;
public static final long DEFAULT_KEEP_ALIVE_TIME_IN_MILLIS = 20000;
public static final String ADAPTER_MIN_THREAD_POOL_SIZE_NAME = "minThread";
public static final String ADAPTER_MAX_THREAD_POOL_SIZE_NAME = "maxThread";
public static final String ADAPTER_KEEP_ALIVE_TIME_NAME = "keepAliveTimeInMillis";
public static final String ADAPTER_EXECUTOR_JOB_QUEUE_SIZE_NAME = "jobQueueSize";
public static final class MessageType {
public static final String NORMAL = "normal";
public static final String CHAT = "chat";
public static final String GROUP_CHAT = "groupchat";
public static final String HEADLINE = "headline";
public static final String ERROR = "error";
}
}

@ -0,0 +1,63 @@
/*
* 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.device.mgt.iot.output.adapter.xmpp.util;
public class XMPPServerConnectionConfiguration {
private String host;
private int port;
private String username;
private String password;
private int timeoutInterval;
private String resource;
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public int getTimeoutInterval() {
return timeoutInterval;
}
public String getResource() {
return resource;
}
public XMPPServerConnectionConfiguration(String host, int port, String username, String password,
int timeoutInterval, String resource) {
this.host = host;
this.port = port;
this.username = username;
this.password = password;
this.timeoutInterval = timeoutInterval;
this.resource = resource;
}
}

@ -0,0 +1,36 @@
#
# 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.
#
host=Server Url
host.hint=XMPP Server url
port=Server Port
port.hint=Server Port Number
username=Username
username.hint=Username of the broker
password=Password
password.hint=Password to connect to the server.
timeoutInterval=Time out Interval
timeoutInterval.hint=used by listeners to the server and for reconnection schedules.
resource=Resource
resource.hint=specific to the XMPP-Account to which the login is made to.
jid=JID
jid.hint=the JID (XMPP Account ID) to which the message is to be sent to.
subject=Subject
subject.hint=Subject of the message.
messageType=Message Type
messageType.hint=Type of the XMPP Message (chat, groupchat, error, headline, normal)

@ -35,6 +35,9 @@
<modules>
<module>org.wso2.carbon.device.mgt.iot</module>
<module>org.wso2.carbon.device.mgt.iot.ui</module>
<module>org.wso2.carbon.device.mgt.iot.output.adapter.mqtt</module>
<module>org.wso2.carbon.device.mgt.iot.output.adapter.xmpp</module>
<module>org.wso2.carbon.device.mgt.iot.input.adapter</module>
</modules>
<build>

@ -41,27 +41,6 @@ import javax.ws.rs.core.Response;
@DeviceType(value = "virtual_firealarm")
public interface VirtualFireAlarmControllerService {
/**
* This is an API used/called by the device. It registers the IP of a VirtualFirealarm device against its DeviceID
* when the device connects with the server for the first time. This DeviceID to IP mapping is necessary only for
* cases where HTTP communication is to be used. At such instances, this mapping is used by the server to
* identify the IP of the device to which it has some message to be sent. This method becomes useful only in
* scenarios where HTTP communication is used in a setup where the IoT-Server and the devices communicating with it
* are in the same IP network.
*
* @param deviceId the ID of the VirtualFirealarm device from which this register-IP call was initiated.
* @param deviceIP the IP of the VirtualFirealarm device which has sent this register-IP request.
* @param devicePort the PORT on the VirtualFirealarm device (on this IP) that's open for HTTP communication.
* @param request the HTTP servlet request object received by default as part of the HTTP call to this API.
* @return a custom message indicating whether the DeviceID to IP mapping was successful.
*/
@POST
@Path("device/register/{deviceId}/{ip}/{port}")
@Permission(scope = "virtual_firealarm_admin", permissions = {"device-mgt/virtual_firealarm/admin"})
Response registerDeviceIP(@PathParam("deviceId") String deviceId, @PathParam("ip") String deviceIP,
@PathParam("port") String devicePort, @Context HttpServletRequest request);
/**
* This is an API called/used from within the Server(Front-End) or by a device Owner. It sends a control command to
* the VirtualFirealarm device to switch `ON` or `OFF` its buzzer. The method also takes in the protocol to be used
@ -79,19 +58,6 @@ public interface VirtualFireAlarmControllerService {
description = "Switch on/off Virtual Fire Alarm Buzzer. (On / Off)")
Response switchBuzzer(@PathParam("deviceId") String deviceId, @QueryParam("protocol") String protocol,
@FormParam("state") String state);
/**
* This is an API called/used by the VirtualFirealarm device to publish its temperature to the IoT-Server. The
* received data from the device is stored in a 'DeviceRecord' under the device's ID in the 'SensorDataManager'
* of the Server.
*
* @param dataMsg the temperature data received from the device in JSON format complying to type 'DeviceData'.
*/
@POST
@Path("device/temperature")
@Permission(scope = "virtual_firealarm_admin", permissions = {"device-mgt/virtual_firealarm/admin"})
@Consumes(MediaType.APPLICATION_JSON)
Response pushTemperatureData(final DeviceData dataMsg);
/**

@ -1,20 +1,20 @@
/*
* Copyright (c) 2016, 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.
*/
* Copyright (c) 2016, 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.device.mgt.iot.virtualfirealarm.service.impl;
@ -35,6 +35,7 @@ import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto.DeviceData;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto.SensorRecord;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.exception.VirtualFireAlarmException;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.transport.VirtualFireAlarmMQTTConnector;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.transport.VirtualFireAlarmXMPPConnector;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.APIUtil;
@ -54,8 +55,12 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@SuppressWarnings("Non-Annoted WebService")
@ -71,26 +76,7 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
private VirtualFireAlarmMQTTConnector virtualFireAlarmMQTTConnector;
// connects to the given XMPP server and handles XMPP communication
private VirtualFireAlarmXMPPConnector virtualFireAlarmXMPPConnector;
// holds a mapping of the IP addresses to Device-IDs for HTTP communication
private ConcurrentHashMap<String, String> deviceToIpMap = new ConcurrentHashMap<>();
@Permission(scope = "virtual_firealarm_user", permissions = { "device-mgt/virtual_firealarm/user" })
@POST
@Path("device/register/{deviceId}/{ip}/{port}")
public Response registerDeviceIP(@PathParam("deviceId") String deviceId, @PathParam("ip") String deviceIP,
@PathParam("port") String devicePort, @Context HttpServletRequest request) {
if (log.isDebugEnabled()) {
log.debug("Got register call from IP: " + deviceIP + " for Device ID: " + deviceId);
}
String deviceHttpEndpoint = deviceIP + ":" + devicePort;
deviceToIpMap.put(deviceId, deviceHttpEndpoint);
String result = "Device-IP Registered";
if (log.isDebugEnabled()) {
log.debug(result);
}
return Response.ok().entity(result).build();
}
@POST
@Path("device/{deviceId}/buzz")
@ -106,7 +92,7 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
String callUrlPattern = VirtualFireAlarmConstants.BULB_CONTEXT + switchToState;
if (log.isDebugEnabled()) {
log.debug("Sending request to switch-bulb of device [" + deviceId + "] via " +
protocolString);
protocolString);
}
try {
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(
@ -115,29 +101,35 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
switch (protocolString) {
case HTTP_PROTOCOL:
String deviceHTTPEndpoint = deviceToIpMap.get(deviceId);
if (deviceHTTPEndpoint == null) {
return Response.status(Response.Status.PRECONDITION_FAILED).build();
}
VirtualFireAlarmServiceUtils.sendCommandViaHTTP(deviceHTTPEndpoint, callUrlPattern, true);
break;
case XMPP_PROTOCOL:
String xmppResource = VirtualFireAlarmConstants.BULB_CONTEXT.replace("/", "");
virtualFireAlarmXMPPConnector.publishDeviceData(deviceId, xmppResource, switchToState);
break;
default:
String mqttResource = VirtualFireAlarmConstants.BULB_CONTEXT.replace("/", "");
virtualFireAlarmMQTTConnector.publishDeviceData(deviceId, mqttResource, switchToState);
String publishTopic = "wso2/" + APIUtil.getTenantDomainOftheUser() + "/"
+ VirtualFireAlarmConstants.DEVICE_TYPE + "/" + deviceId;
PrivateKey serverPrivateKey = SecurityManager.getServerPrivateKey();
String actualMessage = mqttResource + ":" + state.toUpperCase();
String encryptedMsg = VirtualFireAlarmServiceUtils.prepareSecurePayLoad(actualMessage,
serverPrivateKey);
Map<String, String> dynamicProperties = new HashMap<>();
dynamicProperties.put(VirtualFireAlarmConstants.ADAPTER_TOPIC_PROPERTY, publishTopic);
APIUtil.getOutputEventAdapterService().publish(VirtualFireAlarmConstants.ADAPTER_NAME,
dynamicProperties, encryptedMsg);
break;
}
return Response.ok().build();
} catch (DeviceManagementException | TransportHandlerException e) {
} catch (TransportHandlerException e) {
log.error("Failed to send switch-bulb request to device [" + deviceId + "] via " + protocolString);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
} catch (VirtualFireAlarmException e) {
String errorMsg = "Preparing Secure payload failed for device - [" + deviceId + "]";
log.error(errorMsg);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
}
@ -157,17 +149,14 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
switch (protocolString) {
case HTTP_PROTOCOL:
throw new UnsupportedOperationException(
"Sending request to update-policy via HTTP protocol not supported.");
case XMPP_PROTOCOL:
String xmppResource = VirtualFireAlarmConstants.POLICY_CONTEXT.replace("/", "");
virtualFireAlarmXMPPConnector.publishDeviceData(deviceId, xmppResource, policy);
break;
default:
String mqttResource = VirtualFireAlarmConstants.POLICY_CONTEXT.replace("/", "");
virtualFireAlarmMQTTConnector.publishDeviceData(deviceId, mqttResource, policy);
break;
case XMPP_PROTOCOL:
String xmppResource = VirtualFireAlarmConstants.POLICY_CONTEXT.replace("/", "");
virtualFireAlarmXMPPConnector.publishDeviceData(deviceId, xmppResource, policy);
break;
default:
String mqttResource = VirtualFireAlarmConstants.POLICY_CONTEXT.replace("/", "");
virtualFireAlarmMQTTConnector.publishDeviceData(deviceId, mqttResource, policy);
break;
}
return Response.ok().build();
} catch (TransportHandlerException e) {
@ -179,36 +168,6 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
}
}
@POST
@Path("device/temperature")
@Consumes(MediaType.APPLICATION_JSON)
public Response pushTemperatureData(final DeviceData dataMsg) {
String deviceId = dataMsg.deviceId;
String deviceIp = dataMsg.reply;
String registeredIp = deviceToIpMap.get(deviceId);
if (registeredIp == null) {
log.warn("Unregistered IP: Temperature Data Received from an un-registered IP " +
deviceIp + " for device ID - " + deviceId);
return Response.status(Response.Status.PRECONDITION_FAILED).build();
} else if (!registeredIp.equals(deviceIp)) {
log.warn("Conflicting IP: Received IP is " + deviceIp + ". Device with ID " + deviceId +
" is already registered under some other IP. Re-registration required");
return Response.status(Response.Status.CONFLICT).build();
}
try {
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(
new DeviceIdentifier(deviceId, VirtualFireAlarmConstants.DEVICE_TYPE))) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
if (!VirtualFireAlarmServiceUtils.publishToDAS(dataMsg.deviceId, dataMsg.value)) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
return Response.ok().build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
}
@Path("device/stats/{deviceId}")
@GET
@ -303,7 +262,8 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
if (waitForServerStartup()) {
return;
}
VirtualFireAlarmControllerServiceImpl.this.virtualFireAlarmXMPPConnector = virtualFireAlarmXMPPConnector;
VirtualFireAlarmControllerServiceImpl.this.virtualFireAlarmXMPPConnector =
virtualFireAlarmXMPPConnector;
if (XmppConfig.getInstance().isEnabled()) {
Runnable xmppStarter = new Runnable() {
@ -318,7 +278,9 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
xmppStarterThread.setDaemon(true);
xmppStarterThread.start();
} else {
log.warn("XMPP disabled in 'devicemgt-config.xml'. Hence, VirtualFireAlarmXMPPConnector not started.");
log.warn(
"XMPP disabled in 'devicemgt-config.xml'. Hence, VirtualFireAlarmXMPPConnector not " +
"started.");
}
}
};
@ -357,11 +319,13 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
VirtualFireAlarmControllerServiceImpl.this.virtualFireAlarmMQTTConnector = virtualFireAlarmMQTTConnector;
VirtualFireAlarmControllerServiceImpl.this.virtualFireAlarmMQTTConnector =
virtualFireAlarmMQTTConnector;
if (MqttConfig.getInstance().isEnabled()) {
virtualFireAlarmMQTTConnector.connect();
} else {
log.warn("MQTT disabled in 'devicemgt-config.xml'. Hence, VirtualFireAlarmMQTTConnector not started.");
log.warn(
"MQTT disabled in 'devicemgt-config.xml'. Hence, VirtualFireAlarmMQTTConnector not started.");
}
}
};

@ -269,8 +269,7 @@ public class VirtualFireAlarmManagerServiceImpl implements VirtualFireAlarmManag
if (XmppConfig.getInstance().isEnabled()) {
status = xmppServerClient.createXMPPAccount(newXmppAccount);
if (!status) {
String msg =
"XMPP Account was not created for device - " + deviceId + " of owner - " + owner +
String msg = "XMPP Account was not created for device - " + deviceId + " of owner - " + owner +
".XMPP might have been disabled in org.wso2.carbon.device.mgt.iot" +
".common.config.server.configs";
throw new DeviceManagementException(msg);

@ -257,7 +257,6 @@ public class VirtualFireAlarmXMPPConnector extends XMPPTransportHandler {
}
}
};
Thread terminatorThread = new Thread(stopConnection);
terminatorThread.start();
}

@ -16,6 +16,7 @@ import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationService;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto.SensorRecord;
import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterService;
import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService;
import java.util.ArrayList;
@ -168,4 +169,16 @@ public class APIUtil {
}
return deviceAccessAuthorizationService;
}
public static OutputEventAdapterService getOutputEventAdapterService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
OutputEventAdapterService outputEventAdapterService =
(OutputEventAdapterService) ctx.getOSGiService(OutputEventAdapterService.class, null);
if (outputEventAdapterService == null) {
String msg = "Device Authorization service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return outputEventAdapterService;
}
}

@ -1,26 +0,0 @@
/*
* 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.device.mgt.iot.virtualfirealarm.service.impl.util.scep;
public class ContentType {
public static final String X_PKI_MESSAGE = "application/x-pki-message";
public static final String X_X509_CA_CERT = "application/x-x509-ca-cert";
public static final String X_X509_CA_RA_CERT = "application/x-x509-ca-ra-cert";
}

@ -1,39 +0,0 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.virtualfirealarm.service.impl.util.scep;
public enum SCEPOperation {
GET_CA_CERT("GetCACert"),
GET_CA_CAPS("GetCACaps"),
PKI_OPERATION("PKIOperation");
private String value;
private SCEPOperation(String value) {
this.setValue(value);
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

@ -71,11 +71,17 @@
org.wso2.carbon.device.mgt.common,
org.wso2.carbon.device.mgt.iot.*,
org.wso2.carbon.device.mgt.extensions.feature.mgt.*,
org.wso2.carbon.utils.*
org.wso2.carbon.utils.*,
org.wso2.carbon.event.output.adapter.core,
org.wso2.carbon.event.output.adapter.core.exception,
org.wso2.carbon.base,
org.wso2.carbon.core.util,
org.wso2.carbon.context,
org.wso2.carbon.core
</Import-Package>
<Export-Package>
!org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.internal,
org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.*
org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.*,
</Export-Package>
</instructions>
</configuration>
@ -112,5 +118,10 @@
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.utils</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.analytics-common</groupId>
<artifactId>org.wso2.carbon.event.output.adapter.core</artifactId>
</dependency>
</dependencies>
</project>

@ -28,15 +28,28 @@ public class VirtualFireAlarmConstants {
public static final String URL_PREFIX = "http://";
public static final String BULB_CONTEXT = "/BULB/";
public static final String POLICY_CONTEXT = "/POLICY/";
public static final String HUMIDITY_CONTEXT = "/HUMIDITY/";
public static final String TEMPERATURE_CONTEXT = "/TEMPERATURE/";
public static final String SENSOR_TEMP = "temperature";
//sensor events sumerized table name for temperature
public static final String TEMPERATURE_EVENT_TABLE = "DEVICE_TEMPERATURE_SUMMARY";
public static final String SENSOR_HUMIDITY = "humidity";
//sensor events summerized table name for humidity
public static final String HUMIDITY_EVENT_TABLE = "DEVICE_HUMIDITY_SUMMARY";
public static final String DATA_SOURCE_NAME = "jdbc/VirtualFireAlarmDM_DB";
public final static String DEVICE_TYPE_PROVIDER_DOMAIN = "carbon.super";
//tranport related constants
public static final String ADAPTER_NAME = "virtual_firealarm_mqtt";
public static final String ADAPTER_TYPE = "oauth-mqtt";
public static final String ADAPTER_TOPIC_PROPERTY = "topic";
public static final String MQTT_PORT = "\\$\\{mqtt.broker.port\\}";
public static final String MQTT_BROKER_HOST = "\\$\\{mqtt.broker.host\\}";
public static final String CARBON_CONFIG_PORT_OFFSET = "Ports.Offset";
public static final String DEFAULT_CARBON_SERVER_HOST_PROPERTY = "server.host";
public static final int CARBON_DEFAULT_PORT_OFFSET = 0;
public static final int DEFAULT_MQTT_PORT = 1883;
public static final String USERNAME_PROPERTY_KEY = "username";
public static final String DCR_PROPERTY_KEY = "dcrUrl";
public static final String BROKER_URL_PROPERTY_KEY = "url";
public static final String SCOPES_PROPERTY_KEY = "scopes";
public static final String QOS_PROPERTY_KEY = "qos";
public static final String CLIENT_ID_PROPERTY_KEY = "qos";
public static final String CLEAR_SESSION_PROPERTY_KEY = "clearSession";
}

@ -20,20 +20,31 @@ package org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.base.ServerConfiguration;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.core.util.Utils;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.exception.VirtualFirealarmDeviceMgtPluginException;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.internal.VirtualFirealarmManagementDataHolder;
import org.wso2.carbon.event.output.adapter.core.MessageType;
import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterConfiguration;
import org.wso2.carbon.event.output.adapter.core.exception.OutputEventAdapterException;
import org.wso2.carbon.utils.CarbonUtils;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* Contains utility methods used by FireAlarm plugin.
@ -41,26 +52,9 @@ import java.util.Map;
public class VirtualFireAlarmUtils {
private static Log log = LogFactory.getLog(VirtualFireAlarmUtils.class);
public static String getDeviceProperty(List<Device.Property> deviceProperties, String propertyKey) {
String deviceProperty = "";
for(Device.Property property :deviceProperties){
if(propertyKey.equals(property.getName())){
deviceProperty = property.getValue();
}
}
return deviceProperty;
}
public static Device.Property getProperty(String property, String value) {
if (property != null) {
Device.Property prop = new Device.Property();
prop.setName(property);
prop.setValue(value);
return prop;
}
return null;
}
private static final String VIRTUAL_FIREALARM_CONFIG_LOCATION =
CarbonUtils.getCarbonHome() + File.separator + "repository" + File.separator + "resources" +
File.separator + "device-types" + File.separator + "virtual-firealarm.properties";
public static void cleanupResources(Connection conn, PreparedStatement stmt, ResultSet rs) {
if (rs != null) {
@ -105,7 +99,89 @@ public class VirtualFireAlarmUtils {
log.error("Error while looking up the data source: " + VirtualFireAlarmConstants.DATA_SOURCE_NAME);
} catch (Exception e) {
throw new VirtualFirealarmDeviceMgtPluginException("Error occurred while initializing Iot Device " +
"Management database schema", e);
"Management database schema", e);
}
}
public static void setupOutputAdapter() throws IOException {
OutputEventAdapterConfiguration outputEventAdapterConfiguration =
createOutputEventAdapterConfiguration(VirtualFireAlarmConstants.ADAPTER_NAME,
VirtualFireAlarmConstants.ADAPTER_TYPE, MessageType.TEXT);
try {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(
VirtualFireAlarmConstants.DEVICE_TYPE_PROVIDER_DOMAIN, true);
VirtualFirealarmManagementDataHolder.getInstance().getOutputEventAdapterService()
.create(outputEventAdapterConfiguration);
} catch (OutputEventAdapterException e) {
log.error("Unable to create Output Event Adapter : " + VirtualFireAlarmConstants.ADAPTER_NAME, e);
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
/**
* Create Output Event Adapter Configuration for given configuration.
*
* @param name Output Event Adapter name
* @param type Output Event Adapter type
* @param msgFormat Output Event Adapter message format
* @return OutputEventAdapterConfiguration instance for given configuration
*/
private static OutputEventAdapterConfiguration createOutputEventAdapterConfiguration(String name, String type,
String msgFormat)
throws IOException {
OutputEventAdapterConfiguration outputEventAdapterConfiguration = new OutputEventAdapterConfiguration();
outputEventAdapterConfiguration.setName(name);
outputEventAdapterConfiguration.setType(type);
outputEventAdapterConfiguration.setMessageFormat(msgFormat);
File configFile = new File(VIRTUAL_FIREALARM_CONFIG_LOCATION);
if (configFile.exists()) {
Map<String, String> mqttAdapterProperties = new HashMap<>();
InputStream propertyStream = configFile.toURI().toURL().openStream();
Properties properties = new Properties();
properties.load(propertyStream);
mqttAdapterProperties.put(VirtualFireAlarmConstants.USERNAME_PROPERTY_KEY, properties.getProperty(
VirtualFireAlarmConstants.USERNAME_PROPERTY_KEY));
mqttAdapterProperties.put(VirtualFireAlarmConstants.DCR_PROPERTY_KEY, Utils.replaceSystemProperty(
properties.getProperty(VirtualFireAlarmConstants.DCR_PROPERTY_KEY)));
mqttAdapterProperties.put(VirtualFireAlarmConstants.BROKER_URL_PROPERTY_KEY, replaceMqttProperty(
properties.getProperty(VirtualFireAlarmConstants.BROKER_URL_PROPERTY_KEY)));
mqttAdapterProperties.put(VirtualFireAlarmConstants.SCOPES_PROPERTY_KEY, properties.getProperty(
VirtualFireAlarmConstants.SCOPES_PROPERTY_KEY));
mqttAdapterProperties.put(VirtualFireAlarmConstants.CLEAR_SESSION_PROPERTY_KEY, properties.getProperty(
VirtualFireAlarmConstants.CLEAR_SESSION_PROPERTY_KEY));
mqttAdapterProperties.put(VirtualFireAlarmConstants.QOS_PROPERTY_KEY, properties.getProperty(
VirtualFireAlarmConstants.QOS_PROPERTY_KEY));
mqttAdapterProperties.put(VirtualFireAlarmConstants.CLIENT_ID_PROPERTY_KEY, properties.getProperty(
VirtualFireAlarmConstants.CLIENT_ID_PROPERTY_KEY));
outputEventAdapterConfiguration.setStaticProperties(mqttAdapterProperties);
}
return outputEventAdapterConfiguration;
}
public static String replaceMqttProperty(String urlWithPlaceholders) {
urlWithPlaceholders = Utils.replaceSystemProperty(urlWithPlaceholders);
urlWithPlaceholders = urlWithPlaceholders.replaceAll(VirtualFireAlarmConstants.MQTT_PORT, "" +
(VirtualFireAlarmConstants.DEFAULT_MQTT_PORT + getPortOffset()));
urlWithPlaceholders = urlWithPlaceholders.replaceAll(VirtualFireAlarmConstants.MQTT_BROKER_HOST,
System.getProperty(VirtualFireAlarmConstants.DEFAULT_CARBON_SERVER_HOST_PROPERTY, "localhost"));
return urlWithPlaceholders;
}
private static int getPortOffset() {
ServerConfiguration carbonConfig = ServerConfiguration.getInstance();
String portOffset = System.getProperty("portOffset", carbonConfig.getFirstProperty(
VirtualFireAlarmConstants.CARBON_CONFIG_PORT_OFFSET));
try {
if ((portOffset != null)) {
return Integer.parseInt(portOffset.trim());
} else {
return VirtualFireAlarmConstants.CARBON_DEFAULT_PORT_OFFSET;
}
} catch (NumberFormatException e) {
return VirtualFireAlarmConstants.CARBON_DEFAULT_PORT_OFFSET;
}
}
}

@ -0,0 +1,43 @@
/*
* Copyright (c) 2016, 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.device.mgt.iot.virtualfirealarm.plugin.impl.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.core.ServerStartupObserver;
import java.io.IOException;
public class VirtualFirealarmStartupListener implements ServerStartupObserver {
private static final Log log = LogFactory.getLog(VirtualFirealarmStartupListener.class);
@Override
public void completingServerStartup() {
}
@Override
public void completedServerStartup() {
try {
VirtualFireAlarmUtils.setupOutputAdapter();
} catch (IOException e) {
log.error("Failed to intilaize the virtual firealarm output adapter", e);
}
}
}

@ -0,0 +1,47 @@
/*
* 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.device.mgt.iot.virtualfirealarm.plugin.internal;
import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterService;
/**
* DataHolder class of virtual firealarm plugins component.
*/
public class VirtualFirealarmManagementDataHolder {
private OutputEventAdapterService outputEventAdapterService;
private static VirtualFirealarmManagementDataHolder thisInstance = new VirtualFirealarmManagementDataHolder();
private VirtualFirealarmManagementDataHolder() {
}
public static VirtualFirealarmManagementDataHolder getInstance() {
return thisInstance;
}
public OutputEventAdapterService getOutputEventAdapterService() {
return outputEventAdapterService;
}
public void setOutputEventAdapterService(
OutputEventAdapterService outputEventAdapterService) {
this.outputEventAdapterService = outputEventAdapterService;
}
}

@ -1,20 +1,20 @@
/*
* 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.
*/
* 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.device.mgt.iot.virtualfirealarm.plugin.internal;
@ -23,15 +23,24 @@ import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.wso2.carbon.core.ServerStartupObserver;
import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.exception.VirtualFirealarmDeviceMgtPluginException;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.VirtualFireAlarmManagerService;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.util.VirtualFireAlarmUtils;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.util.VirtualFirealarmStartupListener;
import org.wso2.carbon.event.output.adapter.core.OutputEventAdapterService;
/**
* @scr.component name="org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.internal
* .VirtualFirealarmManagementServiceComponent"
* immediate="true"
* @scr.reference name="event.output.adapter.service"
* interface="org.wso2.carbon.event.output.adapter.core.OutputEventAdapterService"
* cardinality="1..1"
* policy="dynamic"
* bind="setOutputEventAdapterService"
* unbind="unsetOutputEventAdapterService"
*/
public class VirtualFirealarmManagementServiceComponent {
@ -45,7 +54,9 @@ public class VirtualFirealarmManagementServiceComponent {
try {
BundleContext bundleContext = ctx.getBundleContext();
firealarmServiceRegRef = bundleContext.registerService(DeviceManagementService.class.getName(),
new VirtualFireAlarmManagerService(), null);
new VirtualFireAlarmManagerService(), null);
bundleContext.registerService(ServerStartupObserver.class.getName(), new VirtualFirealarmStartupListener(),
null);
String setupOption = System.getProperty("setup");
if (setupOption != null) {
if (log.isDebugEnabled()) {
@ -81,4 +92,22 @@ public class VirtualFirealarmManagementServiceComponent {
log.error("Error occurred while de-activating Virtual Firealarm Device Management bundle", e);
}
}
/**
* Initialize the Output EventAdapter Service dependency
*
* @param outputEventAdapterService Output EventAdapter Service reference
*/
protected void setOutputEventAdapterService(OutputEventAdapterService outputEventAdapterService) {
VirtualFirealarmManagementDataHolder.getInstance().setOutputEventAdapterService(outputEventAdapterService);
}
/**
* De-reference the Output EventAdapter Service dependency.
*
* @param outputEventAdapterService
*/
protected void unsetOutputEventAdapterService(OutputEventAdapterService outputEventAdapterService) {
VirtualFirealarmManagementDataHolder.getInstance().setOutputEventAdapterService(null);
}
}

@ -41,6 +41,10 @@
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.output.adapter.mqtt</artifactId>
</dependency>
<dependency>
<groupId>org.json.wso2</groupId>
<artifactId>json</artifactId>
@ -140,6 +144,9 @@
<bundleDef>
org.wso2.carbon.devicemgt-plugins:org.wso2.carbon.device.mgt.iot:${carbon.devicemgt.plugins.version}
</bundleDef>
<bundleDef>
org.wso2.carbon.devicemgt-plugins:org.wso2.carbon.device.mgt.iot.output.adapter.mqtt:${carbon.devicemgt.plugins.version}
</bundleDef>
<bundleDef>
org.json.wso2:json:${commons-json.version}
</bundleDef>
@ -158,6 +165,9 @@
</importFeatureDef>
<importFeatureDef>org.wso2.carbon.device.mgt.server:${carbon.devicemgt.version}
</importFeatureDef>
<importFeatureDef>
org.wso2.carbon.event.output.adapter.server:${carbon.analytics.common.version}
</importFeatureDef>
</importFeatures>
</configuration>
</execution>

@ -3,4 +3,4 @@ org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../depl
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot_${feature.version}/jaggeryapps/,target:${installFolder}/../../deployment/server/jaggeryapps/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../conf/iot/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot_${feature.version}/conf/devicemgt-config.xml,target:${installFolder}/../../conf/iot/devicemgt-config.xml,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot_${feature.version}/conf/devicemgt-config.xsd,target:${installFolder}/../../conf/iot/devicemgt-config.xsd,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot_${feature.version}/conf/devicemgt-config.xsd,target:${installFolder}/../../conf/iot/devicemgt-config.xsd,overwrite:true);\

@ -16,9 +16,12 @@ org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../data
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.virtualfirealarm_${feature.version}/database/,target:${installFolder}/../../database/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../resources/security/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.virtualfirealarm_${feature.version}/certs/,target:${installFolder}/../../resources/security/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../resources/device-types/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.virtualfirealarm_${feature.version}/virtual-firealarm.properties,target:${installFolder}/../../resources/device-types/virtual-firealarm.properties,overwrite:true);\
instructions.unconfigure = \
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../conf/device-types/virtual_firealarm.json);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../resources/device-types/virtual_firealarm.properties);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/webapps/virtual_firealarm.war);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/webapps/virtual_firealarm);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/webapps/virtual_firealarm_scep.war);\

@ -0,0 +1,7 @@
url=tcp://${mqtt.broker.host}:${mqtt.broker.port}
username=admin
dcrUrl=https://${server.host}:${mgt.transport.https.port}/dynamic-client-web/register
scopes=
clearSession=true
qos=0
clientId=

@ -304,6 +304,16 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.wso2.carbon.analytics-common</groupId>
<artifactId>org.wso2.carbon.event.output.adapter.core</artifactId>
<version>${carbon.analytics.common.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.carbon.analytics-common</groupId>
<artifactId>org.wso2.carbon.event.input.adapter.core</artifactId>
<version>${carbon.analytics.common.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.carbon.analytics-common</groupId>
<artifactId>org.wso2.carbon.databridge.commons</artifactId>
@ -316,16 +326,16 @@
</dependency>
<!--IoT Server specific dependencies-->
<!--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<!--Common IoT Server Specific Impl $ API-->
<!--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot</artifactId>
<version>${carbon.devicemgt.plugins.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.output.adapter.mqtt</artifactId>
<version>${carbon.devicemgt.plugins.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.api</artifactId>
@ -333,9 +343,7 @@
<type>war</type>
</dependency>
<!--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<!--Android sense DeviceType Impl, API and Agent-->
<!--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.androidsense.plugin</artifactId>
@ -348,9 +356,7 @@
<type>war</type>
</dependency>
<!--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<!--Arduino DeviceType Impl, API and Agent-->
<!--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.arduino.plugin</artifactId>
@ -363,9 +369,7 @@
<type>war</type>
</dependency>
<!--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<!--RaspberryPi DeviceType Impl, API and Agent-->
<!--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.raspberrypi.plugin</artifactId>
@ -378,9 +382,7 @@
<type>war</type>
</dependency>
<!--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<!--VirtualFireAlarm DeviceType Impl, API and Agent-->
<!--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin</artifactId>
@ -399,27 +401,17 @@
<version>${carbon.devicemgt.plugins.version}</version>
<type>war</type>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl</artifactId>
<version>${carbon.devicemgt.plugins.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl</artifactId>
<version>${carbon.devicemgt.plugins.version}</version>
</dependency>
<!-- Camera Plugin -->
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.camera.plugin</artifactId>
<version>${carbon.devicemgt.plugins.version}</version>
</dependency>
<!--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<!--Carbon Analytics Dependency-->
<dependency>
<groupId>org.wso2.carbon.analytics</groupId>
@ -443,11 +435,6 @@
<artifactId>org.wso2.carbon.device.mgt.mobile.url.printer</artifactId>
<version>${carbon.devicemgt.plugins.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.mobile</artifactId>
<version>${carbon.devicemgt.plugins.version}</version>
</dependency>
<!--Android dependencies-->
<dependency>
@ -525,19 +512,6 @@
<artifactId>tomcat-servlet-api</artifactId>
<version>${orbit.version.tomcat-servlet-api}</version>
</dependency>
<!--APIM dependencies-->
<!-- <dependency>
<groupId>org.wso2.carbon.apimgt</groupId>
<artifactId>org.wso2.carbon.apimgt.core</artifactId>
<version>${carbon.api.mgt.version}</version>
<exclusions>
<exclusion>
<groupId>org.wso2.carbon.mediation</groupId>
<artifactId>org.wso2.carbon.mediation.initializer</artifactId>
</exclusion>
</exclusions>
</dependency>-->
<dependency>
<groupId>org.wso2.carbon.apimgt</groupId>
<artifactId>org.wso2.carbon.apimgt.api</artifactId>
@ -946,7 +920,11 @@
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple.wso2</groupId>
<artifactId>json-simple</artifactId>
<version>${json-simple.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity</groupId>
<artifactId>org.wso2.carbon.identity.oauth.stub</artifactId>
@ -959,7 +937,16 @@
<version>${carbon.identity.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.wso2</groupId>
<artifactId>httpcore</artifactId>
<version>${httpcore.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.orbit.org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
@ -970,19 +957,22 @@
<artifactId>commons-configuration</artifactId>
<version>${commons-configuration.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.carbon.commons</groupId>
<artifactId>org.wso2.carbon.user.mgt</artifactId>
<version>${carbon.commons.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>${json.path.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
@ -1096,11 +1086,16 @@
<commons-io.version>2.4</commons-io.version>
<commons-json.version>3.0.0.wso2v1</commons-json.version>
<json.path.version>0.9.1</json.path.version>
<json-simple.version>1.1.wso2v1</json-simple.version>
<commons-collections.version>3.2.2</commons-collections.version>
<commons-configuration.version>1.8</commons-configuration.version>
<orbit.version.tomcat-servlet-api>7.0.59.wso2v1</orbit.version.tomcat-servlet-api>
<!--http client version-->
<httpclient.version>4.3.1.wso2v2</httpclient.version>
<httpclient.version.range>[4.3.1, 5.0.0)</httpclient.version.range>
<httpcore.version>4.3.3.wso2v1</httpcore.version>
<!-- Release plugin ID for github-->
<project.scm.id>github-scm</project.scm.id>
</properties>

Loading…
Cancel
Save