185 changed files with 5130 additions and 2495 deletions
@ -0,0 +1,24 @@ |
|||||
|
{ |
||||
|
"providerId": "Apple", |
||||
|
"additionalInfo": null, |
||||
|
"accessTokenUri": "https://appleid.apple.com/auth/token", |
||||
|
"authorizationUri": "https://appleid.apple.com/auth/authorize?response_mode=form_post", |
||||
|
"scope": ["email","openid","name"], |
||||
|
"jwkSetUri": "https://appleid.apple.com/auth/keys", |
||||
|
"userInfoUri": null, |
||||
|
"clientAuthenticationMethod": "POST", |
||||
|
"userNameAttributeName": "email", |
||||
|
"mapperConfig": { |
||||
|
"type": "APPLE", |
||||
|
"basic": { |
||||
|
"emailAttributeKey": "email", |
||||
|
"firstNameAttributeKey": "firstName", |
||||
|
"lastNameAttributeKey": "lastName", |
||||
|
"tenantNameStrategy": "DOMAIN" |
||||
|
} |
||||
|
}, |
||||
|
"comment": null, |
||||
|
"loginButtonIcon": "apple-logo", |
||||
|
"loginButtonLabel": "Apple", |
||||
|
"helpLink": "https://developer.apple.com/sign-in-with-apple/get-started/" |
||||
|
} |
||||
@ -0,0 +1,101 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.security.auth.oauth2; |
||||
|
|
||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.util.LinkedMultiValueMap; |
||||
|
import org.springframework.util.MultiValueMap; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
import org.thingsboard.common.util.JacksonUtil; |
||||
|
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig; |
||||
|
import org.thingsboard.server.common.data.oauth2.OAuth2Registration; |
||||
|
import org.thingsboard.server.dao.oauth2.OAuth2User; |
||||
|
import org.thingsboard.server.service.security.model.SecurityUser; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@Service(value = "appleOAuth2ClientMapper") |
||||
|
@Slf4j |
||||
|
public class AppleOAuth2ClientMapper extends AbstractOAuth2ClientMapper implements OAuth2ClientMapper { |
||||
|
|
||||
|
private static final String USER = "user"; |
||||
|
private static final String NAME = "name"; |
||||
|
private static final String FIRST_NAME = "firstName"; |
||||
|
private static final String LAST_NAME = "lastName"; |
||||
|
private static final String EMAIL = "email"; |
||||
|
|
||||
|
@Override |
||||
|
public SecurityUser getOrCreateUserByClientPrincipal(HttpServletRequest request, OAuth2AuthenticationToken token, String providerAccessToken, OAuth2Registration registration) { |
||||
|
OAuth2MapperConfig config = registration.getMapperConfig(); |
||||
|
Map<String, Object> attributes = updateAttributesFromRequestParams(request, token.getPrincipal().getAttributes()); |
||||
|
String email = BasicMapperUtils.getStringAttributeByKey(attributes, config.getBasic().getEmailAttributeKey()); |
||||
|
OAuth2User oauth2User = BasicMapperUtils.getOAuth2User(email, attributes, config); |
||||
|
|
||||
|
return getOrCreateSecurityUserFromOAuth2User(oauth2User, registration); |
||||
|
} |
||||
|
|
||||
|
private static Map<String, Object> updateAttributesFromRequestParams(HttpServletRequest request, Map<String, Object> attributes) { |
||||
|
Map<String, Object> updated = attributes; |
||||
|
MultiValueMap<String, String> params = toMultiMap(request.getParameterMap()); |
||||
|
String userValue = params.getFirst(USER); |
||||
|
if (StringUtils.hasText(userValue)) { |
||||
|
JsonNode user = null; |
||||
|
try { |
||||
|
user = JacksonUtil.toJsonNode(userValue); |
||||
|
} catch (Exception e) {} |
||||
|
if (user != null) { |
||||
|
updated = new HashMap<>(attributes); |
||||
|
if (user.has(NAME)) { |
||||
|
JsonNode name = user.get(NAME); |
||||
|
if (name.isObject()) { |
||||
|
JsonNode firstName = name.get(FIRST_NAME); |
||||
|
if (firstName != null && firstName.isTextual()) { |
||||
|
updated.put(FIRST_NAME, firstName.asText()); |
||||
|
} |
||||
|
JsonNode lastName = name.get(LAST_NAME); |
||||
|
if (lastName != null && lastName.isTextual()) { |
||||
|
updated.put(LAST_NAME, lastName.asText()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if (user.has(EMAIL)) { |
||||
|
JsonNode email = user.get(EMAIL); |
||||
|
if (email != null && email.isTextual()) { |
||||
|
updated.put(EMAIL, email.asText()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return updated; |
||||
|
} |
||||
|
|
||||
|
private static MultiValueMap<String, String> toMultiMap(Map<String, String[]> map) { |
||||
|
MultiValueMap<String, String> params = new LinkedMultiValueMap<>(map.size()); |
||||
|
map.forEach((key, values) -> { |
||||
|
if (values.length > 0) { |
||||
|
for (String value : values) { |
||||
|
params.add(key, value); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
return params; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,211 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.queue.common; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.junit.After; |
||||
|
import org.junit.Before; |
||||
|
import org.junit.Test; |
||||
|
import org.junit.runner.RunWith; |
||||
|
import org.mockito.ArgumentCaptor; |
||||
|
import org.mockito.Mock; |
||||
|
import org.mockito.junit.MockitoJUnitRunner; |
||||
|
import org.thingsboard.server.queue.TbQueueAdmin; |
||||
|
import org.thingsboard.server.queue.TbQueueConsumer; |
||||
|
import org.thingsboard.server.queue.TbQueueMsg; |
||||
|
import org.thingsboard.server.queue.TbQueueProducer; |
||||
|
|
||||
|
import java.util.Collections; |
||||
|
import java.util.List; |
||||
|
import java.util.UUID; |
||||
|
import java.util.concurrent.CountDownLatch; |
||||
|
import java.util.concurrent.ExecutorService; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
import java.util.concurrent.atomic.AtomicLong; |
||||
|
|
||||
|
import static org.hamcrest.Matchers.equalTo; |
||||
|
import static org.hamcrest.Matchers.greaterThanOrEqualTo; |
||||
|
import static org.hamcrest.Matchers.is; |
||||
|
import static org.hamcrest.Matchers.lessThan; |
||||
|
import static org.mockito.ArgumentMatchers.any; |
||||
|
import static org.mockito.ArgumentMatchers.anyLong; |
||||
|
import static org.mockito.BDDMockito.willAnswer; |
||||
|
import static org.mockito.BDDMockito.willDoNothing; |
||||
|
import static org.mockito.BDDMockito.willReturn; |
||||
|
import static org.mockito.Mockito.RETURNS_DEEP_STUBS; |
||||
|
import static org.mockito.Mockito.atLeastOnce; |
||||
|
import static org.mockito.Mockito.mock; |
||||
|
import static org.mockito.Mockito.never; |
||||
|
import static org.mockito.Mockito.spy; |
||||
|
import static org.mockito.Mockito.times; |
||||
|
import static org.mockito.Mockito.verify; |
||||
|
|
||||
|
import static org.hamcrest.MatcherAssert.assertThat; |
||||
|
import static org.mockito.hamcrest.MockitoHamcrest.longThat; |
||||
|
|
||||
|
@Slf4j |
||||
|
@RunWith(MockitoJUnitRunner.class) |
||||
|
public class DefaultTbQueueRequestTemplateTest { |
||||
|
|
||||
|
@Mock |
||||
|
TbQueueAdmin queueAdmin; |
||||
|
@Mock |
||||
|
TbQueueProducer<TbQueueMsg> requestTemplate; |
||||
|
@Mock |
||||
|
TbQueueConsumer<TbQueueMsg> responseTemplate; |
||||
|
@Mock |
||||
|
ExecutorService executorMock; |
||||
|
|
||||
|
ExecutorService executor; |
||||
|
String topic = "js-responses-tb-node-0"; |
||||
|
long maxRequestTimeout = 10; |
||||
|
long maxPendingRequests = 32; |
||||
|
long pollInterval = 5; |
||||
|
|
||||
|
DefaultTbQueueRequestTemplate inst; |
||||
|
|
||||
|
@Before |
||||
|
public void setUp() throws Exception { |
||||
|
willReturn(topic).given(responseTemplate).getTopic(); |
||||
|
inst = spy(new DefaultTbQueueRequestTemplate( |
||||
|
queueAdmin, requestTemplate, responseTemplate, |
||||
|
maxRequestTimeout, maxPendingRequests, pollInterval, executorMock)); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@After |
||||
|
public void tearDown() throws Exception { |
||||
|
if (executor != null) { |
||||
|
executor.shutdownNow(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void givenInstance_whenVerifyInitialParameters_thenOK() { |
||||
|
assertThat(inst.maxPendingRequests, equalTo(maxPendingRequests)); |
||||
|
assertThat(inst.maxRequestTimeoutNs, equalTo(TimeUnit.MILLISECONDS.toNanos(maxRequestTimeout))); |
||||
|
assertThat(inst.pollInterval, equalTo(pollInterval)); |
||||
|
assertThat(inst.executor, is(executorMock)); |
||||
|
assertThat(inst.stopped, is(false)); |
||||
|
assertThat(inst.internalExecutor, is(false)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void givenExternalExecutor_whenInitStop_thenOK() { |
||||
|
inst.init(); |
||||
|
assertThat(inst.nextCleanupNs, equalTo(0L)); |
||||
|
verify(queueAdmin, times(1)).createTopicIfNotExists(topic); |
||||
|
verify(requestTemplate, times(1)).init(); |
||||
|
verify(responseTemplate, times(1)).subscribe(); |
||||
|
verify(executorMock, times(1)).submit(any(Runnable.class)); |
||||
|
|
||||
|
inst.stop(); |
||||
|
assertThat(inst.stopped, is(true)); |
||||
|
verify(responseTemplate, times(1)).unsubscribe(); |
||||
|
verify(requestTemplate, times(1)).stop(); |
||||
|
verify(executorMock, never()).shutdownNow(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void givenMainLoop_whenLoopFewTimes_thenVerifyInvocationCount() throws InterruptedException { |
||||
|
executor = inst.createExecutor(); |
||||
|
CountDownLatch latch = new CountDownLatch(5); |
||||
|
willDoNothing().given(inst).sleep(anyLong()); |
||||
|
willAnswer(invocation -> { |
||||
|
if (latch.getCount() == 1) { |
||||
|
inst.stop(); //stop the loop in natural way
|
||||
|
} |
||||
|
if (latch.getCount() == 3 || latch.getCount() == 4) { |
||||
|
latch.countDown(); |
||||
|
throw new RuntimeException("test catch block"); |
||||
|
} |
||||
|
latch.countDown(); |
||||
|
return null; |
||||
|
}).given(inst).fetchAndProcessResponses(); |
||||
|
|
||||
|
executor.submit(inst::mainLoop); |
||||
|
latch.await(10, TimeUnit.SECONDS); |
||||
|
|
||||
|
verify(inst, times(5)).fetchAndProcessResponses(); |
||||
|
verify(inst, times(2)).sleep(longThat(lessThan(TimeUnit.MILLISECONDS.toNanos(inst.pollInterval)))); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void givenMessages_whenSend_thenOK() { |
||||
|
willDoNothing().given(inst).sendToRequestTemplate(any(), any(), any(), any()); |
||||
|
inst.init(); |
||||
|
final int msgCount = 10; |
||||
|
for (int i = 0; i < msgCount; i++) { |
||||
|
inst.send(getRequestMsgMock()); |
||||
|
} |
||||
|
assertThat(inst.pendingRequests.mappingCount(), equalTo((long) msgCount)); |
||||
|
verify(inst, times(msgCount)).sendToRequestTemplate(any(), any(), any(), any()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void givenMessagesOverMaxPendingRequests_whenSend_thenImmediateFailedFutureForTheOfRequests() { |
||||
|
willDoNothing().given(inst).sendToRequestTemplate(any(), any(), any(), any()); |
||||
|
inst.init(); |
||||
|
int msgOverflowCount = 10; |
||||
|
for (int i = 0; i < inst.maxPendingRequests; i++) { |
||||
|
assertThat(inst.send(getRequestMsgMock()).isDone(), is(false)); //SettableFuture future - pending only
|
||||
|
} |
||||
|
for (int i = 0; i < msgOverflowCount; i++) { |
||||
|
assertThat("max pending requests overflow", inst.send(getRequestMsgMock()).isDone(), is(true)); //overflow, immediate failed future
|
||||
|
} |
||||
|
assertThat(inst.pendingRequests.mappingCount(), equalTo(inst.maxPendingRequests)); |
||||
|
verify(inst, times((int) inst.maxPendingRequests)).sendToRequestTemplate(any(), any(), any(), any()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void givenNothing_whenSendAndFetchAndProcessResponsesWithTimeout_thenFail() { |
||||
|
//given
|
||||
|
AtomicLong currentTime = new AtomicLong(); |
||||
|
willAnswer(x -> { |
||||
|
log.info("currentTime={}", currentTime.get()); |
||||
|
return currentTime.get(); |
||||
|
}).given(inst).getCurrentClockNs(); |
||||
|
inst.init(); |
||||
|
inst.setupNextCleanup(); |
||||
|
willReturn(Collections.emptyList()).given(inst).doPoll(); |
||||
|
|
||||
|
//when
|
||||
|
long stepNs = TimeUnit.MILLISECONDS.toNanos(1); |
||||
|
for (long i = 0; i <= inst.maxRequestTimeoutNs * 2; i = i + stepNs) { |
||||
|
currentTime.addAndGet(stepNs); |
||||
|
assertThat(inst.send(getRequestMsgMock()).isDone(), is(false)); //SettableFuture future - pending only
|
||||
|
if (i % (inst.maxRequestTimeoutNs * 3 / 2) == 0) { |
||||
|
inst.fetchAndProcessResponses(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//then
|
||||
|
ArgumentCaptor<DefaultTbQueueRequestTemplate.ResponseMetaData> argumentCaptorResp = ArgumentCaptor.forClass(DefaultTbQueueRequestTemplate.ResponseMetaData.class); |
||||
|
ArgumentCaptor<UUID> argumentCaptorUUID = ArgumentCaptor.forClass(UUID.class); |
||||
|
ArgumentCaptor<Long> argumentCaptorLong = ArgumentCaptor.forClass(Long.class); |
||||
|
verify(inst, atLeastOnce()).setTimeoutException(argumentCaptorUUID.capture(), argumentCaptorResp.capture(), argumentCaptorLong.capture()); |
||||
|
|
||||
|
List<DefaultTbQueueRequestTemplate.ResponseMetaData> responseMetaDataList = argumentCaptorResp.getAllValues(); |
||||
|
List<Long> tickTsList = argumentCaptorLong.getAllValues(); |
||||
|
for (int i = 0; i < responseMetaDataList.size(); i++) { |
||||
|
assertThat("tickTs >= calculatedExpTime", tickTsList.get(i), greaterThanOrEqualTo(responseMetaDataList.get(i).getSubmitTime() + responseMetaDataList.get(i).getTimeout())); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
TbQueueMsg getRequestMsgMock() { |
||||
|
return mock(TbQueueMsg.class, RETURNS_DEEP_STUBS); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,150 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.coap; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.eclipse.californium.core.coap.CoAP; |
||||
|
import org.eclipse.californium.core.coap.Request; |
||||
|
import org.eclipse.californium.core.coap.Response; |
||||
|
import org.eclipse.californium.core.network.Exchange; |
||||
|
import org.eclipse.californium.core.observe.ObserveRelation; |
||||
|
import org.eclipse.californium.core.server.resources.CoapExchange; |
||||
|
import org.eclipse.californium.core.server.resources.Resource; |
||||
|
import org.eclipse.californium.core.server.resources.ResourceObserver; |
||||
|
import org.thingsboard.common.util.ThingsBoardExecutors; |
||||
|
import org.thingsboard.server.common.data.DeviceTransportType; |
||||
|
import org.thingsboard.server.common.data.StringUtils; |
||||
|
import org.thingsboard.server.common.data.ota.OtaPackageType; |
||||
|
import org.thingsboard.server.common.data.security.DeviceTokenCredentials; |
||||
|
import org.thingsboard.server.common.transport.TransportServiceCallback; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.Optional; |
||||
|
import java.util.UUID; |
||||
|
import java.util.concurrent.ExecutorService; |
||||
|
|
||||
|
@Slf4j |
||||
|
public class OtaPackageTransportResource extends AbstractCoapTransportResource { |
||||
|
private static final int ACCESS_TOKEN_POSITION = 2; |
||||
|
|
||||
|
private final OtaPackageType otaPackageType; |
||||
|
|
||||
|
public OtaPackageTransportResource(CoapTransportContext ctx, OtaPackageType otaPackageType) { |
||||
|
super(ctx, otaPackageType.getKeyPrefix()); |
||||
|
this.otaPackageType = otaPackageType; |
||||
|
|
||||
|
this.setObservable(true); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void processHandleGet(CoapExchange exchange) { |
||||
|
log.trace("Processing {}", exchange.advanced().getRequest()); |
||||
|
exchange.accept(); |
||||
|
Exchange advanced = exchange.advanced(); |
||||
|
Request request = advanced.getRequest(); |
||||
|
processAccessTokenRequest(exchange, request); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void processHandlePost(CoapExchange exchange) { |
||||
|
exchange.respond(CoAP.ResponseCode.METHOD_NOT_ALLOWED); |
||||
|
} |
||||
|
|
||||
|
private void processAccessTokenRequest(CoapExchange exchange, Request request) { |
||||
|
Optional<DeviceTokenCredentials> credentials = decodeCredentials(request); |
||||
|
if (credentials.isEmpty()) { |
||||
|
exchange.respond(CoAP.ResponseCode.UNAUTHORIZED); |
||||
|
return; |
||||
|
} |
||||
|
transportService.process(DeviceTransportType.COAP, TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(credentials.get().getCredentialsId()).build(), |
||||
|
new CoapDeviceAuthCallback(transportContext, exchange, (sessionInfo, deviceProfile) -> { |
||||
|
getOtaPackageCallback(sessionInfo, exchange, otaPackageType); |
||||
|
})); |
||||
|
} |
||||
|
|
||||
|
private void getOtaPackageCallback(TransportProtos.SessionInfoProto sessionInfo, CoapExchange exchange, OtaPackageType firmwareType) { |
||||
|
TransportProtos.GetOtaPackageRequestMsg requestMsg = TransportProtos.GetOtaPackageRequestMsg.newBuilder() |
||||
|
.setTenantIdMSB(sessionInfo.getTenantIdMSB()) |
||||
|
.setTenantIdLSB(sessionInfo.getTenantIdLSB()) |
||||
|
.setDeviceIdMSB(sessionInfo.getDeviceIdMSB()) |
||||
|
.setDeviceIdLSB(sessionInfo.getDeviceIdLSB()) |
||||
|
.setType(firmwareType.name()).build(); |
||||
|
transportContext.getTransportService().process(sessionInfo, requestMsg, new OtaPackageCallback(exchange)); |
||||
|
} |
||||
|
|
||||
|
private Optional<DeviceTokenCredentials> decodeCredentials(Request request) { |
||||
|
List<String> uriPath = request.getOptions().getUriPath(); |
||||
|
if (uriPath.size() == ACCESS_TOKEN_POSITION) { |
||||
|
return Optional.of(new DeviceTokenCredentials(uriPath.get(ACCESS_TOKEN_POSITION - 1))); |
||||
|
} else { |
||||
|
return Optional.empty(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Resource getChild(String name) { |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
private class OtaPackageCallback implements TransportServiceCallback<TransportProtos.GetOtaPackageResponseMsg> { |
||||
|
private final CoapExchange exchange; |
||||
|
|
||||
|
OtaPackageCallback(CoapExchange exchange) { |
||||
|
this.exchange = exchange; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onSuccess(TransportProtos.GetOtaPackageResponseMsg msg) { |
||||
|
String title = exchange.getQueryParameter("title"); |
||||
|
String version = exchange.getQueryParameter("version"); |
||||
|
if (msg.getResponseStatus().equals(TransportProtos.ResponseStatus.SUCCESS)) { |
||||
|
String firmwareId = new UUID(msg.getOtaPackageIdMSB(), msg.getOtaPackageIdLSB()).toString(); |
||||
|
if ((title == null || msg.getTitle().equals(title)) && (version == null || msg.getVersion().equals(version))) { |
||||
|
String strChunkSize = exchange.getQueryParameter("size"); |
||||
|
String strChunk = exchange.getQueryParameter("chunk"); |
||||
|
int chunkSize = StringUtils.isEmpty(strChunkSize) ? 0 : Integer.parseInt(strChunkSize); |
||||
|
int chunk = StringUtils.isEmpty(strChunk) ? 0 : Integer.parseInt(strChunk); |
||||
|
respondOtaPackage(exchange, transportContext.getOtaPackageDataCache().get(firmwareId, chunkSize, chunk)); |
||||
|
} else { |
||||
|
exchange.respond(CoAP.ResponseCode.BAD_REQUEST); |
||||
|
} |
||||
|
} else { |
||||
|
exchange.respond(CoAP.ResponseCode.NOT_FOUND); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onError(Throwable e) { |
||||
|
log.warn("Failed to process request", e); |
||||
|
exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void respondOtaPackage(CoapExchange exchange, byte[] data) { |
||||
|
Response response = new Response(CoAP.ResponseCode.CONTENT); |
||||
|
if (data != null && data.length > 0) { |
||||
|
response.setPayload(data); |
||||
|
if (exchange.getRequestOptions().getBlock2() != null) { |
||||
|
int chunkSize = exchange.getRequestOptions().getBlock2().getSzx(); |
||||
|
boolean lastFlag = data.length <= chunkSize; |
||||
|
response.getOptions().setBlock2(chunkSize, lastFlag, 0); |
||||
|
} |
||||
|
transportContext.getExecutor().submit(() -> exchange.respond(response)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -1,483 +0,0 @@ |
|||||
/** |
|
||||
* Copyright © 2016-2021 The Thingsboard Authors |
|
||||
* |
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
* you may not use this file except in compliance with the License. |
|
||||
* You may obtain a copy of the License at |
|
||||
* |
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||
* |
|
||||
* Unless required by applicable law or agreed to in writing, software |
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
* See the License for the specific language governing permissions and |
|
||||
* limitations under the License. |
|
||||
*/ |
|
||||
package org.thingsboard.server.transport.lwm2m.server.client; |
|
||||
|
|
||||
import lombok.Getter; |
|
||||
import lombok.Setter; |
|
||||
import lombok.extern.slf4j.Slf4j; |
|
||||
import org.apache.commons.lang3.StringUtils; |
|
||||
import org.eclipse.leshan.server.registration.Registration; |
|
||||
import org.thingsboard.server.common.data.ota.OtaPackageType; |
|
||||
import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; |
|
||||
import org.thingsboard.server.gen.transport.TransportProtos; |
|
||||
import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; |
|
||||
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; |
|
||||
import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; |
|
||||
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; |
|
||||
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; |
|
||||
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteRequest; |
|
||||
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteCallback; |
|
||||
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveRequest; |
|
||||
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveCallback; |
|
||||
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback; |
|
||||
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest; |
|
||||
|
|
||||
import java.util.ArrayList; |
|
||||
import java.util.List; |
|
||||
import java.util.UUID; |
|
||||
import java.util.concurrent.CopyOnWriteArrayList; |
|
||||
|
|
||||
import static org.thingsboard.server.common.data.ota.OtaPackageKey.STATE; |
|
||||
import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; |
|
||||
import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; |
|
||||
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED; |
|
||||
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED; |
|
||||
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.INITIATED; |
|
||||
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATED; |
|
||||
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING; |
|
||||
import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttributeKey; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FIRMWARE_UPDATE_COAP_RESOURCE; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_3_VER_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_5_VER_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_NAME_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_PACKAGE_19_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_PACKAGE_5_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_PACKAGE_URI_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_STATE_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_UPDATE; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_UPDATE_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_19_BINARY; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType.EXECUTE; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType.WRITE_REPLACE; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_INSTALL_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_NAME_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_PACKAGE_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_RESULT_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UN_INSTALL_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UPDATE; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UPDATE_STATE_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_VER_ID; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsFwSateToFirmwareUpdateStatus; |
|
||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.splitCamelCaseString; |
|
||||
|
|
||||
@Slf4j |
|
||||
public class LwM2mFwSwUpdate { |
|
||||
// 5/0/6 PkgName
|
|
||||
// 9/0/0 PkgName
|
|
||||
@Getter |
|
||||
@Setter |
|
||||
private volatile String currentTitle; |
|
||||
// 5/0/7 PkgVersion
|
|
||||
// 9/0/1 PkgVersion
|
|
||||
@Getter |
|
||||
@Setter |
|
||||
private volatile String currentVersion; |
|
||||
@Getter |
|
||||
@Setter |
|
||||
private volatile UUID currentId; |
|
||||
@Getter |
|
||||
@Setter |
|
||||
private volatile String stateUpdate; |
|
||||
@Getter |
|
||||
private String pathPackageId; |
|
||||
@Getter |
|
||||
private String pathStateId; |
|
||||
@Getter |
|
||||
private String pathResultId; |
|
||||
@Getter |
|
||||
private String pathNameId; |
|
||||
@Getter |
|
||||
private String pathVerId; |
|
||||
@Getter |
|
||||
private String pathInstallId; |
|
||||
@Getter |
|
||||
private String pathUnInstallId; |
|
||||
@Getter |
|
||||
private String wUpdate; |
|
||||
@Getter |
|
||||
@Setter |
|
||||
private volatile boolean infoFwSwUpdate = false; |
|
||||
private final OtaPackageType type; |
|
||||
|
|
||||
private final LwM2mUplinkMsgHandler handler; |
|
||||
|
|
||||
@Getter |
|
||||
LwM2mClient lwM2MClient; |
|
||||
@Getter |
|
||||
private final List<String> pendingInfoRequestsStart; |
|
||||
@Getter |
|
||||
@Setter |
|
||||
private volatile int updateStrategy; |
|
||||
|
|
||||
public LwM2mFwSwUpdate(LwM2mUplinkMsgHandler handler, LwM2mClient lwM2MClient, OtaPackageType type, int updateStrategy) { |
|
||||
this.handler = handler; |
|
||||
this.lwM2MClient = lwM2MClient; |
|
||||
this.pendingInfoRequestsStart = new CopyOnWriteArrayList<>(); |
|
||||
this.type = type; |
|
||||
this.stateUpdate = null; |
|
||||
this.updateStrategy = updateStrategy; |
|
||||
this.initPathId(); |
|
||||
} |
|
||||
|
|
||||
private void initPathId() { |
|
||||
if (FIRMWARE.equals(this.type)) { |
|
||||
this.pathPackageId = LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code == this.updateStrategy ? |
|
||||
FW_PACKAGE_5_ID : LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL.code == this.updateStrategy ? |
|
||||
FW_PACKAGE_URI_ID : FW_PACKAGE_19_ID; |
|
||||
this.pathStateId = FW_STATE_ID; |
|
||||
this.pathResultId = FW_RESULT_ID; |
|
||||
this.pathNameId = FW_NAME_ID; |
|
||||
this.pathVerId = FW_5_VER_ID; |
|
||||
this.pathInstallId = FW_UPDATE_ID; |
|
||||
this.wUpdate = FW_UPDATE; |
|
||||
} else if (SOFTWARE.equals(this.type)) { |
|
||||
this.pathPackageId = SW_PACKAGE_ID; |
|
||||
this.pathStateId = SW_UPDATE_STATE_ID; |
|
||||
this.pathResultId = SW_RESULT_ID; |
|
||||
this.pathNameId = SW_NAME_ID; |
|
||||
this.pathVerId = SW_VER_ID; |
|
||||
this.pathInstallId = SW_INSTALL_ID; |
|
||||
this.pathUnInstallId = SW_UN_INSTALL_ID; |
|
||||
this.wUpdate = SW_UPDATE; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public void initReadValue(DefaultLwM2MUplinkMsgHandler handler, LwM2mDownlinkMsgHandler request, String pathIdVer) { |
|
||||
if (pathIdVer != null) { |
|
||||
this.pendingInfoRequestsStart.remove(pathIdVer); |
|
||||
} |
|
||||
if (this.pendingInfoRequestsStart.size() == 0) { |
|
||||
this.infoFwSwUpdate = false; |
|
||||
// if (!FAILED.name().equals(this.stateUpdate)) {
|
|
||||
boolean conditionalStart = this.type.equals(FIRMWARE) ? this.conditionalFwUpdateStart(handler) : |
|
||||
this.conditionalSwUpdateStart(handler); |
|
||||
if (conditionalStart) { |
|
||||
this.writeFwSwWare(handler, request); |
|
||||
} |
|
||||
// }
|
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Send FsSw to Lwm2mClient: |
|
||||
* before operation Write: fw_state = DOWNLOADING |
|
||||
*/ |
|
||||
public void writeFwSwWare(DefaultLwM2MUplinkMsgHandler handler, LwM2mDownlinkMsgHandler request) { |
|
||||
if (this.currentId != null) { |
|
||||
this.stateUpdate = OtaPackageUpdateStatus.INITIATED.name(); |
|
||||
this.sendLogs(handler, WRITE_REPLACE.name(), LOG_LWM2M_INFO, null); |
|
||||
String targetIdVer = convertPathFromObjectIdToIdVer(this.pathPackageId, this.lwM2MClient.getRegistration()); |
|
||||
String fwMsg = String.format("%s: Start type operation %s paths: %s", LOG_LWM2M_INFO, |
|
||||
LwM2mOperationType.FW_UPDATE.name(), this.pathPackageId); |
|
||||
handler.logToTelemetry(fwMsg, lwM2MClient.getRegistration().getId()); |
|
||||
log.warn("8) Start firmware Update. Send save to: [{}] ver: [{}] path: [{}]", this.lwM2MClient.getDeviceName(), this.currentVersion, targetIdVer); |
|
||||
if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code == this.updateStrategy) { |
|
||||
int chunkSize = 0; |
|
||||
int chunk = 0; |
|
||||
byte[] firmwareChunk = handler.otaPackageDataCache.get(this.currentId.toString(), chunkSize, chunk); |
|
||||
|
|
||||
TbLwM2MWriteReplaceRequest downlink = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(firmwareChunk).timeout(handler.config.getTimeout()).build(); |
|
||||
request.sendWriteReplaceRequest(lwM2MClient, downlink, new TbLwM2MWriteResponseCallback(handler, lwM2MClient, targetIdVer)); |
|
||||
} else if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL.code == this.updateStrategy) { |
|
||||
String apiFont = "coap://176.36.143.9:5685"; |
|
||||
String uri = apiFont + "/" + FIRMWARE_UPDATE_COAP_RESOURCE + "/" + this.currentId.toString(); |
|
||||
log.warn("89) coapUri: [{}]", uri); |
|
||||
//TODO: user this.rpcRequest???
|
|
||||
TbLwM2MWriteReplaceRequest downlink = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(uri).timeout(handler.config.getTimeout()).build(); |
|
||||
request.sendWriteReplaceRequest(lwM2MClient, downlink, new TbLwM2MWriteResponseCallback(handler, lwM2MClient, targetIdVer)); |
|
||||
} else if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_19_BINARY.code == this.updateStrategy) { |
|
||||
|
|
||||
} |
|
||||
} else { |
|
||||
String msgError = "FirmWareId is null."; |
|
||||
log.warn("6) [{}]", msgError); |
|
||||
// if (this.rpcRequest != null) {
|
|
||||
// TODO: refactor.
|
|
||||
// handler.sentRpcResponse(this.rpcRequest, CONTENT.name(), msgError, LOG_LW2M_ERROR);
|
|
||||
// }
|
|
||||
log.error(msgError); |
|
||||
this.sendLogs(handler, WRITE_REPLACE.name(), LOG_LWM2M_ERROR, msgError); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public void sendLogs(DefaultLwM2MUplinkMsgHandler handler, String typeOper, String typeInfo, String msgError) { |
|
||||
// this.sendSateOnThingsBoard(handler);
|
|
||||
String msg = String.format("%s: %s, %s, pkgVer: %s: pkgName - %s state - %s.", |
|
||||
typeInfo, this.wUpdate, typeOper, this.currentVersion, this.currentTitle, this.stateUpdate); |
|
||||
if (LOG_LWM2M_ERROR.equals(typeInfo)) { |
|
||||
msg = String.format("%s Error: %s", msg, msgError); |
|
||||
} |
|
||||
handler.logToTelemetry(lwM2MClient, msg); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* After inspection Update Result |
|
||||
* fw_state/sw_state = UPDATING |
|
||||
* send execute |
|
||||
*/ |
|
||||
public void executeFwSwWare(DefaultLwM2MUplinkMsgHandler handler, LwM2mDownlinkMsgHandler request) { |
|
||||
this.sendLogs(handler, EXECUTE.name(), LOG_LWM2M_INFO, null); |
|
||||
//TODO: user this.rpcRequest???
|
|
||||
TbLwM2MExecuteRequest downlink = TbLwM2MExecuteRequest.builder().versionedId(pathInstallId).timeout(handler.config.getTimeout()).build(); |
|
||||
request.sendExecuteRequest(lwM2MClient, downlink, new TbLwM2MExecuteCallback(handler, lwM2MClient, pathInstallId)); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Firmware start: Check if the version has changed and launch a new update. |
|
||||
* -ObjectId 5, Binary or ObjectId 5, URI |
|
||||
* -- If the result of the update - errors (more than 1) - This means that the previous. the update failed. |
|
||||
* - We launch the update regardless of the state of the firmware and its version. |
|
||||
* -- If the result of the update - errors (more than 1) - This means that the previous. the update failed. |
|
||||
* * ObjectId 5, Binary |
|
||||
* -- If the result of the update is not errors (equal to 1 or 0) and ver in Object 5 is not empty - it means that the previous update has passed. |
|
||||
* Compare current versions by equals. |
|
||||
* * ObjectId 5, URI |
|
||||
* -- If the result of the update is not errors (equal to 1 or 0) and ver in Object 5 is not empty - it means that the previous update has passed. |
|
||||
* Compare current versions by contains. |
|
||||
*/ |
|
||||
private boolean conditionalFwUpdateStart(DefaultLwM2MUplinkMsgHandler handler) { |
|
||||
Long updateResultFw = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId); |
|
||||
String ver5 = (String) this.lwM2MClient.getResourceValue(null, this.pathVerId); |
|
||||
String pathName = (String) this.lwM2MClient.getResourceValue(null, this.pathNameId); |
|
||||
String ver3 = (String) this.lwM2MClient.getResourceValue(null, FW_3_VER_ID); |
|
||||
// #1/#2
|
|
||||
String fwMsg = null; |
|
||||
if ((this.currentVersion != null && ( |
|
||||
ver5 != null && ver5.equals(this.currentVersion) || |
|
||||
ver3 != null && ver3.contains(this.currentVersion) |
|
||||
)) || |
|
||||
(this.currentTitle != null && pathName != null && this.currentTitle.equals(pathName))) { |
|
||||
fwMsg = String.format("%s: The update was interrupted. The device has the same version: %s.", LOG_LWM2M_ERROR, |
|
||||
this.currentVersion); |
|
||||
} else if (updateResultFw != null && updateResultFw > LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code) { |
|
||||
fwMsg = String.format("%s: The update was interrupted. The device has the status UpdateResult: error (%d).", LOG_LWM2M_ERROR, |
|
||||
updateResultFw); |
|
||||
} |
|
||||
if (fwMsg != null) { |
|
||||
handler.logToTelemetry(fwMsg, lwM2MClient.getRegistration().getId()); |
|
||||
return false; |
|
||||
} else { |
|
||||
return true; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* Before operation Execute inspection Update Result : |
|
||||
* 0 - Initial value |
|
||||
*/ |
|
||||
public boolean conditionalFwExecuteStart() { |
|
||||
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId); |
|
||||
return LwM2mTransportUtil.UpdateResultFw.INITIAL.code == updateResult; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* After operation Execute success inspection Update Result : |
|
||||
* 1 - "Firmware updated successfully" |
|
||||
*/ |
|
||||
public boolean conditionalFwExecuteAfterSuccess() { |
|
||||
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId); |
|
||||
return LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code == updateResult; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* After operation Execute success inspection Update Result : |
|
||||
* > 1 error: "Firmware updated successfully" |
|
||||
*/ |
|
||||
public boolean conditionalFwExecuteAfterError() { |
|
||||
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId); |
|
||||
return LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code < updateResult; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Software start |
|
||||
* - If Update Result -errors (equal or more than 50) - This means that the previous. the update failed. |
|
||||
* * - We launch the update regardless of the state of the firmware and its version. |
|
||||
* - If Update Result is not errors (less than 50) and ver is not empty - This means that before. the update has passed. |
|
||||
* - If Update Result is not errors and ver is empty - This means that there was no update yet or before. UnInstall update |
|
||||
* - If Update Result is not errors and ver is not empty - This means that before unInstall update |
|
||||
* * - Check if the version has changed and launch a new update. |
|
||||
*/ |
|
||||
private boolean conditionalSwUpdateStart(DefaultLwM2MUplinkMsgHandler handler) { |
|
||||
Long updateResultSw = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId); |
|
||||
// #1/#2
|
|
||||
return updateResultSw >= LwM2mTransportUtil.UpdateResultSw.NOT_ENOUGH_STORAGE.code || |
|
||||
( |
|
||||
(updateResultSw <= LwM2mTransportUtil.UpdateResultSw.NOT_ENOUGH_STORAGE.code |
|
||||
) && |
|
||||
( |
|
||||
(this.currentVersion != null && !this.currentVersion.equals(this.lwM2MClient.getResourceValue(null, this.pathVerId))) || |
|
||||
(this.currentTitle != null && !this.currentTitle.equals(this.lwM2MClient.getResourceValue(null, this.pathNameId))) |
|
||||
) |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Before operation Execute inspection Update Result : |
|
||||
* 3 - Successfully Downloaded and package integrity verified |
|
||||
*/ |
|
||||
public boolean conditionalSwUpdateExecute() { |
|
||||
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId); |
|
||||
return LwM2mTransportUtil.UpdateResultSw.SUCCESSFULLY_DOWNLOADED_VERIFIED.code == updateResult; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* After finish operation Execute (success): |
|
||||
* -- inspection Update Result: |
|
||||
* ---- FW если Update Result == 1 ("Firmware updated successfully") или SW если Update Result == 2 ("Software successfully installed.") |
|
||||
* -- fw_state/sw_state = UPDATED |
|
||||
* <p> |
|
||||
* After finish operation Execute (error): |
|
||||
* -- inspection updateResult and send to thingsboard info about error |
|
||||
* --- send to telemetry ( key - this is name Update Result in model) ( |
|
||||
* -- fw_state/sw_state = FAILED |
|
||||
*/ |
|
||||
public void finishFwSwUpdate(DefaultLwM2MUplinkMsgHandler handler, boolean success) { |
|
||||
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId); |
|
||||
String value = FIRMWARE.equals(this.type) ? LwM2mTransportUtil.UpdateResultFw.fromUpdateResultFwByCode(updateResult.intValue()).type : |
|
||||
LwM2mTransportUtil.UpdateResultSw.fromUpdateResultSwByCode(updateResult.intValue()).type; |
|
||||
String key = splitCamelCaseString((String) this.lwM2MClient.getResourceNameByRezId(null, this.pathResultId)); |
|
||||
if (success) { |
|
||||
this.stateUpdate = OtaPackageUpdateStatus.UPDATED.name(); |
|
||||
this.sendLogs(handler, EXECUTE.name(), LOG_LWM2M_INFO, null); |
|
||||
} else { |
|
||||
this.stateUpdate = OtaPackageUpdateStatus.FAILED.name(); |
|
||||
this.sendLogs(handler, EXECUTE.name(), LOG_LWM2M_ERROR, value); |
|
||||
} |
|
||||
handler.helper.sendParametersOnThingsboardTelemetry( |
|
||||
handler.helper.getKvStringtoThingsboard(key, value), this.lwM2MClient.getSession()); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* After operation Execute success inspection Update Result : |
|
||||
* 2 - "Software successfully installed." |
|
||||
*/ |
|
||||
public boolean conditionalSwExecuteAfterSuccess() { |
|
||||
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId); |
|
||||
return LwM2mTransportUtil.UpdateResultSw.SUCCESSFULLY_INSTALLED.code == updateResult; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* After operation Execute success inspection Update Result : |
|
||||
* >= 50 - error "NOT_ENOUGH_STORAGE" |
|
||||
*/ |
|
||||
public boolean conditionalSwExecuteAfterError() { |
|
||||
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId); |
|
||||
return LwM2mTransportUtil.UpdateResultSw.NOT_ENOUGH_STORAGE.code <= updateResult; |
|
||||
} |
|
||||
|
|
||||
// private void observeStateUpdate(DefaultLwM2MUplinkMsgHandler handler, LwM2mDownlinkMsgHandler request) {
|
|
||||
// request.sendAllRequest(lwM2MClient,
|
|
||||
// convertPathFromObjectIdToIdVer(this.pathStateId, this.lwM2MClient.getRegistration()), OBSERVE,
|
|
||||
// null, null, 0, null);
|
|
||||
// request.sendAllRequest(lwM2MClient,
|
|
||||
// convertPathFromObjectIdToIdVer(this.pathResultId, this.lwM2MClient.getRegistration()), OBSERVE,
|
|
||||
// null, null, 0, null);
|
|
||||
// }
|
|
||||
|
|
||||
public void sendSateOnThingsBoard(DefaultLwM2MUplinkMsgHandler handler) { |
|
||||
if (StringUtils.trimToNull(this.stateUpdate) != null) { |
|
||||
List<TransportProtos.KeyValueProto> result = new ArrayList<>(); |
|
||||
TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(getAttributeKey(this.type, STATE)); |
|
||||
kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV(stateUpdate); |
|
||||
result.add(kvProto.build()); |
|
||||
handler.helper.sendParametersOnThingsboardTelemetry(result, |
|
||||
handler.getSessionInfoOrCloseSession(this.lwM2MClient.getRegistration())); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public void sendReadObserveInfo(LwM2mDownlinkMsgHandler request) { |
|
||||
this.infoFwSwUpdate = true; |
|
||||
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer( |
|
||||
this.pathStateId, this.lwM2MClient.getRegistration())); |
|
||||
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer( |
|
||||
this.pathResultId, this.lwM2MClient.getRegistration())); |
|
||||
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer( |
|
||||
FW_3_VER_ID, this.lwM2MClient.getRegistration())); |
|
||||
if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code == this.updateStrategy || |
|
||||
LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_19_BINARY.code == this.updateStrategy || |
|
||||
SOFTWARE.equals(this.type)) { |
|
||||
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer( |
|
||||
this.pathVerId, this.lwM2MClient.getRegistration())); |
|
||||
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer( |
|
||||
this.pathNameId, this.lwM2MClient.getRegistration())); |
|
||||
} |
|
||||
this.pendingInfoRequestsStart.forEach(versionedId -> { |
|
||||
TbLwM2MObserveRequest downlink = TbLwM2MObserveRequest.builder().versionedId(versionedId).build(); |
|
||||
request.sendObserveRequest(this.lwM2MClient, downlink, new TbLwM2MObserveCallback(handler, lwM2MClient, versionedId)); |
|
||||
}); |
|
||||
|
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Before operation Execute (FwUpdate) inspection Update Result : |
|
||||
* - after finished operation Write result: success (FwUpdate): fw_state = DOWNLOADED |
|
||||
* - before start operation Execute (FwUpdate) Update Result = 0 - Initial value |
|
||||
* - start Execute (FwUpdate) |
|
||||
* After finished operation Execute (FwUpdate) inspection Update Result : |
|
||||
* - after start operation Execute (FwUpdate): fw_state = UPDATING |
|
||||
* - after success finished operation Execute (FwUpdate) Update Result == 1 ("Firmware updated successfully") |
|
||||
* - finished operation Execute (FwUpdate) |
|
||||
*/ |
|
||||
public void updateStateOta(DefaultLwM2MUplinkMsgHandler handler, LwM2mDownlinkMsgHandler request, |
|
||||
Registration registration, String path, int value) { |
|
||||
if (OBJ_5_BINARY.code == this.getUpdateStrategy()) { |
|
||||
if ((convertPathFromObjectIdToIdVer(FW_RESULT_ID, registration).equals(path))) { |
|
||||
if (DOWNLOADED.name().equals(this.getStateUpdate()) |
|
||||
&& this.conditionalFwExecuteStart()) { |
|
||||
this.executeFwSwWare(handler, request); |
|
||||
} else if (UPDATING.name().equals(this.getStateUpdate()) |
|
||||
&& this.conditionalFwExecuteAfterSuccess()) { |
|
||||
this.finishFwSwUpdate(handler, true); |
|
||||
} else if (UPDATING.name().equals(this.getStateUpdate()) |
|
||||
&& this.conditionalFwExecuteAfterError()) { |
|
||||
this.finishFwSwUpdate(handler, false); |
|
||||
} |
|
||||
} |
|
||||
} else if (OBJ_5_TEMP_URL.code == this.getUpdateStrategy()) { |
|
||||
if (this.currentId != null && (convertPathFromObjectIdToIdVer(FW_STATE_ID, registration).equals(path))) { |
|
||||
String state = equalsFwSateToFirmwareUpdateStatus(LwM2mTransportUtil.StateFw.fromStateFwByCode(value)).name(); |
|
||||
if (StringUtils.isNotEmpty(state) && !FAILED.name().equals(this.stateUpdate) && !state.equals(this.stateUpdate)) { |
|
||||
this.stateUpdate = state; |
|
||||
this.sendSateOnThingsBoard(handler); |
|
||||
} |
|
||||
if (value == LwM2mTransportUtil.StateFw.DOWNLOADED.code) { |
|
||||
this.executeFwSwWare(handler, request); |
|
||||
} |
|
||||
handler.firmwareUpdateState.put(lwM2MClient.getEndpoint(), value); |
|
||||
} |
|
||||
if ((convertPathFromObjectIdToIdVer(FW_RESULT_ID, registration).equals(path))) { |
|
||||
if (this.currentId != null && value == LwM2mTransportUtil.UpdateResultFw.INITIAL.code) { |
|
||||
this.setStateUpdate(INITIATED.name()); |
|
||||
} else if (this.currentId != null && value == LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code) { |
|
||||
this.setStateUpdate(UPDATED.name()); |
|
||||
} else if (value > LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code) { |
|
||||
this.setStateUpdate(FAILED.name()); |
|
||||
} |
|
||||
this.sendSateOnThingsBoard(handler); |
|
||||
} |
|
||||
} else if (OBJ_19_BINARY.code == this.getUpdateStrategy()) { |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,41 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.lwm2m.server.common; |
||||
|
|
||||
|
import org.thingsboard.common.util.ThingsBoardExecutors; |
||||
|
|
||||
|
import javax.annotation.PreDestroy; |
||||
|
import java.util.concurrent.ExecutorService; |
||||
|
|
||||
|
public abstract class LwM2MExecutorAwareService { |
||||
|
|
||||
|
protected ExecutorService executor; |
||||
|
|
||||
|
protected abstract int getExecutorSize(); |
||||
|
|
||||
|
protected abstract String getExecutorName(); |
||||
|
|
||||
|
protected void init() { |
||||
|
this.executor = ThingsBoardExecutors.newWorkStealingPool(getExecutorSize(), getExecutorName()); |
||||
|
} |
||||
|
|
||||
|
public void destroy() { |
||||
|
if (executor != null) { |
||||
|
executor.shutdownNow(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.lwm2m.server.downlink; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
||||
|
import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; |
||||
|
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; |
||||
|
|
||||
|
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; |
||||
|
|
||||
|
@Slf4j |
||||
|
public abstract class TbLwM2MUplinkTargetedCallback<R, T> extends TbLwM2MTargetedCallback<R, T> { |
||||
|
|
||||
|
protected LwM2mUplinkMsgHandler handler; |
||||
|
|
||||
|
public TbLwM2MUplinkTargetedCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) { |
||||
|
super(logService, client, versionedId); |
||||
|
this.handler = handler; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.lwm2m.server.log; |
||||
|
|
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; |
||||
|
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; |
||||
|
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
||||
|
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; |
||||
|
|
||||
|
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; |
||||
|
|
||||
|
@Slf4j |
||||
|
@Service |
||||
|
@TbLwM2mTransportComponent |
||||
|
@RequiredArgsConstructor |
||||
|
public class DefaultLwM2MTelemetryLogService implements LwM2MTelemetryLogService { |
||||
|
|
||||
|
private final LwM2mClientContext clientContext; |
||||
|
private final LwM2mTransportServerHelper helper; |
||||
|
|
||||
|
/** |
||||
|
* @param logMsg - text msg |
||||
|
* @param registrationId - Id of Registration LwM2M Client |
||||
|
*/ |
||||
|
@Override |
||||
|
public void log(String registrationId, String logMsg) { |
||||
|
log(clientContext.getClientByRegistrationId(registrationId), logMsg); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void log(LwM2mClient client, String logMsg) { |
||||
|
if (logMsg != null && client != null && client.getSession() != null) { |
||||
|
if (logMsg.length() > 1024) { |
||||
|
logMsg = logMsg.substring(0, 1024); |
||||
|
} |
||||
|
this.helper.sendParametersOnThingsboardTelemetry(this.helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), client.getSession()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.lwm2m.server.log; |
||||
|
|
||||
|
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
||||
|
|
||||
|
public interface LwM2MTelemetryLogService { |
||||
|
|
||||
|
void log(LwM2mClient client, String msg); |
||||
|
|
||||
|
void log(String registrationId, String msg); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,111 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.lwm2m.server.ota; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import org.thingsboard.server.common.data.StringUtils; |
||||
|
import org.thingsboard.server.common.data.ota.OtaPackageType; |
||||
|
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MFirmwareUpdateStrategy; |
||||
|
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult; |
||||
|
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateState; |
||||
|
import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MSoftwareUpdateStrategy; |
||||
|
|
||||
|
import java.util.Optional; |
||||
|
|
||||
|
@Data |
||||
|
public class LwM2MClientOtaInfo { |
||||
|
|
||||
|
private final String endpoint; |
||||
|
private final OtaPackageType type; |
||||
|
|
||||
|
private String baseUrl; |
||||
|
|
||||
|
private boolean targetFetchFailure; |
||||
|
private String targetName; |
||||
|
private String targetVersion; |
||||
|
private String targetUrl; |
||||
|
|
||||
|
private boolean currentFetchFailure; |
||||
|
private String currentName; |
||||
|
private String currentVersion3; |
||||
|
private String currentVersion5; |
||||
|
private Integer deliveryMethod; |
||||
|
|
||||
|
//TODO: use value from device if applicable;
|
||||
|
private LwM2MFirmwareUpdateStrategy fwStrategy; |
||||
|
private LwM2MSoftwareUpdateStrategy swStrategy; |
||||
|
private FirmwareUpdateState updateState; |
||||
|
private FirmwareUpdateResult updateResult; |
||||
|
|
||||
|
private String failedPackageId; |
||||
|
private int retryAttempts; |
||||
|
|
||||
|
public LwM2MClientOtaInfo(String endpoint, OtaPackageType type, Integer strategyCode, String baseUrl) { |
||||
|
this.endpoint = endpoint; |
||||
|
this.type = type; |
||||
|
this.fwStrategy = LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(strategyCode); |
||||
|
this.baseUrl = baseUrl; |
||||
|
} |
||||
|
|
||||
|
public void updateTarget(String targetName, String targetVersion, Optional<String> newFirmwareUrl) { |
||||
|
this.targetName = targetName; |
||||
|
this.targetVersion = targetVersion; |
||||
|
this.targetUrl = newFirmwareUrl.orElse(null); |
||||
|
} |
||||
|
|
||||
|
public boolean isUpdateRequired() { |
||||
|
if (StringUtils.isEmpty(targetName) || StringUtils.isEmpty(targetVersion) || !isSupported()) { |
||||
|
return false; |
||||
|
} else { |
||||
|
String targetPackageId = getPackageId(targetName, targetVersion); |
||||
|
String currentPackageIdUsingObject5 = getPackageId(currentName, currentVersion5); |
||||
|
if (StringUtils.isNotEmpty(failedPackageId) && failedPackageId.equals(targetPackageId)) { |
||||
|
return false; |
||||
|
} else { |
||||
|
if (targetPackageId.equals(currentPackageIdUsingObject5)) { |
||||
|
return false; |
||||
|
} else if (StringUtils.isNotEmpty(currentVersion3)) { |
||||
|
return !currentVersion3.contains(targetPackageId); |
||||
|
} else { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public boolean isSupported() { |
||||
|
return StringUtils.isNotEmpty(currentName) || StringUtils.isNotEmpty(currentVersion5) || StringUtils.isNotEmpty(currentVersion3); |
||||
|
} |
||||
|
|
||||
|
public void setUpdateResult(FirmwareUpdateResult updateResult) { |
||||
|
this.updateResult = updateResult; |
||||
|
switch (updateResult) { |
||||
|
case INITIAL: |
||||
|
break; |
||||
|
case UPDATE_SUCCESSFULLY: |
||||
|
retryAttempts = 0; |
||||
|
break; |
||||
|
default: |
||||
|
failedPackageId = getPackageId(targetName, targetVersion); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static String getPackageId(String name, String version) { |
||||
|
return (StringUtils.isNotEmpty(name) ? name : "") + (StringUtils.isNotEmpty(version) ? version : ""); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.lwm2m.server.ota.firmware; |
||||
|
|
||||
|
public enum FirmwareDeliveryMethod { |
||||
|
PULL(0, "Pull only"), |
||||
|
PUSH(1, "Push only"), |
||||
|
BOTH(2, "Push or Push"); |
||||
|
|
||||
|
public int code; |
||||
|
public String type; |
||||
|
|
||||
|
FirmwareDeliveryMethod(int code, String type) { |
||||
|
this.code = code; |
||||
|
this.type = type; |
||||
|
} |
||||
|
|
||||
|
public static FirmwareDeliveryMethod fromStateFwByType(String type) { |
||||
|
for (FirmwareDeliveryMethod to : FirmwareDeliveryMethod.values()) { |
||||
|
if (to.type.equals(type)) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported FW delivery type : %s", type)); |
||||
|
} |
||||
|
|
||||
|
public static FirmwareDeliveryMethod fromStateFwByCode(int code) { |
||||
|
for (FirmwareDeliveryMethod to : FirmwareDeliveryMethod.values()) { |
||||
|
if (to.code == code) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported FW delivery code : %s", code)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,75 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.lwm2m.server.ota.firmware; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* FW Update Result |
||||
|
* 0: Initial value. Once the updating process is initiated (Download /Update), this Resource MUST be reset to Initial value. |
||||
|
* 1: Firmware updated successfully. |
||||
|
* 2: Not enough flash memory for the new firmware package. |
||||
|
* 3: Out of RAM during downloading process. |
||||
|
* 4: Connection lost during downloading process. |
||||
|
* 5: Integrity check failure for new downloaded package. |
||||
|
* 6: Unsupported package type. |
||||
|
* 7: Invalid URI. |
||||
|
* 8: Firmware update failed. |
||||
|
* 9: Unsupported protocol. |
||||
|
*/ |
||||
|
public enum FirmwareUpdateResult { |
||||
|
INITIAL(0, "Initial value", false), |
||||
|
UPDATE_SUCCESSFULLY(1, "Firmware updated successfully", false), |
||||
|
NOT_ENOUGH(2, "Not enough flash memory for the new firmware package", false), |
||||
|
OUT_OFF_MEMORY(3, "Out of RAM during downloading process", false), |
||||
|
CONNECTION_LOST(4, "Connection lost during downloading process", true), |
||||
|
INTEGRITY_CHECK_FAILURE(5, "Integrity check failure for new downloaded package", true), |
||||
|
UNSUPPORTED_TYPE(6, "Unsupported package type", false), |
||||
|
INVALID_URI(7, "Invalid URI", false), |
||||
|
UPDATE_FAILED(8, "Firmware update failed", false), |
||||
|
UNSUPPORTED_PROTOCOL(9, "Unsupported protocol", false); |
||||
|
|
||||
|
@Getter |
||||
|
private int code; |
||||
|
@Getter |
||||
|
private String type; |
||||
|
@Getter |
||||
|
private boolean again; |
||||
|
|
||||
|
FirmwareUpdateResult(int code, String type, boolean isAgain) { |
||||
|
this.code = code; |
||||
|
this.type = type; |
||||
|
this.again = isAgain; |
||||
|
} |
||||
|
|
||||
|
public static FirmwareUpdateResult fromUpdateResultFwByType(String type) { |
||||
|
for (FirmwareUpdateResult to : FirmwareUpdateResult.values()) { |
||||
|
if (to.type.equals(type)) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported FW Update Result type : %s", type)); |
||||
|
} |
||||
|
|
||||
|
public static FirmwareUpdateResult fromUpdateResultFwByCode(int code) { |
||||
|
for (FirmwareUpdateResult to : FirmwareUpdateResult.values()) { |
||||
|
if (to.code == code) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported FW Update Result code : %s", code)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.lwm2m.server.ota.firmware; |
||||
|
|
||||
|
/** |
||||
|
* /** State R |
||||
|
* 0: Idle (before downloading or after successful updating) |
||||
|
* 1: Downloading (The data sequence is on the way) |
||||
|
* 2: Downloaded |
||||
|
* 3: Updating |
||||
|
*/ |
||||
|
public enum FirmwareUpdateState { |
||||
|
IDLE(0, "Idle"), |
||||
|
DOWNLOADING(1, "Downloading"), |
||||
|
DOWNLOADED(2, "Downloaded"), |
||||
|
UPDATING(3, "Updating"); |
||||
|
|
||||
|
public int code; |
||||
|
public String type; |
||||
|
|
||||
|
FirmwareUpdateState(int code, String type) { |
||||
|
this.code = code; |
||||
|
this.type = type; |
||||
|
} |
||||
|
|
||||
|
public static FirmwareUpdateState fromStateFwByType(String type) { |
||||
|
for (FirmwareUpdateState to : FirmwareUpdateState.values()) { |
||||
|
if (to.type.equals(type)) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type)); |
||||
|
} |
||||
|
|
||||
|
public static FirmwareUpdateState fromStateFwByCode(int code) { |
||||
|
for (FirmwareUpdateState to : FirmwareUpdateState.values()) { |
||||
|
if (to.code == code) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported FW State code : %s", code)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.lwm2m.server.ota.firmware; |
||||
|
|
||||
|
public enum LwM2MFirmwareUpdateStrategy { |
||||
|
OBJ_5_BINARY(1, "ObjectId 5, Binary"), |
||||
|
OBJ_5_TEMP_URL(2, "ObjectId 5, URI"), |
||||
|
OBJ_19_BINARY(3, "ObjectId 19, Binary"); |
||||
|
|
||||
|
public int code; |
||||
|
public String type; |
||||
|
|
||||
|
LwM2MFirmwareUpdateStrategy(int code, String type) { |
||||
|
this.code = code; |
||||
|
this.type = type; |
||||
|
} |
||||
|
|
||||
|
public static LwM2MFirmwareUpdateStrategy fromStrategyFwByType(String type) { |
||||
|
for (LwM2MFirmwareUpdateStrategy to : LwM2MFirmwareUpdateStrategy.values()) { |
||||
|
if (to.type.equals(type)) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type)); |
||||
|
} |
||||
|
|
||||
|
public static LwM2MFirmwareUpdateStrategy fromStrategyFwByCode(int code) { |
||||
|
for (LwM2MFirmwareUpdateStrategy to : LwM2MFirmwareUpdateStrategy.values()) { |
||||
|
if (to.code == code) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported FW Strategy code : %s", code)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.lwm2m.server.ota.software; |
||||
|
|
||||
|
public enum LwM2MSoftwareUpdateStrategy { |
||||
|
BINARY(1, "ObjectId 9, Binary"), |
||||
|
TEMP_URL(2, "ObjectId 9, URI"); |
||||
|
|
||||
|
public int code; |
||||
|
public String type; |
||||
|
|
||||
|
LwM2MSoftwareUpdateStrategy(int code, String type) { |
||||
|
this.code = code; |
||||
|
this.type = type; |
||||
|
} |
||||
|
|
||||
|
public static LwM2MSoftwareUpdateStrategy fromStrategySwByType(String type) { |
||||
|
for (LwM2MSoftwareUpdateStrategy to : LwM2MSoftwareUpdateStrategy.values()) { |
||||
|
if (to.type.equals(type)) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported SW Strategy type : %s", type)); |
||||
|
} |
||||
|
|
||||
|
public static LwM2MSoftwareUpdateStrategy fromStrategySwByCode(int code) { |
||||
|
for (LwM2MSoftwareUpdateStrategy to : LwM2MSoftwareUpdateStrategy.values()) { |
||||
|
if (to.code == code) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported SW Strategy code : %s", code)); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,84 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.lwm2m.server.ota.software; |
||||
|
|
||||
|
/** |
||||
|
* SW Update Result |
||||
|
* Contains the result of downloading or installing/uninstalling the software |
||||
|
* 0: Initial value. |
||||
|
* - Prior to download any new package in the Device, Update Result MUST be reset to this initial value. |
||||
|
* - One side effect of executing the Uninstall resource is to reset Update Result to this initial value "0". |
||||
|
* 1: Downloading. |
||||
|
* - The package downloading process is on-going. |
||||
|
* 2: Software successfully installed. |
||||
|
* 3: Successfully Downloaded and package integrity verified |
||||
|
* (( 4-49, for expansion, of other scenarios)) |
||||
|
* ** Failed |
||||
|
* 50: Not enough storage for the new software package. |
||||
|
* 51: Out of memory during downloading process. |
||||
|
* 52: Connection lost during downloading process. |
||||
|
* 53: Package integrity check failure. |
||||
|
* 54: Unsupported package type. |
||||
|
* 56: Invalid URI |
||||
|
* 57: Device defined update error |
||||
|
* 58: Software installation failure |
||||
|
* 59: Uninstallation Failure during forUpdate(arg=0) |
||||
|
* 60-200 : (for expansion, selection to be in blocks depending on new introduction of features) |
||||
|
* This Resource MAY be reported by sending Observe operation. |
||||
|
*/ |
||||
|
public enum SoftwareUpdateResult { |
||||
|
INITIAL(0, "Initial value", false), |
||||
|
DOWNLOADING(1, "Downloading", false), |
||||
|
SUCCESSFULLY_INSTALLED(2, "Software successfully installed", false), |
||||
|
SUCCESSFULLY_DOWNLOADED_VERIFIED(3, "Successfully Downloaded and package integrity verified", false), |
||||
|
NOT_ENOUGH_STORAGE(50, "Not enough storage for the new software package", true), |
||||
|
OUT_OFF_MEMORY(51, "Out of memory during downloading process", true), |
||||
|
CONNECTION_LOST(52, "Connection lost during downloading process", false), |
||||
|
PACKAGE_CHECK_FAILURE(53, "Package integrity check failure.", false), |
||||
|
UNSUPPORTED_PACKAGE_TYPE(54, "Unsupported package type", false), |
||||
|
INVALID_URI(56, "Invalid URI", true), |
||||
|
UPDATE_ERROR(57, "Device defined update error", true), |
||||
|
INSTALL_FAILURE(58, "Software installation failure", true), |
||||
|
UN_INSTALL_FAILURE(59, "Uninstallation Failure during forUpdate(arg=0)", true); |
||||
|
|
||||
|
public int code; |
||||
|
public String type; |
||||
|
public boolean isAgain; |
||||
|
|
||||
|
SoftwareUpdateResult(int code, String type, boolean isAgain) { |
||||
|
this.code = code; |
||||
|
this.type = type; |
||||
|
this.isAgain = isAgain; |
||||
|
} |
||||
|
|
||||
|
public static SoftwareUpdateResult fromUpdateResultSwByType(String type) { |
||||
|
for (SoftwareUpdateResult to : SoftwareUpdateResult.values()) { |
||||
|
if (to.type.equals(type)) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported SW Update Result type : %s", type)); |
||||
|
} |
||||
|
|
||||
|
public static SoftwareUpdateResult fromUpdateResultSwByCode(int code) { |
||||
|
for (SoftwareUpdateResult to : SoftwareUpdateResult.values()) { |
||||
|
if (to.code == code) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported SW Update Result code : %s", code)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,62 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.lwm2m.server.ota.software; |
||||
|
|
||||
|
/** |
||||
|
* SW Update State R |
||||
|
* 0: INITIAL Before downloading. (see 5.1.2.1) |
||||
|
* 1: DOWNLOAD STARTED The downloading process has started and is on-going. (see 5.1.2.2) |
||||
|
* 2: DOWNLOADED The package has been completely downloaded (see 5.1.2.3) |
||||
|
* 3: DELIVERED In that state, the package has been correctly downloaded and is ready to be installed. (see 5.1.2.4) |
||||
|
* If executing the Install Resource failed, the state remains at DELIVERED. |
||||
|
* If executing the Install Resource was successful, the state changes from DELIVERED to INSTALLED. |
||||
|
* After executing the UnInstall Resource, the state changes to INITIAL. |
||||
|
* 4: INSTALLED |
||||
|
*/ |
||||
|
public enum SoftwareUpdateState { |
||||
|
INITIAL(0, "Initial"), |
||||
|
DOWNLOAD_STARTED(1, "DownloadStarted"), |
||||
|
DOWNLOADED(2, "Downloaded"), |
||||
|
DELIVERED(3, "Delivered"), |
||||
|
INSTALLED(4, "Installed"); |
||||
|
|
||||
|
public int code; |
||||
|
public String type; |
||||
|
|
||||
|
SoftwareUpdateState(int code, String type) { |
||||
|
this.code = code; |
||||
|
this.type = type; |
||||
|
} |
||||
|
|
||||
|
public static SoftwareUpdateState fromUpdateStateSwByType(String type) { |
||||
|
for (SoftwareUpdateState to : SoftwareUpdateState.values()) { |
||||
|
if (to.type.equals(type)) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported SW State type : %s", type)); |
||||
|
} |
||||
|
|
||||
|
public static SoftwareUpdateState fromUpdateStateSwByCode(int code) { |
||||
|
for (SoftwareUpdateState to : SoftwareUpdateState.values()) { |
||||
|
if (to.code == code) { |
||||
|
return to; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported SW State type : %s", code)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,39 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.transport.lwm2m.server.uplink; |
||||
|
|
||||
|
public enum LwM2mTypeServer { |
||||
|
BOOTSTRAP(0, "bootstrap"), |
||||
|
CLIENT(1, "client"); |
||||
|
|
||||
|
public int code; |
||||
|
public String type; |
||||
|
|
||||
|
LwM2mTypeServer(int code, String type) { |
||||
|
this.code = code; |
||||
|
this.type = type; |
||||
|
} |
||||
|
|
||||
|
public static LwM2mTypeServer fromLwM2mTypeServer(String type) { |
||||
|
for (LwM2mTypeServer sm : LwM2mTypeServer.values()) { |
||||
|
if (sm.type.equals(type)) { |
||||
|
return sm; |
||||
|
} |
||||
|
} |
||||
|
throw new IllegalArgumentException(String.format("Unsupported typeServer type : %d", type)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,57 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.common.util; |
||||
|
|
||||
|
import org.springframework.util.StopWatch; |
||||
|
|
||||
|
/** |
||||
|
* Utility method that extends Spring Framework StopWatch |
||||
|
* It is a MONOTONIC time stopwatch. |
||||
|
* It is a replacement for any measurements with a wall-clock like System.currentTimeMillis() |
||||
|
* It is not affected by leap second, day-light saving and wall-clock adjustments by manual or network time synchronization |
||||
|
* The main features is a single call for common use cases: |
||||
|
* - create and start: TbStopWatch sw = TbStopWatch.startNew() |
||||
|
* - stop and get: sw.stopAndGetTotalTimeMillis() or sw.stopAndGetLastTaskTimeMillis() |
||||
|
* */ |
||||
|
public class TbStopWatch extends StopWatch { |
||||
|
|
||||
|
public static TbStopWatch startNew(){ |
||||
|
TbStopWatch stopWatch = new TbStopWatch(); |
||||
|
stopWatch.start(); |
||||
|
return stopWatch; |
||||
|
} |
||||
|
|
||||
|
public long stopAndGetTotalTimeMillis(){ |
||||
|
stop(); |
||||
|
return getTotalTimeMillis(); |
||||
|
} |
||||
|
|
||||
|
public long stopAndGetTotalTimeNanos(){ |
||||
|
stop(); |
||||
|
return getLastTaskTimeNanos(); |
||||
|
} |
||||
|
|
||||
|
public long stopAndGetLastTaskTimeMillis(){ |
||||
|
stop(); |
||||
|
return getLastTaskTimeMillis(); |
||||
|
} |
||||
|
|
||||
|
public long stopAndGetLastTaskTimeNanos(){ |
||||
|
stop(); |
||||
|
return getLastTaskTimeNanos(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.dao.cache; |
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.thingsboard.common.util.AbstractListeningExecutor; |
||||
|
|
||||
|
@Component |
||||
|
public class CacheExecutorService extends AbstractListeningExecutor { |
||||
|
|
||||
|
@Value("${cache.maximumPoolSize}") |
||||
|
private int poolSize; |
||||
|
|
||||
|
@Override |
||||
|
protected int getThreadPollSize() { |
||||
|
return poolSize; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
const config = require('config'), |
||||
|
logger = require('../config/logger')._logger('httpServer'), |
||||
|
express = require('express'); |
||||
|
|
||||
|
const httpPort = Number(config.get('http_port')); |
||||
|
|
||||
|
const app = express(); |
||||
|
|
||||
|
app.get('/livenessProbe', async (req, res) => { |
||||
|
const date = new Date(); |
||||
|
const message = { now: date.toISOString() }; |
||||
|
res.send(message); |
||||
|
}) |
||||
|
|
||||
|
app.listen(httpPort, () => logger.info(`Started http endpoint on port ${httpPort}. Please, use /livenessProbe !`)) |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue