Showing
46 changed files
with
1697 additions
and
1045 deletions
@@ -60,10 +60,6 @@ | @@ -60,10 +60,6 @@ | ||
60 | <groupId>org.thingsboard.common.transport</groupId> | 60 | <groupId>org.thingsboard.common.transport</groupId> |
61 | <artifactId>transport-api</artifactId> | 61 | <artifactId>transport-api</artifactId> |
62 | </dependency> | 62 | </dependency> |
63 | - <!--<dependency>--> | ||
64 | - <!--<groupId>org.thingsboard.transport</groupId>--> | ||
65 | - <!--<artifactId>coap</artifactId>--> | ||
66 | - <!--</dependency>--> | ||
67 | <dependency> | 63 | <dependency> |
68 | <groupId>org.thingsboard.common.transport</groupId> | 64 | <groupId>org.thingsboard.common.transport</groupId> |
69 | <artifactId>mqtt</artifactId> | 65 | <artifactId>mqtt</artifactId> |
@@ -73,6 +69,10 @@ | @@ -73,6 +69,10 @@ | ||
73 | <artifactId>http</artifactId> | 69 | <artifactId>http</artifactId> |
74 | </dependency> | 70 | </dependency> |
75 | <dependency> | 71 | <dependency> |
72 | + <groupId>org.thingsboard.common.transport</groupId> | ||
73 | + <artifactId>coap</artifactId> | ||
74 | + </dependency> | ||
75 | + <dependency> | ||
76 | <groupId>org.thingsboard</groupId> | 76 | <groupId>org.thingsboard</groupId> |
77 | <artifactId>dao</artifactId> | 77 | <artifactId>dao</artifactId> |
78 | </dependency> | 78 | </dependency> |
@@ -455,7 +455,6 @@ transport: | @@ -455,7 +455,6 @@ transport: | ||
455 | enabled: "${MQTT_ENABLED:true}" | 455 | enabled: "${MQTT_ENABLED:true}" |
456 | bind_address: "${MQTT_BIND_ADDRESS:0.0.0.0}" | 456 | bind_address: "${MQTT_BIND_ADDRESS:0.0.0.0}" |
457 | bind_port: "${MQTT_BIND_PORT:1883}" | 457 | bind_port: "${MQTT_BIND_PORT:1883}" |
458 | - adaptor: "${MQTT_ADAPTOR_NAME:JsonMqttAdaptor}" | ||
459 | timeout: "${MQTT_TIMEOUT:10000}" | 458 | timeout: "${MQTT_TIMEOUT:10000}" |
460 | netty: | 459 | netty: |
461 | leak_detector_level: "${NETTY_LEASK_DETECTOR_LVL:DISABLED}" | 460 | leak_detector_level: "${NETTY_LEASK_DETECTOR_LVL:DISABLED}" |
@@ -482,5 +481,4 @@ transport: | @@ -482,5 +481,4 @@ transport: | ||
482 | enabled: "${COAP_ENABLED:true}" | 481 | enabled: "${COAP_ENABLED:true}" |
483 | bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}" | 482 | bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}" |
484 | bind_port: "${COAP_BIND_PORT:5683}" | 483 | bind_port: "${COAP_BIND_PORT:5683}" |
485 | - adaptor: "${COAP_ADAPTOR_NAME:JsonCoapAdaptor}" | ||
486 | timeout: "${COAP_TIMEOUT:10000}" | 484 | timeout: "${COAP_TIMEOUT:10000}" |
common/transport/coap/pom.xml
0 → 100644
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2018 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
19 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
20 | + <modelVersion>4.0.0</modelVersion> | ||
21 | + <parent> | ||
22 | + <groupId>org.thingsboard.common</groupId> | ||
23 | + <version>2.2.0-SNAPSHOT</version> | ||
24 | + <artifactId>transport</artifactId> | ||
25 | + </parent> | ||
26 | + <groupId>org.thingsboard.common.transport</groupId> | ||
27 | + <artifactId>coap</artifactId> | ||
28 | + <packaging>jar</packaging> | ||
29 | + | ||
30 | + <name>Thingsboard CoAP Transport Common</name> | ||
31 | + <url>https://thingsboard.io</url> | ||
32 | + | ||
33 | + <properties> | ||
34 | + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
35 | + <main.dir>${basedir}/../../..</main.dir> | ||
36 | + </properties> | ||
37 | + | ||
38 | + <dependencies> | ||
39 | + <dependency> | ||
40 | + <groupId>org.thingsboard.common.transport</groupId> | ||
41 | + <artifactId>transport-api</artifactId> | ||
42 | + </dependency> | ||
43 | + <dependency> | ||
44 | + <groupId>org.eclipse.californium</groupId> | ||
45 | + <artifactId>californium-core</artifactId> | ||
46 | + </dependency> | ||
47 | + <dependency> | ||
48 | + <groupId>org.springframework</groupId> | ||
49 | + <artifactId>spring-context-support</artifactId> | ||
50 | + </dependency> | ||
51 | + <dependency> | ||
52 | + <groupId>org.springframework</groupId> | ||
53 | + <artifactId>spring-context</artifactId> | ||
54 | + </dependency> | ||
55 | + <dependency> | ||
56 | + <groupId>org.slf4j</groupId> | ||
57 | + <artifactId>slf4j-api</artifactId> | ||
58 | + </dependency> | ||
59 | + <dependency> | ||
60 | + <groupId>org.slf4j</groupId> | ||
61 | + <artifactId>log4j-over-slf4j</artifactId> | ||
62 | + </dependency> | ||
63 | + <dependency> | ||
64 | + <groupId>ch.qos.logback</groupId> | ||
65 | + <artifactId>logback-core</artifactId> | ||
66 | + </dependency> | ||
67 | + <dependency> | ||
68 | + <groupId>ch.qos.logback</groupId> | ||
69 | + <artifactId>logback-classic</artifactId> | ||
70 | + </dependency> | ||
71 | + <dependency> | ||
72 | + <groupId>org.springframework.boot</groupId> | ||
73 | + <artifactId>spring-boot-starter-test</artifactId> | ||
74 | + <scope>test</scope> | ||
75 | + </dependency> | ||
76 | + <dependency> | ||
77 | + <groupId>junit</groupId> | ||
78 | + <artifactId>junit</artifactId> | ||
79 | + <scope>test</scope> | ||
80 | + </dependency> | ||
81 | + <dependency> | ||
82 | + <groupId>org.mockito</groupId> | ||
83 | + <artifactId>mockito-all</artifactId> | ||
84 | + <scope>test</scope> | ||
85 | + </dependency> | ||
86 | + </dependencies> | ||
87 | + | ||
88 | +</project> |
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportContext.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.coap; | ||
17 | + | ||
18 | +import lombok.Getter; | ||
19 | +import lombok.extern.slf4j.Slf4j; | ||
20 | +import org.springframework.beans.factory.annotation.Autowired; | ||
21 | +import org.springframework.beans.factory.annotation.Value; | ||
22 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | ||
23 | +import org.springframework.stereotype.Component; | ||
24 | +import org.thingsboard.server.common.transport.TransportContext; | ||
25 | +import org.thingsboard.server.transport.coap.adaptors.CoapTransportAdaptor; | ||
26 | + | ||
27 | +/** | ||
28 | + * Created by ashvayka on 18.10.18. | ||
29 | + */ | ||
30 | +@Slf4j | ||
31 | +@ConditionalOnExpression("'${transport.type:null}'=='null' || ('${transport.type}'=='local' && '${transport.coap.enabled}'=='true')") | ||
32 | +@Component | ||
33 | +public class CoapTransportContext extends TransportContext { | ||
34 | + | ||
35 | + @Getter | ||
36 | + @Value("${transport.coap.bind_address}") | ||
37 | + private String host; | ||
38 | + | ||
39 | + @Getter | ||
40 | + @Value("${transport.coap.bind_port}") | ||
41 | + private Integer port; | ||
42 | + | ||
43 | + @Getter | ||
44 | + @Value("${transport.coap.timeout}") | ||
45 | + private Long timeout; | ||
46 | + | ||
47 | + @Getter | ||
48 | + @Autowired | ||
49 | + private CoapTransportAdaptor adaptor; | ||
50 | + | ||
51 | +} |
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.coap; | ||
17 | + | ||
18 | +import lombok.extern.slf4j.Slf4j; | ||
19 | +import org.eclipse.californium.core.CoapResource; | ||
20 | +import org.eclipse.californium.core.coap.CoAP.ResponseCode; | ||
21 | +import org.eclipse.californium.core.coap.Request; | ||
22 | +import org.eclipse.californium.core.coap.Response; | ||
23 | +import org.eclipse.californium.core.network.Exchange; | ||
24 | +import org.eclipse.californium.core.network.ExchangeObserver; | ||
25 | +import org.eclipse.californium.core.server.resources.CoapExchange; | ||
26 | +import org.eclipse.californium.core.server.resources.Resource; | ||
27 | +import org.springframework.util.ReflectionUtils; | ||
28 | +import org.thingsboard.server.common.data.security.DeviceTokenCredentials; | ||
29 | +import org.thingsboard.server.common.msg.session.FeatureType; | ||
30 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | ||
31 | +import org.thingsboard.server.common.transport.SessionMsgListener; | ||
32 | +import org.thingsboard.server.common.transport.TransportContext; | ||
33 | +import org.thingsboard.server.common.transport.TransportService; | ||
34 | +import org.thingsboard.server.common.transport.TransportServiceCallback; | ||
35 | +import org.thingsboard.server.common.transport.adaptor.AdaptorException; | ||
36 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
37 | + | ||
38 | +import java.lang.reflect.Field; | ||
39 | +import java.util.List; | ||
40 | +import java.util.Optional; | ||
41 | +import java.util.UUID; | ||
42 | +import java.util.concurrent.ConcurrentHashMap; | ||
43 | +import java.util.concurrent.ConcurrentMap; | ||
44 | +import java.util.concurrent.atomic.AtomicInteger; | ||
45 | +import java.util.function.Consumer; | ||
46 | + | ||
47 | +@Slf4j | ||
48 | +public class CoapTransportResource extends CoapResource { | ||
49 | + // coap://localhost:port/api/v1/DEVICE_TOKEN/[attributes|telemetry|rpc[/requestId]] | ||
50 | + private static final int ACCESS_TOKEN_POSITION = 3; | ||
51 | + private static final int FEATURE_TYPE_POSITION = 4; | ||
52 | + private static final int REQUEST_ID_POSITION = 5; | ||
53 | + | ||
54 | + private final CoapTransportContext transportContext; | ||
55 | + private final TransportService transportService; | ||
56 | + private final Field observerField; | ||
57 | + private final long timeout; | ||
58 | + private final ConcurrentMap<String, TransportProtos.SessionInfoProto> tokenToSessionIdMap = new ConcurrentHashMap<>(); | ||
59 | + | ||
60 | + public CoapTransportResource(CoapTransportContext context, String name) { | ||
61 | + super(name); | ||
62 | + this.transportContext = context; | ||
63 | + this.transportService = context.getTransportService(); | ||
64 | + this.timeout = context.getTimeout(); | ||
65 | + // This is important to turn off existing observable logic in | ||
66 | + // CoapResource. We will have our own observe monitoring due to 1:1 | ||
67 | + // observe relationship. | ||
68 | + this.setObservable(false); | ||
69 | + observerField = ReflectionUtils.findField(Exchange.class, "observer"); | ||
70 | + observerField.setAccessible(true); | ||
71 | + } | ||
72 | + | ||
73 | + @Override | ||
74 | + public void handleGET(CoapExchange exchange) { | ||
75 | + if (transportContext.getQuotaService().isQuotaExceeded(exchange.getSourceAddress().getHostAddress())) { | ||
76 | + log.warn("CoAP Quota exceeded for [{}:{}] . Disconnect", exchange.getSourceAddress().getHostAddress(), exchange.getSourcePort()); | ||
77 | + exchange.respond(ResponseCode.BAD_REQUEST); | ||
78 | + return; | ||
79 | + } | ||
80 | + | ||
81 | + Optional<FeatureType> featureType = getFeatureType(exchange.advanced().getRequest()); | ||
82 | + if (!featureType.isPresent()) { | ||
83 | + log.trace("Missing feature type parameter"); | ||
84 | + exchange.respond(ResponseCode.BAD_REQUEST); | ||
85 | + } else if (featureType.get() == FeatureType.TELEMETRY) { | ||
86 | + log.trace("Can't fetch/subscribe to timeseries updates"); | ||
87 | + exchange.respond(ResponseCode.BAD_REQUEST); | ||
88 | + } else if (exchange.getRequestOptions().hasObserve()) { | ||
89 | + processExchangeGetRequest(exchange, featureType.get()); | ||
90 | + } else if (featureType.get() == FeatureType.ATTRIBUTES) { | ||
91 | + processRequest(exchange, SessionMsgType.GET_ATTRIBUTES_REQUEST); | ||
92 | + } else { | ||
93 | + log.trace("Invalid feature type parameter"); | ||
94 | + exchange.respond(ResponseCode.BAD_REQUEST); | ||
95 | + } | ||
96 | + } | ||
97 | + | ||
98 | + private void processExchangeGetRequest(CoapExchange exchange, FeatureType featureType) { | ||
99 | + boolean unsubscribe = exchange.getRequestOptions().getObserve() == 1; | ||
100 | + SessionMsgType sessionMsgType; | ||
101 | + if (featureType == FeatureType.RPC) { | ||
102 | + sessionMsgType = unsubscribe ? SessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST : SessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST; | ||
103 | + } else { | ||
104 | + sessionMsgType = unsubscribe ? SessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST : SessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST; | ||
105 | + } | ||
106 | + processRequest(exchange, sessionMsgType); | ||
107 | + } | ||
108 | + | ||
109 | + @Override | ||
110 | + public void handlePOST(CoapExchange exchange) { | ||
111 | + if (transportContext.getQuotaService().isQuotaExceeded(exchange.getSourceAddress().getHostAddress())) { | ||
112 | + log.warn("CoAP Quota exceeded for [{}:{}] . Disconnect", exchange.getSourceAddress().getHostAddress(), exchange.getSourcePort()); | ||
113 | + exchange.respond(ResponseCode.BAD_REQUEST); | ||
114 | + return; | ||
115 | + } | ||
116 | + | ||
117 | + Optional<FeatureType> featureType = getFeatureType(exchange.advanced().getRequest()); | ||
118 | + if (!featureType.isPresent()) { | ||
119 | + log.trace("Missing feature type parameter"); | ||
120 | + exchange.respond(ResponseCode.BAD_REQUEST); | ||
121 | + } else { | ||
122 | + switch (featureType.get()) { | ||
123 | + case ATTRIBUTES: | ||
124 | + processRequest(exchange, SessionMsgType.POST_ATTRIBUTES_REQUEST); | ||
125 | + break; | ||
126 | + case TELEMETRY: | ||
127 | + processRequest(exchange, SessionMsgType.POST_TELEMETRY_REQUEST); | ||
128 | + break; | ||
129 | + case RPC: | ||
130 | + Optional<Integer> requestId = getRequestId(exchange.advanced().getRequest()); | ||
131 | + if (requestId.isPresent()) { | ||
132 | + processRequest(exchange, SessionMsgType.TO_DEVICE_RPC_RESPONSE); | ||
133 | + } else { | ||
134 | + processRequest(exchange, SessionMsgType.TO_SERVER_RPC_REQUEST); | ||
135 | + } | ||
136 | + break; | ||
137 | + } | ||
138 | + } | ||
139 | + } | ||
140 | + | ||
141 | + private void processRequest(CoapExchange exchange, SessionMsgType type) { | ||
142 | + log.trace("Processing {}", exchange.advanced().getRequest()); | ||
143 | + exchange.accept(); | ||
144 | + Exchange advanced = exchange.advanced(); | ||
145 | + Request request = advanced.getRequest(); | ||
146 | + | ||
147 | + Optional<DeviceTokenCredentials> credentials = decodeCredentials(request); | ||
148 | + if (!credentials.isPresent()) { | ||
149 | + exchange.respond(ResponseCode.BAD_REQUEST); | ||
150 | + return; | ||
151 | + } | ||
152 | + | ||
153 | + transportService.process(TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(credentials.get().getCredentialsId()).build(), | ||
154 | + new DeviceAuthCallback(transportContext, exchange, sessionInfo -> { | ||
155 | + UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); | ||
156 | + try { | ||
157 | + switch (type) { | ||
158 | + case POST_ATTRIBUTES_REQUEST: | ||
159 | + transportService.process(sessionInfo, | ||
160 | + transportContext.getAdaptor().convertToPostAttributes(sessionId, request), | ||
161 | + new CoapOkCallback(exchange)); | ||
162 | + break; | ||
163 | + case POST_TELEMETRY_REQUEST: | ||
164 | + transportService.process(sessionInfo, | ||
165 | + transportContext.getAdaptor().convertToPostTelemetry(sessionId, request), | ||
166 | + new CoapOkCallback(exchange)); | ||
167 | + break; | ||
168 | + case SUBSCRIBE_ATTRIBUTES_REQUEST: | ||
169 | + advanced.setObserver(new CoapExchangeObserverProxy((ExchangeObserver) observerField.get(advanced), | ||
170 | + registerAsyncCoapSession(exchange, request, sessionInfo, sessionId))); | ||
171 | + transportService.process(sessionInfo, | ||
172 | + TransportProtos.SubscribeToAttributeUpdatesMsg.getDefaultInstance(), | ||
173 | + new CoapNoOpCallback(exchange)); | ||
174 | + break; | ||
175 | + case UNSUBSCRIBE_ATTRIBUTES_REQUEST: | ||
176 | + TransportProtos.SessionInfoProto attrSession = lookupAsyncSessionInfo(request); | ||
177 | + if (attrSession != null) { | ||
178 | + transportService.process(attrSession, | ||
179 | + TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().setUnsubscribe(true).build(), | ||
180 | + new CoapOkCallback(exchange)); | ||
181 | + closeAndDeregister(sessionInfo); | ||
182 | + } | ||
183 | + break; | ||
184 | + case SUBSCRIBE_RPC_COMMANDS_REQUEST: | ||
185 | + advanced.setObserver(new CoapExchangeObserverProxy((ExchangeObserver) observerField.get(advanced), | ||
186 | + registerAsyncCoapSession(exchange, request, sessionInfo, sessionId))); | ||
187 | + transportService.process(sessionInfo, | ||
188 | + TransportProtos.SubscribeToRPCMsg.getDefaultInstance(), | ||
189 | + new CoapNoOpCallback(exchange)); | ||
190 | + break; | ||
191 | + case UNSUBSCRIBE_RPC_COMMANDS_REQUEST: | ||
192 | + TransportProtos.SessionInfoProto rpcSession = lookupAsyncSessionInfo(request); | ||
193 | + if (rpcSession != null) { | ||
194 | + transportService.process(rpcSession, | ||
195 | + TransportProtos.SubscribeToRPCMsg.newBuilder().setUnsubscribe(true).build(), | ||
196 | + new CoapOkCallback(exchange)); | ||
197 | + transportService.process(sessionInfo, getSessionEventMsg(TransportProtos.SessionEvent.CLOSED), null); | ||
198 | + transportService.deregisterSession(rpcSession); | ||
199 | + } | ||
200 | + break; | ||
201 | + case TO_DEVICE_RPC_RESPONSE: | ||
202 | + transportService.process(sessionInfo, | ||
203 | + transportContext.getAdaptor().convertToDeviceRpcResponse(sessionId, request), | ||
204 | + new CoapOkCallback(exchange)); | ||
205 | + break; | ||
206 | + case TO_SERVER_RPC_REQUEST: | ||
207 | + transportService.process(sessionInfo, | ||
208 | + transportContext.getAdaptor().convertToServerRpcRequest(sessionId, request), | ||
209 | + new CoapNoOpCallback(exchange)); | ||
210 | + break; | ||
211 | + case GET_ATTRIBUTES_REQUEST: | ||
212 | + transportService.registerSyncSession(sessionInfo, new CoapSessionListener(sessionId, exchange), transportContext.getTimeout()); | ||
213 | + transportService.process(sessionInfo, | ||
214 | + transportContext.getAdaptor().convertToGetAttributes(sessionId, request), | ||
215 | + new CoapNoOpCallback(exchange)); | ||
216 | + break; | ||
217 | + } | ||
218 | + } catch (AdaptorException e) { | ||
219 | + log.trace("[{}] Failed to decode message: ", sessionId, e); | ||
220 | + exchange.respond(ResponseCode.BAD_REQUEST); | ||
221 | + } catch (IllegalAccessException e) { | ||
222 | + log.trace("[{}] Failed to process message: ", sessionId, e); | ||
223 | + exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); | ||
224 | + } | ||
225 | + })); | ||
226 | + } | ||
227 | + | ||
228 | + private TransportProtos.SessionInfoProto lookupAsyncSessionInfo(Request request) { | ||
229 | + String token = request.getSource().getHostAddress() + ":" + request.getSourcePort() + ":" + request.getTokenString(); | ||
230 | + return tokenToSessionIdMap.remove(token); | ||
231 | + } | ||
232 | + | ||
233 | + private String registerAsyncCoapSession(CoapExchange exchange, Request request, TransportProtos.SessionInfoProto sessionInfo, UUID sessionId) { | ||
234 | + String token = request.getSource().getHostAddress() + ":" + request.getSourcePort() + ":" + request.getTokenString(); | ||
235 | + tokenToSessionIdMap.putIfAbsent(token, sessionInfo); | ||
236 | + CoapSessionListener attrListener = new CoapSessionListener(sessionId, exchange); | ||
237 | + transportService.registerAsyncSession(sessionInfo, attrListener); | ||
238 | + transportService.process(sessionInfo, getSessionEventMsg(TransportProtos.SessionEvent.OPEN), null); | ||
239 | + return token; | ||
240 | + } | ||
241 | + | ||
242 | + private static TransportProtos.SessionEventMsg getSessionEventMsg(TransportProtos.SessionEvent event) { | ||
243 | + return TransportProtos.SessionEventMsg.newBuilder() | ||
244 | + .setSessionType(TransportProtos.SessionType.ASYNC) | ||
245 | + .setEvent(event).build(); | ||
246 | + } | ||
247 | + | ||
248 | + private Optional<DeviceTokenCredentials> decodeCredentials(Request request) { | ||
249 | + List<String> uriPath = request.getOptions().getUriPath(); | ||
250 | + if (uriPath.size() >= ACCESS_TOKEN_POSITION) { | ||
251 | + return Optional.of(new DeviceTokenCredentials(uriPath.get(ACCESS_TOKEN_POSITION - 1))); | ||
252 | + } else { | ||
253 | + return Optional.empty(); | ||
254 | + } | ||
255 | + } | ||
256 | + | ||
257 | + private Optional<FeatureType> getFeatureType(Request request) { | ||
258 | + List<String> uriPath = request.getOptions().getUriPath(); | ||
259 | + try { | ||
260 | + if (uriPath.size() >= FEATURE_TYPE_POSITION) { | ||
261 | + return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION - 1).toUpperCase())); | ||
262 | + } | ||
263 | + } catch (RuntimeException e) { | ||
264 | + log.warn("Failed to decode feature type: {}", uriPath); | ||
265 | + } | ||
266 | + return Optional.empty(); | ||
267 | + } | ||
268 | + | ||
269 | + public static Optional<Integer> getRequestId(Request request) { | ||
270 | + List<String> uriPath = request.getOptions().getUriPath(); | ||
271 | + try { | ||
272 | + if (uriPath.size() >= REQUEST_ID_POSITION) { | ||
273 | + return Optional.of(Integer.valueOf(uriPath.get(REQUEST_ID_POSITION - 1))); | ||
274 | + } | ||
275 | + } catch (RuntimeException e) { | ||
276 | + log.warn("Failed to decode feature type: {}", uriPath); | ||
277 | + } | ||
278 | + return Optional.empty(); | ||
279 | + } | ||
280 | + | ||
281 | + @Override | ||
282 | + public Resource getChild(String name) { | ||
283 | + return this; | ||
284 | + } | ||
285 | + | ||
286 | + private static class DeviceAuthCallback implements TransportServiceCallback<TransportProtos.ValidateDeviceCredentialsResponseMsg> { | ||
287 | + private final TransportContext transportContext; | ||
288 | + private final CoapExchange exchange; | ||
289 | + private final Consumer<TransportProtos.SessionInfoProto> onSuccess; | ||
290 | + | ||
291 | + DeviceAuthCallback(TransportContext transportContext, CoapExchange exchange, Consumer<TransportProtos.SessionInfoProto> onSuccess) { | ||
292 | + this.transportContext = transportContext; | ||
293 | + this.exchange = exchange; | ||
294 | + this.onSuccess = onSuccess; | ||
295 | + } | ||
296 | + | ||
297 | + @Override | ||
298 | + public void onSuccess(TransportProtos.ValidateDeviceCredentialsResponseMsg msg) { | ||
299 | + if (msg.hasDeviceInfo()) { | ||
300 | + UUID sessionId = UUID.randomUUID(); | ||
301 | + TransportProtos.DeviceInfoProto deviceInfoProto = msg.getDeviceInfo(); | ||
302 | + TransportProtos.SessionInfoProto sessionInfo = TransportProtos.SessionInfoProto.newBuilder() | ||
303 | + .setNodeId(transportContext.getNodeId()) | ||
304 | + .setTenantIdMSB(deviceInfoProto.getTenantIdMSB()) | ||
305 | + .setTenantIdLSB(deviceInfoProto.getTenantIdLSB()) | ||
306 | + .setDeviceIdMSB(deviceInfoProto.getDeviceIdMSB()) | ||
307 | + .setDeviceIdLSB(deviceInfoProto.getDeviceIdLSB()) | ||
308 | + .setSessionIdMSB(sessionId.getMostSignificantBits()) | ||
309 | + .setSessionIdLSB(sessionId.getLeastSignificantBits()) | ||
310 | + .build(); | ||
311 | + onSuccess.accept(sessionInfo); | ||
312 | + } else { | ||
313 | + exchange.respond(ResponseCode.UNAUTHORIZED); | ||
314 | + } | ||
315 | + } | ||
316 | + | ||
317 | + @Override | ||
318 | + public void onError(Throwable e) { | ||
319 | + log.warn("Failed to process request", e); | ||
320 | + exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); | ||
321 | + } | ||
322 | + } | ||
323 | + | ||
324 | + private static class CoapOkCallback implements TransportServiceCallback<Void> { | ||
325 | + private final CoapExchange exchange; | ||
326 | + | ||
327 | + CoapOkCallback(CoapExchange exchange) { | ||
328 | + this.exchange = exchange; | ||
329 | + } | ||
330 | + | ||
331 | + @Override | ||
332 | + public void onSuccess(Void msg) { | ||
333 | + exchange.respond(ResponseCode.VALID); | ||
334 | + } | ||
335 | + | ||
336 | + @Override | ||
337 | + public void onError(Throwable e) { | ||
338 | + exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); | ||
339 | + } | ||
340 | + } | ||
341 | + | ||
342 | + private static class CoapNoOpCallback implements TransportServiceCallback<Void> { | ||
343 | + private final CoapExchange exchange; | ||
344 | + | ||
345 | + CoapNoOpCallback(CoapExchange exchange) { | ||
346 | + this.exchange = exchange; | ||
347 | + } | ||
348 | + | ||
349 | + @Override | ||
350 | + public void onSuccess(Void msg) { | ||
351 | + | ||
352 | + } | ||
353 | + | ||
354 | + @Override | ||
355 | + public void onError(Throwable e) { | ||
356 | + exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); | ||
357 | + } | ||
358 | + } | ||
359 | + | ||
360 | + public class CoapSessionListener implements SessionMsgListener { | ||
361 | + | ||
362 | + private final CoapExchange exchange; | ||
363 | + private final AtomicInteger seqNumber = new AtomicInteger(2); | ||
364 | + | ||
365 | + CoapSessionListener(UUID sessionId, CoapExchange exchange) { | ||
366 | + this.exchange = exchange; | ||
367 | + } | ||
368 | + | ||
369 | + @Override | ||
370 | + public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg msg) { | ||
371 | + try { | ||
372 | + exchange.respond(transportContext.getAdaptor().convertToPublish(this, msg)); | ||
373 | + } catch (AdaptorException e) { | ||
374 | + log.trace("Failed to reply due to error", e); | ||
375 | + exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); | ||
376 | + } | ||
377 | + } | ||
378 | + | ||
379 | + @Override | ||
380 | + public void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg) { | ||
381 | + try { | ||
382 | + exchange.respond(transportContext.getAdaptor().convertToPublish(this, msg)); | ||
383 | + } catch (AdaptorException e) { | ||
384 | + log.trace("Failed to reply due to error", e); | ||
385 | + exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); | ||
386 | + } | ||
387 | + } | ||
388 | + | ||
389 | + @Override | ||
390 | + public void onRemoteSessionCloseCommand(TransportProtos.SessionCloseNotificationProto sessionCloseNotification) { | ||
391 | + exchange.respond(ResponseCode.SERVICE_UNAVAILABLE); | ||
392 | + } | ||
393 | + | ||
394 | + @Override | ||
395 | + public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg msg) { | ||
396 | + try { | ||
397 | + exchange.respond(transportContext.getAdaptor().convertToPublish(this, msg)); | ||
398 | + } catch (AdaptorException e) { | ||
399 | + log.trace("Failed to reply due to error", e); | ||
400 | + exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); | ||
401 | + } | ||
402 | + } | ||
403 | + | ||
404 | + @Override | ||
405 | + public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg msg) { | ||
406 | + try { | ||
407 | + exchange.respond(transportContext.getAdaptor().convertToPublish(this, msg)); | ||
408 | + } catch (AdaptorException e) { | ||
409 | + log.trace("Failed to reply due to error", e); | ||
410 | + exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); | ||
411 | + } | ||
412 | + } | ||
413 | + | ||
414 | + public int getNextSeqNumber() { | ||
415 | + return seqNumber.getAndIncrement(); | ||
416 | + } | ||
417 | + } | ||
418 | + | ||
419 | + public class CoapExchangeObserverProxy implements ExchangeObserver { | ||
420 | + | ||
421 | + private final ExchangeObserver proxy; | ||
422 | + private final String token; | ||
423 | + | ||
424 | + CoapExchangeObserverProxy(ExchangeObserver proxy, String token) { | ||
425 | + super(); | ||
426 | + this.proxy = proxy; | ||
427 | + this.token = token; | ||
428 | + } | ||
429 | + | ||
430 | + @Override | ||
431 | + public void completed(Exchange exchange) { | ||
432 | + proxy.completed(exchange); | ||
433 | + TransportProtos.SessionInfoProto session = tokenToSessionIdMap.remove(token); | ||
434 | + if (session != null) { | ||
435 | + closeAndDeregister(session); | ||
436 | + } | ||
437 | + } | ||
438 | + } | ||
439 | + | ||
440 | + private void closeAndDeregister(TransportProtos.SessionInfoProto session) { | ||
441 | + transportService.process(session, getSessionEventMsg(TransportProtos.SessionEvent.CLOSED), null); | ||
442 | + transportService.deregisterSession(session); | ||
443 | + } | ||
444 | + | ||
445 | +} |
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportService.java
renamed from
transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportService.java
@@ -21,6 +21,7 @@ import org.eclipse.californium.core.CoapServer; | @@ -21,6 +21,7 @@ import org.eclipse.californium.core.CoapServer; | ||
21 | import org.eclipse.californium.core.network.CoapEndpoint; | 21 | import org.eclipse.californium.core.network.CoapEndpoint; |
22 | import org.springframework.beans.factory.annotation.Autowired; | 22 | import org.springframework.beans.factory.annotation.Autowired; |
23 | import org.springframework.beans.factory.annotation.Value; | 23 | import org.springframework.beans.factory.annotation.Value; |
24 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | ||
24 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | 25 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
25 | import org.springframework.context.ApplicationContext; | 26 | import org.springframework.context.ApplicationContext; |
26 | import org.springframework.stereotype.Service; | 27 | import org.springframework.stereotype.Service; |
@@ -37,49 +38,26 @@ import java.net.InetSocketAddress; | @@ -37,49 +38,26 @@ import java.net.InetSocketAddress; | ||
37 | import java.net.UnknownHostException; | 38 | import java.net.UnknownHostException; |
38 | 39 | ||
39 | @Service("CoapTransportService") | 40 | @Service("CoapTransportService") |
40 | -@ConditionalOnProperty(prefix = "transport.coap", value = "enabled", havingValue = "true") | 41 | +@ConditionalOnExpression("'${transport.type:null}'=='null' || ('${transport.type}'=='local' && '${transport.coap.enabled}'=='true')") |
41 | @Slf4j | 42 | @Slf4j |
42 | public class CoapTransportService { | 43 | public class CoapTransportService { |
43 | 44 | ||
44 | private static final String V1 = "v1"; | 45 | private static final String V1 = "v1"; |
45 | private static final String API = "api"; | 46 | private static final String API = "api"; |
46 | 47 | ||
47 | - private CoapServer server; | ||
48 | - | ||
49 | - @Autowired(required = false) | ||
50 | - private ApplicationContext appContext; | ||
51 | - | ||
52 | - @Autowired(required = false) | ||
53 | - private SessionMsgProcessor processor; | ||
54 | - | ||
55 | - @Autowired(required = false) | ||
56 | - private DeviceAuthService authService; | 48 | + @Autowired |
49 | + private CoapTransportContext coapTransportContext; | ||
57 | 50 | ||
58 | - @Autowired(required = false) | ||
59 | - private HostRequestsQuotaService quotaService; | ||
60 | - | ||
61 | - | ||
62 | - @Value("${coap.bind_address}") | ||
63 | - private String host; | ||
64 | - @Value("${coap.bind_port}") | ||
65 | - private Integer port; | ||
66 | - @Value("${coap.adaptor}") | ||
67 | - private String adaptorName; | ||
68 | - @Value("${coap.timeout}") | ||
69 | - private Long timeout; | ||
70 | - | ||
71 | - private CoapTransportAdaptor adaptor; | 51 | + private CoapServer server; |
72 | 52 | ||
73 | @PostConstruct | 53 | @PostConstruct |
74 | public void init() throws UnknownHostException { | 54 | public void init() throws UnknownHostException { |
75 | log.info("Starting CoAP transport..."); | 55 | log.info("Starting CoAP transport..."); |
76 | - log.info("Lookup CoAP transport adaptor {}", adaptorName); | ||
77 | - this.adaptor = (CoapTransportAdaptor) appContext.getBean(adaptorName); | ||
78 | log.info("Starting CoAP transport server"); | 56 | log.info("Starting CoAP transport server"); |
79 | this.server = new CoapServer(); | 57 | this.server = new CoapServer(); |
80 | createResources(); | 58 | createResources(); |
81 | - InetAddress addr = InetAddress.getByName(host); | ||
82 | - InetSocketAddress sockAddr = new InetSocketAddress(addr, port); | 59 | + InetAddress addr = InetAddress.getByName(coapTransportContext.getHost()); |
60 | + InetSocketAddress sockAddr = new InetSocketAddress(addr, coapTransportContext.getPort()); | ||
83 | server.addEndpoint(new CoapEndpoint(sockAddr)); | 61 | server.addEndpoint(new CoapEndpoint(sockAddr)); |
84 | server.start(); | 62 | server.start(); |
85 | log.info("CoAP transport started!"); | 63 | log.info("CoAP transport started!"); |
@@ -87,7 +65,7 @@ public class CoapTransportService { | @@ -87,7 +65,7 @@ public class CoapTransportService { | ||
87 | 65 | ||
88 | private void createResources() { | 66 | private void createResources() { |
89 | CoapResource api = new CoapResource(API); | 67 | CoapResource api = new CoapResource(API); |
90 | - api.add(new CoapTransportResource(processor, authService, adaptor, V1, timeout, quotaService)); | 68 | + api.add(new CoapTransportResource(coapTransportContext, V1)); |
91 | server.add(api); | 69 | server.add(api); |
92 | } | 70 | } |
93 | 71 |
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/CoapTransportAdaptor.java
renamed from
transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/CoapTransportAdaptor.java
@@ -17,9 +17,31 @@ package org.thingsboard.server.transport.coap.adaptors; | @@ -17,9 +17,31 @@ package org.thingsboard.server.transport.coap.adaptors; | ||
17 | 17 | ||
18 | import org.eclipse.californium.core.coap.Request; | 18 | import org.eclipse.californium.core.coap.Request; |
19 | import org.eclipse.californium.core.coap.Response; | 19 | import org.eclipse.californium.core.coap.Response; |
20 | -import org.thingsboard.server.common.transport.TransportAdaptor; | ||
21 | -import org.thingsboard.server.transport.coap.session.CoapSessionCtx; | 20 | +import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
21 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
22 | +import org.thingsboard.server.transport.coap.CoapTransportResource; | ||
22 | 23 | ||
23 | -public interface CoapTransportAdaptor extends TransportAdaptor<CoapSessionCtx, Request, Response> { | 24 | +import java.util.UUID; |
25 | +import java.util.Optional; | ||
26 | + | ||
27 | +public interface CoapTransportAdaptor { | ||
28 | + | ||
29 | + TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, Request inbound) throws AdaptorException; | ||
30 | + | ||
31 | + TransportProtos.PostAttributeMsg convertToPostAttributes(UUID sessionId, Request inbound) throws AdaptorException; | ||
32 | + | ||
33 | + TransportProtos.GetAttributeRequestMsg convertToGetAttributes(UUID sessionId, Request inbound) throws AdaptorException; | ||
34 | + | ||
35 | + TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(UUID sessionId, Request inbound) throws AdaptorException; | ||
36 | + | ||
37 | + TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(UUID sessionId, Request inbound) throws AdaptorException; | ||
38 | + | ||
39 | + Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException; | ||
40 | + | ||
41 | + Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException; | ||
42 | + | ||
43 | + Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException; | ||
44 | + | ||
45 | + Response convertToPublish(CoapTransportResource.CoapSessionListener coapSessionListener, TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException; | ||
24 | 46 | ||
25 | } | 47 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.coap.adaptors; | ||
17 | + | ||
18 | +import java.util.*; | ||
19 | + | ||
20 | +import com.google.gson.JsonElement; | ||
21 | +import com.google.gson.JsonObject; | ||
22 | +import lombok.extern.slf4j.Slf4j; | ||
23 | +import org.eclipse.californium.core.coap.CoAP; | ||
24 | +import org.eclipse.californium.core.coap.Request; | ||
25 | +import org.eclipse.californium.core.coap.Response; | ||
26 | +import org.springframework.util.StringUtils; | ||
27 | +import org.thingsboard.server.common.msg.kv.AttributesKVMsg; | ||
28 | +import org.thingsboard.server.common.msg.session.SessionContext; | ||
29 | +import org.thingsboard.server.common.transport.adaptor.AdaptorException; | ||
30 | +import org.thingsboard.server.common.transport.adaptor.JsonConverter; | ||
31 | +import org.springframework.stereotype.Component; | ||
32 | + | ||
33 | +import com.google.gson.JsonParser; | ||
34 | +import com.google.gson.JsonSyntaxException; | ||
35 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
36 | +import org.thingsboard.server.transport.coap.CoapTransportResource; | ||
37 | + | ||
38 | +@Component("JsonCoapAdaptor") | ||
39 | +@Slf4j | ||
40 | +public class JsonCoapAdaptor implements CoapTransportAdaptor { | ||
41 | + | ||
42 | + @Override | ||
43 | + public TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, Request inbound) throws AdaptorException { | ||
44 | + String payload = validatePayload(sessionId, inbound); | ||
45 | + try { | ||
46 | + return JsonConverter.convertToTelemetryProto(new JsonParser().parse(payload)); | ||
47 | + } catch (IllegalStateException | JsonSyntaxException ex) { | ||
48 | + throw new AdaptorException(ex); | ||
49 | + } | ||
50 | + } | ||
51 | + | ||
52 | + @Override | ||
53 | + public TransportProtos.PostAttributeMsg convertToPostAttributes(UUID sessionId, Request inbound) throws AdaptorException { | ||
54 | + String payload = validatePayload(sessionId, inbound); | ||
55 | + try { | ||
56 | + return JsonConverter.convertToAttributesProto(new JsonParser().parse(payload)); | ||
57 | + } catch (IllegalStateException | JsonSyntaxException ex) { | ||
58 | + throw new AdaptorException(ex); | ||
59 | + } | ||
60 | + } | ||
61 | + | ||
62 | + @Override | ||
63 | + public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(UUID sessionId, Request inbound) throws AdaptorException { | ||
64 | + List<String> queryElements = inbound.getOptions().getUriQuery(); | ||
65 | + TransportProtos.GetAttributeRequestMsg.Builder result = TransportProtos.GetAttributeRequestMsg.newBuilder(); | ||
66 | + if (queryElements != null && queryElements.size() > 0) { | ||
67 | + Set<String> clientKeys = toKeys(queryElements, "clientKeys"); | ||
68 | + Set<String> sharedKeys = toKeys(queryElements, "sharedKeys"); | ||
69 | + if (clientKeys != null) { | ||
70 | + result.addAllClientAttributeNames(clientKeys); | ||
71 | + } | ||
72 | + if (sharedKeys != null) { | ||
73 | + result.addAllSharedAttributeNames(sharedKeys); | ||
74 | + } | ||
75 | + } | ||
76 | + return result.build(); | ||
77 | + } | ||
78 | + | ||
79 | + @Override | ||
80 | + public TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(UUID sessionId, Request inbound) throws AdaptorException { | ||
81 | + Optional<Integer> requestId = CoapTransportResource.getRequestId(inbound); | ||
82 | + String payload = validatePayload(sessionId, inbound); | ||
83 | + JsonObject response = new JsonParser().parse(payload).getAsJsonObject(); | ||
84 | + return TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId.orElseThrow(() -> new AdaptorException("Request id is missing!"))) | ||
85 | + .setPayload(response.toString()).build(); | ||
86 | + } | ||
87 | + | ||
88 | + @Override | ||
89 | + public TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(UUID sessionId, Request inbound) throws AdaptorException { | ||
90 | + String payload = validatePayload(sessionId, inbound); | ||
91 | + return JsonConverter.convertToServerRpcRequest(new JsonParser().parse(payload), 0); | ||
92 | + } | ||
93 | + | ||
94 | + @Override | ||
95 | + public Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.AttributeUpdateNotificationMsg msg) throws AdaptorException { | ||
96 | + return getObserveNotification(session.getNextSeqNumber(), JsonConverter.toJson(msg)); | ||
97 | + } | ||
98 | + | ||
99 | + @Override | ||
100 | + public Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.ToDeviceRpcRequestMsg msg) throws AdaptorException { | ||
101 | + return getObserveNotification(session.getNextSeqNumber(), JsonConverter.toJson(msg, true)); | ||
102 | + } | ||
103 | + | ||
104 | + @Override | ||
105 | + public Response convertToPublish(CoapTransportResource.CoapSessionListener coapSessionListener, TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException { | ||
106 | + Response response = new Response(CoAP.ResponseCode.CONTENT); | ||
107 | + JsonElement result = JsonConverter.toJson(msg); | ||
108 | + response.setPayload(result.toString()); | ||
109 | + return response; | ||
110 | + } | ||
111 | + | ||
112 | + @Override | ||
113 | + public Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.GetAttributeResponseMsg msg) throws AdaptorException { | ||
114 | + if (msg.getClientAttributeListCount() == 0 && msg.getSharedAttributeListCount() == 0 && msg.getDeletedAttributeKeysCount() == 0) { | ||
115 | + return new Response(CoAP.ResponseCode.NOT_FOUND); | ||
116 | + } else { | ||
117 | + Response response = new Response(CoAP.ResponseCode.CONTENT); | ||
118 | + JsonObject result = JsonConverter.toJson(msg); | ||
119 | + response.setPayload(result.toString()); | ||
120 | + return response; | ||
121 | + } | ||
122 | + } | ||
123 | + | ||
124 | + private Response getObserveNotification(int seqNumber, JsonElement json) { | ||
125 | + Response response = new Response(CoAP.ResponseCode.CONTENT); | ||
126 | + response.getOptions().setObserve(seqNumber); | ||
127 | + response.setPayload(json.toString()); | ||
128 | + return response; | ||
129 | + } | ||
130 | + | ||
131 | + private String validatePayload(UUID sessionId, Request inbound) throws AdaptorException { | ||
132 | + String payload = inbound.getPayloadString(); | ||
133 | + if (payload == null) { | ||
134 | + log.warn("[{}] Payload is empty!", sessionId); | ||
135 | + throw new AdaptorException(new IllegalArgumentException("Payload is empty!")); | ||
136 | + } | ||
137 | + return payload; | ||
138 | + } | ||
139 | + | ||
140 | + private Set<String> toKeys(List<String> queryElements, String attributeName) throws AdaptorException { | ||
141 | + String keys = null; | ||
142 | + for (String queryElement : queryElements) { | ||
143 | + String[] queryItem = queryElement.split("="); | ||
144 | + if (queryItem.length == 2 && queryItem[0].equals(attributeName)) { | ||
145 | + keys = queryItem[1]; | ||
146 | + } | ||
147 | + } | ||
148 | + if (keys != null && !StringUtils.isEmpty(keys)) { | ||
149 | + return new HashSet<>(Arrays.asList(keys.split(","))); | ||
150 | + } else { | ||
151 | + return null; | ||
152 | + } | ||
153 | + } | ||
154 | + | ||
155 | +} |
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DeviceEmulator.java
renamed from
transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DeviceEmulator.java
@@ -43,8 +43,6 @@ public class MqttTransportService { | @@ -43,8 +43,6 @@ public class MqttTransportService { | ||
43 | private String host; | 43 | private String host; |
44 | @Value("${transport.mqtt.bind_port}") | 44 | @Value("${transport.mqtt.bind_port}") |
45 | private Integer port; | 45 | private Integer port; |
46 | - @Value("${transport.mqtt.adaptor}") | ||
47 | - private String adaptorName; | ||
48 | 46 | ||
49 | @Value("${transport.mqtt.netty.leak_detector_level}") | 47 | @Value("${transport.mqtt.netty.leak_detector_level}") |
50 | private String leakDetectorLevel; | 48 | private String leakDetectorLevel; |
@@ -38,7 +38,7 @@ | @@ -38,7 +38,7 @@ | ||
38 | <module>transport-api</module> | 38 | <module>transport-api</module> |
39 | <module>mqtt</module> | 39 | <module>mqtt</module> |
40 | <module>http</module> | 40 | <module>http</module> |
41 | - <!--module>coap</module--> | 41 | + <module>coap</module> |
42 | </modules> | 42 | </modules> |
43 | 43 | ||
44 | </project> | 44 | </project> |
@@ -370,7 +370,7 @@ | @@ -370,7 +370,7 @@ | ||
370 | <version>${project.version}</version> | 370 | <version>${project.version}</version> |
371 | </dependency> | 371 | </dependency> |
372 | <dependency> | 372 | <dependency> |
373 | - <groupId>org.thingsboard.transport</groupId> | 373 | + <groupId>org.thingsboard.common.transport</groupId> |
374 | <artifactId>coap</artifactId> | 374 | <artifactId>coap</artifactId> |
375 | <version>${project.version}</version> | 375 | <version>${project.version}</version> |
376 | </dependency> | 376 | </dependency> |
transport/coap/build.gradle
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +import org.apache.tools.ant.filters.ReplaceTokens | ||
17 | + | ||
18 | +buildscript { | ||
19 | + ext { | ||
20 | + osPackageVersion = "3.8.0" | ||
21 | + } | ||
22 | + repositories { | ||
23 | + jcenter() | ||
24 | + } | ||
25 | + dependencies { | ||
26 | + classpath("com.netflix.nebula:gradle-ospackage-plugin:${osPackageVersion}") | ||
27 | + } | ||
28 | +} | ||
29 | + | ||
30 | +apply plugin: "nebula.ospackage" | ||
31 | + | ||
32 | +buildDir = projectBuildDir | ||
33 | +version = projectVersion | ||
34 | +distsDirName = "./" | ||
35 | + | ||
36 | +// OS Package plugin configuration | ||
37 | +ospackage { | ||
38 | + packageName = pkgName | ||
39 | + version = "${project.version}" | ||
40 | + release = 1 | ||
41 | + os = LINUX | ||
42 | + type = BINARY | ||
43 | + | ||
44 | + into pkgInstallFolder | ||
45 | + | ||
46 | + user pkgName | ||
47 | + permissionGroup pkgName | ||
48 | + | ||
49 | + // Copy the actual .jar file | ||
50 | + from(mainJar) { | ||
51 | + // Strip the version from the jar filename | ||
52 | + rename { String fileName -> | ||
53 | + "${pkgName}.jar" | ||
54 | + } | ||
55 | + fileMode 0500 | ||
56 | + into "bin" | ||
57 | + } | ||
58 | + | ||
59 | + // Copy the config files | ||
60 | + from("target/conf") { | ||
61 | + exclude "${pkgName}.conf" | ||
62 | + fileType CONFIG | NOREPLACE | ||
63 | + fileMode 0754 | ||
64 | + into "conf" | ||
65 | + } | ||
66 | + | ||
67 | +} | ||
68 | + | ||
69 | +// Configure our RPM build task | ||
70 | +buildRpm { | ||
71 | + | ||
72 | + arch = NOARCH | ||
73 | + | ||
74 | + version = projectVersion.replace('-', '') | ||
75 | + archiveName = "${pkgName}.rpm" | ||
76 | + | ||
77 | + requires("java-1.8.0") | ||
78 | + | ||
79 | + from("target/conf") { | ||
80 | + include "${pkgName}.conf" | ||
81 | + filter(ReplaceTokens, tokens: ['pkg.platform': 'rpm']) | ||
82 | + fileType CONFIG | NOREPLACE | ||
83 | + fileMode 0754 | ||
84 | + into "${pkgInstallFolder}/conf" | ||
85 | + } | ||
86 | + | ||
87 | + preInstall file("${buildDir}/control/rpm/preinst") | ||
88 | + postInstall file("${buildDir}/control/rpm/postinst") | ||
89 | + preUninstall file("${buildDir}/control/rpm/prerm") | ||
90 | + postUninstall file("${buildDir}/control/rpm/postrm") | ||
91 | + | ||
92 | + user pkgName | ||
93 | + permissionGroup pkgName | ||
94 | + | ||
95 | + // Copy the system unit files | ||
96 | + from("${buildDir}/control/${pkgName}.service") { | ||
97 | + addParentDirs = false | ||
98 | + fileMode 0644 | ||
99 | + into "/usr/lib/systemd/system" | ||
100 | + } | ||
101 | + | ||
102 | + directory(pkgLogFolder, 0755) | ||
103 | + link("${pkgInstallFolder}/bin/${pkgName}.yml", "${pkgInstallFolder}/conf/${pkgName}.yml") | ||
104 | + link("/etc/${pkgName}/conf", "${pkgInstallFolder}/conf") | ||
105 | +} | ||
106 | + | ||
107 | +// Same as the buildRpm task | ||
108 | +buildDeb { | ||
109 | + | ||
110 | + arch = "all" | ||
111 | + | ||
112 | + archiveName = "${pkgName}.deb" | ||
113 | + | ||
114 | + requires("openjdk-8-jre").or("java8-runtime").or("oracle-java8-installer").or("openjdk-8-jre-headless") | ||
115 | + | ||
116 | + from("target/conf") { | ||
117 | + include "${pkgName}.conf" | ||
118 | + filter(ReplaceTokens, tokens: ['pkg.platform': 'deb']) | ||
119 | + fileType CONFIG | NOREPLACE | ||
120 | + fileMode 0754 | ||
121 | + into "${pkgInstallFolder}/conf" | ||
122 | + } | ||
123 | + | ||
124 | + configurationFile("${pkgInstallFolder}/conf/${pkgName}.conf") | ||
125 | + configurationFile("${pkgInstallFolder}/conf/${pkgName}.yml") | ||
126 | + configurationFile("${pkgInstallFolder}/conf/logback.xml") | ||
127 | + | ||
128 | + preInstall file("${buildDir}/control/deb/preinst") | ||
129 | + postInstall file("${buildDir}/control/deb/postinst") | ||
130 | + preUninstall file("${buildDir}/control/deb/prerm") | ||
131 | + postUninstall file("${buildDir}/control/deb/postrm") | ||
132 | + | ||
133 | + user pkgName | ||
134 | + permissionGroup pkgName | ||
135 | + | ||
136 | + directory(pkgLogFolder, 0755) | ||
137 | + link("/etc/init.d/${pkgName}", "${pkgInstallFolder}/bin/${pkgName}.jar") | ||
138 | + link("${pkgInstallFolder}/bin/${pkgName}.yml", "${pkgInstallFolder}/conf/${pkgName}.yml") | ||
139 | + link("/etc/${pkgName}/conf", "${pkgInstallFolder}/conf") | ||
140 | +} |
@@ -27,42 +27,37 @@ | @@ -27,42 +27,37 @@ | ||
27 | <artifactId>coap</artifactId> | 27 | <artifactId>coap</artifactId> |
28 | <packaging>jar</packaging> | 28 | <packaging>jar</packaging> |
29 | 29 | ||
30 | - <name>Thingsboard COAP Transport</name> | 30 | + <name>Thingsboard CoAP Transport Service</name> |
31 | <url>https://thingsboard.io</url> | 31 | <url>https://thingsboard.io</url> |
32 | 32 | ||
33 | <properties> | 33 | <properties> |
34 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | 34 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
35 | <main.dir>${basedir}/../..</main.dir> | 35 | <main.dir>${basedir}/../..</main.dir> |
36 | + <pkg.name>tb-coap-transport</pkg.name> | ||
37 | + <pkg.unixLogFolder>/var/log/${pkg.name}</pkg.unixLogFolder> | ||
38 | + <pkg.installFolder>/usr/share/${pkg.name}</pkg.installFolder> | ||
39 | + <pkg.win.dist>${project.build.directory}/windows</pkg.win.dist> | ||
36 | </properties> | 40 | </properties> |
37 | 41 | ||
38 | <dependencies> | 42 | <dependencies> |
39 | <dependency> | 43 | <dependency> |
40 | - <groupId>org.thingsboard.common</groupId> | ||
41 | - <artifactId>transport</artifactId> | ||
42 | - </dependency> | ||
43 | - <dependency> | ||
44 | - <groupId>org.eclipse.californium</groupId> | ||
45 | - <artifactId>californium-core</artifactId> | ||
46 | - </dependency> | ||
47 | - <dependency> | ||
48 | - <groupId>org.springframework</groupId> | ||
49 | - <artifactId>spring-context</artifactId> | 44 | + <groupId>org.thingsboard.common.transport</groupId> |
45 | + <artifactId>coap</artifactId> | ||
50 | </dependency> | 46 | </dependency> |
51 | <dependency> | 47 | <dependency> |
52 | - <groupId>org.slf4j</groupId> | ||
53 | - <artifactId>slf4j-api</artifactId> | ||
54 | - </dependency> | ||
55 | - <dependency> | ||
56 | - <groupId>org.slf4j</groupId> | ||
57 | - <artifactId>log4j-over-slf4j</artifactId> | 48 | + <groupId>org.thingsboard.common</groupId> |
49 | + <artifactId>queue</artifactId> | ||
58 | </dependency> | 50 | </dependency> |
59 | <dependency> | 51 | <dependency> |
60 | - <groupId>ch.qos.logback</groupId> | ||
61 | - <artifactId>logback-core</artifactId> | 52 | + <groupId>org.springframework.boot</groupId> |
53 | + <artifactId>spring-boot-starter-web</artifactId> | ||
62 | </dependency> | 54 | </dependency> |
63 | <dependency> | 55 | <dependency> |
64 | - <groupId>ch.qos.logback</groupId> | ||
65 | - <artifactId>logback-classic</artifactId> | 56 | + <groupId>com.sun.winsw</groupId> |
57 | + <artifactId>winsw</artifactId> | ||
58 | + <classifier>bin</classifier> | ||
59 | + <type>exe</type> | ||
60 | + <scope>provided</scope> | ||
66 | </dependency> | 61 | </dependency> |
67 | <dependency> | 62 | <dependency> |
68 | <groupId>org.springframework.boot</groupId> | 63 | <groupId>org.springframework.boot</groupId> |
@@ -81,4 +76,266 @@ | @@ -81,4 +76,266 @@ | ||
81 | </dependency> | 76 | </dependency> |
82 | </dependencies> | 77 | </dependencies> |
83 | 78 | ||
79 | + <build> | ||
80 | + <finalName>${pkg.name}-${project.version}</finalName> | ||
81 | + <resources> | ||
82 | + <resource> | ||
83 | + <directory>${project.basedir}/src/main/resources</directory> | ||
84 | + </resource> | ||
85 | + </resources> | ||
86 | + <plugins> | ||
87 | + <plugin> | ||
88 | + <groupId>org.apache.maven.plugins</groupId> | ||
89 | + <artifactId>maven-resources-plugin</artifactId> | ||
90 | + <executions> | ||
91 | + <execution> | ||
92 | + <id>copy-conf</id> | ||
93 | + <phase>process-resources</phase> | ||
94 | + <goals> | ||
95 | + <goal>copy-resources</goal> | ||
96 | + </goals> | ||
97 | + <configuration> | ||
98 | + <outputDirectory>${project.build.directory}/conf</outputDirectory> | ||
99 | + <resources> | ||
100 | + <resource> | ||
101 | + <directory>src/main/resources</directory> | ||
102 | + <excludes> | ||
103 | + <exclude>logback.xml</exclude> | ||
104 | + </excludes> | ||
105 | + <filtering>false</filtering> | ||
106 | + </resource> | ||
107 | + </resources> | ||
108 | + </configuration> | ||
109 | + </execution> | ||
110 | + <execution> | ||
111 | + <id>copy-service-conf</id> | ||
112 | + <phase>process-resources</phase> | ||
113 | + <goals> | ||
114 | + <goal>copy-resources</goal> | ||
115 | + </goals> | ||
116 | + <configuration> | ||
117 | + <outputDirectory>${project.build.directory}/conf</outputDirectory> | ||
118 | + <resources> | ||
119 | + <resource> | ||
120 | + <directory>src/main/conf</directory> | ||
121 | + <filtering>true</filtering> | ||
122 | + </resource> | ||
123 | + </resources> | ||
124 | + <filters> | ||
125 | + <filter>src/main/filters/unix.properties</filter> | ||
126 | + </filters> | ||
127 | + </configuration> | ||
128 | + </execution> | ||
129 | + <execution> | ||
130 | + <id>copy-win-conf</id> | ||
131 | + <phase>process-resources</phase> | ||
132 | + <goals> | ||
133 | + <goal>copy-resources</goal> | ||
134 | + </goals> | ||
135 | + <configuration> | ||
136 | + <outputDirectory>${pkg.win.dist}/conf</outputDirectory> | ||
137 | + <resources> | ||
138 | + <resource> | ||
139 | + <directory>src/main/resources</directory> | ||
140 | + <excludes> | ||
141 | + <exclude>logback.xml</exclude> | ||
142 | + </excludes> | ||
143 | + <filtering>false</filtering> | ||
144 | + </resource> | ||
145 | + <resource> | ||
146 | + <directory>src/main/conf</directory> | ||
147 | + <excludes> | ||
148 | + <exclude>tb-coap-transport.conf</exclude> | ||
149 | + </excludes> | ||
150 | + <filtering>true</filtering> | ||
151 | + </resource> | ||
152 | + </resources> | ||
153 | + <filters> | ||
154 | + <filter>src/main/filters/windows.properties</filter> | ||
155 | + </filters> | ||
156 | + </configuration> | ||
157 | + </execution> | ||
158 | + <execution> | ||
159 | + <id>copy-control</id> | ||
160 | + <phase>process-resources</phase> | ||
161 | + <goals> | ||
162 | + <goal>copy-resources</goal> | ||
163 | + </goals> | ||
164 | + <configuration> | ||
165 | + <outputDirectory>${project.build.directory}/control</outputDirectory> | ||
166 | + <resources> | ||
167 | + <resource> | ||
168 | + <directory>src/main/scripts/control</directory> | ||
169 | + <filtering>true</filtering> | ||
170 | + </resource> | ||
171 | + </resources> | ||
172 | + <filters> | ||
173 | + <filter>src/main/filters/unix.properties</filter> | ||
174 | + </filters> | ||
175 | + </configuration> | ||
176 | + </execution> | ||
177 | + <execution> | ||
178 | + <id>copy-windows-control</id> | ||
179 | + <phase>process-resources</phase> | ||
180 | + <goals> | ||
181 | + <goal>copy-resources</goal> | ||
182 | + </goals> | ||
183 | + <configuration> | ||
184 | + <outputDirectory>${pkg.win.dist}</outputDirectory> | ||
185 | + <resources> | ||
186 | + <resource> | ||
187 | + <directory>src/main/scripts/windows</directory> | ||
188 | + <filtering>true</filtering> | ||
189 | + </resource> | ||
190 | + </resources> | ||
191 | + <filters> | ||
192 | + <filter>src/main/filters/windows.properties</filter> | ||
193 | + </filters> | ||
194 | + </configuration> | ||
195 | + </execution> | ||
196 | + </executions> | ||
197 | + </plugin> | ||
198 | + <plugin> | ||
199 | + <groupId>org.apache.maven.plugins</groupId> | ||
200 | + <artifactId>maven-dependency-plugin</artifactId> | ||
201 | + <executions> | ||
202 | + <execution> | ||
203 | + <id>copy-winsw-service</id> | ||
204 | + <phase>package</phase> | ||
205 | + <goals> | ||
206 | + <goal>copy</goal> | ||
207 | + </goals> | ||
208 | + <configuration> | ||
209 | + <artifactItems> | ||
210 | + <artifactItem> | ||
211 | + <groupId>com.sun.winsw</groupId> | ||
212 | + <artifactId>winsw</artifactId> | ||
213 | + <classifier>bin</classifier> | ||
214 | + <type>exe</type> | ||
215 | + <destFileName>service.exe</destFileName> | ||
216 | + </artifactItem> | ||
217 | + </artifactItems> | ||
218 | + <outputDirectory>${pkg.win.dist}</outputDirectory> | ||
219 | + </configuration> | ||
220 | + </execution> | ||
221 | + </executions> | ||
222 | + </plugin> | ||
223 | + <plugin> | ||
224 | + <groupId>org.apache.maven.plugins</groupId> | ||
225 | + <artifactId>maven-jar-plugin</artifactId> | ||
226 | + <configuration> | ||
227 | + <excludes> | ||
228 | + <exclude>**/logback.xml</exclude> | ||
229 | + </excludes> | ||
230 | + <archive> | ||
231 | + <manifestEntries> | ||
232 | + <Implementation-Title>ThingsBoard CoAP Transport Service</Implementation-Title> | ||
233 | + <Implementation-Version>${project.version}</Implementation-Version> | ||
234 | + </manifestEntries> | ||
235 | + </archive> | ||
236 | + </configuration> | ||
237 | + </plugin> | ||
238 | + <plugin> | ||
239 | + <groupId>org.springframework.boot</groupId> | ||
240 | + <artifactId>spring-boot-maven-plugin</artifactId> | ||
241 | + <configuration> | ||
242 | + <mainClass>org.thingsboard.server.coap.ThingsboardCoapTransportApplication</mainClass> | ||
243 | + <classifier>boot</classifier> | ||
244 | + <layout>ZIP</layout> | ||
245 | + <executable>true</executable> | ||
246 | + <excludeDevtools>true</excludeDevtools> | ||
247 | + <embeddedLaunchScriptProperties> | ||
248 | + <confFolder>${pkg.installFolder}/conf</confFolder> | ||
249 | + <logFolder>${pkg.unixLogFolder}</logFolder> | ||
250 | + <logFilename>${pkg.name}.out</logFilename> | ||
251 | + <initInfoProvides>${pkg.name}</initInfoProvides> | ||
252 | + </embeddedLaunchScriptProperties> | ||
253 | + </configuration> | ||
254 | + <executions> | ||
255 | + <execution> | ||
256 | + <goals> | ||
257 | + <goal>repackage</goal> | ||
258 | + </goals> | ||
259 | + </execution> | ||
260 | + </executions> | ||
261 | + </plugin> | ||
262 | + <plugin> | ||
263 | + <groupId>org.fortasoft</groupId> | ||
264 | + <artifactId>gradle-maven-plugin</artifactId> | ||
265 | + <configuration> | ||
266 | + <tasks> | ||
267 | + <task>build</task> | ||
268 | + <task>buildDeb</task> | ||
269 | + <task>buildRpm</task> | ||
270 | + </tasks> | ||
271 | + <args> | ||
272 | + <arg>-PprojectBuildDir=${project.build.directory}</arg> | ||
273 | + <arg>-PprojectVersion=${project.version}</arg> | ||
274 | + <arg>-PmainJar=${project.build.directory}/${project.build.finalName}-boot.${project.packaging}</arg> | ||
275 | + <arg>-PpkgName=${pkg.name}</arg> | ||
276 | + <arg>-PpkgInstallFolder=${pkg.installFolder}</arg> | ||
277 | + <arg>-PpkgLogFolder=${pkg.unixLogFolder}</arg> | ||
278 | + </args> | ||
279 | + </configuration> | ||
280 | + <executions> | ||
281 | + <execution> | ||
282 | + <phase>package</phase> | ||
283 | + <goals> | ||
284 | + <goal>invoke</goal> | ||
285 | + </goals> | ||
286 | + </execution> | ||
287 | + </executions> | ||
288 | + </plugin> | ||
289 | + <plugin> | ||
290 | + <groupId>org.apache.maven.plugins</groupId> | ||
291 | + <artifactId>maven-assembly-plugin</artifactId> | ||
292 | + <configuration> | ||
293 | + <finalName>${pkg.name}</finalName> | ||
294 | + <descriptors> | ||
295 | + <descriptor>src/main/assembly/windows.xml</descriptor> | ||
296 | + </descriptors> | ||
297 | + </configuration> | ||
298 | + <executions> | ||
299 | + <execution> | ||
300 | + <id>assembly</id> | ||
301 | + <phase>package</phase> | ||
302 | + <goals> | ||
303 | + <goal>single</goal> | ||
304 | + </goals> | ||
305 | + </execution> | ||
306 | + </executions> | ||
307 | + </plugin> | ||
308 | + <plugin> | ||
309 | + <groupId>org.apache.maven.plugins</groupId> | ||
310 | + <artifactId>maven-install-plugin</artifactId> | ||
311 | + <configuration> | ||
312 | + <file>${project.build.directory}/${pkg.name}.deb</file> | ||
313 | + <artifactId>${project.artifactId}</artifactId> | ||
314 | + <groupId>${project.groupId}</groupId> | ||
315 | + <version>${project.version}</version> | ||
316 | + <classifier>deb</classifier> | ||
317 | + <packaging>deb</packaging> | ||
318 | + </configuration> | ||
319 | + <executions> | ||
320 | + <execution> | ||
321 | + <id>install-deb</id> | ||
322 | + <phase>package</phase> | ||
323 | + <goals> | ||
324 | + <goal>install-file</goal> | ||
325 | + </goals> | ||
326 | + </execution> | ||
327 | + </executions> | ||
328 | + </plugin> | ||
329 | + </plugins> | ||
330 | + </build> | ||
331 | + <repositories> | ||
332 | + <repository> | ||
333 | + <id>jenkins</id> | ||
334 | + <name>Jenkins Repository</name> | ||
335 | + <url>http://repo.jenkins-ci.org/releases</url> | ||
336 | + <snapshots> | ||
337 | + <enabled>false</enabled> | ||
338 | + </snapshots> | ||
339 | + </repository> | ||
340 | + </repositories> | ||
84 | </project> | 341 | </project> |
transport/coap/src/main/assembly/windows.xml
0 → 100644
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2018 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3" | ||
19 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
20 | + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd"> | ||
21 | + <id>windows</id> | ||
22 | + | ||
23 | + <formats> | ||
24 | + <format>zip</format> | ||
25 | + </formats> | ||
26 | + | ||
27 | + <!-- Workaround to create logs directory --> | ||
28 | + <fileSets> | ||
29 | + <fileSet> | ||
30 | + <directory>${pkg.win.dist}</directory> | ||
31 | + <outputDirectory>logs</outputDirectory> | ||
32 | + <excludes> | ||
33 | + <exclude>*/**</exclude> | ||
34 | + </excludes> | ||
35 | + </fileSet> | ||
36 | + <fileSet> | ||
37 | + <directory>${pkg.win.dist}/conf</directory> | ||
38 | + <outputDirectory>conf</outputDirectory> | ||
39 | + <lineEnding>windows</lineEnding> | ||
40 | + </fileSet> | ||
41 | + </fileSets> | ||
42 | + | ||
43 | + <files> | ||
44 | + <file> | ||
45 | + <source>${project.build.directory}/${project.build.finalName}-boot.${project.packaging}</source> | ||
46 | + <outputDirectory>lib</outputDirectory> | ||
47 | + <destName>${pkg.name}.jar</destName> | ||
48 | + </file> | ||
49 | + <file> | ||
50 | + <source>${pkg.win.dist}/service.exe</source> | ||
51 | + <outputDirectory/> | ||
52 | + <destName>${pkg.name}.exe</destName> | ||
53 | + </file> | ||
54 | + <file> | ||
55 | + <source>${pkg.win.dist}/service.xml</source> | ||
56 | + <outputDirectory/> | ||
57 | + <destName>${pkg.name}.xml</destName> | ||
58 | + <lineEnding>windows</lineEnding> | ||
59 | + </file> | ||
60 | + <file> | ||
61 | + <source>${pkg.win.dist}/install.bat</source> | ||
62 | + <outputDirectory/> | ||
63 | + <lineEnding>windows</lineEnding> | ||
64 | + </file> | ||
65 | + <file> | ||
66 | + <source>${pkg.win.dist}/uninstall.bat</source> | ||
67 | + <outputDirectory/> | ||
68 | + <lineEnding>windows</lineEnding> | ||
69 | + </file> | ||
70 | + </files> | ||
71 | +</assembly> |
transport/coap/src/main/conf/logback.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8" ?> | ||
2 | +<!-- | ||
3 | + | ||
4 | + Copyright © 2016-2018 The Thingsboard Authors | ||
5 | + | ||
6 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
7 | + you may not use this file except in compliance with the License. | ||
8 | + You may obtain a copy of the License at | ||
9 | + | ||
10 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | + | ||
12 | + Unless required by applicable law or agreed to in writing, software | ||
13 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
14 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
15 | + See the License for the specific language governing permissions and | ||
16 | + limitations under the License. | ||
17 | + | ||
18 | +--> | ||
19 | +<!DOCTYPE configuration> | ||
20 | +<configuration> | ||
21 | + | ||
22 | + <appender name="fileLogAppender" | ||
23 | + class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||
24 | + <file>${pkg.logFolder}/${pkg.name}.log</file> | ||
25 | + <rollingPolicy | ||
26 | + class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | ||
27 | + <fileNamePattern>${pkg.logFolder}/${pkg.name}.%d{yyyy-MM-dd}.%i.log</fileNamePattern> | ||
28 | + <maxFileSize>100MB</maxFileSize> | ||
29 | + <maxHistory>30</maxHistory> | ||
30 | + <totalSizeCap>3GB</totalSizeCap> | ||
31 | + </rollingPolicy> | ||
32 | + <encoder> | ||
33 | + <pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern> | ||
34 | + </encoder> | ||
35 | + </appender> | ||
36 | + | ||
37 | + <logger name="org.thingsboard.server" level="INFO" /> | ||
38 | + | ||
39 | + <root level="INFO"> | ||
40 | + <appender-ref ref="fileLogAppender"/> | ||
41 | + </root> | ||
42 | + | ||
43 | +</configuration> |
1 | +# | ||
2 | +# Copyright © 2016-2018 The Thingsboard Authors | ||
3 | +# | ||
4 | +# Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +# you may not use this file except in compliance with the License. | ||
6 | +# You may obtain a copy of the License at | ||
7 | +# | ||
8 | +# http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +# | ||
10 | +# Unless required by applicable law or agreed to in writing, software | ||
11 | +# distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +# See the License for the specific language governing permissions and | ||
14 | +# limitations under the License. | ||
15 | +# | ||
16 | + | ||
17 | +export JAVA_OPTS="$JAVA_OPTS -Xloggc:@pkg.logFolder@/gc.log -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails -XX:+PrintGCDateStamps" | ||
18 | +export JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10" | ||
19 | +export JAVA_OPTS="$JAVA_OPTS -XX:GCLogFileSize=10M -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" | ||
20 | +export JAVA_OPTS="$JAVA_OPTS -XX:CMSWaitDuration=10000 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+CMSParallelInitialMarkEnabled" | ||
21 | +export JAVA_OPTS="$JAVA_OPTS -XX:+CMSEdenChunksRecordAlways -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly" | ||
22 | +export LOG_FILENAME=${pkg.name}.out | ||
23 | +export LOADER_PATH=${pkg.installFolder}/conf |
1 | +pkg.logFolder=${pkg.unixLogFolder} |
transport/coap/src/main/java/org/thingsboard/server/coap/ThingsboardCoapTransportApplication.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.coap; | ||
17 | + | ||
18 | +import org.springframework.boot.SpringApplication; | ||
19 | +import org.springframework.boot.SpringBootConfiguration; | ||
20 | +import org.springframework.context.annotation.ComponentScan; | ||
21 | +import org.springframework.scheduling.annotation.EnableAsync; | ||
22 | +import org.springframework.scheduling.annotation.EnableScheduling; | ||
23 | + | ||
24 | +import java.util.Arrays; | ||
25 | + | ||
26 | +@SpringBootConfiguration | ||
27 | +@EnableAsync | ||
28 | +@EnableScheduling | ||
29 | +@ComponentScan({"org.thingsboard.server.coap", "org.thingsboard.server.common", "org.thingsboard.server.transport.coap", "org.thingsboard.server.kafka"}) | ||
30 | +public class ThingsboardCoapTransportApplication { | ||
31 | + | ||
32 | + private static final String SPRING_CONFIG_NAME_KEY = "--spring.config.name"; | ||
33 | + private static final String DEFAULT_SPRING_CONFIG_PARAM = SPRING_CONFIG_NAME_KEY + "=" + "tb-coap-transport"; | ||
34 | + | ||
35 | + public static void main(String[] args) { | ||
36 | + SpringApplication.run(ThingsboardCoapTransportApplication.class, updateArguments(args)); | ||
37 | + } | ||
38 | + | ||
39 | + private static String[] updateArguments(String[] args) { | ||
40 | + if (Arrays.stream(args).noneMatch(arg -> arg.startsWith(SPRING_CONFIG_NAME_KEY))) { | ||
41 | + String[] modifiedArgs = new String[args.length + 1]; | ||
42 | + System.arraycopy(args, 0, modifiedArgs, 0, args.length); | ||
43 | + modifiedArgs[args.length] = DEFAULT_SPRING_CONFIG_PARAM; | ||
44 | + return modifiedArgs; | ||
45 | + } | ||
46 | + return args; | ||
47 | + } | ||
48 | +} |
transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.transport.coap; | ||
17 | - | ||
18 | -import java.lang.reflect.Field; | ||
19 | -import java.util.List; | ||
20 | -import java.util.Optional; | ||
21 | - | ||
22 | -import lombok.extern.slf4j.Slf4j; | ||
23 | -import org.eclipse.californium.core.CoapResource; | ||
24 | -import org.eclipse.californium.core.coap.CoAP.ResponseCode; | ||
25 | -import org.eclipse.californium.core.coap.Request; | ||
26 | -import org.eclipse.californium.core.network.Exchange; | ||
27 | -import org.eclipse.californium.core.network.ExchangeObserver; | ||
28 | -import org.eclipse.californium.core.server.resources.CoapExchange; | ||
29 | -import org.eclipse.californium.core.server.resources.Resource; | ||
30 | -import org.thingsboard.server.common.data.security.DeviceCredentialsFilter; | ||
31 | -import org.thingsboard.server.common.data.security.DeviceTokenCredentials; | ||
32 | -import org.thingsboard.server.common.msg.session.*; | ||
33 | -import org.thingsboard.server.common.transport.SessionMsgProcessor; | ||
34 | -import org.thingsboard.server.common.transport.adaptor.AdaptorException; | ||
35 | -import org.thingsboard.server.common.transport.auth.DeviceAuthService; | ||
36 | -import org.thingsboard.server.common.transport.quota.QuotaService; | ||
37 | -import org.thingsboard.server.transport.coap.adaptors.CoapTransportAdaptor; | ||
38 | -import org.thingsboard.server.transport.coap.session.CoapExchangeObserverProxy; | ||
39 | -import org.thingsboard.server.transport.coap.session.CoapSessionCtx; | ||
40 | -import org.springframework.util.ReflectionUtils; | ||
41 | - | ||
42 | -@Slf4j | ||
43 | -public class CoapTransportResource extends CoapResource { | ||
44 | - // coap://localhost:port/api/v1/DEVICE_TOKEN/[attributes|telemetry|rpc[/requestId]] | ||
45 | - private static final int ACCESS_TOKEN_POSITION = 3; | ||
46 | - private static final int FEATURE_TYPE_POSITION = 4; | ||
47 | - private static final int REQUEST_ID_POSITION = 5; | ||
48 | - | ||
49 | - private final CoapTransportAdaptor adaptor; | ||
50 | - private final SessionMsgProcessor processor; | ||
51 | - private final DeviceAuthService authService; | ||
52 | - private final QuotaService quotaService; | ||
53 | - private final Field observerField; | ||
54 | - private final long timeout; | ||
55 | - | ||
56 | - public CoapTransportResource(SessionMsgProcessor processor, DeviceAuthService authService, CoapTransportAdaptor adaptor, String name, | ||
57 | - long timeout, QuotaService quotaService) { | ||
58 | - super(name); | ||
59 | - this.processor = processor; | ||
60 | - this.authService = authService; | ||
61 | - this.quotaService = quotaService; | ||
62 | - this.adaptor = adaptor; | ||
63 | - this.timeout = timeout; | ||
64 | - // This is important to turn off existing observable logic in | ||
65 | - // CoapResource. We will have our own observe monitoring due to 1:1 | ||
66 | - // observe relationship. | ||
67 | - this.setObservable(false); | ||
68 | - observerField = ReflectionUtils.findField(Exchange.class, "observer"); | ||
69 | - observerField.setAccessible(true); | ||
70 | - } | ||
71 | - | ||
72 | - @Override | ||
73 | - public void handleGET(CoapExchange exchange) { | ||
74 | - if(quotaService.isQuotaExceeded(exchange.getSourceAddress().getHostAddress())) { | ||
75 | - log.warn("COAP Quota exceeded for [{}:{}] . Disconnect", exchange.getSourceAddress().getHostAddress(), exchange.getSourcePort()); | ||
76 | - exchange.respond(ResponseCode.BAD_REQUEST); | ||
77 | - return; | ||
78 | - } | ||
79 | - | ||
80 | - Optional<FeatureType> featureType = getFeatureType(exchange.advanced().getRequest()); | ||
81 | - if (!featureType.isPresent()) { | ||
82 | - log.trace("Missing feature type parameter"); | ||
83 | - exchange.respond(ResponseCode.BAD_REQUEST); | ||
84 | - } else if (featureType.get() == FeatureType.TELEMETRY) { | ||
85 | - log.trace("Can't fetch/subscribe to timeseries updates"); | ||
86 | - exchange.respond(ResponseCode.BAD_REQUEST); | ||
87 | - } else if (exchange.getRequestOptions().hasObserve()) { | ||
88 | - processExchangeGetRequest(exchange, featureType.get()); | ||
89 | - } else if (featureType.get() == FeatureType.ATTRIBUTES) { | ||
90 | - processRequest(exchange, SessionMsgType.GET_ATTRIBUTES_REQUEST); | ||
91 | - } else { | ||
92 | - log.trace("Invalid feature type parameter"); | ||
93 | - exchange.respond(ResponseCode.BAD_REQUEST); | ||
94 | - } | ||
95 | - } | ||
96 | - | ||
97 | - private void processExchangeGetRequest(CoapExchange exchange, FeatureType featureType) { | ||
98 | - boolean unsubscribe = exchange.getRequestOptions().getObserve() == 1; | ||
99 | - SessionMsgType sessionMsgType; | ||
100 | - if (featureType == FeatureType.RPC) { | ||
101 | - sessionMsgType = unsubscribe ? SessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST : SessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST; | ||
102 | - } else { | ||
103 | - sessionMsgType = unsubscribe ? SessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST : SessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST; | ||
104 | - } | ||
105 | - Optional<SessionId> sessionId = processRequest(exchange, sessionMsgType); | ||
106 | - if (sessionId.isPresent()) { | ||
107 | - if (exchange.getRequestOptions().getObserve() == 1) { | ||
108 | - exchange.respond(ResponseCode.VALID); | ||
109 | - } | ||
110 | - } | ||
111 | - } | ||
112 | - | ||
113 | - @Override | ||
114 | - public void handlePOST(CoapExchange exchange) { | ||
115 | - if(quotaService.isQuotaExceeded(exchange.getSourceAddress().getHostAddress())) { | ||
116 | - log.warn("COAP Quota exceeded for [{}:{}] . Disconnect", exchange.getSourceAddress().getHostAddress(), exchange.getSourcePort()); | ||
117 | - exchange.respond(ResponseCode.BAD_REQUEST); | ||
118 | - return; | ||
119 | - } | ||
120 | - | ||
121 | - Optional<FeatureType> featureType = getFeatureType(exchange.advanced().getRequest()); | ||
122 | - if (!featureType.isPresent()) { | ||
123 | - log.trace("Missing feature type parameter"); | ||
124 | - exchange.respond(ResponseCode.BAD_REQUEST); | ||
125 | - } else { | ||
126 | - switch (featureType.get()) { | ||
127 | - case ATTRIBUTES: | ||
128 | - processRequest(exchange, SessionMsgType.POST_ATTRIBUTES_REQUEST); | ||
129 | - break; | ||
130 | - case TELEMETRY: | ||
131 | - processRequest(exchange, SessionMsgType.POST_TELEMETRY_REQUEST); | ||
132 | - break; | ||
133 | - case RPC: | ||
134 | - Optional<Integer> requestId = getRequestId(exchange.advanced().getRequest()); | ||
135 | - if (requestId.isPresent()) { | ||
136 | - processRequest(exchange, SessionMsgType.TO_DEVICE_RPC_RESPONSE); | ||
137 | - } else { | ||
138 | - processRequest(exchange, SessionMsgType.TO_SERVER_RPC_REQUEST); | ||
139 | - } | ||
140 | - break; | ||
141 | - } | ||
142 | - } | ||
143 | - } | ||
144 | - | ||
145 | - private Optional<SessionId> processRequest(CoapExchange exchange, SessionMsgType type) { | ||
146 | - log.trace("Processing {}", exchange.advanced().getRequest()); | ||
147 | - exchange.accept(); | ||
148 | - Exchange advanced = exchange.advanced(); | ||
149 | - Request request = advanced.getRequest(); | ||
150 | - | ||
151 | - Optional<DeviceCredentialsFilter> credentials = decodeCredentials(request); | ||
152 | - if (!credentials.isPresent()) { | ||
153 | - exchange.respond(ResponseCode.BAD_REQUEST); | ||
154 | - return Optional.empty(); | ||
155 | - } | ||
156 | - | ||
157 | - CoapSessionCtx ctx = new CoapSessionCtx(exchange, adaptor, processor, authService, timeout); | ||
158 | - | ||
159 | -// if (!ctx.login(credentials.get())) { | ||
160 | -// exchange.respond(ResponseCode.UNAUTHORIZED); | ||
161 | -// return Optional.empty(); | ||
162 | -// } | ||
163 | - | ||
164 | - AdaptorToSessionActorMsg msg; | ||
165 | - try { | ||
166 | - switch (type) { | ||
167 | - case GET_ATTRIBUTES_REQUEST: | ||
168 | - case POST_ATTRIBUTES_REQUEST: | ||
169 | - case POST_TELEMETRY_REQUEST: | ||
170 | - case TO_DEVICE_RPC_RESPONSE: | ||
171 | - case TO_SERVER_RPC_REQUEST: | ||
172 | - ctx.setSessionType(SessionType.SYNC); | ||
173 | - msg = adaptor.convertToActorMsg(ctx, type, request); | ||
174 | - break; | ||
175 | - case SUBSCRIBE_ATTRIBUTES_REQUEST: | ||
176 | - case SUBSCRIBE_RPC_COMMANDS_REQUEST: | ||
177 | - ExchangeObserver systemObserver = (ExchangeObserver) observerField.get(advanced); | ||
178 | - advanced.setObserver(new CoapExchangeObserverProxy(systemObserver, ctx)); | ||
179 | - ctx.setSessionType(SessionType.ASYNC); | ||
180 | - msg = adaptor.convertToActorMsg(ctx, type, request); | ||
181 | - break; | ||
182 | - case UNSUBSCRIBE_ATTRIBUTES_REQUEST: | ||
183 | - case UNSUBSCRIBE_RPC_COMMANDS_REQUEST: | ||
184 | - ctx.setSessionType(SessionType.ASYNC); | ||
185 | - msg = adaptor.convertToActorMsg(ctx, type, request); | ||
186 | - break; | ||
187 | - default: | ||
188 | - log.trace("[{}] Unsupported msg type: {}", ctx.getSessionId(), type); | ||
189 | - throw new IllegalArgumentException("Unsupported msg type: " + type); | ||
190 | - } | ||
191 | - log.trace("Processing msg: {}", msg); | ||
192 | -// processor.process(new BasicTransportToDeviceSessionActorMsg(ctx.getDevice(), msg)); | ||
193 | - } catch (AdaptorException e) { | ||
194 | - log.debug("Failed to decode payload {}", e); | ||
195 | - exchange.respond(ResponseCode.BAD_REQUEST, e.getMessage()); | ||
196 | - return Optional.empty(); | ||
197 | - } catch (IllegalArgumentException | IllegalAccessException e) { | ||
198 | - log.debug("Failed to process payload {}", e); | ||
199 | - exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR, e.getMessage()); | ||
200 | - } | ||
201 | - return Optional.of(ctx.getSessionId()); | ||
202 | - } | ||
203 | - | ||
204 | - private Optional<DeviceCredentialsFilter> decodeCredentials(Request request) { | ||
205 | - List<String> uriPath = request.getOptions().getUriPath(); | ||
206 | - DeviceCredentialsFilter credentials = null; | ||
207 | - if (uriPath.size() >= ACCESS_TOKEN_POSITION) { | ||
208 | - credentials = new DeviceTokenCredentials(uriPath.get(ACCESS_TOKEN_POSITION - 1)); | ||
209 | - } | ||
210 | - return Optional.ofNullable(credentials); | ||
211 | - } | ||
212 | - | ||
213 | - private Optional<FeatureType> getFeatureType(Request request) { | ||
214 | - List<String> uriPath = request.getOptions().getUriPath(); | ||
215 | - try { | ||
216 | - if (uriPath.size() >= FEATURE_TYPE_POSITION) { | ||
217 | - return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION - 1).toUpperCase())); | ||
218 | - } | ||
219 | - } catch (RuntimeException e) { | ||
220 | - log.warn("Failed to decode feature type: {}", uriPath); | ||
221 | - } | ||
222 | - return Optional.empty(); | ||
223 | - } | ||
224 | - | ||
225 | - public static Optional<Integer> getRequestId(Request request) { | ||
226 | - List<String> uriPath = request.getOptions().getUriPath(); | ||
227 | - try { | ||
228 | - if (uriPath.size() >= REQUEST_ID_POSITION) { | ||
229 | - return Optional.of(Integer.valueOf(uriPath.get(REQUEST_ID_POSITION - 1))); | ||
230 | - } | ||
231 | - } catch (RuntimeException e) { | ||
232 | - log.warn("Failed to decode feature type: {}", uriPath); | ||
233 | - } | ||
234 | - return Optional.empty(); | ||
235 | - } | ||
236 | - | ||
237 | - @Override | ||
238 | - public Resource getChild(String name) { | ||
239 | - return this; | ||
240 | - } | ||
241 | - | ||
242 | -} |
transport/coap/src/main/java/org/thingsboard/server/transport/coap/adaptors/JsonCoapAdaptor.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.transport.coap.adaptors; | ||
17 | - | ||
18 | -import java.util.*; | ||
19 | - | ||
20 | -import lombok.extern.slf4j.Slf4j; | ||
21 | -import org.eclipse.californium.core.coap.CoAP.ResponseCode; | ||
22 | -import org.eclipse.californium.core.coap.Request; | ||
23 | -import org.eclipse.californium.core.coap.Response; | ||
24 | -import org.springframework.util.StringUtils; | ||
25 | -import org.thingsboard.server.common.msg.core.*; | ||
26 | -import org.thingsboard.server.common.msg.kv.AttributesKVMsg; | ||
27 | -import org.thingsboard.server.common.msg.session.SessionMsgType; | ||
28 | -import org.thingsboard.server.common.msg.session.SessionContext; | ||
29 | -import org.thingsboard.server.common.msg.session.ex.ProcessingTimeoutException; | ||
30 | -import org.thingsboard.server.common.transport.adaptor.AdaptorException; | ||
31 | -import org.thingsboard.server.common.transport.adaptor.JsonConverter; | ||
32 | -import org.springframework.stereotype.Component; | ||
33 | - | ||
34 | -import com.google.gson.JsonObject; | ||
35 | -import com.google.gson.JsonParser; | ||
36 | -import com.google.gson.JsonSyntaxException; | ||
37 | -import org.thingsboard.server.transport.coap.CoapTransportResource; | ||
38 | -import org.thingsboard.server.transport.coap.session.CoapSessionCtx; | ||
39 | - | ||
40 | -@Component("JsonCoapAdaptor") | ||
41 | -@Slf4j | ||
42 | -public class JsonCoapAdaptor implements CoapTransportAdaptor { | ||
43 | - | ||
44 | - @Override | ||
45 | - public AdaptorToSessionActorMsg convertToActorMsg(CoapSessionCtx ctx, SessionMsgType type, Request inbound) throws AdaptorException { | ||
46 | - FromDeviceMsg msg = null; | ||
47 | - switch (type) { | ||
48 | - case POST_TELEMETRY_REQUEST: | ||
49 | - msg = convertToTelemetryUploadRequest(ctx, inbound); | ||
50 | - break; | ||
51 | - case POST_ATTRIBUTES_REQUEST: | ||
52 | - msg = convertToUpdateAttributesRequest(ctx, inbound); | ||
53 | - break; | ||
54 | - case GET_ATTRIBUTES_REQUEST: | ||
55 | - msg = convertToGetAttributesRequest(ctx, inbound); | ||
56 | - break; | ||
57 | - case SUBSCRIBE_RPC_COMMANDS_REQUEST: | ||
58 | - msg = new RpcSubscribeMsg(); | ||
59 | - break; | ||
60 | - case UNSUBSCRIBE_RPC_COMMANDS_REQUEST: | ||
61 | - msg = new RpcUnsubscribeMsg(); | ||
62 | - break; | ||
63 | - case TO_DEVICE_RPC_RESPONSE: | ||
64 | - msg = convertToDeviceRpcResponse(ctx, inbound); | ||
65 | - break; | ||
66 | - case TO_SERVER_RPC_REQUEST: | ||
67 | - msg = convertToServerRpcRequest(ctx, inbound); | ||
68 | - break; | ||
69 | - case SUBSCRIBE_ATTRIBUTES_REQUEST: | ||
70 | - msg = new AttributesSubscribeMsg(); | ||
71 | - break; | ||
72 | - case UNSUBSCRIBE_ATTRIBUTES_REQUEST: | ||
73 | - msg = new AttributesUnsubscribeMsg(); | ||
74 | - break; | ||
75 | - default: | ||
76 | - log.warn("[{}] Unsupported msg type: {}!", ctx.getSessionId(), type); | ||
77 | - throw new AdaptorException(new IllegalArgumentException("Unsupported msg type: " + type + "!")); | ||
78 | - } | ||
79 | - return new BasicAdaptorToSessionActorMsg(ctx, msg); | ||
80 | - } | ||
81 | - | ||
82 | - private FromDeviceMsg convertToDeviceRpcResponse(CoapSessionCtx ctx, Request inbound) throws AdaptorException { | ||
83 | - Optional<Integer> requestId = CoapTransportResource.getRequestId(inbound); | ||
84 | - String payload = validatePayload(ctx, inbound); | ||
85 | - JsonObject response = new JsonParser().parse(payload).getAsJsonObject(); | ||
86 | - return new ToDeviceRpcResponseMsg( | ||
87 | - requestId.orElseThrow(() -> new AdaptorException("Request id is missing!")), | ||
88 | - response.get("response").toString()); | ||
89 | - } | ||
90 | - | ||
91 | - private FromDeviceMsg convertToServerRpcRequest(CoapSessionCtx ctx, Request inbound) throws AdaptorException { | ||
92 | - | ||
93 | - String payload = validatePayload(ctx, inbound); | ||
94 | - | ||
95 | -// return JsonConverter.convertToServerRpcRequest(new JsonParser().parse(payload), 0); | ||
96 | - return null; | ||
97 | - } | ||
98 | - | ||
99 | - @Override | ||
100 | - public Optional<Response> convertToAdaptorMsg(CoapSessionCtx ctx, SessionActorToAdaptorMsg source) throws AdaptorException { | ||
101 | - ToDeviceMsg msg = source.getMsg(); | ||
102 | - switch (msg.getSessionMsgType()) { | ||
103 | - case STATUS_CODE_RESPONSE: | ||
104 | - case TO_DEVICE_RPC_RESPONSE_ACK: | ||
105 | - return Optional.of(convertStatusCodeResponse((StatusCodeResponse) msg)); | ||
106 | - case GET_ATTRIBUTES_RESPONSE: | ||
107 | - return Optional.of(convertGetAttributesResponse((GetAttributesResponse) msg)); | ||
108 | - case ATTRIBUTES_UPDATE_NOTIFICATION: | ||
109 | - return Optional.of(convertNotificationResponse(ctx, (AttributesUpdateNotification) msg)); | ||
110 | - case TO_DEVICE_RPC_REQUEST: | ||
111 | - return Optional.of(convertToDeviceRpcRequest(ctx, (ToDeviceRpcRequestMsg) msg)); | ||
112 | - case TO_SERVER_RPC_RESPONSE: | ||
113 | - return Optional.of(convertToServerRpcResponse(ctx, (ToServerRpcResponseMsg) msg)); | ||
114 | - case RULE_ENGINE_ERROR: | ||
115 | - return Optional.of(convertToRuleEngineErrorResponse(ctx, (RuleEngineErrorMsg) msg)); | ||
116 | - default: | ||
117 | - log.warn("[{}] Unsupported msg type: {}!", source.getSessionId(), msg.getSessionMsgType()); | ||
118 | - throw new AdaptorException(new IllegalArgumentException("Unsupported msg type: " + msg.getSessionMsgType() + "!")); | ||
119 | - } | ||
120 | - } | ||
121 | - | ||
122 | - private Response convertToRuleEngineErrorResponse(CoapSessionCtx ctx, RuleEngineErrorMsg msg) { | ||
123 | - ResponseCode status = ResponseCode.INTERNAL_SERVER_ERROR; | ||
124 | - switch (msg.getError()) { | ||
125 | - case QUEUE_PUT_TIMEOUT: | ||
126 | - status = ResponseCode.GATEWAY_TIMEOUT; | ||
127 | - break; | ||
128 | - default: | ||
129 | - if (msg.getInSessionMsgType() == SessionMsgType.TO_SERVER_RPC_REQUEST) { | ||
130 | - status = ResponseCode.BAD_REQUEST; | ||
131 | - } | ||
132 | - break; | ||
133 | - } | ||
134 | - Response response = new Response(status); | ||
135 | - response.setPayload(JsonConverter.toErrorJson(msg.getErrorMsg()).toString()); | ||
136 | - return response; | ||
137 | - } | ||
138 | - | ||
139 | - private Response convertNotificationResponse(CoapSessionCtx ctx, AttributesUpdateNotification msg) { | ||
140 | - return getObserveNotification(ctx, JsonConverter.toJson(msg.getData(), false)); | ||
141 | - } | ||
142 | - | ||
143 | - private Response convertToDeviceRpcRequest(CoapSessionCtx ctx, ToDeviceRpcRequestMsg msg) { | ||
144 | - return getObserveNotification(ctx, JsonConverter.toJson(msg, true)); | ||
145 | - } | ||
146 | - | ||
147 | - private Response getObserveNotification(CoapSessionCtx ctx, JsonObject json) { | ||
148 | - Response response = new Response(ResponseCode.CONTENT); | ||
149 | - response.getOptions().setObserve(ctx.nextSeqNumber()); | ||
150 | - response.setPayload(json.toString()); | ||
151 | - return response; | ||
152 | - } | ||
153 | - | ||
154 | - private AttributesUpdateRequest convertToUpdateAttributesRequest(SessionContext ctx, Request inbound) throws AdaptorException { | ||
155 | - String payload = validatePayload(ctx, inbound); | ||
156 | - try { | ||
157 | - return JsonConverter.convertToAttributes(new JsonParser().parse(payload)); | ||
158 | - } catch (IllegalStateException | JsonSyntaxException ex) { | ||
159 | - throw new AdaptorException(ex); | ||
160 | - } | ||
161 | - } | ||
162 | - | ||
163 | - private FromDeviceMsg convertToGetAttributesRequest(SessionContext ctx, Request inbound) throws AdaptorException { | ||
164 | - List<String> queryElements = inbound.getOptions().getUriQuery(); | ||
165 | - if (queryElements != null && queryElements.size() > 0) { | ||
166 | - Set<String> clientKeys = toKeys(ctx, queryElements, "clientKeys"); | ||
167 | - Set<String> sharedKeys = toKeys(ctx, queryElements, "sharedKeys"); | ||
168 | - return new BasicGetAttributesRequest(0, clientKeys, sharedKeys); | ||
169 | - } else { | ||
170 | - return new BasicGetAttributesRequest(0); | ||
171 | - } | ||
172 | - } | ||
173 | - | ||
174 | - private Set<String> toKeys(SessionContext ctx, List<String> queryElements, String attributeName) throws AdaptorException { | ||
175 | - String keys = null; | ||
176 | - for (String queryElement : queryElements) { | ||
177 | - String[] queryItem = queryElement.split("="); | ||
178 | - if (queryItem.length == 2 && queryItem[0].equals(attributeName)) { | ||
179 | - keys = queryItem[1]; | ||
180 | - } | ||
181 | - } | ||
182 | - if (keys != null && !StringUtils.isEmpty(keys)) { | ||
183 | - return new HashSet<>(Arrays.asList(keys.split(","))); | ||
184 | - } else { | ||
185 | - return null; | ||
186 | - } | ||
187 | - } | ||
188 | - | ||
189 | - private TelemetryUploadRequest convertToTelemetryUploadRequest(SessionContext ctx, Request inbound) throws AdaptorException { | ||
190 | - String payload = validatePayload(ctx, inbound); | ||
191 | - try { | ||
192 | - return JsonConverter.convertToTelemetry(new JsonParser().parse(payload)); | ||
193 | - } catch (IllegalStateException | JsonSyntaxException ex) { | ||
194 | - throw new AdaptorException(ex); | ||
195 | - } | ||
196 | - } | ||
197 | - | ||
198 | - private Response convertStatusCodeResponse(StatusCodeResponse msg) { | ||
199 | - if (msg.isSuccess()) { | ||
200 | - Optional<Integer> code = msg.getData(); | ||
201 | - if (code.isPresent() && code.get() == 200) { | ||
202 | - return new Response(ResponseCode.VALID); | ||
203 | - } else { | ||
204 | - return new Response(ResponseCode.CREATED); | ||
205 | - } | ||
206 | - } else { | ||
207 | - return convertError(msg.getError()); | ||
208 | - } | ||
209 | - } | ||
210 | - | ||
211 | - private String validatePayload(SessionContext ctx, Request inbound) throws AdaptorException { | ||
212 | - String payload = inbound.getPayloadString(); | ||
213 | - if (payload == null) { | ||
214 | - log.warn("[{}] Payload is empty!", ctx.getSessionId()); | ||
215 | - throw new AdaptorException(new IllegalArgumentException("Payload is empty!")); | ||
216 | - } | ||
217 | - return payload; | ||
218 | - } | ||
219 | - | ||
220 | - private Response convertToServerRpcResponse(SessionContext ctx, ToServerRpcResponseMsg msg) { | ||
221 | - if (msg.isSuccess()) { | ||
222 | - Response response = new Response(ResponseCode.CONTENT); | ||
223 | -// JsonElement result = JsonConverter.toJson(msg); | ||
224 | -// response.setPayload(result.toString()); | ||
225 | - return response; | ||
226 | - } else { | ||
227 | - return convertError(Optional.of(new RuntimeException("Server RPC response is empty!"))); | ||
228 | - } | ||
229 | - } | ||
230 | - | ||
231 | - private Response convertGetAttributesResponse(GetAttributesResponse msg) { | ||
232 | - if (msg.isSuccess()) { | ||
233 | - Optional<AttributesKVMsg> payload = msg.getData(); | ||
234 | - if (!payload.isPresent() || (payload.get().getClientAttributes().isEmpty() && payload.get().getSharedAttributes().isEmpty())) { | ||
235 | - return new Response(ResponseCode.NOT_FOUND); | ||
236 | - } else { | ||
237 | - Response response = new Response(ResponseCode.CONTENT); | ||
238 | - JsonObject result = JsonConverter.toJson(payload.get(), false); | ||
239 | - response.setPayload(result.toString()); | ||
240 | - return response; | ||
241 | - } | ||
242 | - } else { | ||
243 | - return convertError(msg.getError()); | ||
244 | - } | ||
245 | - } | ||
246 | - | ||
247 | - private Response convertError(Optional<Exception> exception) { | ||
248 | - if (exception.isPresent()) { | ||
249 | - log.warn("Converting exception: {}", exception.get().getMessage(), exception.get()); | ||
250 | - if (exception.get() instanceof ProcessingTimeoutException) { | ||
251 | - return new Response(ResponseCode.SERVICE_UNAVAILABLE); | ||
252 | - } else { | ||
253 | - return new Response(ResponseCode.INTERNAL_SERVER_ERROR); | ||
254 | - } | ||
255 | - } else { | ||
256 | - return new Response(ResponseCode.INTERNAL_SERVER_ERROR); | ||
257 | - } | ||
258 | - } | ||
259 | - | ||
260 | -} |
transport/coap/src/main/java/org/thingsboard/server/transport/coap/session/CoapExchangeObserverProxy.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.transport.coap.session; | ||
17 | - | ||
18 | -import org.eclipse.californium.core.network.Exchange; | ||
19 | -import org.eclipse.californium.core.network.ExchangeObserver; | ||
20 | - | ||
21 | -public class CoapExchangeObserverProxy implements ExchangeObserver { | ||
22 | - | ||
23 | - private final ExchangeObserver proxy; | ||
24 | - private final CoapSessionCtx ctx; | ||
25 | - | ||
26 | - public CoapExchangeObserverProxy(ExchangeObserver proxy, CoapSessionCtx ctx) { | ||
27 | - super(); | ||
28 | - this.proxy = proxy; | ||
29 | - this.ctx = ctx; | ||
30 | - } | ||
31 | - | ||
32 | - @Override | ||
33 | - public void completed(Exchange exchange) { | ||
34 | - proxy.completed(exchange); | ||
35 | - ctx.close(); | ||
36 | - } | ||
37 | - | ||
38 | -} |
transport/coap/src/main/java/org/thingsboard/server/transport/coap/session/CoapSessionCtx.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.transport.coap.session; | ||
17 | - | ||
18 | -import lombok.extern.slf4j.Slf4j; | ||
19 | -import org.eclipse.californium.core.coap.CoAP.ResponseCode; | ||
20 | -import org.eclipse.californium.core.coap.Request; | ||
21 | -import org.eclipse.californium.core.coap.Response; | ||
22 | -import org.eclipse.californium.core.server.resources.CoapExchange; | ||
23 | -import org.thingsboard.server.common.msg.session.ex.SessionException; | ||
24 | -import org.thingsboard.server.common.transport.SessionMsgProcessor; | ||
25 | -import org.thingsboard.server.common.transport.adaptor.AdaptorException; | ||
26 | -import org.thingsboard.server.common.transport.auth.DeviceAuthService; | ||
27 | -import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext; | ||
28 | -import org.thingsboard.server.transport.coap.adaptors.CoapTransportAdaptor; | ||
29 | - | ||
30 | -import java.util.concurrent.atomic.AtomicInteger; | ||
31 | - | ||
32 | -@Slf4j | ||
33 | -public class CoapSessionCtx extends DeviceAwareSessionContext { | ||
34 | - | ||
35 | - private final SessionId sessionId; | ||
36 | - private final CoapExchange exchange; | ||
37 | - private final CoapTransportAdaptor adaptor; | ||
38 | - private final String token; | ||
39 | - private final long timeout; | ||
40 | - private SessionType sessionType; | ||
41 | - private final AtomicInteger seqNumber = new AtomicInteger(2); | ||
42 | - | ||
43 | - public CoapSessionCtx(CoapExchange exchange, CoapTransportAdaptor adaptor, SessionMsgProcessor processor, DeviceAuthService authService, long timeout) { | ||
44 | - super(); | ||
45 | - Request request = exchange.advanced().getRequest(); | ||
46 | - this.token = request.getTokenString(); | ||
47 | - this.sessionId = new CoapSessionId(request.getSource().getHostAddress(), request.getSourcePort(), this.token); | ||
48 | - this.exchange = exchange; | ||
49 | - this.adaptor = adaptor; | ||
50 | - this.timeout = timeout; | ||
51 | - } | ||
52 | - | ||
53 | - | ||
54 | - @Override | ||
55 | - public void onMsg(SessionActorToAdaptorMsg msg) throws SessionException { | ||
56 | - try { | ||
57 | - adaptor.convertToAdaptorMsg(this, msg).ifPresent(this::pushToNetwork); | ||
58 | - } catch (AdaptorException e) { | ||
59 | - logAndWrap(e); | ||
60 | - } | ||
61 | - } | ||
62 | - | ||
63 | - private void pushToNetwork(Response response) { | ||
64 | - exchange.respond(response); | ||
65 | - } | ||
66 | - | ||
67 | - private void logAndWrap(AdaptorException e) throws SessionException { | ||
68 | - log.warn("Failed to convert msg: {}", e.getMessage(), e); | ||
69 | - throw new SessionException(e); | ||
70 | - } | ||
71 | - | ||
72 | - @Override | ||
73 | - public void onMsg(SessionCtrlMsg msg) throws SessionException { | ||
74 | - log.debug("[{}] onCtrl: {}", sessionId, msg); | ||
75 | - if (msg instanceof SessionCloseMsg) { | ||
76 | - onSessionClose((SessionCloseMsg) msg); | ||
77 | - } | ||
78 | - } | ||
79 | - | ||
80 | - private void onSessionClose(SessionCloseMsg msg) { | ||
81 | - if (msg.isTimeout()) { | ||
82 | - exchange.respond(ResponseCode.SERVICE_UNAVAILABLE); | ||
83 | - } else if (msg.isCredentialsRevoked()) { | ||
84 | - exchange.respond(ResponseCode.UNAUTHORIZED); | ||
85 | - } else { | ||
86 | - exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); | ||
87 | - } | ||
88 | - } | ||
89 | - | ||
90 | - @Override | ||
91 | - public SessionId getSessionId() { | ||
92 | - return sessionId; | ||
93 | - } | ||
94 | - | ||
95 | - @Override | ||
96 | - public String toString() { | ||
97 | - return "CoapSessionCtx [sessionId=" + sessionId + "]"; | ||
98 | - } | ||
99 | - | ||
100 | - @Override | ||
101 | - public boolean isClosed() { | ||
102 | - return exchange.advanced().isComplete() || exchange.advanced().isTimedOut(); | ||
103 | - } | ||
104 | - | ||
105 | - public void close() { | ||
106 | - log.info("[{}] Closing processing context. Timeout: {}", sessionId, exchange.advanced().isTimedOut()); | ||
107 | -// processor.process(exchange.advanced().isTimedOut() ? SessionCloseMsg.onTimeout(sessionId) : SessionCloseMsg.onError(sessionId)); | ||
108 | - } | ||
109 | - | ||
110 | - @Override | ||
111 | - public long getTimeout() { | ||
112 | - return timeout; | ||
113 | - } | ||
114 | - | ||
115 | - public void setSessionType(SessionType sessionType) { | ||
116 | - this.sessionType = sessionType; | ||
117 | - } | ||
118 | - | ||
119 | - @Override | ||
120 | - public SessionType getSessionType() { | ||
121 | - return sessionType; | ||
122 | - } | ||
123 | - | ||
124 | - public int nextSeqNumber() { | ||
125 | - return seqNumber.getAndIncrement(); | ||
126 | - } | ||
127 | -} |
transport/coap/src/main/java/org/thingsboard/server/transport/coap/session/CoapSessionId.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.transport.coap.session; | ||
17 | - | ||
18 | -public final class CoapSessionId implements SessionId { | ||
19 | - | ||
20 | - private final String clientAddress; | ||
21 | - private final int clientPort; | ||
22 | - private final String token; | ||
23 | - | ||
24 | - public CoapSessionId(String host, int port, String token) { | ||
25 | - super(); | ||
26 | - this.clientAddress = host; | ||
27 | - this.clientPort = port; | ||
28 | - this.token = token; | ||
29 | - } | ||
30 | - | ||
31 | - @Override | ||
32 | - public int hashCode() { | ||
33 | - final int prime = 31; | ||
34 | - int result = 1; | ||
35 | - result = prime * result + ((clientAddress == null) ? 0 : clientAddress.hashCode()); | ||
36 | - result = prime * result + clientPort; | ||
37 | - result = prime * result + ((token == null) ? 0 : token.hashCode()); | ||
38 | - return result; | ||
39 | - } | ||
40 | - | ||
41 | - @Override | ||
42 | - public boolean equals(Object obj) { | ||
43 | - if (this == obj) | ||
44 | - return true; | ||
45 | - if (obj == null) | ||
46 | - return false; | ||
47 | - if (getClass() != obj.getClass()) | ||
48 | - return false; | ||
49 | - CoapSessionId other = (CoapSessionId) obj; | ||
50 | - if (clientAddress == null) { | ||
51 | - if (other.clientAddress != null) | ||
52 | - return false; | ||
53 | - } else if (!clientAddress.equals(other.clientAddress)) | ||
54 | - return false; | ||
55 | - if (clientPort != other.clientPort) | ||
56 | - return false; | ||
57 | - if (token == null) { | ||
58 | - if (other.token != null) | ||
59 | - return false; | ||
60 | - } else if (!token.equals(other.token)) | ||
61 | - return false; | ||
62 | - return true; | ||
63 | - } | ||
64 | - | ||
65 | - @Override | ||
66 | - public String toString() { | ||
67 | - return "CoapSessionId [clientAddress=" + clientAddress + ", clientPort=" + clientPort + ", token=" + token + "]"; | ||
68 | - } | ||
69 | - | ||
70 | - @Override | ||
71 | - public String toUidStr() { | ||
72 | - return clientAddress + ":" + clientPort + ":" + token; | ||
73 | - } | ||
74 | - | ||
75 | -} |
1 | +<?xml version="1.0" encoding="UTF-8" ?> | ||
2 | +<!-- | ||
3 | + | ||
4 | + Copyright © 2016-2018 The Thingsboard Authors | ||
5 | + | ||
6 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
7 | + you may not use this file except in compliance with the License. | ||
8 | + You may obtain a copy of the License at | ||
9 | + | ||
10 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | + | ||
12 | + Unless required by applicable law or agreed to in writing, software | ||
13 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
14 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
15 | + See the License for the specific language governing permissions and | ||
16 | + limitations under the License. | ||
17 | + | ||
18 | +--> | ||
19 | +<!DOCTYPE configuration> | ||
20 | +<configuration scan="true" scanPeriod="10 seconds"> | ||
21 | + | ||
22 | + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | ||
23 | + <encoder> | ||
24 | + <pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern> | ||
25 | + </encoder> | ||
26 | + </appender> | ||
27 | + | ||
28 | + <logger name="org.thingsboard.server" level="TRACE" /> | ||
29 | + | ||
30 | + <root level="INFO"> | ||
31 | + <appender-ref ref="STDOUT"/> | ||
32 | + </root> | ||
33 | + | ||
34 | +</configuration> |
1 | +# | ||
2 | +# Copyright © 2016-2018 The Thingsboard Authors | ||
3 | +# | ||
4 | +# Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +# you may not use this file except in compliance with the License. | ||
6 | +# You may obtain a copy of the License at | ||
7 | +# | ||
8 | +# http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +# | ||
10 | +# Unless required by applicable law or agreed to in writing, software | ||
11 | +# distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +# See the License for the specific language governing permissions and | ||
14 | +# limitations under the License. | ||
15 | +# | ||
16 | + | ||
17 | +spring.main.web-environment: false | ||
18 | +spring.main.web-application-type: none | ||
19 | + | ||
20 | +# MQTT server parameters | ||
21 | +transport: | ||
22 | + coap: | ||
23 | + bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}" | ||
24 | + bind_port: "${COAP_BIND_PORT:5683}" | ||
25 | + timeout: "${COAP_TIMEOUT:10000}" | ||
26 | + | ||
27 | +#Quota parameters | ||
28 | +quota: | ||
29 | + host: | ||
30 | + # Max allowed number of API requests in interval for single host | ||
31 | + limit: "${QUOTA_HOST_LIMIT:10000}" | ||
32 | + # Interval duration | ||
33 | + intervalMs: "${QUOTA_HOST_INTERVAL_MS:60000}" | ||
34 | + # Maximum silence duration for host after which Host removed from QuotaService. Must be bigger than intervalMs | ||
35 | + ttlMs: "${QUOTA_HOST_TTL_MS:60000}" | ||
36 | + # Interval for scheduled task that cleans expired records. TTL is used for expiring | ||
37 | + cleanPeriodMs: "${QUOTA_HOST_CLEAN_PERIOD_MS:300000}" | ||
38 | + # Enable Host API Limits | ||
39 | + enabled: "${QUOTA_HOST_ENABLED:true}" | ||
40 | + # Array of whitelist hosts | ||
41 | + whitelist: "${QUOTA_HOST_WHITELIST:localhost,127.0.0.1}" | ||
42 | + # Array of blacklist hosts | ||
43 | + blacklist: "${QUOTA_HOST_BLACKLIST:}" | ||
44 | + log: | ||
45 | + topSize: 10 | ||
46 | + intervalMin: 2 | ||
47 | + | ||
48 | +kafka: | ||
49 | + enabled: true | ||
50 | + bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" | ||
51 | + acks: "${TB_KAFKA_ACKS:all}" | ||
52 | + retries: "${TB_KAFKA_RETRIES:1}" | ||
53 | + batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" | ||
54 | + linger.ms: "${TB_KAFKA_LINGER_MS:1}" | ||
55 | + buffer.memory: "${TB_BUFFER_MEMORY:33554432}" | ||
56 | + transport_api: | ||
57 | + requests_topic: "${TB_TRANSPORT_API_REQUEST_TOPIC:tb.transport.api.requests}" | ||
58 | + responses_topic: "${TB_TRANSPORT_API_RESPONSE_TOPIC:tb.transport.api.responses}" | ||
59 | + max_pending_requests: "${TB_TRANSPORT_MAX_PENDING_REQUESTS:10000}" | ||
60 | + max_requests_timeout: "${TB_TRANSPORT_MAX_REQUEST_TIMEOUT:10000}" | ||
61 | + response_poll_interval: "${TB_TRANSPORT_RESPONSE_POLL_INTERVAL_MS:25}" | ||
62 | + response_auto_commit_interval: "${TB_TRANSPORT_RESPONSE_AUTO_COMMIT_INTERVAL_MS:100}" | ||
63 | + rule_engine: | ||
64 | + topic: "${TB_RULE_ENGINE_TOPIC:tb.rule-engine}" | ||
65 | + notifications: | ||
66 | + topic: "${TB_TRANSPORT_NOTIFICATIONS_TOPIC:tb.transport.notifications}" | ||
67 | + poll_interval: "${TB_TRANSPORT_NOTIFICATIONS_POLL_INTERVAL_MS:25}" | ||
68 | + auto_commit_interval: "${TB_TRANSPORT_NOTIFICATIONS_AUTO_COMMIT_INTERVAL_MS:100}" |
1 | +#!/bin/sh | ||
2 | + | ||
3 | +if ! getent group ${pkg.name} >/dev/null; then | ||
4 | + addgroup --system ${pkg.name} | ||
5 | +fi | ||
6 | + | ||
7 | +if ! getent passwd ${pkg.name} >/dev/null; then | ||
8 | + adduser --quiet \ | ||
9 | + --system \ | ||
10 | + --ingroup ${pkg.name} \ | ||
11 | + --quiet \ | ||
12 | + --disabled-login \ | ||
13 | + --disabled-password \ | ||
14 | + --home ${pkg.installFolder} \ | ||
15 | + --no-create-home \ | ||
16 | + -gecos "Thingsboard application" \ | ||
17 | + ${pkg.name} | ||
18 | +fi |
1 | +@ECHO OFF | ||
2 | + | ||
3 | +setlocal ENABLEEXTENSIONS | ||
4 | + | ||
5 | +@ECHO Detecting Java version installed. | ||
6 | +:CHECK_JAVA_64 | ||
7 | +@ECHO Detecting if it is 64 bit machine | ||
8 | +set KEY_NAME="HKEY_LOCAL_MACHINE\Software\Wow6432Node\JavaSoft\Java Runtime Environment" | ||
9 | +set VALUE_NAME=CurrentVersion | ||
10 | + | ||
11 | +FOR /F "usebackq skip=2 tokens=1-3" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO ( | ||
12 | + set ValueName=%%A | ||
13 | + set ValueType=%%B | ||
14 | + set ValueValue=%%C | ||
15 | +) | ||
16 | +@ECHO CurrentVersion %ValueValue% | ||
17 | + | ||
18 | +SET KEY_NAME="%KEY_NAME:~1,-1%\%ValueValue%" | ||
19 | +SET VALUE_NAME=JavaHome | ||
20 | + | ||
21 | +if defined ValueName ( | ||
22 | + FOR /F "usebackq skip=2 tokens=1,2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO ( | ||
23 | + set ValueName2=%%A | ||
24 | + set ValueType2=%%B | ||
25 | + set JRE_PATH2=%%C | ||
26 | + | ||
27 | + if defined ValueName2 ( | ||
28 | + set ValueName = %ValueName2% | ||
29 | + set ValueType = %ValueType2% | ||
30 | + set ValueValue = %JRE_PATH2% | ||
31 | + ) | ||
32 | + ) | ||
33 | +) | ||
34 | + | ||
35 | +IF NOT "%JRE_PATH2%" == "" GOTO JAVA_INSTALLED | ||
36 | + | ||
37 | +:CHECK_JAVA_32 | ||
38 | +@ECHO Detecting if it is 32 bit machine | ||
39 | +set KEY_NAME="HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment" | ||
40 | +set VALUE_NAME=CurrentVersion | ||
41 | + | ||
42 | +FOR /F "usebackq skip=2 tokens=1-3" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO ( | ||
43 | + set ValueName=%%A | ||
44 | + set ValueType=%%B | ||
45 | + set ValueValue=%%C | ||
46 | +) | ||
47 | +@ECHO CurrentVersion %ValueValue% | ||
48 | + | ||
49 | +SET KEY_NAME="%KEY_NAME:~1,-1%\%ValueValue%" | ||
50 | +SET VALUE_NAME=JavaHome | ||
51 | + | ||
52 | +if defined ValueName ( | ||
53 | + FOR /F "usebackq skip=2 tokens=1,2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO ( | ||
54 | + set ValueName2=%%A | ||
55 | + set ValueType2=%%B | ||
56 | + set JRE_PATH2=%%C | ||
57 | + | ||
58 | + if defined ValueName2 ( | ||
59 | + set ValueName = %ValueName2% | ||
60 | + set ValueType = %ValueType2% | ||
61 | + set ValueValue = %JRE_PATH2% | ||
62 | + ) | ||
63 | + ) | ||
64 | +) | ||
65 | + | ||
66 | +IF "%JRE_PATH2%" == "" GOTO JAVA_NOT_INSTALLED | ||
67 | + | ||
68 | +:JAVA_INSTALLED | ||
69 | + | ||
70 | +@ECHO Java 1.8 found! | ||
71 | +@ECHO Installing ${pkg.name} ... | ||
72 | + | ||
73 | +%BASE%${pkg.name}.exe install | ||
74 | + | ||
75 | +@ECHO ${pkg.name} installed successfully! | ||
76 | + | ||
77 | +GOTO END | ||
78 | + | ||
79 | +:JAVA_NOT_INSTALLED | ||
80 | +@ECHO Java 1.8 or above is not installed | ||
81 | +@ECHO Please go to https://java.com/ and install Java. Then retry installation. | ||
82 | +PAUSE | ||
83 | +GOTO END | ||
84 | + | ||
85 | +:END | ||
86 | + | ||
87 | + |
1 | +<service> | ||
2 | + <id>${pkg.name}</id> | ||
3 | + <name>${project.name}</name> | ||
4 | + <description>${project.description}</description> | ||
5 | + <workingdirectory>%BASE%\conf</workingdirectory> | ||
6 | + <logpath>${pkg.winWrapperLogFolder}</logpath> | ||
7 | + <logmode>rotate</logmode> | ||
8 | + <env name="LOADER_PATH" value="%BASE%\conf" /> | ||
9 | + <executable>java</executable> | ||
10 | + <startargument>-Xloggc:%BASE%\logs\gc.log</startargument> | ||
11 | + <startargument>-XX:+HeapDumpOnOutOfMemoryError</startargument> | ||
12 | + <startargument>-XX:+PrintGCDetails</startargument> | ||
13 | + <startargument>-XX:+PrintGCDateStamps</startargument> | ||
14 | + <startargument>-XX:+PrintHeapAtGC</startargument> | ||
15 | + <startargument>-XX:+PrintTenuringDistribution</startargument> | ||
16 | + <startargument>-XX:+PrintGCApplicationStoppedTime</startargument> | ||
17 | + <startargument>-XX:+UseGCLogFileRotation</startargument> | ||
18 | + <startargument>-XX:NumberOfGCLogFiles=10</startargument> | ||
19 | + <startargument>-XX:GCLogFileSize=10M</startargument> | ||
20 | + <startargument>-XX:-UseBiasedLocking</startargument> | ||
21 | + <startargument>-XX:+UseTLAB</startargument> | ||
22 | + <startargument>-XX:+ResizeTLAB</startargument> | ||
23 | + <startargument>-XX:+PerfDisableSharedMem</startargument> | ||
24 | + <startargument>-XX:+UseCondCardMark</startargument> | ||
25 | + <startargument>-XX:CMSWaitDuration=10000</startargument> | ||
26 | + <startargument>-XX:+UseParNewGC</startargument> | ||
27 | + <startargument>-XX:+UseConcMarkSweepGC</startargument> | ||
28 | + <startargument>-XX:+CMSParallelRemarkEnabled</startargument> | ||
29 | + <startargument>-XX:+CMSParallelInitialMarkEnabled</startargument> | ||
30 | + <startargument>-XX:+CMSEdenChunksRecordAlways</startargument> | ||
31 | + <startargument>-XX:CMSInitiatingOccupancyFraction=75</startargument> | ||
32 | + <startargument>-XX:+UseCMSInitiatingOccupancyOnly</startargument> | ||
33 | + <startargument>-jar</startargument> | ||
34 | + <startargument>%BASE%\lib\${pkg.name}.jar</startargument> | ||
35 | + | ||
36 | +</service> |
transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapServerTest.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.transport.coap; | ||
17 | - | ||
18 | -import lombok.extern.slf4j.Slf4j; | ||
19 | -import org.eclipse.californium.core.CoapClient; | ||
20 | -import org.eclipse.californium.core.CoapResponse; | ||
21 | -import org.eclipse.californium.core.coap.CoAP.ResponseCode; | ||
22 | -import org.eclipse.californium.core.coap.MediaTypeRegistry; | ||
23 | -import org.junit.Assert; | ||
24 | -import org.junit.Before; | ||
25 | -import org.junit.Test; | ||
26 | -import org.junit.runner.RunWith; | ||
27 | -import org.springframework.beans.factory.annotation.Autowired; | ||
28 | -import org.springframework.context.annotation.Bean; | ||
29 | -import org.springframework.context.annotation.Configuration; | ||
30 | -import org.springframework.test.annotation.DirtiesContext; | ||
31 | -import org.springframework.test.annotation.DirtiesContext.ClassMode; | ||
32 | -import org.springframework.test.context.junit4.SpringRunner; | ||
33 | -import org.thingsboard.server.common.data.Device; | ||
34 | -import org.thingsboard.server.common.data.id.CustomerId; | ||
35 | -import org.thingsboard.server.common.data.id.DeviceId; | ||
36 | -import org.thingsboard.server.common.data.id.TenantId; | ||
37 | -import org.thingsboard.server.common.data.security.DeviceCredentialsFilter; | ||
38 | -import org.thingsboard.server.common.data.security.DeviceCredentialsType; | ||
39 | -import org.thingsboard.server.common.data.security.DeviceTokenCredentials; | ||
40 | -import org.thingsboard.server.common.msg.session.*; | ||
41 | -import org.thingsboard.server.common.transport.SessionMsgProcessor; | ||
42 | -import org.thingsboard.server.common.transport.auth.DeviceAuthResult; | ||
43 | -import org.thingsboard.server.common.transport.auth.DeviceAuthService; | ||
44 | -import org.thingsboard.server.common.transport.quota.host.HostRequestsQuotaService; | ||
45 | - | ||
46 | -import java.util.Optional; | ||
47 | -import java.util.UUID; | ||
48 | - | ||
49 | -@RunWith(SpringRunner.class) | ||
50 | -@DirtiesContext(classMode = ClassMode.BEFORE_CLASS) | ||
51 | -@Slf4j | ||
52 | -public class CoapServerTest { | ||
53 | - | ||
54 | - private static final int TEST_PORT = 5555; | ||
55 | - private static final String TELEMETRY_POST_MESSAGE = "[{\"key1\":\"value1\"}]"; | ||
56 | - private static final String TEST_ATTRIBUTES_RESPONSE = "{\"key1\":\"value1\",\"key2\":42}"; | ||
57 | - private static final String DEVICE1_TOKEN = "Device1Token"; | ||
58 | - | ||
59 | - @Configuration | ||
60 | - public static class EchoCoapServerITConfiguration extends CoapServerTestConfiguration { | ||
61 | - | ||
62 | - @Bean | ||
63 | - public static DeviceAuthService authService() { | ||
64 | - return new DeviceAuthService() { | ||
65 | - | ||
66 | - private final DeviceId devId = new DeviceId(UUID.randomUUID()); | ||
67 | - | ||
68 | - @Override | ||
69 | - public DeviceAuthResult process(DeviceCredentialsFilter credentials) { | ||
70 | - if (credentials != null && credentials.getCredentialsType() == DeviceCredentialsType.ACCESS_TOKEN) { | ||
71 | - DeviceTokenCredentials tokenCredentials = (DeviceTokenCredentials) credentials; | ||
72 | - if (tokenCredentials.getCredentialsId().equals(DEVICE1_TOKEN)) { | ||
73 | - return DeviceAuthResult.of(devId); | ||
74 | - } | ||
75 | - } | ||
76 | - return DeviceAuthResult.of("Credentials are invalid!"); | ||
77 | - } | ||
78 | - | ||
79 | - @Override | ||
80 | - public Optional<Device> findDeviceById(DeviceId deviceId) { | ||
81 | - if (deviceId.equals(devId)) { | ||
82 | - Device dev = new Device(); | ||
83 | - dev.setId(devId); | ||
84 | - dev.setTenantId(new TenantId(UUID.randomUUID())); | ||
85 | - dev.setCustomerId(new CustomerId(UUID.randomUUID())); | ||
86 | - return Optional.of(dev); | ||
87 | - } else { | ||
88 | - return Optional.empty(); | ||
89 | - } | ||
90 | - } | ||
91 | - }; | ||
92 | - } | ||
93 | - | ||
94 | - @Bean | ||
95 | - public static SessionMsgProcessor sessionMsgProcessor() { | ||
96 | - return new SessionMsgProcessor() { | ||
97 | - | ||
98 | -// @Override | ||
99 | -// public void process(SessionAwareMsg toActorMsg) { | ||
100 | -// if (toActorMsg instanceof TransportToDeviceSessionActorMsg) { | ||
101 | -// AdaptorToSessionActorMsg sessionMsg = ((TransportToDeviceSessionActorMsg) toActorMsg).getSessionMsg(); | ||
102 | -// try { | ||
103 | -// FromDeviceMsg deviceMsg = sessionMsg.getMsg(); | ||
104 | -// ToDeviceMsg toDeviceMsg = null; | ||
105 | -// if (deviceMsg.getMsgType() == SessionMsgType.POST_TELEMETRY_REQUEST) { | ||
106 | -// toDeviceMsg = BasicStatusCodeResponse.onSuccess(deviceMsg.getMsgType(), BasicRequest.DEFAULT_REQUEST_ID); | ||
107 | -// } else if (deviceMsg.getMsgType() == SessionMsgType.GET_ATTRIBUTES_REQUEST) { | ||
108 | -// List<AttributeKvEntry> data = new ArrayList<>(); | ||
109 | -// data.add(new BaseAttributeKvEntry(new StringDataEntry("key1", "value1"), System.currentTimeMillis())); | ||
110 | -// data.add(new BaseAttributeKvEntry(new LongDataEntry("key2", 42L), System.currentTimeMillis())); | ||
111 | -// BasicAttributeKVMsg kv = BasicAttributeKVMsg.fromClient(data); | ||
112 | -// toDeviceMsg = BasicGetAttributesResponse.onSuccess(deviceMsg.getMsgType(), BasicRequest.DEFAULT_REQUEST_ID, kv); | ||
113 | -// } | ||
114 | -// if (toDeviceMsg != null) { | ||
115 | -// sessionMsg.getSessionContext().onMsg(new BasicSessionActorToAdaptorMsg(sessionMsg.getSessionContext(), toDeviceMsg)); | ||
116 | -// } | ||
117 | -// } catch (Exception e) { | ||
118 | -// e.printStackTrace(); | ||
119 | -// } | ||
120 | -// } | ||
121 | -// } | ||
122 | - | ||
123 | - @Override | ||
124 | - public void onDeviceAdded(Device device) { | ||
125 | - | ||
126 | - } | ||
127 | - | ||
128 | - | ||
129 | - }; | ||
130 | - } | ||
131 | - | ||
132 | - @Bean | ||
133 | - public static HostRequestsQuotaService quotaService() { | ||
134 | - return new HostRequestsQuotaService(null, null, null, null, false); | ||
135 | - } | ||
136 | - } | ||
137 | - | ||
138 | - @Autowired | ||
139 | - private CoapTransportService service; | ||
140 | - | ||
141 | - @Before | ||
142 | - public void beforeTest() { | ||
143 | - log.info("Service info: {}", service.toString()); | ||
144 | - } | ||
145 | - | ||
146 | - @Test | ||
147 | - public void testBadJsonTelemetryPostRequest() { | ||
148 | - CoapClient client = new CoapClient(getBaseTestUrl() + DEVICE1_TOKEN + "/" + FeatureType.TELEMETRY.name().toLowerCase()); | ||
149 | - CoapResponse response = client.setTimeout(6000).post("test", MediaTypeRegistry.APPLICATION_JSON); | ||
150 | - Assert.assertEquals(ResponseCode.BAD_REQUEST, response.getCode()); | ||
151 | - log.info("Response: {}, {}", response.getCode(), response.getResponseText()); | ||
152 | - } | ||
153 | - | ||
154 | - @Test | ||
155 | - public void testNoCredentialsPostRequest() { | ||
156 | - CoapClient client = new CoapClient(getBaseTestUrl()); | ||
157 | - CoapResponse response = client.setTimeout(6000).post(TELEMETRY_POST_MESSAGE, MediaTypeRegistry.APPLICATION_JSON); | ||
158 | - Assert.assertEquals(ResponseCode.BAD_REQUEST, response.getCode()); | ||
159 | - log.info("Response: {}, {}", response.getCode(), response.getResponseText()); | ||
160 | - } | ||
161 | - | ||
162 | - @Test | ||
163 | - public void testValidJsonTelemetryPostRequest() { | ||
164 | - CoapClient client = new CoapClient(getBaseTestUrl() + DEVICE1_TOKEN + "/" + FeatureType.TELEMETRY.name().toLowerCase()); | ||
165 | - CoapResponse response = client.setTimeout(6000).post(TELEMETRY_POST_MESSAGE, MediaTypeRegistry.APPLICATION_JSON); | ||
166 | - Assert.assertEquals(ResponseCode.CREATED, response.getCode()); | ||
167 | - log.info("Response: {}, {}", response.getCode(), response.getResponseText()); | ||
168 | - } | ||
169 | - | ||
170 | - @Test | ||
171 | - public void testNoCredentialsAttributesGetRequest() { | ||
172 | - CoapClient client = new CoapClient("coap://localhost:5555/api/v1?keys=key1,key2"); | ||
173 | - CoapResponse response = client.setTimeout(6000).get(); | ||
174 | - Assert.assertEquals(ResponseCode.BAD_REQUEST, response.getCode()); | ||
175 | - } | ||
176 | - | ||
177 | - @Test | ||
178 | - public void testNoKeysAttributesGetRequest() { | ||
179 | - CoapClient client = new CoapClient(getBaseTestUrl() + DEVICE1_TOKEN + "/" + FeatureType.ATTRIBUTES.name().toLowerCase() + "?data=key1,key2"); | ||
180 | - CoapResponse response = client.setTimeout(6000).get(); | ||
181 | - Assert.assertEquals(ResponseCode.CONTENT, response.getCode()); | ||
182 | - } | ||
183 | - | ||
184 | - @Test | ||
185 | - public void testValidAttributesGetRequest() { | ||
186 | - CoapClient client = new CoapClient(getBaseTestUrl() + DEVICE1_TOKEN + "/" + FeatureType.ATTRIBUTES.name().toLowerCase() + "?clientKeys=key1,key2"); | ||
187 | - CoapResponse response = client.setTimeout(6000).get(); | ||
188 | - Assert.assertEquals(ResponseCode.CONTENT, response.getCode()); | ||
189 | - Assert.assertEquals(TEST_ATTRIBUTES_RESPONSE, response.getResponseText()); | ||
190 | - log.info("Response: {}, {}", response.getCode(), response.getResponseText()); | ||
191 | - } | ||
192 | - | ||
193 | - private String getBaseTestUrl() { | ||
194 | - return "coap://localhost:" + TEST_PORT + "/api/v1/"; | ||
195 | - } | ||
196 | - | ||
197 | -} |
transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapServerTestConfiguration.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.transport.coap; | ||
17 | - | ||
18 | -import org.springframework.context.annotation.Bean; | ||
19 | -import org.springframework.context.annotation.ComponentScan; | ||
20 | -import org.springframework.context.annotation.Configuration; | ||
21 | -import org.springframework.context.annotation.PropertySource; | ||
22 | -import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; | ||
23 | -import org.springframework.test.context.TestPropertySource; | ||
24 | - | ||
25 | -@Configuration | ||
26 | -@ComponentScan({ "org.thingsboard.server.transport.coap" }) | ||
27 | -@PropertySource("classpath:coap-transport-test.properties") | ||
28 | -public class CoapServerTestConfiguration { | ||
29 | - | ||
30 | - @Bean | ||
31 | - public static PropertySourcesPlaceholderConfigurer propertyConfig() { | ||
32 | - return new PropertySourcesPlaceholderConfigurer(); | ||
33 | - } | ||
34 | - | ||
35 | -} |
transport/coap/src/test/resources/coap-transport-test.properties
deleted
100644 → 0
@@ -145,7 +145,7 @@ | @@ -145,7 +145,7 @@ | ||
145 | <resource> | 145 | <resource> |
146 | <directory>src/main/conf</directory> | 146 | <directory>src/main/conf</directory> |
147 | <excludes> | 147 | <excludes> |
148 | - <exclude>tb-mqtt-transport.conf</exclude> | 148 | + <exclude>tb-http-transport.conf</exclude> |
149 | </excludes> | 149 | </excludes> |
150 | <filtering>true</filtering> | 150 | <filtering>true</filtering> |
151 | </resource> | 151 | </resource> |
@@ -229,7 +229,7 @@ | @@ -229,7 +229,7 @@ | ||
229 | </excludes> | 229 | </excludes> |
230 | <archive> | 230 | <archive> |
231 | <manifestEntries> | 231 | <manifestEntries> |
232 | - <Implementation-Title>ThingsBoard MQTT Transport Service</Implementation-Title> | 232 | + <Implementation-Title>ThingsBoard HTTP Transport Service</Implementation-Title> |
233 | <Implementation-Version>${project.version}</Implementation-Version> | 233 | <Implementation-Version>${project.version}</Implementation-Version> |
234 | </manifestEntries> | 234 | </manifestEntries> |
235 | </archive> | 235 | </archive> |
@@ -239,7 +239,7 @@ | @@ -239,7 +239,7 @@ | ||
239 | <groupId>org.springframework.boot</groupId> | 239 | <groupId>org.springframework.boot</groupId> |
240 | <artifactId>spring-boot-maven-plugin</artifactId> | 240 | <artifactId>spring-boot-maven-plugin</artifactId> |
241 | <configuration> | 241 | <configuration> |
242 | - <mainClass>org.thingsboard.server.mqtt.ThingsboardHttpTransportApplication</mainClass> | 242 | + <mainClass>org.thingsboard.server.http.ThingsboardHttpTransportApplication</mainClass> |
243 | <classifier>boot</classifier> | 243 | <classifier>boot</classifier> |
244 | <layout>ZIP</layout> | 244 | <layout>ZIP</layout> |
245 | <executable>true</executable> | 245 | <executable>true</executable> |
@@ -49,6 +49,10 @@ | @@ -49,6 +49,10 @@ | ||
49 | <artifactId>queue</artifactId> | 49 | <artifactId>queue</artifactId> |
50 | </dependency> | 50 | </dependency> |
51 | <dependency> | 51 | <dependency> |
52 | + <groupId>org.springframework.boot</groupId> | ||
53 | + <artifactId>spring-boot-starter-web</artifactId> | ||
54 | + </dependency> | ||
55 | + <dependency> | ||
52 | <groupId>com.sun.winsw</groupId> | 56 | <groupId>com.sun.winsw</groupId> |
53 | <artifactId>winsw</artifactId> | 57 | <artifactId>winsw</artifactId> |
54 | <classifier>bin</classifier> | 58 | <classifier>bin</classifier> |
@@ -14,6 +14,7 @@ | @@ -14,6 +14,7 @@ | ||
14 | # limitations under the License. | 14 | # limitations under the License. |
15 | # | 15 | # |
16 | 16 | ||
17 | +spring.main.web-environment: false | ||
17 | spring.main.web-application-type: none | 18 | spring.main.web-application-type: none |
18 | 19 | ||
19 | # MQTT server parameters | 20 | # MQTT server parameters |