Commit 1150d4e4f30180ae2c54e3bdca5f36e525c2772a
1 parent
ca46f5fb
Lwm2m: backEnd: add saveDeviceWithCredential
Showing
12 changed files
with
313 additions
and
161 deletions
... | ... | @@ -278,7 +278,6 @@ public class DeviceController extends BaseController { |
278 | 278 | try { |
279 | 279 | Device device = checkDeviceId(deviceCredentials.getDeviceId(), Operation.WRITE_CREDENTIALS); |
280 | 280 | DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(getCurrentUser().getTenantId(), deviceCredentials)); |
281 | - //log.info("0 LwM2M CredentialsUpdate start) | |
282 | 281 | tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId(), result), null); |
283 | 282 | logEntityAction(device.getId(), device, |
284 | 283 | device.getCustomerId(), | ... | ... |
... | ... | @@ -15,17 +15,32 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.controller; |
17 | 17 | |
18 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
18 | 19 | import lombok.extern.slf4j.Slf4j; |
19 | 20 | import org.springframework.security.access.prepost.PreAuthorize; |
20 | -import org.springframework.web.bind.annotation.*; | |
21 | +import org.springframework.web.bind.annotation.PathVariable; | |
22 | +import org.springframework.web.bind.annotation.RequestBody; | |
23 | +import org.springframework.web.bind.annotation.RequestMapping; | |
24 | +import org.springframework.web.bind.annotation.RequestMethod; | |
25 | +import org.springframework.web.bind.annotation.RequestParam; | |
26 | +import org.springframework.web.bind.annotation.ResponseBody; | |
27 | +import org.springframework.web.bind.annotation.RestController; | |
28 | +import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; | |
29 | +import org.thingsboard.server.common.data.Device; | |
30 | +import org.thingsboard.server.common.data.EntityType; | |
31 | +import org.thingsboard.server.common.data.audit.ActionType; | |
21 | 32 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
22 | 33 | import org.thingsboard.server.common.data.lwm2m.LwM2mObject; |
23 | 34 | import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; |
24 | 35 | import org.thingsboard.server.common.data.page.PageData; |
25 | 36 | import org.thingsboard.server.common.data.page.PageLink; |
37 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | |
38 | +import org.thingsboard.server.common.data.security.DeviceCredentials; | |
26 | 39 | import org.thingsboard.server.queue.util.TbCoreComponent; |
40 | +import org.thingsboard.server.service.security.permission.Resource; | |
27 | 41 | |
28 | 42 | import java.util.List; |
43 | +import java.util.Map; | |
29 | 44 | |
30 | 45 | @Slf4j |
31 | 46 | @RestController |
... | ... | @@ -72,4 +87,40 @@ public class DeviceLwm2mController extends BaseController { |
72 | 87 | throw handleException(e); |
73 | 88 | } |
74 | 89 | } |
90 | + | |
91 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
92 | + @RequestMapping(value = "/lwm2m/device-credentials", method = RequestMethod.POST) | |
93 | + @ResponseBody | |
94 | + public Device saveDeviceWithCredentials(@RequestBody (required=false) Map<Class<?>, Object> deviceWithDeviceCredentials) throws ThingsboardException { | |
95 | + ObjectMapper mapper = new ObjectMapper(); | |
96 | + Device device = checkNotNull(mapper.convertValue(deviceWithDeviceCredentials.get(Device.class), Device.class)); | |
97 | + DeviceCredentials credentials = checkNotNull(mapper.convertValue( deviceWithDeviceCredentials.get(DeviceCredentials.class), DeviceCredentials.class)); | |
98 | + try { | |
99 | + device.setTenantId(getCurrentUser().getTenantId()); | |
100 | + checkEntity(device.getId(), device, Resource.DEVICE); | |
101 | + Device savedDevice = deviceService.saveDeviceWithCredentials(device, credentials); | |
102 | + checkNotNull(savedDevice); | |
103 | + | |
104 | + tbClusterService.onDeviceChange(savedDevice, null); | |
105 | + tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(), | |
106 | + savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null); | |
107 | + tbClusterService.onEntityStateChange(savedDevice.getTenantId(), savedDevice.getId(), | |
108 | + device.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); | |
109 | + | |
110 | + logEntityAction(savedDevice.getId(), savedDevice, | |
111 | + savedDevice.getCustomerId(), | |
112 | + device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); | |
113 | + | |
114 | + if (device.getId() == null) { | |
115 | + deviceStateService.onDeviceAdded(savedDevice); | |
116 | + } else { | |
117 | + deviceStateService.onDeviceUpdated(savedDevice); | |
118 | + } | |
119 | + return savedDevice; | |
120 | + } catch (Exception e) { | |
121 | + logEntityAction(emptyId(EntityType.DEVICE), device, | |
122 | + null, device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); | |
123 | + throw handleException(e); | |
124 | + } | |
125 | + } | |
75 | 126 | } | ... | ... |
... | ... | @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; |
27 | 27 | import org.thingsboard.server.common.data.id.TenantId; |
28 | 28 | import org.thingsboard.server.common.data.page.PageData; |
29 | 29 | import org.thingsboard.server.common.data.page.PageLink; |
30 | +import org.thingsboard.server.common.data.security.DeviceCredentials; | |
30 | 31 | import org.thingsboard.server.dao.device.provision.ProvisionRequest; |
31 | 32 | |
32 | 33 | import java.util.List; |
... | ... | @@ -45,6 +46,8 @@ public interface DeviceService { |
45 | 46 | |
46 | 47 | Device saveDeviceWithAccessToken(Device device, String accessToken); |
47 | 48 | |
49 | + Device saveDeviceWithCredentials(Device device, DeviceCredentials deviceCredentials); | |
50 | + | |
48 | 51 | Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, CustomerId customerId); |
49 | 52 | |
50 | 53 | Device unassignDeviceFromCustomer(TenantId tenantId, DeviceId deviceId); | ... | ... |
... | ... | @@ -20,7 +20,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; |
20 | 20 | import lombok.EqualsAndHashCode; |
21 | 21 | import lombok.extern.slf4j.Slf4j; |
22 | 22 | import org.thingsboard.server.common.data.device.data.DeviceData; |
23 | -import org.thingsboard.server.common.data.device.profile.DeviceProfileData; | |
24 | 23 | import org.thingsboard.server.common.data.id.CustomerId; |
25 | 24 | import org.thingsboard.server.common.data.id.DeviceId; |
26 | 25 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
... | ... | @@ -64,6 +63,17 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen |
64 | 63 | this.setDeviceData(device.getDeviceData()); |
65 | 64 | } |
66 | 65 | |
66 | + public Device updateDevice(Device device) { | |
67 | + this.tenantId = device.getTenantId(); | |
68 | + this.customerId = device.getCustomerId(); | |
69 | + this.name = device.getName(); | |
70 | + this.type = device.getType(); | |
71 | + this.label = device.getLabel(); | |
72 | + this.deviceProfileId = device.getDeviceProfileId(); | |
73 | + this.setDeviceData(device.getDeviceData()); | |
74 | + return this; | |
75 | + } | |
76 | + | |
67 | 77 | public TenantId getTenantId() { |
68 | 78 | return tenantId; |
69 | 79 | } | ... | ... |
... | ... | @@ -45,15 +45,9 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; |
45 | 45 | import javax.annotation.PostConstruct; |
46 | 46 | import java.io.File; |
47 | 47 | import java.io.IOException; |
48 | -import java.text.DateFormat; | |
49 | -import java.text.SimpleDateFormat; | |
50 | -import java.util.ArrayList; | |
51 | 48 | import java.util.Arrays; |
52 | -import java.util.Collections; | |
53 | 49 | import java.util.Date; |
54 | 50 | import java.util.LinkedList; |
55 | -import java.util.List; | |
56 | -import java.util.Map; | |
57 | 51 | import java.util.Optional; |
58 | 52 | |
59 | 53 | @Slf4j |
... | ... | @@ -127,14 +121,19 @@ public class LwM2MTransportHandler{ |
127 | 121 | |
128 | 122 | @PostConstruct |
129 | 123 | public void init() { |
130 | - LwM2mServerListener lwM2mServerListener = new LwM2mServerListener(lhServerCert, service); | |
131 | - this.lhServerCert.getRegistrationService().addListener(lwM2mServerListener.registrationListener); | |
132 | - this.lhServerCert.getPresenceService().addListener(lwM2mServerListener.presenceListener); | |
133 | - this.lhServerCert.getObservationService().addListener(lwM2mServerListener.observationListener); | |
134 | - lwM2mServerListener = new LwM2mServerListener(lhServerNoSecPskRpk, service); | |
135 | - this.lhServerNoSecPskRpk.getRegistrationService().addListener(lwM2mServerListener.registrationListener); | |
136 | - this.lhServerNoSecPskRpk.getPresenceService().addListener(lwM2mServerListener.presenceListener); | |
137 | - this.lhServerNoSecPskRpk.getObservationService().addListener(lwM2mServerListener.observationListener); | |
124 | + try { | |
125 | + LwM2mServerListener lwM2mServerListener = new LwM2mServerListener(lhServerCert, service); | |
126 | + this.lhServerCert.getRegistrationService().addListener(lwM2mServerListener.registrationListener); | |
127 | + this.lhServerCert.getPresenceService().addListener(lwM2mServerListener.presenceListener); | |
128 | + this.lhServerCert.getObservationService().addListener(lwM2mServerListener.observationListener); | |
129 | + lwM2mServerListener = new LwM2mServerListener(lhServerNoSecPskRpk, service); | |
130 | + this.lhServerNoSecPskRpk.getRegistrationService().addListener(lwM2mServerListener.registrationListener); | |
131 | + this.lhServerNoSecPskRpk.getPresenceService().addListener(lwM2mServerListener.presenceListener); | |
132 | + this.lhServerNoSecPskRpk.getObservationService().addListener(lwM2mServerListener.observationListener); | |
133 | + } | |
134 | + catch (java.lang.NullPointerException e) { | |
135 | + log.error("init [{}]", e.toString()); | |
136 | + } | |
138 | 137 | } |
139 | 138 | |
140 | 139 | public static NetworkConfig getCoapConfig() { |
... | ... | @@ -150,7 +149,8 @@ public class LwM2MTransportHandler{ |
150 | 149 | return coapConfig; |
151 | 150 | } |
152 | 151 | |
153 | - public static String getValueTypeToString (Object value, ResourceModel.Type type) { | |
152 | + public static String getValueTypeToString (Object value, ResourceModel.Type type, int val) { | |
153 | + try{ | |
154 | 154 | switch (type) { |
155 | 155 | case STRING: // String |
156 | 156 | case OBJLNK: // ObjectLink |
... | ... | @@ -160,16 +160,21 @@ public class LwM2MTransportHandler{ |
160 | 160 | case BOOLEAN: // Boolean |
161 | 161 | return Boolean.toString((Boolean) value); |
162 | 162 | case FLOAT: // Double |
163 | - return Double.toString((Float)value); | |
163 | + return Double.toString((Double) value); | |
164 | 164 | case TIME: // Date |
165 | - String DATE_FORMAT = "MMM d, yyyy HH:mm a"; | |
166 | - DateFormat formatter = new SimpleDateFormat(DATE_FORMAT); | |
167 | - return formatter.format(new Date(Integer.toUnsignedLong((Integer) value))); | |
165 | + return Long.toString(((Date) value).getTime()); | |
166 | +// String DATE_FORMAT = "MMM d, yyyy HH:mm a"; | |
167 | +// DateFormat formatter = new SimpleDateFormat(DATE_FORMAT); | |
168 | +// return formatter.format(new Date(Integer.toUnsignedLong((Integer) value))); | |
168 | 169 | case OPAQUE: // byte[] value, base64 |
169 | 170 | return Hex.encodeHexString((byte[])value); |
170 | 171 | default: |
171 | 172 | return null; |
172 | 173 | } |
174 | + } catch (Exception e) { | |
175 | + log.error(e.getStackTrace().toString()); | |
176 | + return null; | |
177 | + } | |
173 | 178 | } |
174 | 179 | |
175 | 180 | public static LwM2mNode getLvM2mNodeToObject(LwM2mNode content) { |
... | ... | @@ -305,28 +310,6 @@ public class LwM2MTransportHandler{ |
305 | 310 | } |
306 | 311 | } |
307 | 312 | |
308 | - /** | |
309 | - * Equals to Map for values | |
310 | - * @param map1 - | |
311 | - * @param map2 - | |
312 | - * @param <V> - | |
313 | - * @return - true if equals | |
314 | - */ | |
315 | - public static <V extends Comparable<V>> boolean mapsEquals(Map<?,V> map1, Map<?,V> map2) { | |
316 | - List<V> values1 = new ArrayList<>(map1.values()); | |
317 | - List<V> values2 = new ArrayList<>(map2.values()); | |
318 | - Collections.sort(values1); | |
319 | - Collections.sort(values2); | |
320 | - return values1.equals(values2); | |
321 | - } | |
322 | - | |
323 | - public static String convertCamelCase (String str) { | |
324 | - str = str.toLowerCase().replace("/[^a-z ]+/g", " "); | |
325 | - str = str.replace("/^(.)|\\s(.)/g", "$1"); | |
326 | - str = str.replace("/[^a-zA-Z]+/g", ""); | |
327 | - return str; | |
328 | - } | |
329 | - | |
330 | 313 | public static String splitCamelCaseString(String s){ |
331 | 314 | LinkedList<String> linkedListOut = new LinkedList<>(); |
332 | 315 | LinkedList<String> linkedList = new LinkedList<String>((Arrays.asList(s.split(" ")))); | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import org.eclipse.californium.core.coap.Response; |
20 | 20 | import org.eclipse.leshan.core.attributes.Attribute; |
21 | 21 | import org.eclipse.leshan.core.attributes.AttributeSet; |
22 | 22 | import org.eclipse.leshan.core.model.ResourceModel; |
23 | +import org.eclipse.leshan.core.node.LwM2mPath; | |
23 | 24 | import org.eclipse.leshan.core.node.LwM2mSingleResource; |
24 | 25 | import org.eclipse.leshan.core.node.ObjectLink; |
25 | 26 | import org.eclipse.leshan.core.observation.Observation; |
... | ... | @@ -50,6 +51,7 @@ import org.springframework.beans.factory.annotation.Autowired; |
50 | 51 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
51 | 52 | import org.springframework.stereotype.Service; |
52 | 53 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; |
54 | +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; | |
53 | 55 | |
54 | 56 | import javax.annotation.PostConstruct; |
55 | 57 | import java.util.ArrayList; |
... | ... | @@ -79,16 +81,17 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandle |
79 | 81 | public class LwM2MTransportRequest { |
80 | 82 | private final ExecutorService executorService; |
81 | 83 | private static final String RESPONSE_CHANNEL = "THINGSBOARD_RESP"; |
84 | + private final LwM2mValueConverterImpl converter; | |
82 | 85 | |
83 | 86 | @Autowired |
84 | 87 | LwM2MTransportService service; |
85 | 88 | |
86 | 89 | public LwM2MTransportRequest() { |
90 | + this.converter = new LwM2mValueConverterImpl(); | |
87 | 91 | executorService = Executors.newCachedThreadPool( |
88 | 92 | new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL))); |
89 | 93 | } |
90 | 94 | |
91 | - | |
92 | 95 | @PostConstruct |
93 | 96 | public void init() { |
94 | 97 | } |
... | ... | @@ -115,12 +118,12 @@ public class LwM2MTransportRequest { |
115 | 118 | */ |
116 | 119 | public void sendAllRequest(LeshanServer lwServer, Registration registration, String target, String typeOper, String contentFormatParam, |
117 | 120 | LwM2MClient lwM2MClient, Observation observation, Object params, long timeoutInMs, boolean isDelayedUpdate) { |
118 | - ResultIds resultIds = new ResultIds(target); | |
121 | + LwM2mPath resultIds = new LwM2mPath(target); | |
119 | 122 | if (registration != null && resultIds.getObjectId() >= 0) { |
120 | 123 | DownlinkRequest request = null; |
121 | 124 | ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null; |
122 | - ResourceModel resource = (resultIds.resourceId >= 0) ? (lwM2MClient != null) ? | |
123 | - lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.resourceId) : null : null; | |
125 | + ResourceModel resource = (resultIds.getResourceId() !=null && lwM2MClient != null) ? | |
126 | + lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()) : null; | |
124 | 127 | ResourceModel.Type resType = (resource == null) ? null : resource.type; |
125 | 128 | boolean resMultiple = (resource == null) ? false : resource.multiple; |
126 | 129 | timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; |
... | ... | @@ -132,10 +135,10 @@ public class LwM2MTransportRequest { |
132 | 135 | request = new DiscoverRequest(target); |
133 | 136 | break; |
134 | 137 | case GET_TYPE_OPER_OBSERVE: |
135 | - if (resultIds.getResourceId() >= 0) { | |
136 | - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId()); | |
137 | - } else if (resultIds.getInstanceId() >= 0) { | |
138 | - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getInstanceId()); | |
138 | + if (resultIds.isResource()) { | |
139 | + request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId()); | |
140 | + } else if (resultIds.isObjectInstance()) { | |
141 | + request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId()); | |
139 | 142 | } else if (resultIds.getObjectId() >= 0) { |
140 | 143 | request = new ObserveRequest(resultIds.getObjectId()); |
141 | 144 | } |
... | ... | @@ -145,7 +148,8 @@ public class LwM2MTransportRequest { |
145 | 148 | break; |
146 | 149 | case POST_TYPE_OPER_EXECUTE: |
147 | 150 | if (params != null && !resMultiple) { |
148 | - request = new ExecuteRequest(target, LwM2MTransportHandler.getValueTypeToString(params, resType)); | |
151 | +// request = new ExecuteRequest(target, LwM2MTransportHandler.getValueTypeToString(params, resType)); | |
152 | + request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resType, ResourceModel.Type.STRING, resultIds)); | |
149 | 153 | } else { |
150 | 154 | request = new ExecuteRequest(target); |
151 | 155 | } |
... | ... | @@ -153,11 +157,11 @@ public class LwM2MTransportRequest { |
153 | 157 | case POST_TYPE_OPER_WRITE_REPLACE: |
154 | 158 | // Request to write a <b>String Single-Instance Resource</b> using the TLV content format. |
155 | 159 | if (contentFormat.equals(ContentFormat.TLV) && !resMultiple) { |
156 | - request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType, registration); | |
160 | + request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resType, registration); | |
157 | 161 | } |
158 | 162 | // Mode.REPLACE && Request to write a <b>String Single-Instance Resource</b> using the given content format (TEXT, TLV, JSON) |
159 | 163 | else if (!contentFormat.equals(ContentFormat.TLV) && !resMultiple) { |
160 | - request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType, registration); | |
164 | + request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resType, registration); | |
161 | 165 | } |
162 | 166 | break; |
163 | 167 | case PUT_TYPE_OPER_WRITE_UPDATE: |
... | ... | @@ -202,10 +206,10 @@ public class LwM2MTransportRequest { |
202 | 206 | Attribute pmin = new Attribute(MINIMUM_PERIOD, Integer.toUnsignedLong(Integer.valueOf("1"))); |
203 | 207 | Attribute[] attrs = {pmin}; |
204 | 208 | AttributeSet attrSet = new AttributeSet(attrs); |
205 | - if (resultIds.getResourceId() >= 0) { | |
206 | - request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), attrSet); | |
207 | - } else if (resultIds.getInstanceId() >= 0) { | |
208 | - request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getInstanceId(), attrSet); | |
209 | + if (resultIds.isResource()) { | |
210 | + request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), attrSet); | |
211 | + } else if (resultIds.isObjectInstance()) { | |
212 | + request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), attrSet); | |
209 | 213 | } else if (resultIds.getObjectId() >= 0) { |
210 | 214 | request = new WriteAttributesRequest(resultIds.getObjectId(), attrSet); |
211 | 215 | } | ... | ... |
... | ... | @@ -64,7 +64,6 @@ import java.util.HashSet; |
64 | 64 | import java.util.List; |
65 | 65 | import java.util.Map; |
66 | 66 | import java.util.NoSuchElementException; |
67 | -import java.util.Objects; | |
68 | 67 | import java.util.Optional; |
69 | 68 | import java.util.Random; |
70 | 69 | import java.util.Set; |
... | ... | @@ -186,9 +185,9 @@ public class LwM2MTransportService { |
186 | 185 | if (lwM2mInMemorySecurityStore.getProfiles().size() > 0) { |
187 | 186 | this.syncSessionsAndProfiles(); |
188 | 187 | } |
189 | - log.info("Client: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); | |
188 | + log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); | |
190 | 189 | } else { |
191 | - log.error("Client: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); | |
190 | + log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); | |
192 | 191 | } |
193 | 192 | } |
194 | 193 | |
... | ... | @@ -242,15 +241,15 @@ public class LwM2MTransportService { |
242 | 241 | private void setLwM2MClient(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) { |
243 | 242 | // #1 |
244 | 243 | Arrays.stream(registration.getObjectLinks()).forEach(url -> { |
245 | - ResultIds pathIds = new ResultIds(url.getUrl()); | |
246 | - if (pathIds.instanceId > -1 && pathIds.resourceId == -1) { | |
244 | + LwM2mPath pathIds = new LwM2mPath(url.getUrl()); | |
245 | + if (pathIds.isObjectInstance() && !pathIds.isResource()) { | |
247 | 246 | lwM2MClient.getPendingRequests().add(url.getUrl()); |
248 | 247 | } |
249 | 248 | }); |
250 | 249 | // #2 |
251 | 250 | Arrays.stream(registration.getObjectLinks()).forEach(url -> { |
252 | - ResultIds pathIds = new ResultIds(url.getUrl()); | |
253 | - if (pathIds.instanceId > -1 && pathIds.resourceId == -1) { | |
251 | + LwM2mPath pathIds = new LwM2mPath(url.getUrl()); | |
252 | + if (pathIds.isObjectInstance() && !pathIds.isResource()) { | |
254 | 253 | lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), |
255 | 254 | lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false); |
256 | 255 | } |
... | ... | @@ -361,10 +360,10 @@ public class LwM2MTransportService { |
361 | 360 | } |
362 | 361 | }); |
363 | 362 | // #2.1 |
364 | - lwM2MClient.getDelayedRequests().forEach((k, v)->{ | |
363 | + lwM2MClient.getDelayedRequests().forEach((k, v) -> { | |
365 | 364 | List listV = new ArrayList<TransportProtos.KeyValueProto>(); |
366 | 365 | listV.add(v.getKv()); |
367 | - this.putDelayedUpdateResourcesClient (lwM2MClient, lwM2MClient.getResourceValue(k), getJsonObject(listV).get(v.getKv().getKey()), k); | |
366 | + this.putDelayedUpdateResourcesClient(lwM2MClient, lwM2MClient.getResourceValue(k), getJsonObject(listV).get(v.getKv().getKey()), k); | |
368 | 367 | System.out.printf(" k: %s, v: %s%n, v1: %s%n", k, v.getKv().getStringV(), lwM2MClient.getResourceValue(k)); |
369 | 368 | }); |
370 | 369 | lwM2MClient.getDelayedRequestsId().remove(attributesResponse.getRequestId()); |
... | ... | @@ -374,7 +373,7 @@ public class LwM2MTransportService { |
374 | 373 | } |
375 | 374 | } |
376 | 375 | |
377 | - private void putDelayedUpdateResourcesClient (LwM2MClient lwM2MClient, Object valueOld, Object valueNew, String path){ | |
376 | + private void putDelayedUpdateResourcesClient(LwM2MClient lwM2MClient, Object valueOld, Object valueNew, String path) { | |
378 | 377 | if (!valueOld.toString().equals(valueNew.toString())) { |
379 | 378 | lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, |
380 | 379 | ContentFormat.TLV.getName(), lwM2MClient, null, valueNew, this.context.getCtxServer().getTimeout(), |
... | ... | @@ -465,18 +464,20 @@ public class LwM2MTransportService { |
465 | 464 | private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set<String> path) { |
466 | 465 | AttrTelemetryObserveValue attrTelemetryObserveValue = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid()); |
467 | 466 | attrTelemetryObserveValue.getPostAttributeProfile().forEach(p -> { |
468 | - ResultIds pathIds = new ResultIds(p.getAsString().toString()); | |
469 | - if (pathIds.getResourceId() > -1) { | |
467 | +// ResultIds pathIds = new ResultIds(p.getAsString().toString()); | |
468 | + LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); | |
469 | + if (pathIds.isResource()) { | |
470 | 470 | if (path == null || path.contains(p.getAsString())) { |
471 | - this.addParameters(p.getAsString().toString(), attributes, registration); | |
471 | + this.addParameters(p.getAsString().toString(), attributes, registration, "attributes"); | |
472 | 472 | } |
473 | 473 | } |
474 | 474 | }); |
475 | 475 | attrTelemetryObserveValue.getPostTelemetryProfile().forEach(p -> { |
476 | - ResultIds pathIds = new ResultIds(p.getAsString().toString()); | |
477 | - if (pathIds.getResourceId() > -1) { | |
476 | +// ResultIds pathIds = new ResultIds(p.getAsString().toString()); | |
477 | + LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); | |
478 | + if (pathIds.isResource()) { | |
478 | 479 | if (path == null || path.contains(p.getAsString())) { |
479 | - this.addParameters(p.getAsString().toString(), telemetry, registration); | |
480 | + this.addParameters(p.getAsString().toString(), telemetry, registration, "telemetry"); | |
480 | 481 | } |
481 | 482 | } |
482 | 483 | }); |
... | ... | @@ -486,13 +487,19 @@ public class LwM2MTransportService { |
486 | 487 | * @param parameters - JsonObject attributes/telemetry |
487 | 488 | * @param registration - Registration LwM2M Client |
488 | 489 | */ |
489 | - private void addParameters(String path, JsonObject parameters, Registration registration) { | |
490 | + private void addParameters(String path, JsonObject parameters, Registration registration, String nameParam) { | |
490 | 491 | JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid()).getPostKeyNameProfile(); |
491 | 492 | String resName = String.valueOf(names.get(path)); |
492 | 493 | if (resName != null && !resName.isEmpty()) { |
493 | - String resValue = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(path); | |
494 | - if (resValue != null) { | |
495 | - parameters.addProperty(resName, resValue); | |
494 | + String resValue = null; | |
495 | + try { | |
496 | + resValue = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(path); | |
497 | + if (resValue != null) { | |
498 | +// log.info("addParameters Path: [{}] ResValue : [{}] nameParam [{}]", path, lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(path), nameParam); | |
499 | + parameters.addProperty(resName, resValue); | |
500 | + } | |
501 | + } catch (Exception e) { | |
502 | + log.error(e.getStackTrace().toString()); | |
496 | 503 | } |
497 | 504 | } |
498 | 505 | } |
... | ... | @@ -629,42 +636,73 @@ public class LwM2MTransportService { |
629 | 636 | * @param path - resource |
630 | 637 | */ |
631 | 638 | private void onObservationSetResourcesValue(Registration registration, Object value, Map<Integer, ?> values, String path) { |
632 | - ResultIds resultIds = new ResultIds(path); | |
633 | - // #1 | |
634 | - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); | |
635 | - ModelObject modelObject = lwM2MClient.getModelObjects().get(resultIds.getObjectId()); | |
636 | - Map<Integer, LwM2mObjectInstance> instancesModelObject = modelObject.getInstances(); | |
637 | - LwM2mObjectInstance instanceOld = (instancesModelObject.get(resultIds.instanceId) != null) ? instancesModelObject.get(resultIds.instanceId) : null; | |
638 | - Map<Integer, LwM2mResource> resourcesOld = (instanceOld != null) ? instanceOld.getResources() : null; | |
639 | - LwM2mResource resourceOld = (resourcesOld != null && resourcesOld.get(resultIds.getResourceId()) != null) ? resourcesOld.get(resultIds.getResourceId()) : null; | |
640 | - // #2 | |
641 | - LwM2mResource resourceNew; | |
642 | - if (Objects.requireNonNull(resourceOld).isMultiInstances()) { | |
643 | - resourceNew = LwM2mMultipleResource.newResource(resultIds.getResourceId(), values, resourceOld.getType()); | |
644 | - } else { | |
645 | - resourceNew = LwM2mSingleResource.newResource(resultIds.getResourceId(), value, resourceOld.getType()); | |
646 | - } | |
647 | - //#3 | |
648 | - Map<Integer, LwM2mResource> resourcesNew = new HashMap<>(resourcesOld); | |
649 | - // #4 | |
650 | - resourcesNew.remove(resourceOld); | |
651 | - // #5 | |
652 | - resourcesNew.put(resultIds.getResourceId(), resourceNew); | |
653 | - // #6 | |
654 | - LwM2mObjectInstance instanceNew = new LwM2mObjectInstance(resultIds.instanceId, resourcesNew.values()); | |
655 | - // #7 | |
656 | - CountDownLatch respLatch = new CountDownLatch(1); | |
657 | - lwM2MClient.getModelObjects().get(resultIds.getObjectId()).removeInstance(resultIds.instanceId); | |
658 | - instancesModelObject.put(resultIds.instanceId, instanceNew); | |
659 | - respLatch.countDown(); | |
660 | 639 | try { |
661 | - respLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); | |
662 | - } catch (InterruptedException ex) { | |
663 | - ex.printStackTrace(); | |
640 | + CountDownLatch respLatch = new CountDownLatch(1); | |
641 | + try { | |
642 | + // #1 | |
643 | + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); | |
644 | + LwM2mPath resultIds = new LwM2mPath(path); | |
645 | + log.warn("#0 nameDevice: [{}] resultIds: [{}] value: [{}], values: [{}] ", lwM2MClient.getDeviceName(), resultIds, value, values); | |
646 | + ResourceModel.Type resType = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).type; | |
647 | + Map<Integer, LwM2mObjectInstance> instancesModelObject = (lwM2MClient.getModelObjects().get(resultIds.getObjectId()) != null) ? lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances() : null; | |
648 | + Map<Integer, LwM2mResource> resourcesOld = null; | |
649 | + try { | |
650 | + CountDownLatch respResLatch = new CountDownLatch(1); | |
651 | + try { | |
652 | + resourcesOld = (instancesModelObject != null && | |
653 | + instancesModelObject.get(resultIds.getObjectInstanceId()) != null && | |
654 | + instancesModelObject.get(resultIds.getObjectInstanceId()).getResources() != null) ? instancesModelObject.get(resultIds.getObjectInstanceId()).getResources() : null; | |
655 | + | |
656 | + } finally { | |
657 | + respResLatch.countDown(); | |
658 | + } | |
659 | + try { | |
660 | + respResLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); | |
661 | + } catch (InterruptedException ex) { | |
662 | + ex.printStackTrace(); | |
663 | + log.error("#1_2 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value); | |
664 | + } | |
665 | + } catch (Exception e) { | |
666 | + e.printStackTrace(); | |
667 | + log.error("#1_2_1 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value); | |
668 | + } | |
669 | + LwM2mResource resourceOld = (resourcesOld != null && resourcesOld.get(resultIds.getResourceId()) != null) ? resourcesOld.get(resultIds.getResourceId()) : null; | |
670 | + // #2 | |
671 | + LwM2mResource resourceNew = null; | |
672 | + if ((resourceOld != null && resourceOld.isMultiInstances() && !resourceOld.getValues().equals(values)) || | |
673 | + (resourceOld == null && value == null)) { | |
674 | + resourceNew = LwM2mMultipleResource.newResource(resultIds.getResourceId(), values, resType); | |
675 | + } else if ((resourceOld != null && !resourceOld.isMultiInstances() && !resourceOld.getValue().equals(values)) || | |
676 | + (resourceOld == null && value != null)) { | |
677 | + resourceNew = LwM2mSingleResource.newResource(resultIds.getResourceId(), value, resType); | |
678 | + } | |
679 | + if (resourceNew != null) { | |
680 | + //#3 | |
681 | + Map<Integer, LwM2mResource> resourcesNew = (resourcesOld == null) ? new HashMap<>() : new HashMap<>(resourcesOld); | |
682 | + // #4 | |
683 | + if ((resourceOld != null)) resourcesNew.remove(resourceOld); | |
684 | + // #5 | |
685 | + resourcesNew.put(resultIds.getResourceId(), resourceNew); | |
686 | + // #6 | |
687 | + LwM2mObjectInstance instanceNew = new LwM2mObjectInstance(resultIds.getObjectInstanceId(), resourcesNew.values()); | |
688 | + // #7 | |
689 | + lwM2MClient.getModelObjects().get(resultIds.getObjectId()).removeInstance(resultIds.getObjectInstanceId()); | |
690 | + instancesModelObject.put(resultIds.getObjectInstanceId(), instanceNew); | |
691 | + Set<String> paths = new HashSet<>(); | |
692 | + paths.add(path); | |
693 | + this.updateAttrTelemetry(registration, false, paths); | |
694 | + } | |
695 | + } finally { | |
696 | + respLatch.countDown(); | |
697 | + } | |
698 | + try { | |
699 | + respLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); | |
700 | + } catch (InterruptedException ex) { | |
701 | + ex.printStackTrace(); | |
702 | + log.error("#1_1 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value); | |
703 | + } | |
704 | + } catch (Exception ignored) { | |
664 | 705 | } |
665 | - Set<String> paths = new HashSet<>(); | |
666 | - paths.add(path); | |
667 | - this.updateAttrTelemetry(registration, false, paths); | |
668 | 706 | } |
669 | 707 | |
670 | 708 | /** |
... | ... | @@ -696,7 +734,7 @@ public class LwM2MTransportService { |
696 | 734 | lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, |
697 | 735 | ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout(), |
698 | 736 | false); |
699 | - log.info("[{}] path onAttributeUpdate", path); | |
737 | +// log.info("[{}] path onAttributeUpdate", path); | |
700 | 738 | } else { |
701 | 739 | log.error(LOG_LW2M_ERROR + ": Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value); |
702 | 740 | String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value); |
... | ... | @@ -728,7 +766,7 @@ public class LwM2MTransportService { |
728 | 766 | |
729 | 767 | /** |
730 | 768 | * @param profile - |
731 | - * @param path - | |
769 | + * @param path - | |
732 | 770 | * @return true if path isPresent in postAttributeProfile |
733 | 771 | */ |
734 | 772 | private boolean validatePathInAttrProfile(AttrTelemetryObserveValue profile, String path) { |
... | ... | @@ -738,7 +776,7 @@ public class LwM2MTransportService { |
738 | 776 | |
739 | 777 | /** |
740 | 778 | * @param profile - |
741 | - * @param path - | |
779 | + * @param path - | |
742 | 780 | * @return true if path isPresent in postAttributeProfile |
743 | 781 | */ |
744 | 782 | private boolean validatePathInTelemetryProfile(AttrTelemetryObserveValue profile, String path) { |
... | ... | @@ -793,9 +831,10 @@ public class LwM2MTransportService { |
793 | 831 | * @param request - |
794 | 832 | */ |
795 | 833 | public void onAttributeUpdateOk(Registration registration, String path, WriteRequest request, boolean isDelayedUpdate) { |
796 | - ResultIds resultIds = new ResultIds(path); | |
834 | +// ResultIds resultIds = new ResultIds(path); | |
835 | + LwM2mPath resultIds = new LwM2mPath(path); | |
797 | 836 | LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId()); |
798 | - LwM2mResource resource = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances().get(resultIds.getInstanceId()).getResource(resultIds.getResourceId()); | |
837 | + LwM2mResource resource = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances().get(resultIds.getObjectInstanceId()).getResource(resultIds.getResourceId()); | |
799 | 838 | if (resource.isMultiInstances()) { |
800 | 839 | this.onObservationSetResourcesValue(registration, null, ((LwM2mSingleResource) request.getNode()).getValues(), path); |
801 | 840 | } else { |
... | ... | @@ -996,9 +1035,10 @@ public class LwM2MTransportService { |
996 | 1035 | */ |
997 | 1036 | private void updateResourceValueObserve(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient, Set<String> targets, String typeOper) { |
998 | 1037 | targets.forEach(target -> { |
999 | - ResultIds pathIds = new ResultIds(target); | |
1000 | - if (pathIds.resourceId >= 0 && lwM2MClient.getModelObjects().get(pathIds.getObjectId()) | |
1001 | - .getInstances().get(pathIds.getInstanceId()).getResource(pathIds.getResourceId()).getValue() != null) { | |
1038 | +// ResultIds pathIds = new ResultIds(target); | |
1039 | + LwM2mPath pathIds = new LwM2mPath(target); | |
1040 | + if (pathIds.isResource() && lwM2MClient.getModelObjects().get(pathIds.getObjectId()) | |
1041 | + .getInstances().get(pathIds.getObjectInstanceId()).getResource(pathIds.getResourceId()).getValue() != null) { | |
1002 | 1042 | if (GET_TYPE_OPER_READ.equals(typeOper)) { |
1003 | 1043 | lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, |
1004 | 1044 | ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout(), |
... | ... | @@ -1024,9 +1064,10 @@ public class LwM2MTransportService { |
1024 | 1064 | |
1025 | 1065 | private ResourceValue getResourceValue(LwM2MClient lwM2MClient, String path) { |
1026 | 1066 | ResourceValue resourceValue = null; |
1027 | - ResultIds pathIds = new ResultIds(path); | |
1028 | - if (pathIds.getResourceId() > -1) { | |
1029 | - LwM2mResource resource = lwM2MClient.getModelObjects().get(pathIds.getObjectId()).getInstances().get(pathIds.getInstanceId()).getResource(pathIds.getResourceId()); | |
1067 | +// ResultIds pathIds = new ResultIds(path); | |
1068 | + LwM2mPath pathIds = new LwM2mPath(path); | |
1069 | + if (pathIds.isResource()) { | |
1070 | + LwM2mResource resource = lwM2MClient.getModelObjects().get(pathIds.getObjectId()).getInstances().get(pathIds.getObjectInstanceId()).getResource(pathIds.getResourceId()); | |
1030 | 1071 | if (resource.isMultiInstances()) { |
1031 | 1072 | if (resource.getValues().size() > 0) { |
1032 | 1073 | resourceValue = new ResourceValue(); | ... | ... |
... | ... | @@ -44,7 +44,6 @@ public class LwM2mServerListener { |
44 | 44 | @Override |
45 | 45 | public void registered(Registration registration, Registration previousReg, |
46 | 46 | Collection<Observation> previousObsersations) { |
47 | - | |
48 | 47 | service.onRegistered(lhServer, registration, previousObsersations); |
49 | 48 | } |
50 | 49 | |
... | ... | @@ -54,6 +53,7 @@ public class LwM2mServerListener { |
54 | 53 | @Override |
55 | 54 | public void updated(RegistrationUpdate update, Registration updatedRegistration, |
56 | 55 | Registration previousRegistration) { |
56 | + log.info("updated"); | |
57 | 57 | service.updatedReg(lhServer, updatedRegistration); |
58 | 58 | } |
59 | 59 | |
... | ... | @@ -63,6 +63,7 @@ public class LwM2mServerListener { |
63 | 63 | @Override |
64 | 64 | public void unregistered(Registration registration, Collection<Observation> observations, boolean expired, |
65 | 65 | Registration newReg) { |
66 | + log.info("unregistered"); | |
66 | 67 | service.unReg(registration, observations); |
67 | 68 | } |
68 | 69 | |
... | ... | @@ -71,11 +72,13 @@ public class LwM2mServerListener { |
71 | 72 | public final PresenceListener presenceListener = new PresenceListener() { |
72 | 73 | @Override |
73 | 74 | public void onSleeping(Registration registration) { |
75 | + log.info("onSleeping"); | |
74 | 76 | service.onSleepingDev(registration); |
75 | 77 | } |
76 | 78 | |
77 | 79 | @Override |
78 | 80 | public void onAwake(Registration registration) { |
81 | + log.info("onAwake"); | |
79 | 82 | service.onAwakeDev(registration); |
80 | 83 | } |
81 | 84 | }; |
... | ... | @@ -92,8 +95,10 @@ public class LwM2mServerListener { |
92 | 95 | if (registration != null) { |
93 | 96 | try { |
94 | 97 | service.onObservationResponse(registration, observation.getPath().toString(), response); |
95 | - } catch (java.lang.NullPointerException e) { | |
96 | - log.error(e.toString()); | |
98 | + } catch (Exception e) { | |
99 | + e.printStackTrace(); | |
100 | + log.error("onResponse"); | |
101 | + | |
97 | 102 | } |
98 | 103 | } |
99 | 104 | } | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import lombok.extern.slf4j.Slf4j; |
20 | 20 | import org.eclipse.leshan.core.model.ObjectModel; |
21 | 21 | import org.eclipse.leshan.core.model.ResourceModel; |
22 | 22 | import org.eclipse.leshan.core.node.LwM2mObjectInstance; |
23 | +import org.eclipse.leshan.core.node.LwM2mPath; | |
23 | 24 | import org.eclipse.leshan.core.response.LwM2mResponse; |
24 | 25 | import org.eclipse.leshan.core.response.ReadResponse; |
25 | 26 | import org.eclipse.leshan.core.util.Hex; |
... | ... | @@ -29,12 +30,11 @@ import org.eclipse.leshan.server.security.SecurityInfo; |
29 | 30 | import org.thingsboard.server.gen.transport.TransportProtos; |
30 | 31 | import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; |
31 | 32 | import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportService; |
32 | -import org.thingsboard.server.transport.lwm2m.server.ResultIds; | |
33 | +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; | |
33 | 34 | |
34 | -import java.util.UUID; | |
35 | 35 | import java.util.Map; |
36 | 36 | import java.util.Set; |
37 | -import java.util.Collection; | |
37 | +import java.util.UUID; | |
38 | 38 | import java.util.concurrent.ConcurrentHashMap; |
39 | 39 | import java.util.stream.Collectors; |
40 | 40 | |
... | ... | @@ -61,6 +61,7 @@ public class LwM2MClient implements Cloneable { |
61 | 61 | private Map<String, TransportProtos.TsKvProto> delayedRequests; |
62 | 62 | private Set<Integer> delayedRequestsId; |
63 | 63 | private Map<String, LwM2mResponse> responses; |
64 | + private final LwM2mValueConverterImpl converter; | |
64 | 65 | |
65 | 66 | public Object clone() throws CloneNotSupportedException { |
66 | 67 | return super.clone(); |
... | ... | @@ -81,11 +82,13 @@ public class LwM2MClient implements Cloneable { |
81 | 82 | * Key <objectId>, response<Value -> instance -> resources: value...> |
82 | 83 | */ |
83 | 84 | this.responses = new ConcurrentHashMap<>(); |
85 | + this.converter = new LwM2mValueConverterImpl(); | |
84 | 86 | } |
85 | 87 | |
86 | 88 | /** |
87 | - * Fill with data -> Model client | |
88 | - * @param path - | |
89 | + * Fill with data -> Model client | |
90 | + * | |
91 | + * @param path - | |
89 | 92 | * @param response - |
90 | 93 | */ |
91 | 94 | public void onSuccessHandler(String path, LwM2mResponse response) { |
... | ... | @@ -99,9 +102,9 @@ public class LwM2MClient implements Cloneable { |
99 | 102 | |
100 | 103 | private void initValue() { |
101 | 104 | this.responses.forEach((key, resp) -> { |
102 | - ResultIds pathIds = new ResultIds(key); | |
103 | - if (pathIds.getObjectId() > -1) { | |
104 | - ObjectModel objectModel = ((Collection<ObjectModel>) this.lwServer.getModelProvider().getObjectModel(registration).getObjectModels()).stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0); | |
105 | + LwM2mPath pathIds = new LwM2mPath(key); | |
106 | + if (pathIds.isObject() || pathIds.isObjectInstance() || pathIds.isResource()) { | |
107 | + ObjectModel objectModel = this.lwServer.getModelProvider().getObjectModel(registration).getObjectModels().stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0); | |
105 | 108 | if (this.modelObjects.get(pathIds.getObjectId()) != null) { |
106 | 109 | this.modelObjects.get(pathIds.getObjectId()).getInstances().put(((ReadResponse) resp).getContent().getId(), (LwM2mObjectInstance) ((ReadResponse) resp).getContent()); |
107 | 110 | } else { |
... | ... | @@ -122,30 +125,39 @@ public class LwM2MClient implements Cloneable { |
122 | 125 | } |
123 | 126 | |
124 | 127 | public ResourceModel.Operations getOperation(String path) { |
125 | - ResultIds resultIds = new ResultIds(path); | |
126 | - return (this.getModelObjects().get(resultIds.getObjectId()) != null) ? this.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).operations : ResourceModel.Operations.NONE; | |
128 | + LwM2mPath resultIds = new LwM2mPath(path); | |
129 | + return (this.getModelObjects().get(resultIds.getObjectId()) != null) ? | |
130 | + this.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).operations : | |
131 | + ResourceModel.Operations.NONE; | |
127 | 132 | } |
128 | 133 | |
129 | - public String getResourceName (String path) { | |
130 | - ResultIds resultIds = new ResultIds(path); | |
134 | + public String getResourceName(String path) { | |
135 | + LwM2mPath resultIds = new LwM2mPath(path); | |
131 | 136 | return (this.getModelObjects().get(resultIds.getObjectId()) != null) ? this.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).name : ""; |
132 | 137 | } |
133 | 138 | |
134 | 139 | /** |
135 | 140 | * @param path - path resource |
136 | 141 | * @return - value of Resource or null |
137 | - */public String getResourceValue(String path) { | |
142 | + */ | |
143 | + public String getResourceValue(String path) { | |
138 | 144 | String resValue = null; |
139 | - ResultIds pathIds = new ResultIds(path); | |
145 | + LwM2mPath pathIds = new LwM2mPath(path); | |
140 | 146 | ModelObject modelObject = this.getModelObjects().get(pathIds.getObjectId()); |
141 | - if (modelObject != null && modelObject.getInstances().get(pathIds.getInstanceId()) != null) { | |
142 | - LwM2mObjectInstance instance = modelObject.getInstances().get(pathIds.getInstanceId()); | |
147 | + | |
148 | + if (modelObject != null && modelObject.getInstances().get(pathIds.getObjectInstanceId()) != null) { | |
149 | + LwM2mObjectInstance instance = modelObject.getInstances().get(pathIds.getObjectInstanceId()); | |
143 | 150 | if (instance.getResource(pathIds.getResourceId()) != null) { |
144 | - resValue = instance.getResource(pathIds.getResourceId()).getType() == OPAQUE ? | |
145 | - Hex.encodeHexString((byte[]) instance.getResource(pathIds.getResourceId()).getValue()).toLowerCase() : | |
146 | - (instance.getResource(pathIds.getResourceId()).isMultiInstances()) ? | |
147 | - instance.getResource(pathIds.getResourceId()).getValues().toString() : | |
148 | - instance.getResource(pathIds.getResourceId()).getValue().toString(); | |
151 | + try { | |
152 | + resValue = instance.getResource(pathIds.getResourceId()).getType() == OPAQUE ? | |
153 | + Hex.encodeHexString((byte[]) instance.getResource(pathIds.getResourceId()).getValue()).toLowerCase() : | |
154 | + (instance.getResource(pathIds.getResourceId()).isMultiInstances()) ? | |
155 | + instance.getResource(pathIds.getResourceId()).getValues().toString() : | |
156 | +// getValueTypeToString(instance.getResource(pathIds.getResourceId()).getValue(), instance.getResource(pathIds.getResourceId()).getType()); | |
157 | + (String) converter.convertValue(instance.getResource(pathIds.getResourceId()).getValue(), instance.getResource(pathIds.getResourceId()).getType(), ResourceModel.Type.STRING, pathIds); | |
158 | + } catch (Exception e) { | |
159 | + log.warn("getResourceValue [{}]", e.getStackTrace().toString()); | |
160 | + } | |
149 | 161 | } |
150 | 162 | } |
151 | 163 | return resValue; | ... | ... |
... | ... | @@ -21,7 +21,7 @@ import org.eclipse.leshan.core.node.LwM2mObjectInstance; |
21 | 21 | import java.util.Map; |
22 | 22 | |
23 | 23 | @Data |
24 | -public class ModelObject { | |
24 | +public class ModelObject implements Cloneable { | |
25 | 25 | /** |
26 | 26 | * model one on all instance |
27 | 27 | * for each instance only id resource with parameters of resources (observe, attr, telemetry) |
... | ... | @@ -38,4 +38,8 @@ public class ModelObject { |
38 | 38 | LwM2mObjectInstance instance = this.instances.get(id); |
39 | 39 | return this.instances.remove(id, instance); |
40 | 40 | } |
41 | + | |
42 | + public ModelObject clone() throws CloneNotSupportedException { | |
43 | + return (ModelObject) super.clone(); | |
44 | + } | |
41 | 45 | } | ... | ... |
... | ... | @@ -177,10 +177,40 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe |
177 | 177 | return doSaveDevice(device, null); |
178 | 178 | } |
179 | 179 | |
180 | + @CacheEvict(cacheNames = DEVICE_CACHE, key = "{#device.tenantId, #device.name}") | |
181 | + @Override | |
182 | + public Device saveDeviceWithCredentials(Device device, DeviceCredentials deviceCredentials) { | |
183 | + if (device.getId() == null) { | |
184 | + Device deviceWithName = this.findDeviceByTenantIdAndName(device.getTenantId(), device.getName()); | |
185 | + device = deviceWithName == null ? device : deviceWithName.updateDevice(device); | |
186 | + } | |
187 | + Device savedDevice = this.saveDeviceWithoutCredentials(device); | |
188 | + deviceCredentials.setDeviceId(savedDevice.getId()); | |
189 | + if (device.getId() == null) { | |
190 | + deviceCredentials = deviceCredentialsService.createDeviceCredentials(savedDevice.getTenantId(), deviceCredentials); | |
191 | + } | |
192 | + else { | |
193 | + deviceCredentials.setId(deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), savedDevice.getId()).getId()); | |
194 | + deviceCredentials = deviceCredentialsService.updateDeviceCredentials(device.getTenantId(), deviceCredentials); | |
195 | + } | |
196 | + return savedDevice; | |
197 | + } | |
198 | + | |
180 | 199 | private Device doSaveDevice(Device device, String accessToken) { |
200 | + Device savedDevice = this.saveDeviceWithoutCredentials(device); | |
201 | + if (device.getId() == null) { | |
202 | + DeviceCredentials deviceCredentials = new DeviceCredentials(); | |
203 | + deviceCredentials.setDeviceId(new DeviceId(savedDevice.getUuidId())); | |
204 | + deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); | |
205 | + deviceCredentials.setCredentialsId(!StringUtils.isEmpty(accessToken) ? accessToken : RandomStringUtils.randomAlphanumeric(20)); | |
206 | + deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials); | |
207 | + } | |
208 | + return savedDevice; | |
209 | + } | |
210 | + | |
211 | + private Device saveDeviceWithoutCredentials(Device device) { | |
181 | 212 | log.trace("Executing saveDevice [{}]", device); |
182 | 213 | deviceValidator.validate(device, Device::getTenantId); |
183 | - Device savedDevice; | |
184 | 214 | try { |
185 | 215 | DeviceProfile deviceProfile; |
186 | 216 | if (device.getDeviceProfileId() == null) { |
... | ... | @@ -198,8 +228,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe |
198 | 228 | } |
199 | 229 | device.setType(deviceProfile.getName()); |
200 | 230 | device.setDeviceData(syncDeviceData(deviceProfile, device.getDeviceData())); |
201 | - | |
202 | - savedDevice = deviceDao.save(device.getTenantId(), device); | |
231 | + return deviceDao.save(device.getTenantId(), device); | |
203 | 232 | } catch (Exception t) { |
204 | 233 | ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); |
205 | 234 | if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("device_name_unq_key")) { |
... | ... | @@ -208,14 +237,6 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe |
208 | 237 | throw t; |
209 | 238 | } |
210 | 239 | } |
211 | - if (device.getId() == null) { | |
212 | - DeviceCredentials deviceCredentials = new DeviceCredentials(); | |
213 | - deviceCredentials.setDeviceId(new DeviceId(savedDevice.getUuidId())); | |
214 | - deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); | |
215 | - deviceCredentials.setCredentialsId(!StringUtils.isEmpty(accessToken) ? accessToken : RandomStringUtils.randomAlphanumeric(20)); | |
216 | - deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials); | |
217 | - } | |
218 | - return savedDevice; | |
219 | 240 | } |
220 | 241 | |
221 | 242 | private DeviceData syncDeviceData(DeviceProfile deviceProfile, DeviceData deviceData) { |
... | ... | @@ -530,7 +551,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe |
530 | 551 | @Override |
531 | 552 | protected void validateCreate(TenantId tenantId, Device device) { |
532 | 553 | DefaultTenantProfileConfiguration profileConfiguration = |
533 | - (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); | |
554 | + (DefaultTenantProfileConfiguration) tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); | |
534 | 555 | long maxDevices = profileConfiguration.getMaxDevices(); |
535 | 556 | validateNumberOfEntitiesPerTenant(tenantId, deviceDao, maxDevices, EntityType.DEVICE); |
536 | 557 | } | ... | ... |
... | ... | @@ -121,6 +121,7 @@ import java.util.HashMap; |
121 | 121 | import java.util.List; |
122 | 122 | import java.util.Map; |
123 | 123 | import java.util.Optional; |
124 | +import java.util.concurrent.ConcurrentHashMap; | |
124 | 125 | import java.util.concurrent.ExecutorService; |
125 | 126 | import java.util.concurrent.Executors; |
126 | 127 | import java.util.concurrent.Future; |
... | ... | @@ -1091,6 +1092,24 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { |
1091 | 1092 | return restTemplate.postForEntity(baseURL + "/api/device/credentials", deviceCredentials, DeviceCredentials.class).getBody(); |
1092 | 1093 | } |
1093 | 1094 | |
1095 | + public Optional<Device> saveDeviceWithCredentials(Device device, DeviceCredentials credentials) { | |
1096 | + try { | |
1097 | + Map<Class<?>, Object> deviceCredentials = new ConcurrentHashMap<>(); | |
1098 | + deviceCredentials.put(Device.class, device); | |
1099 | + deviceCredentials.put(DeviceCredentials.class, credentials); | |
1100 | +// return restTemplate.postForEntity(baseURL + "/api/lwm2m/device-credentials", deviceCredentials, Device.class).getBody(); | |
1101 | + ResponseEntity<Device> deviceOpt = restTemplate.postForEntity(baseURL + "/api/lwm2m/device-credentials", deviceCredentials, Device.class); | |
1102 | + return Optional.ofNullable(deviceOpt.getBody()); | |
1103 | + } catch (HttpClientErrorException exception) { | |
1104 | + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) { | |
1105 | + return Optional.empty(); | |
1106 | + } else { | |
1107 | + throw exception; | |
1108 | + } | |
1109 | + } | |
1110 | + } | |
1111 | + | |
1112 | + | |
1094 | 1113 | public PageData<Device> getTenantDevices(String type, PageLink pageLink) { |
1095 | 1114 | Map<String, String> params = new HashMap<>(); |
1096 | 1115 | params.put("type", type); | ... | ... |