50 changed files with 2587 additions and 0 deletions
@ -0,0 +1,38 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.dao.cache; |
|||
|
|||
import org.springframework.cache.interceptor.KeyGenerator; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.dao.device.DeviceCredentialsService; |
|||
|
|||
import java.lang.reflect.Method; |
|||
|
|||
public class PreviousDeviceCredentialsIdKeyGenerator implements KeyGenerator { |
|||
|
|||
@Override |
|||
public Object generate(Object o, Method method, Object... objects) { |
|||
DeviceCredentialsService deviceCredentialsService = (DeviceCredentialsService) o; |
|||
DeviceCredentials deviceCredentials = (DeviceCredentials) objects[0]; |
|||
if (deviceCredentials.getDeviceId() != null) { |
|||
DeviceCredentials oldDeviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(deviceCredentials.getDeviceId()); |
|||
if (oldDeviceCredentials != null) { |
|||
return oldDeviceCredentials.getCredentialsId(); |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.dao.cache; |
|||
|
|||
import com.hazelcast.config.Config; |
|||
import com.hazelcast.config.DiscoveryStrategyConfig; |
|||
import com.hazelcast.config.MapConfig; |
|||
import com.hazelcast.config.MaxSizeConfig; |
|||
import com.hazelcast.core.Hazelcast; |
|||
import com.hazelcast.core.HazelcastInstance; |
|||
import com.hazelcast.instance.GroupProperty; |
|||
import com.hazelcast.spring.cache.HazelcastCacheManager; |
|||
import com.hazelcast.zookeeper.ZookeeperDiscoveryProperties; |
|||
import com.hazelcast.zookeeper.ZookeeperDiscoveryStrategyFactory; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.cache.CacheManager; |
|||
import org.springframework.cache.annotation.EnableCaching; |
|||
import org.springframework.cache.interceptor.KeyGenerator; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.thingsboard.server.common.data.CacheConstants; |
|||
|
|||
@Configuration |
|||
@EnableCaching |
|||
@ConditionalOnProperty(prefix = "cache", value = "enabled", havingValue = "true") |
|||
public class ServiceCacheConfiguration { |
|||
|
|||
private static final String HAZELCAST_CLUSTER_NAME = "hazelcast"; |
|||
|
|||
@Value("${cache.device_credentials.max_size}") |
|||
private Integer deviceCredentialsCacheMaxSize; |
|||
@Value("${cache.device_credentials.time_to_live}") |
|||
private Integer deviceCredentialsCacheTTL; |
|||
|
|||
@Value("${zk.enabled}") |
|||
private boolean zkEnabled; |
|||
@Value("${zk.url}") |
|||
private String zkUrl; |
|||
@Value("${zk.zk_dir}") |
|||
private String zkDir; |
|||
|
|||
@Bean |
|||
public HazelcastInstance hazelcastInstance() { |
|||
Config config = new Config(); |
|||
|
|||
if (zkEnabled) { |
|||
config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false); |
|||
|
|||
config.setProperty(GroupProperty.DISCOVERY_SPI_ENABLED.getName(), Boolean.TRUE.toString()); |
|||
DiscoveryStrategyConfig discoveryStrategyConfig = new DiscoveryStrategyConfig(new ZookeeperDiscoveryStrategyFactory()); |
|||
discoveryStrategyConfig.addProperty(ZookeeperDiscoveryProperties.ZOOKEEPER_URL.key(), zkUrl); |
|||
discoveryStrategyConfig.addProperty(ZookeeperDiscoveryProperties.ZOOKEEPER_PATH.key(), zkDir); |
|||
discoveryStrategyConfig.addProperty(ZookeeperDiscoveryProperties.GROUP.key(), HAZELCAST_CLUSTER_NAME); |
|||
config.getNetworkConfig().getJoin().getDiscoveryConfig().addDiscoveryStrategyConfig(discoveryStrategyConfig); |
|||
} |
|||
|
|||
MapConfig deviceCredentialsCacheConfig = new MapConfig(CacheConstants.DEVICE_CREDENTIALS_CACHE); |
|||
deviceCredentialsCacheConfig.setTimeToLiveSeconds(deviceCredentialsCacheTTL); |
|||
deviceCredentialsCacheConfig.setMaxSizeConfig(new MaxSizeConfig(deviceCredentialsCacheMaxSize, MaxSizeConfig.MaxSizePolicy.PER_NODE)); |
|||
config.addMapConfig(deviceCredentialsCacheConfig); |
|||
|
|||
return Hazelcast.newHazelcastInstance(config); |
|||
} |
|||
|
|||
@Bean |
|||
public KeyGenerator previousDeviceCredentialsId() { |
|||
return new PreviousDeviceCredentialsIdKeyGenerator(); |
|||
} |
|||
|
|||
@Bean |
|||
public CacheManager cacheManager() { |
|||
return new HazelcastCacheManager(hazelcastInstance()); |
|||
} |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
#Db schema configuration |
|||
|
|||
SKIP_SCHEMA_CREATION=false |
|||
SKIP_SYSTEM_DATA=false |
|||
SKIP_DEMO_DATA=false |
|||
@ -0,0 +1,26 @@ |
|||
# |
|||
# Copyright © 2016 The Thingsboard Authors |
|||
# |
|||
# 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. |
|||
# |
|||
|
|||
FROM cassandra:3.9 |
|||
|
|||
ADD install_schema.sh /root/install_schema.sh |
|||
|
|||
RUN apt-get update \ |
|||
&& apt-get install -y nmap |
|||
|
|||
RUN chmod +x /root/install_schema.sh |
|||
|
|||
WORKDIR /root |
|||
@ -0,0 +1,53 @@ |
|||
#!/bin/bash |
|||
# |
|||
# Copyright © 2016 The Thingsboard Authors |
|||
# |
|||
# 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. |
|||
# |
|||
|
|||
|
|||
until nmap db -p 9042 | grep "9042/tcp open" |
|||
do |
|||
echo "Wait for Cassandra..." |
|||
sleep 10 |
|||
done |
|||
|
|||
if [ "$SKIP_SCHEMA_CREATION" == "false" ]; then |
|||
echo "Creating 'Thingsboard' keyspace..." |
|||
cqlsh db -f /root/schema.cql |
|||
if [ "$?" -eq 0 ]; then |
|||
echo "'Thingsboard' keyspace was successfully created!" |
|||
else |
|||
echo "There were issues while creating 'Thingsboard' keyspace!" |
|||
fi |
|||
fi |
|||
|
|||
if [ "$SKIP_SYSTEM_DATA" == "false" ]; then |
|||
echo "Adding system data..." |
|||
cqlsh db -f /root/system-data.cql |
|||
if [ "$?" -eq 0 ]; then |
|||
echo "System data was successfully added!" |
|||
else |
|||
echo "There were issues while adding System data!" |
|||
fi |
|||
fi |
|||
|
|||
if [ "$SKIP_DEMO_DATA" == "false" ]; then |
|||
echo "Adding demo data..." |
|||
cqlsh db -f /root/demo-data.cql |
|||
if [ "$?" -eq 0 ]; then |
|||
echo "Demo data was successfully added!" |
|||
else |
|||
echo "There were issues while adding Demo data!" |
|||
fi |
|||
fi |
|||
@ -0,0 +1,31 @@ |
|||
#!/bin/bash |
|||
# |
|||
# Copyright © 2016 The Thingsboard Authors |
|||
# |
|||
# 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. |
|||
# |
|||
|
|||
|
|||
command='docker-compose -f docker-compose.yml -f docker-compose.random.yml' |
|||
|
|||
echo "stopping images.." |
|||
$command stop |
|||
|
|||
echo "removing stopped images.." |
|||
$command rm -f |
|||
|
|||
echo "building images.." |
|||
$command build |
|||
|
|||
echo "starting images..." |
|||
$command up -d |
|||
@ -0,0 +1,31 @@ |
|||
#!/bin/bash |
|||
# |
|||
# Copyright © 2016 The Thingsboard Authors |
|||
# |
|||
# 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. |
|||
# |
|||
|
|||
|
|||
command='docker-compose -f docker-compose.yml -f docker-compose.static.yml' |
|||
|
|||
echo "stopping images.." |
|||
$command stop |
|||
|
|||
echo "removing stopped images.." |
|||
$command rm -f |
|||
|
|||
echo "building images.." |
|||
$command build |
|||
|
|||
echo "starting cassandra, zookeeper, db-schema images..." |
|||
$command up -d cassandra zookeeper db-schema |
|||
@ -0,0 +1,26 @@ |
|||
# |
|||
# Copyright © 2016 The Thingsboard Authors |
|||
# |
|||
# 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. |
|||
# |
|||
|
|||
version: '2' |
|||
|
|||
services: |
|||
cassandra: |
|||
ports: |
|||
- "9042" |
|||
- "9160" |
|||
zookeeper: |
|||
ports: |
|||
- "2181" |
|||
@ -0,0 +1,26 @@ |
|||
# |
|||
# Copyright © 2016 The Thingsboard Authors |
|||
# |
|||
# 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. |
|||
# |
|||
|
|||
version: '2' |
|||
|
|||
services: |
|||
cassandra: |
|||
ports: |
|||
- "9042:9042" |
|||
- "9160:9160" |
|||
zookeeper: |
|||
ports: |
|||
- "2181:2181" |
|||
@ -0,0 +1,52 @@ |
|||
# |
|||
# Copyright © 2016 The Thingsboard Authors |
|||
# |
|||
# 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. |
|||
# |
|||
|
|||
version: '2' |
|||
|
|||
services: |
|||
thingsboard: |
|||
build: thingsboard |
|||
ports: |
|||
- "8080:8080" |
|||
- "1883:1883" |
|||
- "5683:5683" |
|||
links: |
|||
- cassandra:db |
|||
- zookeeper:zk |
|||
- db-schema:db-schema |
|||
volumes: |
|||
- "../application/target/thingsboard.deb:/root/thingsboard.deb" |
|||
env_file: |
|||
- thingsboard.env |
|||
entrypoint: ./run_web_app.sh |
|||
db-schema: |
|||
build: db-schema |
|||
links: |
|||
- cassandra:db |
|||
env_file: |
|||
- db-schema.env |
|||
volumes: |
|||
- "../dao/src/main/resources/schema.cql:/root/schema.cql" |
|||
- "../dao/src/main/resources/demo-data.cql:/root/demo-data.cql" |
|||
- "../dao/src/main/resources/system-data.cql:/root/system-data.cql" |
|||
entrypoint: ./install_schema.sh |
|||
cassandra: |
|||
image: "cassandra:3.9" |
|||
volumes: |
|||
- "${CASSANDRA_DATA_DIR}:/var/lib/cassandra" |
|||
zookeeper: |
|||
image: "zookeeper:3.4.9" |
|||
restart: always |
|||
@ -0,0 +1,8 @@ |
|||
#Thingsboard server configuration |
|||
|
|||
CASSANDRA_URL=db:9042 |
|||
ZOOKEEPER_URL=zk:2181 |
|||
MQTT_BIND_ADDRESS=0.0.0.0 |
|||
MQTT_BIND_PORT=1883 |
|||
COAP_BIND_ADDRESS=0.0.0.0 |
|||
COAP_BIND_PORT=5683 |
|||
@ -0,0 +1,23 @@ |
|||
# |
|||
# Copyright © 2016 The Thingsboard Authors |
|||
# |
|||
# 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. |
|||
# |
|||
|
|||
FROM java:8-jre |
|||
|
|||
ADD run_web_app.sh /root/run_web_app.sh |
|||
|
|||
RUN chmod +x /root/run_web_app.sh |
|||
|
|||
WORKDIR /root |
|||
@ -0,0 +1,36 @@ |
|||
#!/bin/bash |
|||
# |
|||
# Copyright © 2016 The Thingsboard Authors |
|||
# |
|||
# 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. |
|||
# |
|||
|
|||
|
|||
dpkg -i /root/thingsboard.deb |
|||
|
|||
reachable=0 |
|||
while [ $reachable -eq 0 ]; |
|||
do |
|||
echo "db-schema container is still in progress. waiting until it completed..." |
|||
sleep 3 |
|||
ping -q -c 1 db-schema > /dev/null 2>&1 |
|||
if [ "$?" -ne 0 ]; |
|||
then |
|||
echo "db-schema container completed!" |
|||
reachable=1 |
|||
fi |
|||
done |
|||
|
|||
echo "Starting 'Thingsboard' service..." |
|||
thingsboard start |
|||
|
|||
@ -0,0 +1,97 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!-- |
|||
|
|||
Copyright © 2016 The Thingsboard Authors |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<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"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<parent> |
|||
<groupId>org.thingsboard.server</groupId> |
|||
<version>0.0.1-SNAPSHOT</version> |
|||
<artifactId>extensions</artifactId> |
|||
</parent> |
|||
<groupId>org.thingsboard.server.extensions</groupId> |
|||
<artifactId>extension-kafka</artifactId> |
|||
<packaging>jar</packaging> |
|||
|
|||
<name>Thingsboard Server Kafka Extension</name> |
|||
<url>http://thingsboard.org</url> |
|||
|
|||
<properties> |
|||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|||
<main.dir>${basedir}/../..</main.dir> |
|||
</properties> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>ch.qos.logback</groupId> |
|||
<artifactId>logback-core</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>ch.qos.logback</groupId> |
|||
<artifactId>logback-classic</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.thingsboard.server</groupId> |
|||
<artifactId>extensions-api</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.thingsboard.server</groupId> |
|||
<artifactId>extensions-core</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.velocity</groupId> |
|||
<artifactId>velocity</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.velocity</groupId> |
|||
<artifactId>velocity-tools</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.kafka</groupId> |
|||
<artifactId>kafka_2.10</artifactId> |
|||
</dependency> |
|||
</dependencies> |
|||
<build> |
|||
<plugins> |
|||
<plugin> |
|||
<artifactId>maven-assembly-plugin</artifactId> |
|||
<configuration> |
|||
<descriptors> |
|||
<descriptor>src/assembly/extension.xml</descriptor> |
|||
</descriptors> |
|||
</configuration> |
|||
<executions> |
|||
<execution> |
|||
<id>make-assembly</id> |
|||
<phase>package</phase> |
|||
<goals> |
|||
<goal>single</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
</project> |
|||
@ -0,0 +1,39 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016 The Thingsboard Authors |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd"> |
|||
<id>extension</id> |
|||
<formats> |
|||
<format>jar</format> |
|||
</formats> |
|||
<includeBaseDirectory>false</includeBaseDirectory> |
|||
<dependencySets> |
|||
<dependencySet> |
|||
<outputDirectory>/</outputDirectory> |
|||
<useProjectArtifact>true</useProjectArtifact> |
|||
<unpack>true</unpack> |
|||
<scope>runtime</scope> |
|||
<excludes> |
|||
<exclude>org.apache.zookeeper:zookeeper</exclude> |
|||
<exclude>org.scala-lang:scala-library</exclude> |
|||
<exclude>io.netty:netty</exclude> |
|||
</excludes> |
|||
</dependencySet> |
|||
</dependencySets> |
|||
</assembly> |
|||
@ -0,0 +1,28 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.kafka.action; |
|||
|
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.AbstractRuleToPluginMsg; |
|||
|
|||
public class KafkaActionMsg extends AbstractRuleToPluginMsg<KafkaActionPayload> { |
|||
|
|||
public KafkaActionMsg(TenantId tenantId, CustomerId customerId, DeviceId deviceId, KafkaActionPayload payload) { |
|||
super(tenantId, customerId, deviceId, payload); |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.kafka.action; |
|||
|
|||
import lombok.Builder; |
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.msg.session.MsgType; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
@Data |
|||
@Builder |
|||
public class KafkaActionPayload implements Serializable { |
|||
|
|||
private final String topic; |
|||
private final String msgBody; |
|||
private final boolean sync; |
|||
|
|||
private final Integer requestId; |
|||
private final MsgType msgType; |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.kafka.action; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; |
|||
import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; |
|||
import org.thingsboard.server.extensions.api.component.Action; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; |
|||
import org.thingsboard.server.extensions.api.rules.RuleContext; |
|||
import org.thingsboard.server.extensions.core.action.template.AbstractTemplatePluginAction; |
|||
|
|||
import java.util.Optional; |
|||
|
|||
@Action(name = "Kafka Plugin Action", descriptor = "KafkaActionDescriptor.json", configuration = KafkaPluginActionConfiguration.class) |
|||
@Slf4j |
|||
public class KafkaPluginAction extends AbstractTemplatePluginAction<KafkaPluginActionConfiguration> { |
|||
|
|||
@Override |
|||
protected Optional<RuleToPluginMsg<?>> buildRuleToPluginMsg(RuleContext ctx, ToDeviceActorMsg msg, FromDeviceRequestMsg payload) { |
|||
KafkaActionPayload.KafkaActionPayloadBuilder builder = KafkaActionPayload.builder(); |
|||
builder.msgType(payload.getMsgType()); |
|||
builder.requestId(payload.getRequestId()); |
|||
builder.sync(configuration.isSync()); |
|||
builder.topic(configuration.getTopic()); |
|||
builder.msgBody(getMsgBody(ctx, msg)); |
|||
return Optional.of(new KafkaActionMsg(msg.getTenantId(), |
|||
msg.getCustomerId(), |
|||
msg.getDeviceId(), |
|||
builder.build())); |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.kafka.action; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.extensions.core.action.template.TemplateActionConfiguration; |
|||
|
|||
@Data |
|||
public class KafkaPluginActionConfiguration implements TemplateActionConfiguration { |
|||
private boolean sync; |
|||
private String topic; |
|||
private String template; |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.kafka.plugin; |
|||
|
|||
import lombok.RequiredArgsConstructor; |
|||
import org.apache.kafka.clients.producer.Producer; |
|||
import org.apache.kafka.clients.producer.ProducerRecord; |
|||
import org.thingsboard.server.common.data.id.RuleId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse; |
|||
import org.thingsboard.server.extensions.api.plugins.PluginContext; |
|||
import org.thingsboard.server.extensions.api.plugins.handlers.RuleMsgHandler; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.ResponsePluginToRuleMsg; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; |
|||
import org.thingsboard.server.extensions.api.rules.RuleException; |
|||
import org.thingsboard.server.extensions.kafka.action.KafkaActionMsg; |
|||
import org.thingsboard.server.extensions.kafka.action.KafkaActionPayload; |
|||
|
|||
@RequiredArgsConstructor |
|||
public class KafkaMsgHandler implements RuleMsgHandler { |
|||
|
|||
private final Producer<?, String> producer; |
|||
|
|||
@Override |
|||
public void process(PluginContext ctx, TenantId tenantId, RuleId ruleId, RuleToPluginMsg<?> msg) throws RuleException { |
|||
if (!(msg instanceof KafkaActionMsg)) { |
|||
throw new RuleException("Unsupported message type " + msg.getClass().getName() + "!"); |
|||
} |
|||
KafkaActionPayload payload = ((KafkaActionMsg) msg).getPayload(); |
|||
|
|||
try { |
|||
producer.send(new ProducerRecord<>(payload.getTopic(), payload.getMsgBody()), |
|||
(metadata, e) -> { |
|||
if (payload.isSync()) { |
|||
if (metadata != null) { |
|||
ctx.reply(new ResponsePluginToRuleMsg(msg.getUid(), tenantId, ruleId, |
|||
BasicStatusCodeResponse.onSuccess(payload.getMsgType(), payload.getRequestId()))); |
|||
} else { |
|||
ctx.reply(new ResponsePluginToRuleMsg(msg.getUid(), tenantId, ruleId, |
|||
BasicStatusCodeResponse.onError(payload.getMsgType(), payload.getRequestId(), e))); |
|||
} |
|||
} |
|||
}); |
|||
} catch (Exception e) { |
|||
throw new RuleException(e.getMessage(), e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,93 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.kafka.plugin; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.kafka.clients.producer.KafkaProducer; |
|||
import org.apache.kafka.clients.producer.Producer; |
|||
import org.thingsboard.server.extensions.api.component.Plugin; |
|||
import org.thingsboard.server.extensions.api.plugins.AbstractPlugin; |
|||
import org.thingsboard.server.extensions.api.plugins.PluginContext; |
|||
import org.thingsboard.server.extensions.api.plugins.handlers.RuleMsgHandler; |
|||
import org.thingsboard.server.extensions.kafka.action.KafkaPluginAction; |
|||
|
|||
import java.util.Properties; |
|||
|
|||
@Plugin(name = "Kafka Plugin", actions = {KafkaPluginAction.class}, |
|||
descriptor = "KafkaPluginDescriptor.json", configuration = KafkaPluginConfiguration.class) |
|||
@Slf4j |
|||
public class KafkaPlugin extends AbstractPlugin<KafkaPluginConfiguration> { |
|||
|
|||
private KafkaMsgHandler handler; |
|||
private Producer<?, String> producer; |
|||
private final Properties properties = new Properties(); |
|||
|
|||
@Override |
|||
public void init(KafkaPluginConfiguration configuration) { |
|||
properties.put("bootstrap.servers", configuration.getBootstrapServers()); |
|||
properties.put("value.serializer", configuration.getValueSerializer()); |
|||
properties.put("key.serializer", configuration.getKeySerializer()); |
|||
properties.put("acks", String.valueOf(configuration.getAcks())); |
|||
properties.put("retries", configuration.getRetries()); |
|||
properties.put("batch.size", configuration.getBatchSize()); |
|||
properties.put("linger.ms", configuration.getLinger()); |
|||
properties.put("buffer.memory", configuration.getBufferMemory()); |
|||
if (configuration.getOtherProperties() != null) { |
|||
configuration.getOtherProperties() |
|||
.stream().forEach(p -> properties.put(p.getKey(), p.getValue())); |
|||
} |
|||
init(); |
|||
} |
|||
|
|||
private void init() { |
|||
try { |
|||
this.producer = new KafkaProducer<>(properties); |
|||
this.handler = new KafkaMsgHandler(producer); |
|||
} catch (Exception e) { |
|||
log.error("Failed to start kafka producer", e); |
|||
throw new RuntimeException(e); |
|||
} |
|||
} |
|||
|
|||
private void destroy() { |
|||
try { |
|||
this.handler = null; |
|||
this.producer.close(); |
|||
} catch (Exception e) { |
|||
log.error("Failed to close producer during destroy()", e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected RuleMsgHandler getRuleMsgHandler() { |
|||
return handler; |
|||
} |
|||
|
|||
@Override |
|||
public void resume(PluginContext ctx) { |
|||
init(); |
|||
} |
|||
|
|||
@Override |
|||
public void suspend(PluginContext ctx) { |
|||
destroy(); |
|||
} |
|||
|
|||
@Override |
|||
public void stop(PluginContext ctx) { |
|||
destroy(); |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.kafka.plugin; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.extensions.core.plugin.KeyValuePluginProperties; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Data |
|||
public class KafkaPluginConfiguration { |
|||
private String bootstrapServers; |
|||
private int retries; |
|||
private int batchSize; |
|||
private int linger; |
|||
private int bufferMemory; |
|||
private int acks; |
|||
private String keySerializer; |
|||
private String valueSerializer; |
|||
private List<KeyValuePluginProperties> otherProperties; |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
{ |
|||
"schema": { |
|||
"title": "Kafka Action Configuration", |
|||
"type": "object", |
|||
"properties": { |
|||
"sync": { |
|||
"title": "Requires delivery confirmation", |
|||
"type": "boolean" |
|||
}, |
|||
"topic": { |
|||
"title": "Topic Name", |
|||
"type": "string" |
|||
}, |
|||
"template": { |
|||
"title": "Body Template", |
|||
"type": "string" |
|||
} |
|||
}, |
|||
"required": [ |
|||
"sync", |
|||
"topic", |
|||
"template" |
|||
] |
|||
}, |
|||
"form": [ |
|||
"sync", |
|||
"topic", |
|||
{ |
|||
"key": "template", |
|||
"type": "textarea", |
|||
"rows": 5 |
|||
} |
|||
] |
|||
} |
|||
@ -0,0 +1,80 @@ |
|||
{ |
|||
"schema": { |
|||
"title": "Kafka Plugin Configuration", |
|||
"type": "object", |
|||
"properties": { |
|||
"bootstrapServers": { |
|||
"title": "Bootstrap Servers", |
|||
"type": "string", |
|||
"default": "localhost:9092" |
|||
}, |
|||
"retries": { |
|||
"title": "Automatically Retry Times If Fails", |
|||
"type": "integer", |
|||
"default": 0 |
|||
}, |
|||
"batchSize": { |
|||
"title": "Producer Batch Size On Client", |
|||
"type": "integer", |
|||
"default": 16384 |
|||
}, |
|||
"linger": { |
|||
"title": "Time To Buffer Locally Before Sending To Kafka Broker (in ms)", |
|||
"type": "integer", |
|||
"default": 0 |
|||
}, |
|||
"bufferMemory": { |
|||
"title": "Buffer Max Size On Client", |
|||
"type": "integer", |
|||
"default": 33554432 |
|||
}, |
|||
"acks": { |
|||
"title": "Minimum Number Of Replicas That Must Acknowledge A Write (-1 for 'all')", |
|||
"type": "integer", |
|||
"default": -1 |
|||
}, |
|||
"keySerializer": { |
|||
"title": "Key Serializer", |
|||
"type": "string", |
|||
"default": "org.apache.kafka.common.serialization.StringSerializer" |
|||
}, |
|||
"valueSerializer": { |
|||
"title": "Value Serializer", |
|||
"type": "string", |
|||
"default": "org.apache.kafka.common.serialization.StringSerializer" |
|||
}, |
|||
"otherProperties": { |
|||
"title": "Other Kafka properties", |
|||
"type": "array", |
|||
"items": { |
|||
"title": "Kafka property", |
|||
"type": "object", |
|||
"properties": { |
|||
"key": { |
|||
"title": "Key", |
|||
"type": "string" |
|||
}, |
|||
"value": { |
|||
"title": "Value", |
|||
"type": "string" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"required": [ |
|||
"bootstrapServers" |
|||
] |
|||
}, |
|||
"form": [ |
|||
"bootstrapServers", |
|||
"retries", |
|||
"batchSize", |
|||
"linger", |
|||
"bufferMemory", |
|||
"acks", |
|||
"keySerializer", |
|||
"valueSerializer", |
|||
"otherProperties" |
|||
] |
|||
} |
|||
@ -0,0 +1,83 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.kafka; |
|||
|
|||
import kafka.server.KafkaConfig; |
|||
import kafka.server.KafkaServerStartable; |
|||
import org.apache.zookeeper.server.ServerConfig; |
|||
import org.apache.zookeeper.server.ZooKeeperServerMain; |
|||
import org.apache.zookeeper.server.quorum.QuorumPeerConfig; |
|||
|
|||
import java.io.File; |
|||
import java.io.IOException; |
|||
import java.util.Properties; |
|||
|
|||
public class KafkaDemoClient { |
|||
|
|||
private static final int ZK_PORT = 2222; |
|||
private static final String HOSTNAME = "localhost"; |
|||
private static final String ZOOKEEPER_CONNECT = HOSTNAME + ":" + ZK_PORT; |
|||
private static final int KAFKA_PORT = 9092; |
|||
private static final int BROKER_ID = 1; |
|||
|
|||
public static void main(String[] args) { |
|||
try { |
|||
startZkLocal(); |
|||
startKafkaLocal(); |
|||
} catch (Exception e) { |
|||
System.out.println("Error running local Kafka broker"); |
|||
e.printStackTrace(System.out); |
|||
} |
|||
} |
|||
|
|||
private static void startZkLocal() throws Exception { |
|||
final File zkTmpDir = File.createTempFile("zookeeper", "test"); |
|||
if (zkTmpDir.delete() && zkTmpDir.mkdir()) { |
|||
Properties zkProperties = new Properties(); |
|||
zkProperties.setProperty("dataDir", zkTmpDir.getAbsolutePath()); |
|||
zkProperties.setProperty("clientPort", String.valueOf(ZK_PORT)); |
|||
|
|||
ServerConfig configuration = new ServerConfig(); |
|||
QuorumPeerConfig quorumConfiguration = new QuorumPeerConfig(); |
|||
quorumConfiguration.parseProperties(zkProperties); |
|||
configuration.readFrom(quorumConfiguration); |
|||
|
|||
new Thread() { |
|||
public void run() { |
|||
try { |
|||
new ZooKeeperServerMain().runFromConfig(configuration); |
|||
} catch (IOException e) { |
|||
System.out.println("Start of Local ZooKeeper Failed"); |
|||
e.printStackTrace(System.err); |
|||
} |
|||
} |
|||
}.start(); |
|||
} else { |
|||
System.out.println("Failed to delete or create data dir for Zookeeper"); |
|||
} |
|||
} |
|||
|
|||
private static void startKafkaLocal() { |
|||
Properties kafkaProperties = new Properties(); |
|||
kafkaProperties.setProperty("host.name", HOSTNAME); |
|||
kafkaProperties.setProperty("port", String.valueOf(KAFKA_PORT)); |
|||
kafkaProperties.setProperty("broker.id", String.valueOf(BROKER_ID)); |
|||
kafkaProperties.setProperty("zookeeper.connect", ZOOKEEPER_CONNECT); |
|||
KafkaConfig kafkaConfig = new KafkaConfig(kafkaProperties); |
|||
KafkaServerStartable kafka = new KafkaServerStartable(kafkaConfig); |
|||
kafka.startup(); |
|||
} |
|||
} |
|||
@ -0,0 +1,139 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016 The Thingsboard Authors |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<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"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<parent> |
|||
<groupId>org.thingsboard.server</groupId> |
|||
<version>0.0.1-SNAPSHOT</version> |
|||
<artifactId>extensions</artifactId> |
|||
</parent> |
|||
<groupId>org.thingsboard.server.extensions</groupId> |
|||
<artifactId>extension-rabbitmq</artifactId> |
|||
<packaging>jar</packaging> |
|||
|
|||
<name>Thingsboard Server RabbitMQ Extension</name> |
|||
<url>http://thingsboard.org</url> |
|||
|
|||
<properties> |
|||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|||
<main.dir>${basedir}/../..</main.dir> |
|||
</properties> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>com.rabbitmq</groupId> |
|||
<artifactId>amqp-client</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.thingsboard.server</groupId> |
|||
<artifactId>extensions-api</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.thingsboard.server</groupId> |
|||
<artifactId>extensions-core</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.velocity</groupId> |
|||
<artifactId>velocity</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.velocity</groupId> |
|||
<artifactId>velocity-tools</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-web</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework</groupId> |
|||
<artifactId>spring-context-support</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.slf4j</groupId> |
|||
<artifactId>slf4j-api</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.slf4j</groupId> |
|||
<artifactId>log4j-over-slf4j</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>ch.qos.logback</groupId> |
|||
<artifactId>logback-core</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>ch.qos.logback</groupId> |
|||
<artifactId>logback-classic</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>junit</groupId> |
|||
<artifactId>junit</artifactId> |
|||
<scope>test</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.mockito</groupId> |
|||
<artifactId>mockito-all</artifactId> |
|||
<scope>test</scope> |
|||
</dependency> |
|||
</dependencies> |
|||
|
|||
<build> |
|||
<plugins> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-dependency-plugin</artifactId> |
|||
</plugin> |
|||
<plugin> |
|||
<groupId>org.xolstice.maven.plugins</groupId> |
|||
<artifactId>protobuf-maven-plugin</artifactId> |
|||
</plugin> |
|||
<plugin> |
|||
<groupId>org.codehaus.mojo</groupId> |
|||
<artifactId>build-helper-maven-plugin</artifactId> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-assembly-plugin</artifactId> |
|||
<configuration> |
|||
<descriptors> |
|||
<descriptor>src/assembly/extension.xml</descriptor> |
|||
</descriptors> |
|||
</configuration> |
|||
<executions> |
|||
<execution> |
|||
<id>make-assembly</id> |
|||
<phase>package</phase> |
|||
<goals> |
|||
<goal>single</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
|
|||
</project> |
|||
@ -0,0 +1,34 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016 The Thingsboard Authors |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd"> |
|||
<id>extension</id> |
|||
<formats> |
|||
<format>jar</format> |
|||
</formats> |
|||
<includeBaseDirectory>false</includeBaseDirectory> |
|||
<dependencySets> |
|||
<dependencySet> |
|||
<outputDirectory>/</outputDirectory> |
|||
<useProjectArtifact>true</useProjectArtifact> |
|||
<unpack>true</unpack> |
|||
<scope>runtime</scope> |
|||
</dependencySet> |
|||
</dependencySets> |
|||
</assembly> |
|||
@ -0,0 +1,31 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rabbitmq.action; |
|||
|
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.AbstractRuleToPluginMsg; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
public class RabbitMqActionMsg extends AbstractRuleToPluginMsg<RabbitMqActionPayload> { |
|||
|
|||
public RabbitMqActionMsg(TenantId tenantId, CustomerId customerId, DeviceId deviceId, RabbitMqActionPayload payload) { |
|||
super(tenantId, customerId, deviceId, payload); |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rabbitmq.action; |
|||
|
|||
import lombok.Builder; |
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.msg.session.MsgType; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
@Data |
|||
@Builder |
|||
public class RabbitMqActionPayload implements Serializable { |
|||
|
|||
private final String exchange; |
|||
private final String queueName; |
|||
private final String messageProperties; |
|||
private final String payload; |
|||
|
|||
private final boolean sync; |
|||
private final Integer requestId; |
|||
private final MsgType msgType; |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rabbitmq.action; |
|||
|
|||
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; |
|||
import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; |
|||
import org.thingsboard.server.extensions.api.component.Action; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; |
|||
import org.thingsboard.server.extensions.api.rules.RuleContext; |
|||
import org.thingsboard.server.extensions.core.action.template.AbstractTemplatePluginAction; |
|||
|
|||
import java.util.Optional; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
@Action(name = "RabbitMQ Plugin Action", |
|||
descriptor = "RabbitMqActionDescriptor.json", configuration = RabbitMqPluginActionConfiguration.class) |
|||
public class RabbitMqPluginAction extends AbstractTemplatePluginAction<RabbitMqPluginActionConfiguration> { |
|||
|
|||
@Override |
|||
protected Optional<RuleToPluginMsg<?>> buildRuleToPluginMsg(RuleContext ctx, ToDeviceActorMsg msg, FromDeviceRequestMsg payload) { |
|||
RabbitMqActionPayload.RabbitMqActionPayloadBuilder builder = RabbitMqActionPayload.builder(); |
|||
builder.sync(configuration.isSync()); |
|||
builder.exchange(configuration.getExchange()); |
|||
builder.queueName(configuration.getQueueName()); |
|||
builder.messageProperties(configuration.getMessageProperties()[0]); |
|||
builder.msgType(payload.getMsgType()); |
|||
builder.requestId(payload.getRequestId()); |
|||
builder.payload(getMsgBody(ctx, msg)); |
|||
return Optional.of(new RabbitMqActionMsg(msg.getTenantId(), |
|||
msg.getCustomerId(), |
|||
msg.getDeviceId(), |
|||
builder.build())); |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rabbitmq.action; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.extensions.core.action.template.TemplateActionConfiguration; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
@Data |
|||
public class RabbitMqPluginActionConfiguration implements TemplateActionConfiguration{ |
|||
|
|||
private boolean sync; |
|||
private String exchange; |
|||
private String queueName; |
|||
private String[] messageProperties; |
|||
private String template; |
|||
} |
|||
@ -0,0 +1,86 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rabbitmq.plugin; |
|||
|
|||
import com.rabbitmq.client.AMQP; |
|||
import com.rabbitmq.client.Channel; |
|||
import com.rabbitmq.client.MessageProperties; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.thingsboard.server.common.data.id.RuleId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse; |
|||
import org.thingsboard.server.extensions.api.plugins.PluginContext; |
|||
import org.thingsboard.server.extensions.api.plugins.handlers.RuleMsgHandler; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.ResponsePluginToRuleMsg; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; |
|||
import org.thingsboard.server.extensions.api.rules.RuleException; |
|||
import org.thingsboard.server.extensions.rabbitmq.action.RabbitMqActionMsg; |
|||
import org.thingsboard.server.extensions.rabbitmq.action.RabbitMqActionPayload; |
|||
|
|||
import java.io.IOException; |
|||
import java.nio.charset.Charset; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
@RequiredArgsConstructor |
|||
public class RabbitMqMsgHandler implements RuleMsgHandler { |
|||
private static final Charset UTF8 = Charset.forName("UTF-8"); |
|||
|
|||
private final Channel channel; |
|||
|
|||
@Override |
|||
public void process(PluginContext ctx, TenantId tenantId, RuleId ruleId, RuleToPluginMsg<?> msg) throws RuleException { |
|||
if (!(msg instanceof RabbitMqActionMsg)) { |
|||
throw new RuleException("Unsupported message type " + msg.getClass().getName() + "!"); |
|||
} |
|||
RabbitMqActionPayload payload = ((RabbitMqActionMsg) msg).getPayload(); |
|||
AMQP.BasicProperties properties = convert(payload.getMessageProperties()); |
|||
try { |
|||
channel.basicPublish( |
|||
payload.getExchange() != null ? payload.getExchange() : "", |
|||
payload.getQueueName(), |
|||
properties, |
|||
payload.getPayload().getBytes(UTF8)); |
|||
if (payload.isSync()) { |
|||
ctx.reply(new ResponsePluginToRuleMsg(msg.getUid(), tenantId, ruleId, |
|||
BasicStatusCodeResponse.onSuccess(payload.getMsgType(), payload.getRequestId()))); |
|||
} |
|||
} catch (IOException e) { |
|||
throw new RuleException(e.getMessage(), e); |
|||
} |
|||
} |
|||
|
|||
private static AMQP.BasicProperties convert(String name) throws RuleException { |
|||
switch (name) { |
|||
case "BASIC": |
|||
return MessageProperties.BASIC; |
|||
case "TEXT_PLAIN": |
|||
return MessageProperties.TEXT_PLAIN; |
|||
case "MINIMAL_BASIC": |
|||
return MessageProperties.MINIMAL_BASIC; |
|||
case "MINIMAL_PERSISTENT_BASIC": |
|||
return MessageProperties.MINIMAL_PERSISTENT_BASIC; |
|||
case "PERSISTENT_BASIC": |
|||
return MessageProperties.PERSISTENT_BASIC; |
|||
case "PERSISTENT_TEXT_PLAIN": |
|||
return MessageProperties.PERSISTENT_TEXT_PLAIN; |
|||
default: |
|||
throw new RuleException("Message Properties: '" + name + "' is undefined!"); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,109 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rabbitmq.plugin; |
|||
|
|||
import com.rabbitmq.client.Connection; |
|||
import com.rabbitmq.client.ConnectionFactory; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang.StringUtils; |
|||
import org.thingsboard.server.extensions.api.component.Plugin; |
|||
import org.thingsboard.server.extensions.api.plugins.AbstractPlugin; |
|||
import org.thingsboard.server.extensions.api.plugins.PluginContext; |
|||
import org.thingsboard.server.extensions.api.plugins.handlers.RuleMsgHandler; |
|||
import org.thingsboard.server.extensions.rabbitmq.action.RabbitMqPluginAction; |
|||
|
|||
import java.io.IOException; |
|||
import java.util.concurrent.TimeoutException; |
|||
import java.util.function.Consumer; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
@Plugin(name = "RabbitMQ Plugin", actions = {RabbitMqPluginAction.class}, |
|||
descriptor = "RabbitMqPluginDescriptor.json", configuration = RabbitMqPluginConfiguration.class) |
|||
@Slf4j |
|||
public class RabbitMqPlugin extends AbstractPlugin<RabbitMqPluginConfiguration> { |
|||
|
|||
private ConnectionFactory factory; |
|||
private Connection connection; |
|||
private RabbitMqMsgHandler handler; |
|||
|
|||
@Override |
|||
public void init(RabbitMqPluginConfiguration configuration) { |
|||
factory = new ConnectionFactory(); |
|||
factory.setHost(configuration.getHost()); |
|||
factory.setPort(configuration.getPort()); |
|||
set(configuration.getVirtualHost(), factory::setVirtualHost); |
|||
set(configuration.getUserName(), factory::setUsername); |
|||
set(configuration.getPassword(), factory::setPassword); |
|||
set(configuration.getAutomaticRecoveryEnabled(), factory::setAutomaticRecoveryEnabled); |
|||
set(configuration.getConnectionTimeout(), factory::setConnectionTimeout); |
|||
set(configuration.getHandshakeTimeout(), factory::setHandshakeTimeout); |
|||
set(configuration.getClientProperties(), props -> { |
|||
factory.setClientProperties(props.stream().collect(Collectors.toMap( |
|||
RabbitMqPluginConfiguration.RabbitMqPluginProperties::getKey, |
|||
RabbitMqPluginConfiguration.RabbitMqPluginProperties::getValue))); |
|||
}); |
|||
|
|||
init(); |
|||
} |
|||
|
|||
private <T> void set(T source, Consumer<T> setter) { |
|||
if (source != null && !StringUtils.isEmpty(source.toString())) { |
|||
setter.accept(source); |
|||
} |
|||
} |
|||
|
|||
private void init() { |
|||
try { |
|||
this.connection = factory.newConnection(); |
|||
this.handler = new RabbitMqMsgHandler(connection.createChannel()); |
|||
} catch (IOException | TimeoutException e) { |
|||
throw new RuntimeException(e); |
|||
} |
|||
} |
|||
|
|||
private void destroy() { |
|||
try { |
|||
this.handler = null; |
|||
this.connection.close(); |
|||
} catch (Exception e) { |
|||
log.info("Failed to close connection during destroy()", e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected RuleMsgHandler getRuleMsgHandler() { |
|||
return handler; |
|||
} |
|||
|
|||
@Override |
|||
public void resume(PluginContext ctx) { |
|||
init(); |
|||
} |
|||
|
|||
@Override |
|||
public void suspend(PluginContext ctx) { |
|||
destroy(); |
|||
} |
|||
|
|||
@Override |
|||
public void stop(PluginContext ctx) { |
|||
destroy(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rabbitmq.plugin; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
@Data |
|||
public class RabbitMqPluginConfiguration { |
|||
private String host; |
|||
private int port; |
|||
private String virtualHost; |
|||
|
|||
private String userName; |
|||
private String password; |
|||
|
|||
private Boolean automaticRecoveryEnabled; |
|||
|
|||
private Integer connectionTimeout; |
|||
private Integer handshakeTimeout; |
|||
|
|||
private List<RabbitMqPluginProperties> clientProperties; |
|||
|
|||
@Data |
|||
public static class RabbitMqPluginProperties { |
|||
private String key; |
|||
private String value; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
{ |
|||
"schema": { |
|||
"title": "RabbitMQ Action Configuration", |
|||
"type": "object", |
|||
"properties": { |
|||
"sync": { |
|||
"title": "Requires delivery confirmation", |
|||
"type": "boolean" |
|||
}, |
|||
"exchange": { |
|||
"title": "Exchange", |
|||
"type": "string", |
|||
"default": "" |
|||
}, |
|||
"queueName": { |
|||
"title": "Queue Name", |
|||
"type": "string" |
|||
}, |
|||
"messageProperties": { |
|||
"title": "Message properties", |
|||
"type": "array", |
|||
"minItems" : 1, |
|||
"items": [ |
|||
{ |
|||
"value": "BASIC", |
|||
"label": "BASIC" |
|||
}, |
|||
{ |
|||
"value": "MINIMAL_BASIC", |
|||
"label": "MINIMAL_BASIC" |
|||
}, |
|||
{ |
|||
"value": "MINIMAL_PERSISTENT_BASIC", |
|||
"label": "MINIMAL_PERSISTENT_BASIC" |
|||
}, |
|||
{ |
|||
"value": "PERSISTENT_BASIC", |
|||
"label": "PERSISTENT_BASIC" |
|||
}, |
|||
{ |
|||
"value": "PERSISTENT_TEXT_PLAIN", |
|||
"label": "PERSISTENT_TEXT_PLAIN" |
|||
}, |
|||
{ |
|||
"value": "TEXT_PLAIN", |
|||
"label": "TEXT_PLAIN" |
|||
} |
|||
], |
|||
"uniqueItems": true |
|||
}, |
|||
"template": { |
|||
"title": "Body Template", |
|||
"type": "string" |
|||
} |
|||
}, |
|||
"required": [ |
|||
"sync", |
|||
"queueName", |
|||
"messageProperties", |
|||
"template" |
|||
] |
|||
}, |
|||
"form": [ |
|||
"sync", |
|||
"exchange", |
|||
"queueName", |
|||
{ |
|||
"key": "messageProperties", |
|||
"type": "rc-select", |
|||
"multiple": false |
|||
}, |
|||
{ |
|||
"key": "template", |
|||
"type": "textarea", |
|||
"rows": 5 |
|||
} |
|||
] |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
{ |
|||
"schema": { |
|||
"title": "RabbitMQ Plugin Configuration", |
|||
"type": "object", |
|||
"properties": { |
|||
"host": { |
|||
"title": "Host", |
|||
"type": "string" |
|||
}, |
|||
"port": { |
|||
"title": "Port", |
|||
"type": "integer", |
|||
"default": 5672, |
|||
"minimum": 0, |
|||
"maximum": 65536 |
|||
}, |
|||
"virtualHost": { |
|||
"title": "Virtual Host", |
|||
"type": "string" |
|||
}, |
|||
"userName": { |
|||
"title": "Username", |
|||
"type": "string" |
|||
}, |
|||
"password": { |
|||
"title": "Password", |
|||
"type": "string" |
|||
}, |
|||
"automaticRecoveryEnabled": { |
|||
"title": "Automatic Recovery Enabled", |
|||
"type": "boolean" |
|||
}, |
|||
"connectionTimeout": { |
|||
"title": "Connection Timeout", |
|||
"type": "integer" |
|||
}, |
|||
"handshakeTimeout": { |
|||
"title": "Handshake Timeout", |
|||
"type": "integer" |
|||
}, |
|||
"clientProperties": { |
|||
"title": "Client properties", |
|||
"type": "array", |
|||
"items": { |
|||
"title": "Client property", |
|||
"type": "object", |
|||
"properties": { |
|||
"key": { |
|||
"title": "Key", |
|||
"type": "string" |
|||
}, |
|||
"value": { |
|||
"title": "Value", |
|||
"type": "string" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"required": [ |
|||
"host", |
|||
"port" |
|||
] |
|||
}, |
|||
"form": [ |
|||
"host", |
|||
"port", |
|||
"virtualHost", |
|||
"userName", |
|||
{ |
|||
"key": "password", |
|||
"type": "password" |
|||
}, |
|||
"automaticRecoveryEnabled", |
|||
"connectionTimeout", |
|||
"handshakeTimeout", |
|||
"clientProperties" |
|||
] |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rabbitmq; |
|||
|
|||
import com.rabbitmq.client.*; |
|||
|
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
public class DemoClient { |
|||
|
|||
private static final String HOST = "localhost"; |
|||
private static final String USERNAME = "guest"; |
|||
private static final String PASSWORD = "guest"; |
|||
private static final String QUEUE_NAME = "queue"; |
|||
|
|||
|
|||
public static void main(String[] argv) throws Exception { |
|||
|
|||
ConnectionFactory factory = new ConnectionFactory(); |
|||
factory.setHost(HOST); |
|||
factory.setUsername(USERNAME); |
|||
factory.setPassword(PASSWORD); |
|||
|
|||
Connection connection = factory.newConnection(); |
|||
Channel channel = connection.createChannel(); |
|||
|
|||
channel.queueDeclare(QUEUE_NAME, false, false, false, null); |
|||
System.out.println(" [*] Waiting for messages."); |
|||
Consumer consumer = new DefaultConsumer(channel) { |
|||
@Override |
|||
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) |
|||
throws IOException { |
|||
String message = new String(body, "UTF-8"); |
|||
System.out.println(" [x] Received '" + message + "'"); |
|||
} |
|||
}; |
|||
channel.basicConsume(QUEUE_NAME, true, consumer); |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,98 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!-- |
|||
|
|||
Copyright © 2016 The Thingsboard Authors |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<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"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<parent> |
|||
<groupId>org.thingsboard.server</groupId> |
|||
<version>0.0.1-SNAPSHOT</version> |
|||
<artifactId>extensions</artifactId> |
|||
</parent> |
|||
<groupId>org.thingsboard.server.extensions</groupId> |
|||
<artifactId>extension-rest-api-call</artifactId> |
|||
<packaging>jar</packaging> |
|||
|
|||
<name>Thingsboard Server REST API Call Extension</name> |
|||
<url>http://thingsboard.org</url> |
|||
|
|||
<properties> |
|||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|||
<main.dir>${basedir}/../..</main.dir> |
|||
</properties> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>ch.qos.logback</groupId> |
|||
<artifactId>logback-core</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>ch.qos.logback</groupId> |
|||
<artifactId>logback-classic</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.thingsboard.server</groupId> |
|||
<artifactId>extensions-api</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework</groupId> |
|||
<artifactId>spring-web</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.thingsboard.server</groupId> |
|||
<artifactId>extensions-core</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.velocity</groupId> |
|||
<artifactId>velocity</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.velocity</groupId> |
|||
<artifactId>velocity-tools</artifactId> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
</dependencies> |
|||
<build> |
|||
<plugins> |
|||
<plugin> |
|||
<artifactId>maven-assembly-plugin</artifactId> |
|||
<configuration> |
|||
<descriptors> |
|||
<descriptor>src/assembly/extension.xml</descriptor> |
|||
</descriptors> |
|||
</configuration> |
|||
<executions> |
|||
<execution> |
|||
<id>make-assembly</id> |
|||
<phase>package</phase> |
|||
<goals> |
|||
<goal>single</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
</project> |
|||
@ -0,0 +1,34 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016 The Thingsboard Authors |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd"> |
|||
<id>extension</id> |
|||
<formats> |
|||
<format>jar</format> |
|||
</formats> |
|||
<includeBaseDirectory>false</includeBaseDirectory> |
|||
<dependencySets> |
|||
<dependencySet> |
|||
<outputDirectory>/</outputDirectory> |
|||
<useProjectArtifact>true</useProjectArtifact> |
|||
<unpack>true</unpack> |
|||
<scope>runtime</scope> |
|||
</dependencySet> |
|||
</dependencySets> |
|||
</assembly> |
|||
@ -0,0 +1,28 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rest.action; |
|||
|
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.AbstractRuleToPluginMsg; |
|||
|
|||
public class RestApiCallActionMsg extends AbstractRuleToPluginMsg<RestApiCallActionPayload> { |
|||
|
|||
public RestApiCallActionMsg(TenantId tenantId, CustomerId customerId, DeviceId deviceId, RestApiCallActionPayload payload) { |
|||
super(tenantId, customerId, deviceId, payload); |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rest.action; |
|||
|
|||
import lombok.Builder; |
|||
import lombok.Data; |
|||
import org.springframework.http.HttpMethod; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.thingsboard.server.common.msg.session.MsgType; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
@Data |
|||
@Builder |
|||
public class RestApiCallActionPayload implements Serializable { |
|||
private final String actionPath; |
|||
private final String msgBody; |
|||
private final HttpMethod httpMethod; |
|||
private final HttpStatus expectedResultCode; |
|||
private final boolean sync; |
|||
|
|||
private final Integer requestId; |
|||
private final MsgType msgType; |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rest.action; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.velocity.Template; |
|||
import org.apache.velocity.VelocityContext; |
|||
import org.apache.velocity.runtime.parser.ParseException; |
|||
import org.springframework.http.HttpMethod; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; |
|||
import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; |
|||
import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
|||
import org.thingsboard.server.extensions.api.component.Action; |
|||
import org.thingsboard.server.extensions.api.plugins.PluginAction; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.PluginToRuleMsg; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.ResponsePluginToRuleMsg; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; |
|||
import org.thingsboard.server.extensions.api.rules.RuleContext; |
|||
import org.thingsboard.server.extensions.api.rules.RuleProcessingMetaData; |
|||
import org.thingsboard.server.extensions.core.action.template.AbstractTemplatePluginAction; |
|||
import org.thingsboard.server.extensions.core.utils.VelocityUtils; |
|||
|
|||
import java.util.Optional; |
|||
|
|||
@Action(name = "REST API Call Plugin Action", |
|||
descriptor = "RestApiCallActionDescriptor.json", configuration = RestApiCallPluginActionConfiguration.class) |
|||
@Slf4j |
|||
public class RestApiCallPluginAction extends AbstractTemplatePluginAction<RestApiCallPluginActionConfiguration> { |
|||
|
|||
@Override |
|||
protected Optional<RuleToPluginMsg<?>> buildRuleToPluginMsg(RuleContext ctx, ToDeviceActorMsg msg, FromDeviceRequestMsg payload) { |
|||
RestApiCallActionPayload.RestApiCallActionPayloadBuilder builder = RestApiCallActionPayload.builder(); |
|||
builder.msgType(payload.getMsgType()); |
|||
builder.requestId(payload.getRequestId()); |
|||
builder.sync(configuration.isSync()); |
|||
builder.actionPath(configuration.getActionPath()); |
|||
builder.httpMethod(HttpMethod.valueOf(configuration.getRequestMethod()[0])); |
|||
builder.expectedResultCode(HttpStatus.valueOf(configuration.getExpectedResultCode())); |
|||
builder.msgBody(getMsgBody(ctx, msg)); |
|||
return Optional.of(new RestApiCallActionMsg(msg.getTenantId(), |
|||
msg.getCustomerId(), |
|||
msg.getDeviceId(), |
|||
builder.build())); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rest.action; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.extensions.core.action.template.TemplateActionConfiguration; |
|||
|
|||
@Data |
|||
public class RestApiCallPluginActionConfiguration implements TemplateActionConfiguration { |
|||
private boolean sync; |
|||
private String template; |
|||
private String actionPath; |
|||
private int expectedResultCode; |
|||
private String[] requestMethod; |
|||
} |
|||
@ -0,0 +1,67 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rest.plugin; |
|||
|
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.http.HttpEntity; |
|||
import org.springframework.http.HttpHeaders; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.web.client.RestClientException; |
|||
import org.springframework.web.client.RestTemplate; |
|||
import org.thingsboard.server.common.data.id.RuleId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse; |
|||
import org.thingsboard.server.extensions.api.plugins.PluginContext; |
|||
import org.thingsboard.server.extensions.api.plugins.handlers.RuleMsgHandler; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.ResponsePluginToRuleMsg; |
|||
import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; |
|||
import org.thingsboard.server.extensions.api.rules.RuleException; |
|||
import org.thingsboard.server.extensions.rest.action.RestApiCallActionMsg; |
|||
import org.thingsboard.server.extensions.rest.action.RestApiCallActionPayload; |
|||
|
|||
@RequiredArgsConstructor |
|||
public class RestApiCallMsgHandler implements RuleMsgHandler { |
|||
|
|||
private final String baseUrl; |
|||
private final HttpHeaders headers; |
|||
|
|||
@Override |
|||
public void process(PluginContext ctx, TenantId tenantId, RuleId ruleId, RuleToPluginMsg<?> msg) throws RuleException { |
|||
if (!(msg instanceof RestApiCallActionMsg)) { |
|||
throw new RuleException("Unsupported message type " + msg.getClass().getName() + "!"); |
|||
} |
|||
RestApiCallActionPayload payload = ((RestApiCallActionMsg)msg).getPayload(); |
|||
try { |
|||
ResponseEntity<String> exchangeResponse = new RestTemplate().exchange( |
|||
baseUrl + payload.getActionPath(), |
|||
payload.getHttpMethod(), |
|||
new HttpEntity<>(payload.getMsgBody(), headers), |
|||
String.class); |
|||
if (exchangeResponse.getStatusCode().equals(payload.getExpectedResultCode()) && payload.isSync()) { |
|||
ctx.reply(new ResponsePluginToRuleMsg(msg.getUid(), tenantId, ruleId, |
|||
BasicStatusCodeResponse.onSuccess(payload.getMsgType(), payload.getRequestId()))); |
|||
} else if(!exchangeResponse.getStatusCode().equals(payload.getExpectedResultCode())) { |
|||
throw new RuntimeException("Response Status Code '" |
|||
+ exchangeResponse.getStatusCode() |
|||
+ "' doesn't equals to Expected Status Code '" |
|||
+ payload.getExpectedResultCode() + "'"); |
|||
} |
|||
|
|||
} catch (RestClientException e) { |
|||
throw new RuleException(e.getMessage(), e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,84 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rest.plugin; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.http.HttpHeaders; |
|||
import org.thingsboard.server.extensions.api.component.Plugin; |
|||
import org.thingsboard.server.extensions.api.plugins.AbstractPlugin; |
|||
import org.thingsboard.server.extensions.api.plugins.PluginContext; |
|||
import org.thingsboard.server.extensions.api.plugins.handlers.RuleMsgHandler; |
|||
import org.thingsboard.server.extensions.rest.action.RestApiCallPluginAction; |
|||
|
|||
import java.util.Base64; |
|||
|
|||
@Plugin(name = "REST API Call Plugin", actions = {RestApiCallPluginAction.class}, |
|||
descriptor = "RestApiCallPluginDescriptor.json", configuration = RestApiCallPluginConfiguration.class) |
|||
@Slf4j |
|||
public class RestApiCallPlugin extends AbstractPlugin<RestApiCallPluginConfiguration> { |
|||
|
|||
private static final String BASIC_AUTH_METHOD = "BASIC_AUTH"; |
|||
private static final String AUTHORIZATION_HEADER_NAME = "Authorization"; |
|||
private static final String AUTHORIZATION_HEADER_FORMAT = "Basic %s"; |
|||
private static final String CREDENTIALS_TEMPLATE = "%s:%s"; |
|||
private static final String BASE_URL_TEMPLATE = "http://%s:%d%s"; |
|||
private RestApiCallMsgHandler handler; |
|||
private String baseUrl; |
|||
private HttpHeaders headers = new HttpHeaders(); |
|||
|
|||
@Override |
|||
public void init(RestApiCallPluginConfiguration configuration) { |
|||
this.baseUrl = String.format( |
|||
BASE_URL_TEMPLATE, |
|||
configuration.getHost(), |
|||
configuration.getPort(), |
|||
configuration.getBasePath()); |
|||
|
|||
if (configuration.getAuthMethod()[0].equals(BASIC_AUTH_METHOD)) { |
|||
String userName = configuration.getUserName(); |
|||
String password = configuration.getPassword(); |
|||
String credentials = String.format(CREDENTIALS_TEMPLATE, userName, password); |
|||
byte[] token = Base64.getEncoder().encode(credentials.getBytes()); |
|||
this.headers.add(AUTHORIZATION_HEADER_NAME, String.format(AUTHORIZATION_HEADER_FORMAT, new String(token))); |
|||
} |
|||
|
|||
init(); |
|||
} |
|||
|
|||
private void init() { |
|||
this.handler = new RestApiCallMsgHandler(baseUrl, headers); |
|||
} |
|||
|
|||
@Override |
|||
protected RuleMsgHandler getRuleMsgHandler() { |
|||
return handler; |
|||
} |
|||
|
|||
@Override |
|||
public void resume(PluginContext ctx) { |
|||
init(); |
|||
} |
|||
|
|||
@Override |
|||
public void suspend(PluginContext ctx) { |
|||
log.debug("Suspend method was called, but no impl provided!"); |
|||
} |
|||
|
|||
@Override |
|||
public void stop(PluginContext ctx) { |
|||
log.debug("Stop method was called, but no impl provided!"); |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rest.plugin; |
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class RestApiCallPluginConfiguration { |
|||
private String host; |
|||
private int port; |
|||
private String basePath; |
|||
|
|||
private String[] authMethod; |
|||
|
|||
private String userName; |
|||
private String password; |
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
{ |
|||
"schema": { |
|||
"title": "REST API Call Action Configuration", |
|||
"type": "object", |
|||
"properties": { |
|||
"sync": { |
|||
"title": "Requires delivery confirmation", |
|||
"type": "boolean" |
|||
}, |
|||
"template": { |
|||
"title": "Body Template", |
|||
"type": "string" |
|||
}, |
|||
"actionPath": { |
|||
"title": "Action Path", |
|||
"type": "string", |
|||
"default": "/" |
|||
}, |
|||
"requestMethod": { |
|||
"title": "Request method", |
|||
"type": "array", |
|||
"minItems" : 1, |
|||
"items": [ |
|||
{ |
|||
"value": "POST", |
|||
"label": "POST" |
|||
}, |
|||
{ |
|||
"value": "PUT", |
|||
"label": "PUT" |
|||
} |
|||
], |
|||
"uniqueItems": true |
|||
}, |
|||
"expectedResultCode": { |
|||
"title": "Expected Result Code", |
|||
"type": "integer" |
|||
} |
|||
}, |
|||
"required": [ |
|||
"sync", |
|||
"template", |
|||
"actionPath", |
|||
"expectedResultCode", |
|||
"requestMethod" |
|||
] |
|||
}, |
|||
"form": [ |
|||
"sync", |
|||
{ |
|||
"key": "template", |
|||
"type": "textarea", |
|||
"rows": 5 |
|||
}, |
|||
"actionPath", |
|||
{ |
|||
"key": "requestMethod", |
|||
"type": "rc-select", |
|||
"multiple": false |
|||
}, |
|||
"expectedResultCode" |
|||
] |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
{ |
|||
"schema": { |
|||
"title": "REST API Call Plugin Configuration", |
|||
"type": "object", |
|||
"properties": { |
|||
"host": { |
|||
"title": "Host", |
|||
"type": "string" |
|||
}, |
|||
"port": { |
|||
"title": "Port", |
|||
"type": "integer", |
|||
"default": 8080, |
|||
"minimum": 0, |
|||
"maximum": 65536 |
|||
}, |
|||
"basePath": { |
|||
"title": "Base Path", |
|||
"type": "string", |
|||
"default": "/" |
|||
}, |
|||
"authMethod": { |
|||
"title": "Authentication method", |
|||
"type": "array", |
|||
"minItems" : 1, |
|||
"items": [ |
|||
{ |
|||
"value": "NO_AUTH", |
|||
"label": "No authentication" |
|||
}, |
|||
{ |
|||
"value": "BASIC_AUTH", |
|||
"label": "Basic authentication" |
|||
} |
|||
], |
|||
"uniqueItems": true |
|||
}, |
|||
"userName": { |
|||
"title": "Username", |
|||
"type": "string" |
|||
}, |
|||
"password": { |
|||
"title": "Password", |
|||
"type": "string" |
|||
} |
|||
}, |
|||
"required": [ |
|||
"host", |
|||
"port", |
|||
"basePath", |
|||
"authMethod" |
|||
] |
|||
}, |
|||
"form": [ |
|||
"host", |
|||
"port", |
|||
"basePath", |
|||
{ |
|||
"key": "authMethod", |
|||
"type": "rc-select", |
|||
"multiple": false |
|||
}, |
|||
"userName", |
|||
{ |
|||
"key": "password", |
|||
"type": "password" |
|||
} |
|||
] |
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
/** |
|||
* Copyright © 2016 The Thingsboard Authors |
|||
* |
|||
* 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.thingsboard.server.extensions.rest; |
|||
|
|||
import com.sun.net.httpserver.*; |
|||
|
|||
import java.io.BufferedReader; |
|||
import java.io.IOException; |
|||
import java.io.InputStreamReader; |
|||
import java.io.OutputStream; |
|||
import java.net.InetSocketAddress; |
|||
import java.util.stream.Collectors; |
|||
|
|||
public class RestApiCallDemoClient { |
|||
|
|||
private static final String DEMO_REST_BASIC_AUTH = "/demo-rest-basic-auth"; |
|||
private static final String DEMO_REST_NO_AUTH = "/demo-rest-no-auth"; |
|||
private static final String USERNAME = "demo"; |
|||
private static final String PASSWORD = "demo"; |
|||
private static final int HTTP_SERVER_PORT = 8888; |
|||
|
|||
public static void main(String[] args) throws IOException { |
|||
HttpServer server = HttpServer.create(new InetSocketAddress(HTTP_SERVER_PORT), 0); |
|||
|
|||
HttpContext secureContext = server.createContext(DEMO_REST_BASIC_AUTH, new RestDemoHandler()); |
|||
secureContext.setAuthenticator(new BasicAuthenticator("demo-auth") { |
|||
@Override |
|||
public boolean checkCredentials(String user, String pwd) { |
|||
return user.equals(USERNAME) && pwd.equals(PASSWORD); |
|||
} |
|||
}); |
|||
|
|||
server.createContext(DEMO_REST_NO_AUTH, new RestDemoHandler()); |
|||
server.setExecutor(null); |
|||
System.out.println("[*] Waiting for messages."); |
|||
server.start(); |
|||
} |
|||
|
|||
private static class RestDemoHandler implements HttpHandler { |
|||
@Override |
|||
public void handle(HttpExchange exchange) throws IOException { |
|||
String requestBody; |
|||
try (BufferedReader br = new BufferedReader(new InputStreamReader(exchange.getRequestBody(), "utf-8"))) { |
|||
requestBody = br.lines().collect(Collectors.joining(System.lineSeparator())); |
|||
} |
|||
System.out.println("[x] Received body: \n" + requestBody); |
|||
|
|||
String response = "Hello from demo client!"; |
|||
exchange.sendResponseHeaders(200, response.length()); |
|||
System.out.println("[x] Sending response: \n" + response); |
|||
|
|||
OutputStream os = exchange.getResponseBody(); |
|||
os.write(response.getBytes()); |
|||
os.close(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016 The Thingsboard Authors |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<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"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<parent> |
|||
<groupId>org.thingsboard</groupId> |
|||
<version>0.0.1-SNAPSHOT</version> |
|||
<artifactId>server</artifactId> |
|||
</parent> |
|||
<groupId>org.thingsboard.server</groupId> |
|||
<artifactId>extensions</artifactId> |
|||
<packaging>pom</packaging> |
|||
|
|||
<name>Thingsboard Extensions</name> |
|||
<url>http://thingsboard.org</url> |
|||
|
|||
<properties> |
|||
<main.dir>${basedir}/..</main.dir> |
|||
</properties> |
|||
|
|||
<modules> |
|||
<module>extension-rabbitmq</module> |
|||
<module>extension-rest-api-call</module> |
|||
<module>extension-kafka</module> |
|||
</modules> |
|||
|
|||
</project> |
|||
Loading…
Reference in new issue