Showing
75 changed files
with
3479 additions
and
220 deletions
Too many changes to show.
To preserve performance only 75 of 248 files are displayed.
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>1.2.3-SNAPSHOT</version> | |
23 | + <version>1.3.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>thingsboard</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard</groupId> | ... | ... |
... | ... | @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
37 | 37 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
38 | 38 | import org.thingsboard.server.common.transport.auth.DeviceAuthService; |
39 | 39 | import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint; |
40 | +import org.thingsboard.server.dao.asset.AssetService; | |
40 | 41 | import org.thingsboard.server.dao.attributes.AttributesService; |
41 | 42 | import org.thingsboard.server.dao.customer.CustomerService; |
42 | 43 | import org.thingsboard.server.dao.device.DeviceService; |
... | ... | @@ -81,6 +82,9 @@ public class ActorSystemContext { |
81 | 82 | @Getter private DeviceService deviceService; |
82 | 83 | |
83 | 84 | @Autowired |
85 | + @Getter private AssetService assetService; | |
86 | + | |
87 | + @Autowired | |
84 | 88 | @Getter private TenantService tenantService; |
85 | 89 | |
86 | 90 | @Autowired | ... | ... |
... | ... | @@ -17,7 +17,6 @@ package org.thingsboard.server.actors.plugin; |
17 | 17 | |
18 | 18 | import java.io.IOException; |
19 | 19 | import java.util.*; |
20 | -import java.util.concurrent.ExecutionException; | |
21 | 20 | import java.util.concurrent.Executor; |
22 | 21 | import java.util.concurrent.Executors; |
23 | 22 | import java.util.stream.Collectors; |
... | ... | @@ -30,15 +29,19 @@ import com.google.common.util.concurrent.FutureCallback; |
30 | 29 | import com.google.common.util.concurrent.Futures; |
31 | 30 | import com.google.common.util.concurrent.ListenableFuture; |
32 | 31 | import lombok.extern.slf4j.Slf4j; |
33 | -import org.thingsboard.server.common.data.DataConstants; | |
32 | +import org.thingsboard.server.common.data.Customer; | |
34 | 33 | import org.thingsboard.server.common.data.Device; |
34 | +import org.thingsboard.server.common.data.EntityType; | |
35 | +import org.thingsboard.server.common.data.Tenant; | |
36 | +import org.thingsboard.server.common.data.asset.Asset; | |
35 | 37 | import org.thingsboard.server.common.data.id.*; |
36 | 38 | import org.thingsboard.server.common.data.kv.AttributeKey; |
37 | 39 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
38 | 40 | import org.thingsboard.server.common.data.kv.TsKvEntry; |
39 | 41 | import org.thingsboard.server.common.data.kv.TsKvQuery; |
40 | -import org.thingsboard.server.common.data.page.TextPageData; | |
41 | 42 | import org.thingsboard.server.common.data.page.TextPageLink; |
43 | +import org.thingsboard.server.common.data.plugin.PluginMetaData; | |
44 | +import org.thingsboard.server.common.data.rule.RuleMetaData; | |
42 | 45 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
43 | 46 | import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; |
44 | 47 | import org.thingsboard.server.extensions.api.plugins.PluginApiCallSecurityContext; |
... | ... | @@ -53,7 +56,6 @@ import org.thingsboard.server.extensions.api.plugins.ws.PluginWebsocketSessionRe |
53 | 56 | import org.thingsboard.server.extensions.api.plugins.ws.msg.PluginWebsocketMsg; |
54 | 57 | |
55 | 58 | import akka.actor.ActorRef; |
56 | -import org.w3c.dom.Attr; | |
57 | 59 | |
58 | 60 | import javax.annotation.Nullable; |
59 | 61 | |
... | ... | @@ -91,103 +93,107 @@ public final class PluginProcessingContext implements PluginContext { |
91 | 93 | } |
92 | 94 | |
93 | 95 | @Override |
94 | - public void saveAttributes(final TenantId tenantId, final DeviceId deviceId, final String scope, final List<AttributeKvEntry> attributes, final PluginCallback<Void> callback) { | |
95 | - validate(deviceId, new ValidationCallback(callback, ctx -> { | |
96 | - ListenableFuture<List<ResultSet>> rsListFuture = pluginCtx.attributesService.save(deviceId, scope, attributes); | |
96 | + public void saveAttributes(final TenantId tenantId, final EntityId entityId, final String scope, final List<AttributeKvEntry> attributes, final PluginCallback<Void> callback) { | |
97 | + validate(entityId, new ValidationCallback(callback, ctx -> { | |
98 | + ListenableFuture<List<ResultSet>> rsListFuture = pluginCtx.attributesService.save(entityId, scope, attributes); | |
97 | 99 | Futures.addCallback(rsListFuture, getListCallback(callback, v -> { |
98 | - onDeviceAttributesChanged(tenantId, deviceId, scope, attributes); | |
100 | + if (entityId.getEntityType() == EntityType.DEVICE) { | |
101 | + onDeviceAttributesChanged(tenantId, new DeviceId(entityId.getId()), scope, attributes); | |
102 | + } | |
99 | 103 | return null; |
100 | 104 | }), executor); |
101 | 105 | })); |
102 | 106 | } |
103 | 107 | |
104 | 108 | @Override |
105 | - public void removeAttributes(final TenantId tenantId, final DeviceId deviceId, final String scope, final List<String> keys, final PluginCallback<Void> callback) { | |
106 | - validate(deviceId, new ValidationCallback(callback, ctx -> { | |
107 | - ListenableFuture<List<ResultSet>> future = pluginCtx.attributesService.removeAll(deviceId, scope, keys); | |
109 | + public void removeAttributes(final TenantId tenantId, final EntityId entityId, final String scope, final List<String> keys, final PluginCallback<Void> callback) { | |
110 | + validate(entityId, new ValidationCallback(callback, ctx -> { | |
111 | + ListenableFuture<List<ResultSet>> future = pluginCtx.attributesService.removeAll(entityId, scope, keys); | |
108 | 112 | Futures.addCallback(future, getCallback(callback, v -> null), executor); |
109 | - onDeviceAttributesDeleted(tenantId, deviceId, keys.stream().map(key -> new AttributeKey(scope, key)).collect(Collectors.toSet())); | |
113 | + if (entityId.getEntityType() == EntityType.DEVICE) { | |
114 | + onDeviceAttributesDeleted(tenantId, new DeviceId(entityId.getId()), keys.stream().map(key -> new AttributeKey(scope, key)).collect(Collectors.toSet())); | |
115 | + } | |
110 | 116 | })); |
111 | 117 | } |
112 | 118 | |
113 | 119 | @Override |
114 | - public void loadAttribute(DeviceId deviceId, String attributeType, String attributeKey, final PluginCallback<Optional<AttributeKvEntry>> callback) { | |
115 | - validate(deviceId, new ValidationCallback(callback, ctx -> { | |
116 | - ListenableFuture<Optional<AttributeKvEntry>> future = pluginCtx.attributesService.find(deviceId, attributeType, attributeKey); | |
120 | + public void loadAttribute(EntityId entityId, String attributeType, String attributeKey, final PluginCallback<Optional<AttributeKvEntry>> callback) { | |
121 | + validate(entityId, new ValidationCallback(callback, ctx -> { | |
122 | + ListenableFuture<Optional<AttributeKvEntry>> future = pluginCtx.attributesService.find(entityId, attributeType, attributeKey); | |
117 | 123 | Futures.addCallback(future, getCallback(callback, v -> v), executor); |
118 | 124 | })); |
119 | 125 | } |
120 | 126 | |
121 | 127 | @Override |
122 | - public void loadAttributes(DeviceId deviceId, String attributeType, Collection<String> attributeKeys, final PluginCallback<List<AttributeKvEntry>> callback) { | |
123 | - validate(deviceId, new ValidationCallback(callback, ctx -> { | |
124 | - ListenableFuture<List<AttributeKvEntry>> future = pluginCtx.attributesService.find(deviceId, attributeType, attributeKeys); | |
128 | + public void loadAttributes(EntityId entityId, String attributeType, Collection<String> attributeKeys, final PluginCallback<List<AttributeKvEntry>> callback) { | |
129 | + validate(entityId, new ValidationCallback(callback, ctx -> { | |
130 | + ListenableFuture<List<AttributeKvEntry>> future = pluginCtx.attributesService.find(entityId, attributeType, attributeKeys); | |
125 | 131 | Futures.addCallback(future, getCallback(callback, v -> v), executor); |
126 | 132 | })); |
127 | 133 | } |
128 | 134 | |
129 | 135 | @Override |
130 | - public void loadAttributes(DeviceId deviceId, String attributeType, PluginCallback<List<AttributeKvEntry>> callback) { | |
131 | - validate(deviceId, new ValidationCallback(callback, ctx -> { | |
132 | - ListenableFuture<List<AttributeKvEntry>> future = pluginCtx.attributesService.findAll(deviceId, attributeType); | |
136 | + public void loadAttributes(EntityId entityId, String attributeType, PluginCallback<List<AttributeKvEntry>> callback) { | |
137 | + validate(entityId, new ValidationCallback(callback, ctx -> { | |
138 | + ListenableFuture<List<AttributeKvEntry>> future = pluginCtx.attributesService.findAll(entityId, attributeType); | |
133 | 139 | Futures.addCallback(future, getCallback(callback, v -> v), executor); |
134 | 140 | })); |
135 | 141 | } |
136 | 142 | |
137 | 143 | @Override |
138 | - public void loadAttributes(final DeviceId deviceId, final Collection<String> attributeTypes, final PluginCallback<List<AttributeKvEntry>> callback) { | |
139 | - validate(deviceId, new ValidationCallback(callback, ctx -> { | |
144 | + public void loadAttributes(final EntityId entityId, final Collection<String> attributeTypes, final PluginCallback<List<AttributeKvEntry>> callback) { | |
145 | + validate(entityId, new ValidationCallback(callback, ctx -> { | |
140 | 146 | List<ListenableFuture<List<AttributeKvEntry>>> futures = new ArrayList<>(); |
141 | - attributeTypes.forEach(attributeType -> futures.add(pluginCtx.attributesService.findAll(deviceId, attributeType))); | |
147 | + attributeTypes.forEach(attributeType -> futures.add(pluginCtx.attributesService.findAll(entityId, attributeType))); | |
142 | 148 | convertFuturesAndAddCallback(callback, futures); |
143 | 149 | })); |
144 | 150 | } |
145 | 151 | |
146 | 152 | @Override |
147 | - public void loadAttributes(final DeviceId deviceId, final Collection<String> attributeTypes, final Collection<String> attributeKeys, final PluginCallback<List<AttributeKvEntry>> callback) { | |
148 | - validate(deviceId, new ValidationCallback(callback, ctx -> { | |
153 | + public void loadAttributes(final EntityId entityId, final Collection<String> attributeTypes, final Collection<String> attributeKeys, final PluginCallback<List<AttributeKvEntry>> callback) { | |
154 | + validate(entityId, new ValidationCallback(callback, ctx -> { | |
149 | 155 | List<ListenableFuture<List<AttributeKvEntry>>> futures = new ArrayList<>(); |
150 | - attributeTypes.forEach(attributeType -> futures.add(pluginCtx.attributesService.find(deviceId, attributeType, attributeKeys))); | |
156 | + attributeTypes.forEach(attributeType -> futures.add(pluginCtx.attributesService.find(entityId, attributeType, attributeKeys))); | |
151 | 157 | convertFuturesAndAddCallback(callback, futures); |
152 | 158 | })); |
153 | 159 | } |
154 | 160 | |
155 | 161 | @Override |
156 | - public void saveTsData(final DeviceId deviceId, final TsKvEntry entry, final PluginCallback<Void> callback) { | |
157 | - validate(deviceId, new ValidationCallback(callback, ctx -> { | |
158 | - ListenableFuture<List<ResultSet>> rsListFuture = pluginCtx.tsService.save(DataConstants.DEVICE, deviceId, entry); | |
162 | + public void saveTsData(final EntityId entityId, final TsKvEntry entry, final PluginCallback<Void> callback) { | |
163 | + validate(entityId, new ValidationCallback(callback, ctx -> { | |
164 | + ListenableFuture<List<ResultSet>> rsListFuture = pluginCtx.tsService.save(entityId, entry); | |
159 | 165 | Futures.addCallback(rsListFuture, getListCallback(callback, v -> null), executor); |
160 | 166 | })); |
161 | 167 | } |
162 | 168 | |
163 | 169 | @Override |
164 | - public void saveTsData(final DeviceId deviceId, final List<TsKvEntry> entries, final PluginCallback<Void> callback) { | |
165 | - validate(deviceId, new ValidationCallback(callback, ctx -> { | |
166 | - ListenableFuture<List<ResultSet>> rsListFuture = pluginCtx.tsService.save(DataConstants.DEVICE, deviceId, entries); | |
170 | + public void saveTsData(final EntityId entityId, final List<TsKvEntry> entries, final PluginCallback<Void> callback) { | |
171 | + validate(entityId, new ValidationCallback(callback, ctx -> { | |
172 | + ListenableFuture<List<ResultSet>> rsListFuture = pluginCtx.tsService.save(entityId, entries); | |
167 | 173 | Futures.addCallback(rsListFuture, getListCallback(callback, v -> null), executor); |
168 | 174 | })); |
169 | 175 | } |
170 | 176 | |
171 | 177 | @Override |
172 | - public void loadTimeseries(final DeviceId deviceId, final List<TsKvQuery> queries, final PluginCallback<List<TsKvEntry>> callback) { | |
173 | - validate(deviceId, new ValidationCallback(callback, ctx -> { | |
174 | - ListenableFuture<List<TsKvEntry>> future = pluginCtx.tsService.findAll(DataConstants.DEVICE, deviceId, queries); | |
178 | + public void loadTimeseries(final EntityId entityId, final List<TsKvQuery> queries, final PluginCallback<List<TsKvEntry>> callback) { | |
179 | + validate(entityId, new ValidationCallback(callback, ctx -> { | |
180 | + ListenableFuture<List<TsKvEntry>> future = pluginCtx.tsService.findAll(entityId, queries); | |
175 | 181 | Futures.addCallback(future, getCallback(callback, v -> v), executor); |
176 | 182 | })); |
177 | 183 | } |
178 | 184 | |
179 | 185 | @Override |
180 | - public void loadLatestTimeseries(final DeviceId deviceId, final PluginCallback<List<TsKvEntry>> callback) { | |
181 | - validate(deviceId, new ValidationCallback(callback, ctx -> { | |
182 | - ResultSetFuture future = pluginCtx.tsService.findAllLatest(DataConstants.DEVICE, deviceId); | |
186 | + public void loadLatestTimeseries(final EntityId entityId, final PluginCallback<List<TsKvEntry>> callback) { | |
187 | + validate(entityId, new ValidationCallback(callback, ctx -> { | |
188 | + ResultSetFuture future = pluginCtx.tsService.findAllLatest(entityId); | |
183 | 189 | Futures.addCallback(future, getCallback(callback, pluginCtx.tsService::convertResultSetToTsKvEntryList), executor); |
184 | 190 | })); |
185 | 191 | } |
186 | 192 | |
187 | 193 | @Override |
188 | - public void loadLatestTimeseries(final DeviceId deviceId, final Collection<String> keys, final PluginCallback<List<TsKvEntry>> callback) { | |
189 | - validate(deviceId, new ValidationCallback(callback, ctx -> { | |
190 | - ListenableFuture<List<ResultSet>> rsListFuture = pluginCtx.tsService.findLatest(DataConstants.DEVICE, deviceId, keys); | |
194 | + public void loadLatestTimeseries(final EntityId entityId, final Collection<String> keys, final PluginCallback<List<TsKvEntry>> callback) { | |
195 | + validate(entityId, new ValidationCallback(callback, ctx -> { | |
196 | + ListenableFuture<List<ResultSet>> rsListFuture = pluginCtx.tsService.findLatest(entityId, keys); | |
191 | 197 | Futures.addCallback(rsListFuture, getListCallback(callback, rsList -> |
192 | 198 | { |
193 | 199 | List<TsKvEntry> result = new ArrayList<>(); |
... | ... | @@ -270,24 +276,101 @@ public final class PluginProcessingContext implements PluginContext { |
270 | 276 | validate(deviceId, new ValidationCallback(callback, ctx -> callback.onSuccess(ctx, null))); |
271 | 277 | } |
272 | 278 | |
273 | - private void validate(DeviceId deviceId, ValidationCallback callback) { | |
279 | + private void validate(EntityId entityId, ValidationCallback callback) { | |
274 | 280 | if (securityCtx.isPresent()) { |
275 | 281 | final PluginApiCallSecurityContext ctx = securityCtx.get(); |
276 | - if (ctx.isTenantAdmin() || ctx.isCustomerUser()) { | |
277 | - ListenableFuture<Device> deviceFuture = pluginCtx.deviceService.findDeviceByIdAsync(deviceId); | |
278 | - Futures.addCallback(deviceFuture, getCallback(callback, device -> { | |
279 | - if (device == null) { | |
280 | - return Boolean.FALSE; | |
281 | - } else { | |
282 | - if (!device.getTenantId().equals(ctx.getTenantId())) { | |
283 | - return Boolean.FALSE; | |
284 | - } else if (ctx.isCustomerUser() && !device.getCustomerId().equals(ctx.getCustomerId())) { | |
285 | - return Boolean.FALSE; | |
282 | + if (ctx.isTenantAdmin() || ctx.isCustomerUser() || ctx.isSystemAdmin()) { | |
283 | + switch (entityId.getEntityType()) { | |
284 | + case DEVICE: | |
285 | + if (ctx.isSystemAdmin()) { | |
286 | + callback.onSuccess(this, Boolean.FALSE); | |
286 | 287 | } else { |
287 | - return Boolean.TRUE; | |
288 | + ListenableFuture<Device> deviceFuture = pluginCtx.deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId())); | |
289 | + Futures.addCallback(deviceFuture, getCallback(callback, device -> { | |
290 | + if (device == null) { | |
291 | + return Boolean.FALSE; | |
292 | + } else { | |
293 | + if (!device.getTenantId().equals(ctx.getTenantId())) { | |
294 | + return Boolean.FALSE; | |
295 | + } else if (ctx.isCustomerUser() && !device.getCustomerId().equals(ctx.getCustomerId())) { | |
296 | + return Boolean.FALSE; | |
297 | + } else { | |
298 | + return Boolean.TRUE; | |
299 | + } | |
300 | + } | |
301 | + })); | |
288 | 302 | } |
289 | - } | |
290 | - })); | |
303 | + return; | |
304 | + case ASSET: | |
305 | + if (ctx.isSystemAdmin()) { | |
306 | + callback.onSuccess(this, Boolean.FALSE); | |
307 | + } else { | |
308 | + ListenableFuture<Asset> assetFuture = pluginCtx.assetService.findAssetByIdAsync(new AssetId(entityId.getId())); | |
309 | + Futures.addCallback(assetFuture, getCallback(callback, asset -> { | |
310 | + if (asset == null) { | |
311 | + return Boolean.FALSE; | |
312 | + } else { | |
313 | + if (!asset.getTenantId().equals(ctx.getTenantId())) { | |
314 | + return Boolean.FALSE; | |
315 | + } else if (ctx.isCustomerUser() && !asset.getCustomerId().equals(ctx.getCustomerId())) { | |
316 | + return Boolean.FALSE; | |
317 | + } else { | |
318 | + return Boolean.TRUE; | |
319 | + } | |
320 | + } | |
321 | + })); | |
322 | + } | |
323 | + return; | |
324 | + case RULE: | |
325 | + if (ctx.isCustomerUser()) { | |
326 | + callback.onSuccess(this, Boolean.FALSE); | |
327 | + } else { | |
328 | + ListenableFuture<RuleMetaData> ruleFuture = pluginCtx.ruleService.findRuleByIdAsync(new RuleId(entityId.getId())); | |
329 | + Futures.addCallback(ruleFuture, getCallback(callback, rule -> rule != null && rule.getTenantId().equals(ctx.getTenantId()))); | |
330 | + } | |
331 | + return; | |
332 | + case PLUGIN: | |
333 | + if (ctx.isCustomerUser()) { | |
334 | + callback.onSuccess(this, Boolean.FALSE); | |
335 | + } else { | |
336 | + ListenableFuture<PluginMetaData> pluginFuture = pluginCtx.pluginService.findPluginByIdAsync(new PluginId(entityId.getId())); | |
337 | + Futures.addCallback(pluginFuture, getCallback(callback, plugin -> plugin != null && plugin.getTenantId().equals(ctx.getTenantId()))); | |
338 | + } | |
339 | + return; | |
340 | + case CUSTOMER: | |
341 | + if (ctx.isSystemAdmin()) { | |
342 | + callback.onSuccess(this, Boolean.FALSE); | |
343 | + } else { | |
344 | + ListenableFuture<Customer> customerFuture = pluginCtx.customerService.findCustomerByIdAsync(new CustomerId(entityId.getId())); | |
345 | + Futures.addCallback(customerFuture, getCallback(callback, customer -> { | |
346 | + if (customer == null) { | |
347 | + return Boolean.FALSE; | |
348 | + } else { | |
349 | + if (!customer.getTenantId().equals(ctx.getTenantId())) { | |
350 | + return Boolean.FALSE; | |
351 | + } else if (ctx.isCustomerUser() && !customer.getId().equals(ctx.getCustomerId())) { | |
352 | + return Boolean.FALSE; | |
353 | + } else { | |
354 | + return Boolean.TRUE; | |
355 | + } | |
356 | + } | |
357 | + })); | |
358 | + } | |
359 | + return; | |
360 | + case TENANT: | |
361 | + if (ctx.isCustomerUser()) { | |
362 | + callback.onSuccess(this, Boolean.FALSE); | |
363 | + } else if (ctx.isSystemAdmin()) { | |
364 | + callback.onSuccess(this, Boolean.TRUE); | |
365 | + } else { | |
366 | + ListenableFuture<Tenant> tenantFuture = pluginCtx.tenantService.findTenantByIdAsync(new TenantId(entityId.getId())); | |
367 | + Futures.addCallback(tenantFuture, getCallback(callback, tenant -> tenant != null && tenant.getId().equals(ctx.getTenantId()))); | |
368 | + } | |
369 | + return; | |
370 | + default: | |
371 | + //TODO: add support of other entities | |
372 | + throw new IllegalStateException("Not Implemented!"); | |
373 | + } | |
291 | 374 | } else { |
292 | 375 | callback.onSuccess(this, Boolean.FALSE); |
293 | 376 | } |
... | ... | @@ -297,8 +380,8 @@ public final class PluginProcessingContext implements PluginContext { |
297 | 380 | } |
298 | 381 | |
299 | 382 | @Override |
300 | - public Optional<ServerAddress> resolve(DeviceId deviceId) { | |
301 | - return pluginCtx.routingService.resolve(deviceId); | |
383 | + public Optional<ServerAddress> resolve(EntityId entityId) { | |
384 | + return pluginCtx.routingService.resolveById(entityId); | |
302 | 385 | } |
303 | 386 | |
304 | 387 | @Override | ... | ... |
... | ... | @@ -25,8 +25,13 @@ import org.thingsboard.server.common.data.id.TenantId; |
25 | 25 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
26 | 26 | import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint; |
27 | 27 | import org.thingsboard.server.common.data.id.PluginId; |
28 | +import org.thingsboard.server.dao.asset.AssetService; | |
28 | 29 | import org.thingsboard.server.dao.attributes.AttributesService; |
30 | +import org.thingsboard.server.dao.customer.CustomerService; | |
29 | 31 | import org.thingsboard.server.dao.device.DeviceService; |
32 | +import org.thingsboard.server.dao.plugin.PluginService; | |
33 | +import org.thingsboard.server.dao.rule.RuleService; | |
34 | +import org.thingsboard.server.dao.tenant.TenantService; | |
30 | 35 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
31 | 36 | import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; |
32 | 37 | import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; |
... | ... | @@ -46,7 +51,12 @@ public final class SharedPluginProcessingContext { |
46 | 51 | final ActorRef currentActor; |
47 | 52 | final ActorSystemContext systemContext; |
48 | 53 | final PluginWebSocketMsgEndpoint msgEndpoint; |
54 | + final AssetService assetService; | |
49 | 55 | final DeviceService deviceService; |
56 | + final RuleService ruleService; | |
57 | + final PluginService pluginService; | |
58 | + final CustomerService customerService; | |
59 | + final TenantService tenantService; | |
50 | 60 | final TimeseriesService tsService; |
51 | 61 | final AttributesService attributesService; |
52 | 62 | final ClusterRpcService rpcService; |
... | ... | @@ -65,9 +75,14 @@ public final class SharedPluginProcessingContext { |
65 | 75 | this.msgEndpoint = sysContext.getWsMsgEndpoint(); |
66 | 76 | this.tsService = sysContext.getTsService(); |
67 | 77 | this.attributesService = sysContext.getAttributesService(); |
78 | + this.assetService = sysContext.getAssetService(); | |
68 | 79 | this.deviceService = sysContext.getDeviceService(); |
69 | 80 | this.rpcService = sysContext.getRpcService(); |
70 | 81 | this.routingService = sysContext.getRoutingService(); |
82 | + this.ruleService = sysContext.getRuleService(); | |
83 | + this.pluginService = sysContext.getPluginService(); | |
84 | + this.customerService = sysContext.getCustomerService(); | |
85 | + this.tenantService = sysContext.getTenantService(); | |
71 | 86 | } |
72 | 87 | |
73 | 88 | public PluginId getPluginId() { |
... | ... | @@ -89,7 +104,7 @@ public final class SharedPluginProcessingContext { |
89 | 104 | } |
90 | 105 | |
91 | 106 | private <T> void forward(DeviceId deviceId, T msg, BiConsumer<ServerAddress, T> rpcFunction) { |
92 | - Optional<ServerAddress> instance = routingService.resolve(deviceId); | |
107 | + Optional<ServerAddress> instance = routingService.resolveById(deviceId); | |
93 | 108 | if (instance.isPresent()) { |
94 | 109 | log.trace("[{}] Forwarding msg {} to remote device actor!", pluginId, msg); |
95 | 110 | rpcFunction.accept(instance.get(), msg); | ... | ... |
... | ... | @@ -38,7 +38,7 @@ public class ValidationCallback implements PluginCallback<Boolean> { |
38 | 38 | if (value) { |
39 | 39 | action.accept(ctx); |
40 | 40 | } else { |
41 | - onFailure(ctx, new UnauthorizedException()); | |
41 | + onFailure(ctx, new UnauthorizedException("Permission denied.")); | |
42 | 42 | } |
43 | 43 | } |
44 | 44 | ... | ... |
... | ... | @@ -230,7 +230,7 @@ public class DefaultActorService implements ActorService { |
230 | 230 | @Override |
231 | 231 | public void onCredentialsUpdate(TenantId tenantId, DeviceId deviceId) { |
232 | 232 | DeviceCredentialsUpdateNotificationMsg msg = new DeviceCredentialsUpdateNotificationMsg(tenantId, deviceId); |
233 | - Optional<ServerAddress> address = actorContext.getRoutingService().resolve(deviceId); | |
233 | + Optional<ServerAddress> address = actorContext.getRoutingService().resolveById(deviceId); | |
234 | 234 | if (address.isPresent()) { |
235 | 235 | rpcService.tell(address.get(), msg); |
236 | 236 | } else { | ... | ... |
... | ... | @@ -116,7 +116,7 @@ class ASyncMsgProcessor extends AbstractSessionActorMsgProcessor { |
116 | 116 | @Override |
117 | 117 | public void processClusterEvent(ActorContext context, ClusterEventMsg msg) { |
118 | 118 | if (pendingMap.size() > 0 || subscribedToAttributeUpdates || subscribedToRpcCommands) { |
119 | - Optional<ServerAddress> newTargetServer = systemContext.getRoutingService().resolve(getDeviceId()); | |
119 | + Optional<ServerAddress> newTargetServer = systemContext.getRoutingService().resolveById(getDeviceId()); | |
120 | 120 | if (!newTargetServer.equals(currentTargetServer)) { |
121 | 121 | firstMsg = true; |
122 | 122 | currentTargetServer = newTargetServer; | ... | ... |
... | ... | @@ -81,13 +81,13 @@ abstract class AbstractSessionActorMsgProcessor extends AbstractContextAwareMsgP |
81 | 81 | } |
82 | 82 | |
83 | 83 | protected Optional<ServerAddress> forwardToAppActor(ActorContext ctx, ToDeviceActorMsg toForward) { |
84 | - Optional<ServerAddress> address = systemContext.getRoutingService().resolve(toForward.getDeviceId()); | |
84 | + Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(toForward.getDeviceId()); | |
85 | 85 | forwardToAppActor(ctx, toForward, address); |
86 | 86 | return address; |
87 | 87 | } |
88 | 88 | |
89 | 89 | protected Optional<ServerAddress> forwardToAppActorIfAdressChanged(ActorContext ctx, ToDeviceActorMsg toForward, Optional<ServerAddress> oldAddress) { |
90 | - Optional<ServerAddress> newAddress = systemContext.getRoutingService().resolve(toForward.getDeviceId()); | |
90 | + Optional<ServerAddress> newAddress = systemContext.getRoutingService().resolveById(toForward.getDeviceId()); | |
91 | 91 | if (!newAddress.equals(oldAddress)) { |
92 | 92 | if (newAddress.isPresent()) { |
93 | 93 | systemContext.getRpcService().tell(newAddress.get(), | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
19 | +import org.springframework.http.HttpStatus; | |
20 | +import org.springframework.security.access.prepost.PreAuthorize; | |
21 | +import org.springframework.web.bind.annotation.*; | |
22 | +import org.thingsboard.server.common.data.Customer; | |
23 | +import org.thingsboard.server.common.data.asset.Asset; | |
24 | +import org.thingsboard.server.common.data.id.AssetId; | |
25 | +import org.thingsboard.server.common.data.id.CustomerId; | |
26 | +import org.thingsboard.server.common.data.id.TenantId; | |
27 | +import org.thingsboard.server.common.data.page.TextPageData; | |
28 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
29 | +import org.thingsboard.server.dao.asset.AssetSearchQuery; | |
30 | +import org.thingsboard.server.dao.exception.IncorrectParameterException; | |
31 | +import org.thingsboard.server.dao.model.ModelConstants; | |
32 | +import org.thingsboard.server.exception.ThingsboardException; | |
33 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
34 | + | |
35 | +import java.util.ArrayList; | |
36 | +import java.util.List; | |
37 | +import java.util.stream.Collectors; | |
38 | + | |
39 | +@RestController | |
40 | +@RequestMapping("/api") | |
41 | +public class AssetController extends BaseController { | |
42 | + | |
43 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
44 | + @RequestMapping(value = "/asset/{assetId}", method = RequestMethod.GET) | |
45 | + @ResponseBody | |
46 | + public Asset getAssetById(@PathVariable("assetId") String strAssetId) throws ThingsboardException { | |
47 | + checkParameter("assetId", strAssetId); | |
48 | + try { | |
49 | + AssetId assetId = new AssetId(toUUID(strAssetId)); | |
50 | + return checkAssetId(assetId); | |
51 | + } catch (Exception e) { | |
52 | + throw handleException(e); | |
53 | + } | |
54 | + } | |
55 | + | |
56 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
57 | + @RequestMapping(value = "/asset", method = RequestMethod.POST) | |
58 | + @ResponseBody | |
59 | + public Asset saveAsset(@RequestBody Asset asset) throws ThingsboardException { | |
60 | + try { | |
61 | + asset.setTenantId(getCurrentUser().getTenantId()); | |
62 | + return checkNotNull(assetService.saveAsset(asset)); | |
63 | + } catch (Exception e) { | |
64 | + throw handleException(e); | |
65 | + } | |
66 | + } | |
67 | + | |
68 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
69 | + @RequestMapping(value = "/asset/{assetId}", method = RequestMethod.DELETE) | |
70 | + @ResponseStatus(value = HttpStatus.OK) | |
71 | + public void deleteAsset(@PathVariable("assetId") String strAssetId) throws ThingsboardException { | |
72 | + checkParameter("assetId", strAssetId); | |
73 | + try { | |
74 | + AssetId assetId = new AssetId(toUUID(strAssetId)); | |
75 | + checkAssetId(assetId); | |
76 | + assetService.deleteAsset(assetId); | |
77 | + } catch (Exception e) { | |
78 | + throw handleException(e); | |
79 | + } | |
80 | + } | |
81 | + | |
82 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
83 | + @RequestMapping(value = "/customer/{customerId}/asset/{assetId}", method = RequestMethod.POST) | |
84 | + @ResponseBody | |
85 | + public Asset assignAssetToCustomer(@PathVariable("customerId") String strCustomerId, | |
86 | + @PathVariable("assetId") String strAssetId) throws ThingsboardException { | |
87 | + checkParameter("customerId", strCustomerId); | |
88 | + checkParameter("assetId", strAssetId); | |
89 | + try { | |
90 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
91 | + checkCustomerId(customerId); | |
92 | + | |
93 | + AssetId assetId = new AssetId(toUUID(strAssetId)); | |
94 | + checkAssetId(assetId); | |
95 | + | |
96 | + return checkNotNull(assetService.assignAssetToCustomer(assetId, customerId)); | |
97 | + } catch (Exception e) { | |
98 | + throw handleException(e); | |
99 | + } | |
100 | + } | |
101 | + | |
102 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
103 | + @RequestMapping(value = "/customer/asset/{assetId}", method = RequestMethod.DELETE) | |
104 | + @ResponseBody | |
105 | + public Asset unassignAssetFromCustomer(@PathVariable("assetId") String strAssetId) throws ThingsboardException { | |
106 | + checkParameter("assetId", strAssetId); | |
107 | + try { | |
108 | + AssetId assetId = new AssetId(toUUID(strAssetId)); | |
109 | + Asset asset = checkAssetId(assetId); | |
110 | + if (asset.getCustomerId() == null || asset.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
111 | + throw new IncorrectParameterException("Asset isn't assigned to any customer!"); | |
112 | + } | |
113 | + return checkNotNull(assetService.unassignAssetFromCustomer(assetId)); | |
114 | + } catch (Exception e) { | |
115 | + throw handleException(e); | |
116 | + } | |
117 | + } | |
118 | + | |
119 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
120 | + @RequestMapping(value = "/customer/public/asset/{assetId}", method = RequestMethod.POST) | |
121 | + @ResponseBody | |
122 | + public Asset assignAssetToPublicCustomer(@PathVariable("assetId") String strAssetId) throws ThingsboardException { | |
123 | + checkParameter("assetId", strAssetId); | |
124 | + try { | |
125 | + AssetId assetId = new AssetId(toUUID(strAssetId)); | |
126 | + Asset asset = checkAssetId(assetId); | |
127 | + Customer publicCustomer = customerService.findOrCreatePublicCustomer(asset.getTenantId()); | |
128 | + return checkNotNull(assetService.assignAssetToCustomer(assetId, publicCustomer.getId())); | |
129 | + } catch (Exception e) { | |
130 | + throw handleException(e); | |
131 | + } | |
132 | + } | |
133 | + | |
134 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
135 | + @RequestMapping(value = "/tenant/assets", params = {"limit"}, method = RequestMethod.GET) | |
136 | + @ResponseBody | |
137 | + public TextPageData<Asset> getTenantAssets( | |
138 | + @RequestParam int limit, | |
139 | + @RequestParam(required = false) String textSearch, | |
140 | + @RequestParam(required = false) String idOffset, | |
141 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
142 | + try { | |
143 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
144 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
145 | + return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink)); | |
146 | + } catch (Exception e) { | |
147 | + throw handleException(e); | |
148 | + } | |
149 | + } | |
150 | + | |
151 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
152 | + @RequestMapping(value = "/tenant/assets", params = {"assetName"}, method = RequestMethod.GET) | |
153 | + @ResponseBody | |
154 | + public Asset getTenantAsset( | |
155 | + @RequestParam String assetName) throws ThingsboardException { | |
156 | + try { | |
157 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
158 | + return checkNotNull(assetService.findAssetByTenantIdAndName(tenantId, assetName)); | |
159 | + } catch (Exception e) { | |
160 | + throw handleException(e); | |
161 | + } | |
162 | + } | |
163 | + | |
164 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
165 | + @RequestMapping(value = "/customer/{customerId}/assets", params = {"limit"}, method = RequestMethod.GET) | |
166 | + @ResponseBody | |
167 | + public TextPageData<Asset> getCustomerAssets( | |
168 | + @PathVariable("customerId") String strCustomerId, | |
169 | + @RequestParam int limit, | |
170 | + @RequestParam(required = false) String textSearch, | |
171 | + @RequestParam(required = false) String idOffset, | |
172 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
173 | + checkParameter("customerId", strCustomerId); | |
174 | + try { | |
175 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
176 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
177 | + checkCustomerId(customerId); | |
178 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
179 | + return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); | |
180 | + } catch (Exception e) { | |
181 | + throw handleException(e); | |
182 | + } | |
183 | + } | |
184 | + | |
185 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
186 | + @RequestMapping(value = "/assets", params = {"assetIds"}, method = RequestMethod.GET) | |
187 | + @ResponseBody | |
188 | + public List<Asset> getAssetsByIds( | |
189 | + @RequestParam("assetIds") String[] strAssetIds) throws ThingsboardException { | |
190 | + checkArrayParameter("assetIds", strAssetIds); | |
191 | + try { | |
192 | + SecurityUser user = getCurrentUser(); | |
193 | + TenantId tenantId = user.getTenantId(); | |
194 | + CustomerId customerId = user.getCustomerId(); | |
195 | + List<AssetId> assetIds = new ArrayList<>(); | |
196 | + for (String strAssetId : strAssetIds) { | |
197 | + assetIds.add(new AssetId(toUUID(strAssetId))); | |
198 | + } | |
199 | + ListenableFuture<List<Asset>> assets; | |
200 | + if (customerId == null || customerId.isNullUid()) { | |
201 | + assets = assetService.findAssetsByTenantIdAndIdsAsync(tenantId, assetIds); | |
202 | + } else { | |
203 | + assets = assetService.findAssetsByTenantIdCustomerIdAndIdsAsync(tenantId, customerId, assetIds); | |
204 | + } | |
205 | + return checkNotNull(assets.get()); | |
206 | + } catch (Exception e) { | |
207 | + throw handleException(e); | |
208 | + } | |
209 | + } | |
210 | + | |
211 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
212 | + @RequestMapping(value = "/assets", method = RequestMethod.POST) | |
213 | + @ResponseBody | |
214 | + public List<Asset> findByQuery(@RequestBody AssetSearchQuery query) throws ThingsboardException { | |
215 | + checkNotNull(query); | |
216 | + checkNotNull(query.getParameters()); | |
217 | + checkNotNull(query.getAssetTypes()); | |
218 | + checkEntityId(query.getParameters().getEntityId()); | |
219 | + try { | |
220 | + List<Asset> assets = checkNotNull(assetService.findAssetsByQuery(query).get()); | |
221 | + assets = assets.stream().filter(asset -> { | |
222 | + try { | |
223 | + checkAsset(asset); | |
224 | + return true; | |
225 | + } catch (ThingsboardException e) { | |
226 | + return false; | |
227 | + } | |
228 | + }).collect(Collectors.toList()); | |
229 | + return assets; | |
230 | + } catch (Exception e) { | |
231 | + throw handleException(e); | |
232 | + } | |
233 | + } | |
234 | +} | ... | ... |
... | ... | @@ -24,10 +24,8 @@ import org.springframework.security.core.Authentication; |
24 | 24 | import org.springframework.security.core.context.SecurityContextHolder; |
25 | 25 | import org.springframework.web.bind.annotation.ExceptionHandler; |
26 | 26 | import org.thingsboard.server.actors.service.ActorService; |
27 | -import org.thingsboard.server.common.data.Customer; | |
28 | -import org.thingsboard.server.common.data.Dashboard; | |
29 | -import org.thingsboard.server.common.data.Device; | |
30 | -import org.thingsboard.server.common.data.User; | |
27 | +import org.thingsboard.server.common.data.*; | |
28 | +import org.thingsboard.server.common.data.asset.Asset; | |
31 | 29 | import org.thingsboard.server.common.data.id.*; |
32 | 30 | import org.thingsboard.server.common.data.page.TextPageLink; |
33 | 31 | import org.thingsboard.server.common.data.page.TimePageLink; |
... | ... | @@ -38,6 +36,7 @@ import org.thingsboard.server.common.data.rule.RuleMetaData; |
38 | 36 | import org.thingsboard.server.common.data.security.Authority; |
39 | 37 | import org.thingsboard.server.common.data.widget.WidgetType; |
40 | 38 | import org.thingsboard.server.common.data.widget.WidgetsBundle; |
39 | +import org.thingsboard.server.dao.asset.AssetService; | |
41 | 40 | import org.thingsboard.server.dao.customer.CustomerService; |
42 | 41 | import org.thingsboard.server.dao.dashboard.DashboardService; |
43 | 42 | import org.thingsboard.server.dao.device.DeviceCredentialsService; |
... | ... | @@ -46,6 +45,7 @@ import org.thingsboard.server.dao.exception.DataValidationException; |
46 | 45 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
47 | 46 | import org.thingsboard.server.dao.model.ModelConstants; |
48 | 47 | import org.thingsboard.server.dao.plugin.PluginService; |
48 | +import org.thingsboard.server.dao.relation.RelationService; | |
49 | 49 | import org.thingsboard.server.dao.rule.RuleService; |
50 | 50 | import org.thingsboard.server.dao.user.UserService; |
51 | 51 | import org.thingsboard.server.dao.widget.WidgetTypeService; |
... | ... | @@ -81,6 +81,9 @@ public abstract class BaseController { |
81 | 81 | protected DeviceService deviceService; |
82 | 82 | |
83 | 83 | @Autowired |
84 | + protected AssetService assetService; | |
85 | + | |
86 | + @Autowired | |
84 | 87 | protected DeviceCredentialsService deviceCredentialsService; |
85 | 88 | |
86 | 89 | @Autowired |
... | ... | @@ -104,6 +107,9 @@ public abstract class BaseController { |
104 | 107 | @Autowired |
105 | 108 | protected ActorService actorService; |
106 | 109 | |
110 | + @Autowired | |
111 | + protected RelationService relationService; | |
112 | + | |
107 | 113 | |
108 | 114 | @ExceptionHandler(ThingsboardException.class) |
109 | 115 | public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) { |
... | ... | @@ -253,6 +259,43 @@ public abstract class BaseController { |
253 | 259 | } |
254 | 260 | } |
255 | 261 | |
262 | + protected void checkEntityId(EntityId entityId) throws ThingsboardException { | |
263 | + try { | |
264 | + checkNotNull(entityId); | |
265 | + validateId(entityId.getId(), "Incorrect entityId " + entityId); | |
266 | + switch (entityId.getEntityType()) { | |
267 | + case DEVICE: | |
268 | + checkDevice(deviceService.findDeviceById(new DeviceId(entityId.getId()))); | |
269 | + return; | |
270 | + case CUSTOMER: | |
271 | + checkCustomerId(new CustomerId(entityId.getId())); | |
272 | + return; | |
273 | + case TENANT: | |
274 | + checkTenantId(new TenantId(entityId.getId())); | |
275 | + return; | |
276 | + case PLUGIN: | |
277 | + checkPlugin(new PluginId(entityId.getId())); | |
278 | + return; | |
279 | + case RULE: | |
280 | + checkRule(new RuleId(entityId.getId())); | |
281 | + return; | |
282 | + case ASSET: | |
283 | + checkAsset(assetService.findAssetById(new AssetId(entityId.getId()))); | |
284 | + return; | |
285 | + case DASHBOARD: | |
286 | + checkDashboardId(new DashboardId(entityId.getId())); | |
287 | + return; | |
288 | + case USER: | |
289 | + checkUserId(new UserId(entityId.getId())); | |
290 | + return; | |
291 | + default: | |
292 | + throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); | |
293 | + } | |
294 | + } catch (Exception e) { | |
295 | + throw handleException(e, false); | |
296 | + } | |
297 | + } | |
298 | + | |
256 | 299 | Device checkDeviceId(DeviceId deviceId) throws ThingsboardException { |
257 | 300 | try { |
258 | 301 | validateId(deviceId, "Incorrect deviceId " + deviceId); |
... | ... | @@ -264,7 +307,7 @@ public abstract class BaseController { |
264 | 307 | } |
265 | 308 | } |
266 | 309 | |
267 | - private void checkDevice(Device device) throws ThingsboardException { | |
310 | + protected void checkDevice(Device device) throws ThingsboardException { | |
268 | 311 | checkNotNull(device); |
269 | 312 | checkTenantId(device.getTenantId()); |
270 | 313 | if (device.getCustomerId() != null && !device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { |
... | ... | @@ -272,6 +315,25 @@ public abstract class BaseController { |
272 | 315 | } |
273 | 316 | } |
274 | 317 | |
318 | + Asset checkAssetId(AssetId assetId) throws ThingsboardException { | |
319 | + try { | |
320 | + validateId(assetId, "Incorrect assetId " + assetId); | |
321 | + Asset asset = assetService.findAssetById(assetId); | |
322 | + checkAsset(asset); | |
323 | + return asset; | |
324 | + } catch (Exception e) { | |
325 | + throw handleException(e, false); | |
326 | + } | |
327 | + } | |
328 | + | |
329 | + protected void checkAsset(Asset asset) throws ThingsboardException { | |
330 | + checkNotNull(asset); | |
331 | + checkTenantId(asset.getTenantId()); | |
332 | + if (asset.getCustomerId() != null && !asset.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
333 | + checkCustomerId(asset.getCustomerId()); | |
334 | + } | |
335 | + } | |
336 | + | |
275 | 337 | WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, boolean modify) throws ThingsboardException { |
276 | 338 | try { |
277 | 339 | validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId); |
... | ... | @@ -318,14 +380,26 @@ public abstract class BaseController { |
318 | 380 | try { |
319 | 381 | validateId(dashboardId, "Incorrect dashboardId " + dashboardId); |
320 | 382 | Dashboard dashboard = dashboardService.findDashboardById(dashboardId); |
321 | - checkDashboard(dashboard); | |
383 | + checkDashboard(dashboard, true); | |
322 | 384 | return dashboard; |
323 | 385 | } catch (Exception e) { |
324 | 386 | throw handleException(e, false); |
325 | 387 | } |
326 | 388 | } |
327 | 389 | |
328 | - private void checkDashboard(Dashboard dashboard) throws ThingsboardException { | |
390 | + DashboardInfo checkDashboardInfoId(DashboardId dashboardId) throws ThingsboardException { | |
391 | + try { | |
392 | + validateId(dashboardId, "Incorrect dashboardId " + dashboardId); | |
393 | + DashboardInfo dashboardInfo = dashboardService.findDashboardInfoById(dashboardId); | |
394 | + SecurityUser authUser = getCurrentUser(); | |
395 | + checkDashboard(dashboardInfo, authUser.getAuthority() != Authority.SYS_ADMIN); | |
396 | + return dashboardInfo; | |
397 | + } catch (Exception e) { | |
398 | + throw handleException(e, false); | |
399 | + } | |
400 | + } | |
401 | + | |
402 | + private void checkDashboard(DashboardInfo dashboard, boolean checkCustomerId) throws ThingsboardException { | |
329 | 403 | checkNotNull(dashboard); |
330 | 404 | checkTenantId(dashboard.getTenantId()); |
331 | 405 | SecurityUser authUser = getCurrentUser(); |
... | ... | @@ -335,7 +409,8 @@ public abstract class BaseController { |
335 | 409 | ThingsboardErrorCode.PERMISSION_DENIED); |
336 | 410 | } |
337 | 411 | } |
338 | - if (dashboard.getCustomerId() != null && !dashboard.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
412 | + if (checkCustomerId && | |
413 | + dashboard.getCustomerId() != null && !dashboard.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
339 | 414 | checkCustomerId(dashboard.getCustomerId()); |
340 | 415 | } |
341 | 416 | } |
... | ... | @@ -387,6 +462,16 @@ public abstract class BaseController { |
387 | 462 | return plugin; |
388 | 463 | } |
389 | 464 | |
465 | + protected PluginMetaData checkPlugin(PluginId pluginId) throws ThingsboardException { | |
466 | + checkNotNull(pluginId); | |
467 | + return checkPlugin(pluginService.findPluginById(pluginId)); | |
468 | + } | |
469 | + | |
470 | + protected RuleMetaData checkRule(RuleId ruleId) throws ThingsboardException { | |
471 | + checkNotNull(ruleId); | |
472 | + return checkRule(ruleService.findRuleById(ruleId)); | |
473 | + } | |
474 | + | |
390 | 475 | protected RuleMetaData checkRule(RuleMetaData rule) throws ThingsboardException { |
391 | 476 | checkNotNull(rule); |
392 | 477 | SecurityUser authUser = getCurrentUser(); |
... | ... | @@ -412,7 +497,8 @@ public abstract class BaseController { |
412 | 497 | if (request.getHeader("x-forwarded-port") != null) { |
413 | 498 | try { |
414 | 499 | serverPort = request.getIntHeader("x-forwarded-port"); |
415 | - } catch (NumberFormatException e) {} | |
500 | + } catch (NumberFormatException e) { | |
501 | + } | |
416 | 502 | } |
417 | 503 | |
418 | 504 | String baseUrl = String.format("%s://%s:%d", | ... | ... |
... | ... | @@ -41,6 +41,19 @@ public class DashboardController extends BaseController { |
41 | 41 | return System.currentTimeMillis(); |
42 | 42 | } |
43 | 43 | |
44 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
45 | + @RequestMapping(value = "/dashboard/info/{dashboardId}", method = RequestMethod.GET) | |
46 | + @ResponseBody | |
47 | + public DashboardInfo getDashboardInfoById(@PathVariable("dashboardId") String strDashboardId) throws ThingsboardException { | |
48 | + checkParameter("dashboardId", strDashboardId); | |
49 | + try { | |
50 | + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); | |
51 | + return checkDashboardInfoId(dashboardId); | |
52 | + } catch (Exception e) { | |
53 | + throw handleException(e); | |
54 | + } | |
55 | + } | |
56 | + | |
44 | 57 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
45 | 58 | @RequestMapping(value = "/dashboard/{dashboardId}", method = RequestMethod.GET) |
46 | 59 | @ResponseBody |
... | ... | @@ -132,6 +145,25 @@ public class DashboardController extends BaseController { |
132 | 145 | } |
133 | 146 | } |
134 | 147 | |
148 | + @PreAuthorize("hasAuthority('SYS_ADMIN')") | |
149 | + @RequestMapping(value = "/tenant/{tenantId}/dashboards", params = { "limit" }, method = RequestMethod.GET) | |
150 | + @ResponseBody | |
151 | + public TextPageData<DashboardInfo> getTenantDashboards( | |
152 | + @PathVariable("tenantId") String strTenantId, | |
153 | + @RequestParam int limit, | |
154 | + @RequestParam(required = false) String textSearch, | |
155 | + @RequestParam(required = false) String idOffset, | |
156 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
157 | + try { | |
158 | + TenantId tenantId = new TenantId(toUUID(strTenantId)); | |
159 | + checkTenantId(tenantId); | |
160 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
161 | + return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink)); | |
162 | + } catch (Exception e) { | |
163 | + throw handleException(e); | |
164 | + } | |
165 | + } | |
166 | + | |
135 | 167 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
136 | 168 | @RequestMapping(value = "/tenant/dashboards", params = { "limit" }, method = RequestMethod.GET) |
137 | 169 | @ResponseBody | ... | ... |
... | ... | @@ -24,19 +24,18 @@ import org.thingsboard.server.common.data.Device; |
24 | 24 | import org.thingsboard.server.common.data.id.CustomerId; |
25 | 25 | import org.thingsboard.server.common.data.id.DeviceId; |
26 | 26 | import org.thingsboard.server.common.data.id.TenantId; |
27 | -import org.thingsboard.server.common.data.id.UUIDBased; | |
28 | 27 | import org.thingsboard.server.common.data.page.TextPageData; |
29 | 28 | import org.thingsboard.server.common.data.page.TextPageLink; |
30 | 29 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
30 | +import org.thingsboard.server.dao.device.DeviceSearchQuery; | |
31 | 31 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
32 | 32 | import org.thingsboard.server.dao.model.ModelConstants; |
33 | 33 | import org.thingsboard.server.exception.ThingsboardException; |
34 | -import org.thingsboard.server.extensions.api.device.DeviceCredentialsUpdateNotificationMsg; | |
35 | 34 | import org.thingsboard.server.service.security.model.SecurityUser; |
36 | 35 | |
37 | 36 | import java.util.ArrayList; |
38 | 37 | import java.util.List; |
39 | -import java.util.UUID; | |
38 | +import java.util.stream.Collectors; | |
40 | 39 | |
41 | 40 | @RestController |
42 | 41 | @RequestMapping("/api") |
... | ... | @@ -238,4 +237,28 @@ public class DeviceController extends BaseController { |
238 | 237 | throw handleException(e); |
239 | 238 | } |
240 | 239 | } |
240 | + | |
241 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
242 | + @RequestMapping(value = "/devices", method = RequestMethod.POST) | |
243 | + @ResponseBody | |
244 | + public List<Device> findByQuery(@RequestBody DeviceSearchQuery query) throws ThingsboardException { | |
245 | + checkNotNull(query); | |
246 | + checkNotNull(query.getParameters()); | |
247 | + checkNotNull(query.getDeviceTypes()); | |
248 | + checkEntityId(query.getParameters().getEntityId()); | |
249 | + try { | |
250 | + List<Device> devices = checkNotNull(deviceService.findDevicesByQuery(query).get()); | |
251 | + devices = devices.stream().filter(device -> { | |
252 | + try { | |
253 | + checkDevice(device); | |
254 | + return true; | |
255 | + } catch (ThingsboardException e) { | |
256 | + return false; | |
257 | + } | |
258 | + }).collect(Collectors.toList()); | |
259 | + return devices; | |
260 | + } catch (Exception e) { | |
261 | + throw handleException(e); | |
262 | + } | |
263 | + } | |
241 | 264 | } | ... | ... |
application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import org.springframework.http.HttpStatus; | |
19 | +import org.springframework.security.access.prepost.PreAuthorize; | |
20 | +import org.springframework.web.bind.annotation.*; | |
21 | +import org.thingsboard.server.common.data.id.EntityId; | |
22 | +import org.thingsboard.server.common.data.id.EntityIdFactory; | |
23 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
24 | +import org.thingsboard.server.dao.relation.EntityRelationsQuery; | |
25 | +import org.thingsboard.server.exception.ThingsboardErrorCode; | |
26 | +import org.thingsboard.server.exception.ThingsboardException; | |
27 | + | |
28 | +import java.util.List; | |
29 | + | |
30 | + | |
31 | +@RestController | |
32 | +@RequestMapping("/api") | |
33 | +public class EntityRelationController extends BaseController { | |
34 | + | |
35 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
36 | + @RequestMapping(value = "/relation", method = RequestMethod.POST) | |
37 | + @ResponseStatus(value = HttpStatus.OK) | |
38 | + public void saveRelation(@RequestBody EntityRelation relation) throws ThingsboardException { | |
39 | + try { | |
40 | + checkNotNull(relation); | |
41 | + checkEntityId(relation.getFrom()); | |
42 | + checkEntityId(relation.getTo()); | |
43 | + relationService.saveRelation(relation).get(); | |
44 | + } catch (Exception e) { | |
45 | + throw handleException(e); | |
46 | + } | |
47 | + } | |
48 | + | |
49 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
50 | + @RequestMapping(value = "/relation", method = RequestMethod.DELETE, params = {"fromId", "fromType", "relationType", "toId", "toType"}) | |
51 | + @ResponseStatus(value = HttpStatus.OK) | |
52 | + public void deleteRelation(@RequestParam("fromId") String strFromId, | |
53 | + @RequestParam("fromType") String strFromType, @RequestParam("relationType") String strRelationType, | |
54 | + @RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException { | |
55 | + checkParameter("fromId", strFromId); | |
56 | + checkParameter("fromType", strFromType); | |
57 | + checkParameter("relationType", strRelationType); | |
58 | + checkParameter("toId", strToId); | |
59 | + checkParameter("toType", strToType); | |
60 | + EntityId fromId = EntityIdFactory.getByTypeAndId(strFromType, strFromId); | |
61 | + EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId); | |
62 | + checkEntityId(fromId); | |
63 | + checkEntityId(toId); | |
64 | + try { | |
65 | + Boolean found = relationService.deleteRelation(fromId, toId, strRelationType).get(); | |
66 | + if (!found) { | |
67 | + throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); | |
68 | + } | |
69 | + } catch (Exception e) { | |
70 | + throw handleException(e); | |
71 | + } | |
72 | + } | |
73 | + | |
74 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
75 | + @RequestMapping(value = "/relations", method = RequestMethod.DELETE, params = {"id", "type"}) | |
76 | + @ResponseStatus(value = HttpStatus.OK) | |
77 | + public void deleteRelations(@RequestParam("entityId") String strId, | |
78 | + @RequestParam("entityType") String strType) throws ThingsboardException { | |
79 | + checkParameter("entityId", strId); | |
80 | + checkParameter("entityType", strType); | |
81 | + EntityId entityId = EntityIdFactory.getByTypeAndId(strType, strId); | |
82 | + checkEntityId(entityId); | |
83 | + try { | |
84 | + relationService.deleteEntityRelations(entityId).get(); | |
85 | + } catch (Exception e) { | |
86 | + throw handleException(e); | |
87 | + } | |
88 | + } | |
89 | + | |
90 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
91 | + @RequestMapping(value = "/relation", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType", "toId", "toType"}) | |
92 | + @ResponseStatus(value = HttpStatus.OK) | |
93 | + public void checkRelation(@RequestParam("fromId") String strFromId, | |
94 | + @RequestParam("fromType") String strFromType, @RequestParam("relationType") String strRelationType, | |
95 | + @RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException { | |
96 | + try { | |
97 | + checkParameter("fromId", strFromId); | |
98 | + checkParameter("fromType", strFromType); | |
99 | + checkParameter("relationType", strRelationType); | |
100 | + checkParameter("toId", strToId); | |
101 | + checkParameter("toType", strToType); | |
102 | + EntityId fromId = EntityIdFactory.getByTypeAndId(strFromType, strFromId); | |
103 | + EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId); | |
104 | + checkEntityId(fromId); | |
105 | + checkEntityId(toId); | |
106 | + Boolean found = relationService.checkRelation(fromId, toId, strRelationType).get(); | |
107 | + if (!found) { | |
108 | + throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); | |
109 | + } | |
110 | + } catch (Exception e) { | |
111 | + throw handleException(e); | |
112 | + } | |
113 | + } | |
114 | + | |
115 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
116 | + @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType"}) | |
117 | + @ResponseBody | |
118 | + public List<EntityRelation> findByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType) throws ThingsboardException { | |
119 | + checkParameter("fromId", strFromId); | |
120 | + checkParameter("fromType", strFromType); | |
121 | + EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId); | |
122 | + checkEntityId(entityId); | |
123 | + try { | |
124 | + return checkNotNull(relationService.findByFrom(entityId).get()); | |
125 | + } catch (Exception e) { | |
126 | + throw handleException(e); | |
127 | + } | |
128 | + } | |
129 | + | |
130 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
131 | + @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType"}) | |
132 | + @ResponseBody | |
133 | + public List<EntityRelation> findByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType | |
134 | + , @RequestParam("relationType") String strRelationType) throws ThingsboardException { | |
135 | + checkParameter("fromId", strFromId); | |
136 | + checkParameter("fromType", strFromType); | |
137 | + checkParameter("relationType", strRelationType); | |
138 | + EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId); | |
139 | + checkEntityId(entityId); | |
140 | + try { | |
141 | + return checkNotNull(relationService.findByFromAndType(entityId, strRelationType).get()); | |
142 | + } catch (Exception e) { | |
143 | + throw handleException(e); | |
144 | + } | |
145 | + } | |
146 | + | |
147 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
148 | + @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType"}) | |
149 | + @ResponseBody | |
150 | + public List<EntityRelation> findByTo(@RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException { | |
151 | + checkParameter("toId", strToId); | |
152 | + checkParameter("toType", strToType); | |
153 | + EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId); | |
154 | + checkEntityId(entityId); | |
155 | + try { | |
156 | + return checkNotNull(relationService.findByTo(entityId).get()); | |
157 | + } catch (Exception e) { | |
158 | + throw handleException(e); | |
159 | + } | |
160 | + } | |
161 | + | |
162 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
163 | + @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType", "relationType"}) | |
164 | + @ResponseBody | |
165 | + public List<EntityRelation> findByTo(@RequestParam("toId") String strToId, @RequestParam("toType") String strToType | |
166 | + , @RequestParam("relationType") String strRelationType) throws ThingsboardException { | |
167 | + checkParameter("toId", strToId); | |
168 | + checkParameter("toType", strToType); | |
169 | + checkParameter("relationType", strRelationType); | |
170 | + EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId); | |
171 | + checkEntityId(entityId); | |
172 | + try { | |
173 | + return checkNotNull(relationService.findByToAndType(entityId, strRelationType).get()); | |
174 | + } catch (Exception e) { | |
175 | + throw handleException(e); | |
176 | + } | |
177 | + } | |
178 | + | |
179 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
180 | + @RequestMapping(value = "/relations", method = RequestMethod.POST) | |
181 | + @ResponseBody | |
182 | + public List<EntityRelation> findByQuery(@RequestBody EntityRelationsQuery query) throws ThingsboardException { | |
183 | + checkNotNull(query); | |
184 | + checkNotNull(query.getParameters()); | |
185 | + checkNotNull(query.getFilters()); | |
186 | + checkEntityId(query.getParameters().getEntityId()); | |
187 | + try { | |
188 | + return checkNotNull(relationService.findByQuery(query).get()); | |
189 | + } catch (Exception e) { | |
190 | + throw handleException(e); | |
191 | + } | |
192 | + } | |
193 | + | |
194 | +} | ... | ... |
... | ... | @@ -18,7 +18,6 @@ package org.thingsboard.server.controller; |
18 | 18 | import org.springframework.beans.factory.annotation.Autowired; |
19 | 19 | import org.springframework.security.access.prepost.PreAuthorize; |
20 | 20 | import org.springframework.web.bind.annotation.*; |
21 | -import org.thingsboard.server.common.data.EntityType; | |
22 | 21 | import org.thingsboard.server.common.data.Event; |
23 | 22 | import org.thingsboard.server.common.data.id.*; |
24 | 23 | import org.thingsboard.server.common.data.page.TimePageData; |
... | ... | @@ -59,7 +58,7 @@ public class EventController extends BaseController { |
59 | 58 | ThingsboardErrorCode.PERMISSION_DENIED); |
60 | 59 | } |
61 | 60 | TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); |
62 | - return checkNotNull(eventService.findEvents(tenantId, getEntityId(strEntityType, strEntityId), eventType, pageLink)); | |
61 | + return checkNotNull(eventService.findEvents(tenantId, EntityIdFactory.getByTypeAndId(strEntityType, strEntityId), eventType, pageLink)); | |
63 | 62 | } catch (Exception e) { |
64 | 63 | throw handleException(e); |
65 | 64 | } |
... | ... | @@ -88,29 +87,10 @@ public class EventController extends BaseController { |
88 | 87 | ThingsboardErrorCode.PERMISSION_DENIED); |
89 | 88 | } |
90 | 89 | TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); |
91 | - return checkNotNull(eventService.findEvents(tenantId, getEntityId(strEntityType, strEntityId), pageLink)); | |
90 | + return checkNotNull(eventService.findEvents(tenantId, EntityIdFactory.getByTypeAndId(strEntityType, strEntityId), pageLink)); | |
92 | 91 | } catch (Exception e) { |
93 | 92 | throw handleException(e); |
94 | 93 | } |
95 | 94 | } |
96 | 95 | |
97 | - | |
98 | - private EntityId getEntityId(String strEntityType, String strEntityId) throws ThingsboardException { | |
99 | - EntityId entityId; | |
100 | - EntityType entityType = EntityType.valueOf(strEntityType); | |
101 | - switch (entityType) { | |
102 | - case RULE: | |
103 | - entityId = new RuleId(toUUID(strEntityId)); | |
104 | - break; | |
105 | - case PLUGIN: | |
106 | - entityId = new PluginId(toUUID(strEntityId)); | |
107 | - break; | |
108 | - case DEVICE: | |
109 | - entityId = new DeviceId(toUUID(strEntityId)); | |
110 | - break; | |
111 | - default: | |
112 | - throw new ThingsboardException("EntityType ['" + entityType + "'] is incorrect!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); | |
113 | - } | |
114 | - return entityId; | |
115 | - } | |
116 | 96 | } | ... | ... |
... | ... | @@ -15,11 +15,13 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.service.cluster.routing; |
17 | 17 | |
18 | +import org.thingsboard.server.common.data.id.EntityId; | |
18 | 19 | import org.thingsboard.server.common.data.id.UUIDBased; |
19 | 20 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
20 | 21 | import org.thingsboard.server.service.cluster.discovery.ServerInstance; |
21 | 22 | |
22 | 23 | import java.util.Optional; |
24 | +import java.util.UUID; | |
23 | 25 | |
24 | 26 | /** |
25 | 27 | * @author Andrew Shvayka |
... | ... | @@ -28,6 +30,8 @@ public interface ClusterRoutingService { |
28 | 30 | |
29 | 31 | ServerAddress getCurrentServer(); |
30 | 32 | |
31 | - Optional<ServerAddress> resolve(UUIDBased entityId); | |
33 | + Optional<ServerAddress> resolveByUuid(UUID uuid); | |
34 | + | |
35 | + Optional<ServerAddress> resolveById(EntityId entityId); | |
32 | 36 | |
33 | 37 | } | ... | ... |
... | ... | @@ -22,6 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; |
22 | 22 | import org.springframework.beans.factory.annotation.Value; |
23 | 23 | import org.springframework.stereotype.Service; |
24 | 24 | import org.springframework.util.Assert; |
25 | +import org.thingsboard.server.common.data.id.EntityId; | |
25 | 26 | import org.thingsboard.server.common.data.id.UUIDBased; |
26 | 27 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
27 | 28 | import org.thingsboard.server.service.cluster.discovery.DiscoveryService; |
... | ... | @@ -31,6 +32,7 @@ import org.thingsboard.server.utils.MiscUtils; |
31 | 32 | |
32 | 33 | import javax.annotation.PostConstruct; |
33 | 34 | import java.util.Optional; |
35 | +import java.util.UUID; | |
34 | 36 | import java.util.concurrent.ConcurrentNavigableMap; |
35 | 37 | import java.util.concurrent.ConcurrentSkipListMap; |
36 | 38 | |
... | ... | @@ -77,13 +79,18 @@ public class ConsistentClusterRoutingService implements ClusterRoutingService, D |
77 | 79 | } |
78 | 80 | |
79 | 81 | @Override |
80 | - public Optional<ServerAddress> resolve(UUIDBased entityId) { | |
81 | - Assert.notNull(entityId); | |
82 | + public Optional<ServerAddress> resolveById(EntityId entityId) { | |
83 | + return resolveByUuid(entityId.getId()); | |
84 | + } | |
85 | + | |
86 | + @Override | |
87 | + public Optional<ServerAddress> resolveByUuid(UUID uuid) { | |
88 | + Assert.notNull(uuid); | |
82 | 89 | if (circle.isEmpty()) { |
83 | 90 | return Optional.empty(); |
84 | 91 | } |
85 | - Long hash = hashFunction.newHasher().putLong(entityId.getId().getMostSignificantBits()) | |
86 | - .putLong(entityId.getId().getLeastSignificantBits()).hash().asLong(); | |
92 | + Long hash = hashFunction.newHasher().putLong(uuid.getMostSignificantBits()) | |
93 | + .putLong(uuid.getLeastSignificantBits()).hash().asLong(); | |
87 | 94 | if (!circle.containsKey(hash)) { |
88 | 95 | ConcurrentNavigableMap<Long, ServerInstance> tailMap = |
89 | 96 | circle.tailMap(hash); | ... | ... |
... | ... | @@ -60,8 +60,8 @@ plugins: |
60 | 60 | |
61 | 61 | # JWT Token parameters |
62 | 62 | security.jwt: |
63 | - tokenExpirationTime: "${JWT_TOKEN_EXPIRATION_TIME:900}" # Number of seconds (15 mins) | |
64 | - refreshTokenExpTime: "${JWT_REFRESH_TOKEN_EXPIRATION_TIME:3600}" # Seconds (1 hour) | |
63 | + tokenExpirationTime: "${JWT_TOKEN_EXPIRATION_TIME:9000000}" # Number of seconds (15 mins) | |
64 | + refreshTokenExpTime: "${JWT_REFRESH_TOKEN_EXPIRATION_TIME:36000000}" # Seconds (1 hour) | |
65 | 65 | tokenIssuer: "${JWT_TOKEN_ISSUER:thingsboard.io}" |
66 | 66 | tokenSigningKey: "${JWT_TOKEN_SIGNING_KEY:thingsboardDefaultSigningKey}" |
67 | 67 | ... | ... |
... | ... | @@ -145,7 +145,7 @@ public class DefaultActorServiceTest { |
145 | 145 | ReflectionTestUtils.setField(actorContext, "eventService", eventService); |
146 | 146 | |
147 | 147 | |
148 | - when(routingService.resolve(any())).thenReturn(Optional.empty()); | |
148 | + when(routingService.resolveById((EntityId) any())).thenReturn(Optional.empty()); | |
149 | 149 | |
150 | 150 | when(discoveryService.getCurrentServer()).thenReturn(serverInstance); |
151 | 151 | |
... | ... | @@ -239,7 +239,7 @@ public class DefaultActorServiceTest { |
239 | 239 | List<TsKvEntry> expected = new ArrayList<>(); |
240 | 240 | expected.add(new BasicTsKvEntry(ts, entry1)); |
241 | 241 | expected.add(new BasicTsKvEntry(ts, entry2)); |
242 | - verify(tsService, Mockito.timeout(5000)).save(DataConstants.DEVICE, deviceId, expected); | |
242 | + verify(tsService, Mockito.timeout(5000)).save(deviceId, expected); | |
243 | 243 | } |
244 | 244 | |
245 | 245 | } | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>1.2.3-SNAPSHOT</version> | |
23 | + <version>1.3.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -28,6 +28,7 @@ public class Device extends SearchTextBased<DeviceId> { |
28 | 28 | private TenantId tenantId; |
29 | 29 | private CustomerId customerId; |
30 | 30 | private String name; |
31 | + private String type; | |
31 | 32 | private JsonNode additionalInfo; |
32 | 33 | |
33 | 34 | public Device() { |
... | ... | @@ -43,6 +44,7 @@ public class Device extends SearchTextBased<DeviceId> { |
43 | 44 | this.tenantId = device.getTenantId(); |
44 | 45 | this.customerId = device.getCustomerId(); |
45 | 46 | this.name = device.getName(); |
47 | + this.type = device.getType(); | |
46 | 48 | this.additionalInfo = device.getAdditionalInfo(); |
47 | 49 | } |
48 | 50 | |
... | ... | @@ -70,6 +72,14 @@ public class Device extends SearchTextBased<DeviceId> { |
70 | 72 | this.name = name; |
71 | 73 | } |
72 | 74 | |
75 | + public String getType() { | |
76 | + return type; | |
77 | + } | |
78 | + | |
79 | + public void setType(String type) { | |
80 | + this.type = type; | |
81 | + } | |
82 | + | |
73 | 83 | public JsonNode getAdditionalInfo() { |
74 | 84 | return additionalInfo; |
75 | 85 | } |
... | ... | @@ -90,6 +100,7 @@ public class Device extends SearchTextBased<DeviceId> { |
90 | 100 | result = prime * result + ((additionalInfo == null) ? 0 : additionalInfo.hashCode()); |
91 | 101 | result = prime * result + ((customerId == null) ? 0 : customerId.hashCode()); |
92 | 102 | result = prime * result + ((name == null) ? 0 : name.hashCode()); |
103 | + result = prime * result + ((type == null) ? 0 : type.hashCode()); | |
93 | 104 | result = prime * result + ((tenantId == null) ? 0 : tenantId.hashCode()); |
94 | 105 | return result; |
95 | 106 | } |
... | ... | @@ -118,6 +129,11 @@ public class Device extends SearchTextBased<DeviceId> { |
118 | 129 | return false; |
119 | 130 | } else if (!name.equals(other.name)) |
120 | 131 | return false; |
132 | + if (type == null) { | |
133 | + if (other.type != null) | |
134 | + return false; | |
135 | + } else if (!type.equals(other.type)) | |
136 | + return false; | |
121 | 137 | if (tenantId == null) { |
122 | 138 | if (other.tenantId != null) |
123 | 139 | return false; |
... | ... | @@ -135,6 +151,8 @@ public class Device extends SearchTextBased<DeviceId> { |
135 | 151 | builder.append(customerId); |
136 | 152 | builder.append(", name="); |
137 | 153 | builder.append(name); |
154 | + builder.append(", type="); | |
155 | + builder.append(type); | |
138 | 156 | builder.append(", additionalInfo="); |
139 | 157 | builder.append(additionalInfo); |
140 | 158 | builder.append(", createdTime="); | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.alarm; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | +import lombok.Data; | |
20 | +import org.thingsboard.server.common.data.BaseData; | |
21 | +import org.thingsboard.server.common.data.id.EntityId; | |
22 | + | |
23 | +/** | |
24 | + * Created by ashvayka on 11.05.17. | |
25 | + */ | |
26 | +@Data | |
27 | +public class Alarm extends BaseData<AlarmId> { | |
28 | + | |
29 | + private long startTs; | |
30 | + private long endTs; | |
31 | + private long ackTs; | |
32 | + private long clearTs; | |
33 | + private String type; | |
34 | + private EntityId originator; | |
35 | + private AlarmSeverity severity; | |
36 | + private AlarmStatus status; | |
37 | + private JsonNode details; | |
38 | + private boolean propagate; | |
39 | + | |
40 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.alarm; | |
17 | + | |
18 | +import com.fasterxml.jackson.annotation.JsonCreator; | |
19 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
20 | +import com.fasterxml.jackson.annotation.JsonProperty; | |
21 | +import org.thingsboard.server.common.data.EntityType; | |
22 | +import org.thingsboard.server.common.data.id.EntityId; | |
23 | +import org.thingsboard.server.common.data.id.UUIDBased; | |
24 | + | |
25 | +import java.util.UUID; | |
26 | + | |
27 | +public class AlarmId extends UUIDBased implements EntityId { | |
28 | + | |
29 | + private static final long serialVersionUID = 1L; | |
30 | + | |
31 | + @JsonCreator | |
32 | + public AlarmId(@JsonProperty("id") UUID id) { | |
33 | + super(id); | |
34 | + } | |
35 | + | |
36 | + public static AlarmId fromString(String alarmId) { | |
37 | + return new AlarmId(UUID.fromString(alarmId)); | |
38 | + } | |
39 | + | |
40 | + @JsonIgnore | |
41 | + @Override | |
42 | + public EntityType getEntityType() { | |
43 | + return EntityType.ALARM; | |
44 | + } | |
45 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.alarm; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.data.id.EntityId; | |
20 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
21 | + | |
22 | +/** | |
23 | + * Created by ashvayka on 11.05.17. | |
24 | + */ | |
25 | +@Data | |
26 | +public class AlarmQuery { | |
27 | + | |
28 | + private EntityId affectedEntityId; | |
29 | + private TimePageLink pageLink; | |
30 | + private AlarmStatus status; | |
31 | + | |
32 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.alarm; | |
17 | + | |
18 | +/** | |
19 | + * Created by ashvayka on 11.05.17. | |
20 | + */ | |
21 | +public enum AlarmSeverity { | |
22 | + | |
23 | + CRITICAL, MAJOR, MINOR, WARNING, INDETERMINATE; | |
24 | + | |
25 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.alarm; | |
17 | + | |
18 | +/** | |
19 | + * Created by ashvayka on 11.05.17. | |
20 | + */ | |
21 | +public enum AlarmStatus { | |
22 | + | |
23 | + ACTIVE_UNACK, ACTIVE_ACK, CLEARED_UNACK, CLEARED_ACK; | |
24 | + | |
25 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.asset; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | +import org.thingsboard.server.common.data.SearchTextBased; | |
20 | +import org.thingsboard.server.common.data.id.AssetId; | |
21 | +import org.thingsboard.server.common.data.id.CustomerId; | |
22 | +import org.thingsboard.server.common.data.id.TenantId; | |
23 | + | |
24 | +public class Asset extends SearchTextBased<AssetId> { | |
25 | + | |
26 | + private static final long serialVersionUID = 2807343040519543363L; | |
27 | + | |
28 | + private TenantId tenantId; | |
29 | + private CustomerId customerId; | |
30 | + private String name; | |
31 | + private String type; | |
32 | + private JsonNode additionalInfo; | |
33 | + | |
34 | + public Asset() { | |
35 | + super(); | |
36 | + } | |
37 | + | |
38 | + public Asset(AssetId id) { | |
39 | + super(id); | |
40 | + } | |
41 | + | |
42 | + public Asset(Asset asset) { | |
43 | + super(asset); | |
44 | + this.tenantId = asset.getTenantId(); | |
45 | + this.customerId = asset.getCustomerId(); | |
46 | + this.name = asset.getName(); | |
47 | + this.type = asset.getType(); | |
48 | + this.additionalInfo = asset.getAdditionalInfo(); | |
49 | + } | |
50 | + | |
51 | + public TenantId getTenantId() { | |
52 | + return tenantId; | |
53 | + } | |
54 | + | |
55 | + public void setTenantId(TenantId tenantId) { | |
56 | + this.tenantId = tenantId; | |
57 | + } | |
58 | + | |
59 | + public CustomerId getCustomerId() { | |
60 | + return customerId; | |
61 | + } | |
62 | + | |
63 | + public void setCustomerId(CustomerId customerId) { | |
64 | + this.customerId = customerId; | |
65 | + } | |
66 | + | |
67 | + public String getName() { | |
68 | + return name; | |
69 | + } | |
70 | + | |
71 | + public void setName(String name) { | |
72 | + this.name = name; | |
73 | + } | |
74 | + | |
75 | + public String getType() { | |
76 | + return type; | |
77 | + } | |
78 | + | |
79 | + public void setType(String type) { | |
80 | + this.type = type; | |
81 | + } | |
82 | + | |
83 | + public JsonNode getAdditionalInfo() { | |
84 | + return additionalInfo; | |
85 | + } | |
86 | + | |
87 | + public void setAdditionalInfo(JsonNode additionalInfo) { | |
88 | + this.additionalInfo = additionalInfo; | |
89 | + } | |
90 | + | |
91 | + @Override | |
92 | + public String getSearchText() { | |
93 | + return name; | |
94 | + } | |
95 | + | |
96 | + @Override | |
97 | + public int hashCode() { | |
98 | + final int prime = 31; | |
99 | + int result = super.hashCode(); | |
100 | + result = prime * result + ((additionalInfo == null) ? 0 : additionalInfo.hashCode()); | |
101 | + result = prime * result + ((customerId == null) ? 0 : customerId.hashCode()); | |
102 | + result = prime * result + ((name == null) ? 0 : name.hashCode()); | |
103 | + result = prime * result + ((type == null) ? 0 : type.hashCode()); | |
104 | + result = prime * result + ((tenantId == null) ? 0 : tenantId.hashCode()); | |
105 | + return result; | |
106 | + } | |
107 | + | |
108 | + @Override | |
109 | + public boolean equals(Object obj) { | |
110 | + if (this == obj) | |
111 | + return true; | |
112 | + if (!super.equals(obj)) | |
113 | + return false; | |
114 | + if (getClass() != obj.getClass()) | |
115 | + return false; | |
116 | + Asset other = (Asset) obj; | |
117 | + if (additionalInfo == null) { | |
118 | + if (other.additionalInfo != null) | |
119 | + return false; | |
120 | + } else if (!additionalInfo.equals(other.additionalInfo)) | |
121 | + return false; | |
122 | + if (customerId == null) { | |
123 | + if (other.customerId != null) | |
124 | + return false; | |
125 | + } else if (!customerId.equals(other.customerId)) | |
126 | + return false; | |
127 | + if (name == null) { | |
128 | + if (other.name != null) | |
129 | + return false; | |
130 | + } else if (!name.equals(other.name)) | |
131 | + return false; | |
132 | + if (type == null) { | |
133 | + if (other.type != null) | |
134 | + return false; | |
135 | + } else if (!type.equals(other.type)) | |
136 | + return false; | |
137 | + if (tenantId == null) { | |
138 | + if (other.tenantId != null) | |
139 | + return false; | |
140 | + } else if (!tenantId.equals(other.tenantId)) | |
141 | + return false; | |
142 | + return true; | |
143 | + } | |
144 | + | |
145 | + @Override | |
146 | + public String toString() { | |
147 | + StringBuilder builder = new StringBuilder(); | |
148 | + builder.append("Asset [tenantId="); | |
149 | + builder.append(tenantId); | |
150 | + builder.append(", customerId="); | |
151 | + builder.append(customerId); | |
152 | + builder.append(", name="); | |
153 | + builder.append(name); | |
154 | + builder.append(", type="); | |
155 | + builder.append(type); | |
156 | + builder.append(", additionalInfo="); | |
157 | + builder.append(additionalInfo); | |
158 | + builder.append(", createdTime="); | |
159 | + builder.append(createdTime); | |
160 | + builder.append(", id="); | |
161 | + builder.append(id); | |
162 | + builder.append("]"); | |
163 | + return builder.toString(); | |
164 | + } | |
165 | + | |
166 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.id; | |
17 | + | |
18 | +import com.fasterxml.jackson.annotation.JsonCreator; | |
19 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
20 | +import com.fasterxml.jackson.annotation.JsonProperty; | |
21 | +import org.thingsboard.server.common.data.EntityType; | |
22 | + | |
23 | +import java.util.UUID; | |
24 | + | |
25 | +public class AssetId extends UUIDBased implements EntityId { | |
26 | + | |
27 | + private static final long serialVersionUID = 1L; | |
28 | + | |
29 | + @JsonCreator | |
30 | + public AssetId(@JsonProperty("id") UUID id) { | |
31 | + super(id); | |
32 | + } | |
33 | + | |
34 | + public static AssetId fromString(String assetId) { | |
35 | + return new AssetId(UUID.fromString(assetId)); | |
36 | + } | |
37 | + | |
38 | + @JsonIgnore | |
39 | + @Override | |
40 | + public EntityType getEntityType() { | |
41 | + return EntityType.ASSET; | |
42 | + } | |
43 | +} | ... | ... |
... | ... | @@ -18,12 +18,24 @@ package org.thingsboard.server.common.data.id; |
18 | 18 | import java.util.UUID; |
19 | 19 | |
20 | 20 | import com.fasterxml.jackson.annotation.JsonCreator; |
21 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
21 | 22 | import com.fasterxml.jackson.annotation.JsonProperty; |
23 | +import org.thingsboard.server.common.data.EntityType; | |
22 | 24 | |
23 | -public class DashboardId extends UUIDBased { | |
25 | +public class DashboardId extends UUIDBased implements EntityId { | |
24 | 26 | |
25 | 27 | @JsonCreator |
26 | - public DashboardId(@JsonProperty("id") UUID id){ | |
28 | + public DashboardId(@JsonProperty("id") UUID id) { | |
27 | 29 | super(id); |
28 | 30 | } |
31 | + | |
32 | + public static DashboardId fromString(String dashboardId) { | |
33 | + return new DashboardId(UUID.fromString(dashboardId)); | |
34 | + } | |
35 | + | |
36 | + @JsonIgnore | |
37 | + @Override | |
38 | + public EntityType getEntityType() { | |
39 | + return EntityType.DASHBOARD; | |
40 | + } | |
29 | 41 | } | ... | ... |
... | ... | @@ -16,6 +16,8 @@ |
16 | 16 | package org.thingsboard.server.common.data.id; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.annotation.JsonIgnore; |
19 | +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; | |
20 | +import com.fasterxml.jackson.databind.annotation.JsonSerialize; | |
19 | 21 | import org.thingsboard.server.common.data.EntityType; |
20 | 22 | |
21 | 23 | import java.util.UUID; |
... | ... | @@ -23,6 +25,9 @@ import java.util.UUID; |
23 | 25 | /** |
24 | 26 | * @author Andrew Shvayka |
25 | 27 | */ |
28 | + | |
29 | +@JsonDeserialize(using = EntityIdDeserializer.class) | |
30 | +@JsonSerialize(using = EntityIdSerializer.class) | |
26 | 31 | public interface EntityId { |
27 | 32 | |
28 | 33 | UUID NULL_UUID = UUID.fromString("13814000-1dd2-11b2-8080-808080808080"); | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdDeserializer.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.id; | |
17 | + | |
18 | +import com.fasterxml.jackson.core.JsonParser; | |
19 | +import com.fasterxml.jackson.core.JsonProcessingException; | |
20 | +import com.fasterxml.jackson.core.ObjectCodec; | |
21 | +import com.fasterxml.jackson.databind.DeserializationContext; | |
22 | +import com.fasterxml.jackson.databind.JsonDeserializer; | |
23 | +import com.fasterxml.jackson.databind.node.ObjectNode; | |
24 | + | |
25 | +import java.io.IOException; | |
26 | + | |
27 | +/** | |
28 | + * Created by ashvayka on 11.05.17. | |
29 | + */ | |
30 | +public class EntityIdDeserializer extends JsonDeserializer<EntityId> { | |
31 | + | |
32 | + @Override | |
33 | + public EntityId deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException, JsonProcessingException { | |
34 | + ObjectCodec oc = jsonParser.getCodec(); | |
35 | + ObjectNode node = oc.readTree(jsonParser); | |
36 | + if (node.has("entityType") && node.has("id")) { | |
37 | + return EntityIdFactory.getByTypeAndId(node.get("entityType").asText(), node.get("id").asText()); | |
38 | + } else { | |
39 | + throw new IOException("Missing entityType or id!"); | |
40 | + } | |
41 | + } | |
42 | + | |
43 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.id; | |
17 | + | |
18 | +import org.thingsboard.server.common.data.EntityType; | |
19 | + | |
20 | +import java.util.UUID; | |
21 | + | |
22 | +/** | |
23 | + * Created by ashvayka on 25.04.17. | |
24 | + */ | |
25 | +public class EntityIdFactory { | |
26 | + | |
27 | + public static EntityId getByTypeAndId(String type, String uuid) { | |
28 | + return getByTypeAndUuid(EntityType.valueOf(type), UUID.fromString(uuid)); | |
29 | + } | |
30 | + | |
31 | + public static EntityId getByTypeAndUuid(String type, UUID uuid) { | |
32 | + return getByTypeAndUuid(EntityType.valueOf(type), uuid); | |
33 | + } | |
34 | + | |
35 | + public static EntityId getByTypeAndUuid(EntityType type, UUID uuid) { | |
36 | + switch (type) { | |
37 | + case TENANT: | |
38 | + return new TenantId(uuid); | |
39 | + case CUSTOMER: | |
40 | + return new CustomerId(uuid); | |
41 | + case USER: | |
42 | + return new UserId(uuid); | |
43 | + case RULE: | |
44 | + return new RuleId(uuid); | |
45 | + case PLUGIN: | |
46 | + return new PluginId(uuid); | |
47 | + case DASHBOARD: | |
48 | + return new DashboardId(uuid); | |
49 | + case DEVICE: | |
50 | + return new DeviceId(uuid); | |
51 | + case ASSET: | |
52 | + return new AssetId(uuid); | |
53 | + } | |
54 | + throw new IllegalArgumentException("EntityType " + type + " is not supported!"); | |
55 | + } | |
56 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.id; | |
17 | + | |
18 | +import com.fasterxml.jackson.core.JsonGenerator; | |
19 | +import com.fasterxml.jackson.core.JsonProcessingException; | |
20 | +import com.fasterxml.jackson.databind.JsonSerializer; | |
21 | +import com.fasterxml.jackson.databind.SerializerProvider; | |
22 | + | |
23 | +import java.io.IOException; | |
24 | + | |
25 | +/** | |
26 | + * Created by ashvayka on 11.05.17. | |
27 | + */ | |
28 | +public class EntityIdSerializer extends JsonSerializer<EntityId> { | |
29 | + | |
30 | + @Override | |
31 | + public void serialize(EntityId value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException { | |
32 | + gen.writeStartObject(); | |
33 | + gen.writeStringField("entityType", value.getEntityType().name()); | |
34 | + gen.writeStringField("id", value.getId().toString()); | |
35 | + gen.writeEndObject(); | |
36 | + } | |
37 | +} | ... | ... |
... | ... | @@ -18,12 +18,25 @@ package org.thingsboard.server.common.data.id; |
18 | 18 | import java.util.UUID; |
19 | 19 | |
20 | 20 | import com.fasterxml.jackson.annotation.JsonCreator; |
21 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
21 | 22 | import com.fasterxml.jackson.annotation.JsonProperty; |
23 | +import org.thingsboard.server.common.data.EntityType; | |
22 | 24 | |
23 | -public class UserId extends UUIDBased { | |
25 | +public class UserId extends UUIDBased implements EntityId { | |
24 | 26 | |
25 | 27 | @JsonCreator |
26 | - public UserId(@JsonProperty("id") UUID id){ | |
27 | - super(id); | |
28 | - } | |
28 | + public UserId(@JsonProperty("id") UUID id) { | |
29 | + super(id); | |
30 | + } | |
31 | + | |
32 | + public static UserId fromString(String userId) { | |
33 | + return new UserId(UUID.fromString(userId)); | |
34 | + } | |
35 | + | |
36 | + @JsonIgnore | |
37 | + @Override | |
38 | + public EntityType getEntityType() { | |
39 | + return EntityType.USER; | |
40 | + } | |
41 | + | |
29 | 42 | } | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.relation; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | +import org.thingsboard.server.common.data.id.EntityId; | |
20 | + | |
21 | +import java.util.Objects; | |
22 | + | |
23 | +public class EntityRelation { | |
24 | + | |
25 | + private static final long serialVersionUID = 2807343040519543363L; | |
26 | + | |
27 | + public static final String CONTAINS_TYPE = "Contains"; | |
28 | + public static final String MANAGES_TYPE = "Manages"; | |
29 | + | |
30 | + private EntityId from; | |
31 | + private EntityId to; | |
32 | + private String type; | |
33 | + private JsonNode additionalInfo; | |
34 | + | |
35 | + public EntityRelation() { | |
36 | + super(); | |
37 | + } | |
38 | + | |
39 | + public EntityRelation(EntityId from, EntityId to, String type) { | |
40 | + this(from, to, type, null); | |
41 | + } | |
42 | + | |
43 | + public EntityRelation(EntityId from, EntityId to, String type, JsonNode additionalInfo) { | |
44 | + this.from = from; | |
45 | + this.to = to; | |
46 | + this.type = type; | |
47 | + this.additionalInfo = additionalInfo; | |
48 | + } | |
49 | + | |
50 | + public EntityRelation(EntityRelation device) { | |
51 | + this.from = device.getFrom(); | |
52 | + this.to = device.getTo(); | |
53 | + this.type = device.getType(); | |
54 | + this.additionalInfo = device.getAdditionalInfo(); | |
55 | + } | |
56 | + | |
57 | + public EntityId getFrom() { | |
58 | + return from; | |
59 | + } | |
60 | + | |
61 | + public void setFrom(EntityId from) { | |
62 | + this.from = from; | |
63 | + } | |
64 | + | |
65 | + public EntityId getTo() { | |
66 | + return to; | |
67 | + } | |
68 | + | |
69 | + public void setTo(EntityId to) { | |
70 | + this.to = to; | |
71 | + } | |
72 | + | |
73 | + public String getType() { | |
74 | + return type; | |
75 | + } | |
76 | + | |
77 | + public void setType(String type) { | |
78 | + this.type = type; | |
79 | + } | |
80 | + | |
81 | + public JsonNode getAdditionalInfo() { | |
82 | + return additionalInfo; | |
83 | + } | |
84 | + | |
85 | + public void setAdditionalInfo(JsonNode additionalInfo) { | |
86 | + this.additionalInfo = additionalInfo; | |
87 | + } | |
88 | + | |
89 | + @Override | |
90 | + public boolean equals(Object o) { | |
91 | + if (this == o) return true; | |
92 | + if (o == null || getClass() != o.getClass()) return false; | |
93 | + EntityRelation relation = (EntityRelation) o; | |
94 | + return Objects.equals(from, relation.from) && | |
95 | + Objects.equals(to, relation.to) && | |
96 | + Objects.equals(type, relation.type); | |
97 | + } | |
98 | + | |
99 | + @Override | |
100 | + public int hashCode() { | |
101 | + return Objects.hash(from, to, type); | |
102 | + } | |
103 | +} | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>1.2.3-SNAPSHOT</version> | |
23 | + <version>1.3.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>1.2.3-SNAPSHOT</version> | |
23 | + <version>1.3.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>thingsboard</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>1.2.3-SNAPSHOT</version> | |
23 | + <version>1.3.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>1.2.3-SNAPSHOT</version> | |
23 | + <version>1.3.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>thingsboard</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard</groupId> | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.alarm; | |
17 | + | |
18 | +/** | |
19 | + * Created by ashvayka on 11.05.17. | |
20 | + */ | |
21 | +public interface AlarmDao { | |
22 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.alarm; | |
17 | + | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
19 | +import org.thingsboard.server.common.data.alarm.Alarm; | |
20 | +import org.thingsboard.server.common.data.alarm.AlarmId; | |
21 | +import org.thingsboard.server.common.data.alarm.AlarmQuery; | |
22 | +import org.thingsboard.server.common.data.page.TimePageData; | |
23 | + | |
24 | +import java.util.Optional; | |
25 | + | |
26 | +/** | |
27 | + * Created by ashvayka on 11.05.17. | |
28 | + */ | |
29 | +public interface AlarmService { | |
30 | + | |
31 | + Optional<Alarm> saveIfNotExists(Alarm alarm); | |
32 | + | |
33 | + ListenableFuture<Boolean> updateAlarm(Alarm alarm); | |
34 | + | |
35 | + ListenableFuture<Boolean> ackAlarm(Alarm alarm); | |
36 | + | |
37 | + ListenableFuture<Boolean> clearAlarm(AlarmId alarmId); | |
38 | + | |
39 | + ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query); | |
40 | + | |
41 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.asset; | |
17 | + | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
19 | +import org.thingsboard.server.common.data.Device; | |
20 | +import org.thingsboard.server.common.data.asset.Asset; | |
21 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
22 | +import org.thingsboard.server.dao.Dao; | |
23 | +import org.thingsboard.server.dao.model.AssetEntity; | |
24 | +import org.thingsboard.server.dao.model.DeviceEntity; | |
25 | + | |
26 | +import java.util.List; | |
27 | +import java.util.Optional; | |
28 | +import java.util.UUID; | |
29 | + | |
30 | +/** | |
31 | + * The Interface AssetDao. | |
32 | + * | |
33 | + */ | |
34 | +public interface AssetDao extends Dao<AssetEntity> { | |
35 | + | |
36 | + /** | |
37 | + * Save or update asset object | |
38 | + * | |
39 | + * @param asset the asset object | |
40 | + * @return saved asset object | |
41 | + */ | |
42 | + AssetEntity save(Asset asset); | |
43 | + | |
44 | + /** | |
45 | + * Find assets by tenantId and page link. | |
46 | + * | |
47 | + * @param tenantId the tenantId | |
48 | + * @param pageLink the page link | |
49 | + * @return the list of asset objects | |
50 | + */ | |
51 | + List<AssetEntity> findAssetsByTenantId(UUID tenantId, TextPageLink pageLink); | |
52 | + | |
53 | + /** | |
54 | + * Find assets by tenantId and assets Ids. | |
55 | + * | |
56 | + * @param tenantId the tenantId | |
57 | + * @param assetIds the asset Ids | |
58 | + * @return the list of asset objects | |
59 | + */ | |
60 | + ListenableFuture<List<AssetEntity>> findAssetsByTenantIdAndIdsAsync(UUID tenantId, List<UUID> assetIds); | |
61 | + | |
62 | + /** | |
63 | + * Find assets by tenantId, customerId and page link. | |
64 | + * | |
65 | + * @param tenantId the tenantId | |
66 | + * @param customerId the customerId | |
67 | + * @param pageLink the page link | |
68 | + * @return the list of asset objects | |
69 | + */ | |
70 | + List<AssetEntity> findAssetsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink); | |
71 | + | |
72 | + /** | |
73 | + * Find assets by tenantId, customerId and assets Ids. | |
74 | + * | |
75 | + * @param tenantId the tenantId | |
76 | + * @param customerId the customerId | |
77 | + * @param assetIds the asset Ids | |
78 | + * @return the list of asset objects | |
79 | + */ | |
80 | + ListenableFuture<List<AssetEntity>> findAssetsByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> assetIds); | |
81 | + | |
82 | + /** | |
83 | + * Find assets by tenantId and asset name. | |
84 | + * | |
85 | + * @param tenantId the tenantId | |
86 | + * @param name the asset name | |
87 | + * @return the optional asset object | |
88 | + */ | |
89 | + Optional<AssetEntity> findAssetsByTenantIdAndName(UUID tenantId, String name); | |
90 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.asset; | |
17 | + | |
18 | +import com.datastax.driver.core.querybuilder.Select; | |
19 | +import com.google.common.util.concurrent.ListenableFuture; | |
20 | +import lombok.extern.slf4j.Slf4j; | |
21 | +import org.springframework.stereotype.Component; | |
22 | +import org.thingsboard.server.common.data.asset.Asset; | |
23 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
24 | +import org.thingsboard.server.dao.AbstractSearchTextDao; | |
25 | +import org.thingsboard.server.dao.model.AssetEntity; | |
26 | + | |
27 | +import java.util.*; | |
28 | + | |
29 | +import static com.datastax.driver.core.querybuilder.QueryBuilder.*; | |
30 | +import static org.thingsboard.server.dao.model.ModelConstants.*; | |
31 | + | |
32 | +@Component | |
33 | +@Slf4j | |
34 | +public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements AssetDao { | |
35 | + | |
36 | + @Override | |
37 | + protected Class<AssetEntity> getColumnFamilyClass() { | |
38 | + return AssetEntity.class; | |
39 | + } | |
40 | + | |
41 | + @Override | |
42 | + protected String getColumnFamilyName() { | |
43 | + return ASSET_COLUMN_FAMILY_NAME; | |
44 | + } | |
45 | + | |
46 | + @Override | |
47 | + public AssetEntity save(Asset asset) { | |
48 | + log.debug("Save asset [{}] ", asset); | |
49 | + return save(new AssetEntity(asset)); | |
50 | + } | |
51 | + | |
52 | + @Override | |
53 | + public List<AssetEntity> findAssetsByTenantId(UUID tenantId, TextPageLink pageLink) { | |
54 | + log.debug("Try to find assets by tenantId [{}] and pageLink [{}]", tenantId, pageLink); | |
55 | + List<AssetEntity> assetEntities = findPageWithTextSearch(ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, | |
56 | + Collections.singletonList(eq(ASSET_TENANT_ID_PROPERTY, tenantId)), pageLink); | |
57 | + | |
58 | + log.trace("Found assets [{}] by tenantId [{}] and pageLink [{}]", assetEntities, tenantId, pageLink); | |
59 | + return assetEntities; | |
60 | + } | |
61 | + | |
62 | + @Override | |
63 | + public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdAndIdsAsync(UUID tenantId, List<UUID> assetIds) { | |
64 | + log.debug("Try to find assets by tenantId [{}] and asset Ids [{}]", tenantId, assetIds); | |
65 | + Select select = select().from(getColumnFamilyName()); | |
66 | + Select.Where query = select.where(); | |
67 | + query.and(eq(ASSET_TENANT_ID_PROPERTY, tenantId)); | |
68 | + query.and(in(ID_PROPERTY, assetIds)); | |
69 | + return findListByStatementAsync(query); | |
70 | + } | |
71 | + | |
72 | + @Override | |
73 | + public List<AssetEntity> findAssetsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) { | |
74 | + log.debug("Try to find assets by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink); | |
75 | + List<AssetEntity> assetEntities = findPageWithTextSearch(ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, | |
76 | + Arrays.asList(eq(ASSET_CUSTOMER_ID_PROPERTY, customerId), | |
77 | + eq(ASSET_TENANT_ID_PROPERTY, tenantId)), | |
78 | + pageLink); | |
79 | + | |
80 | + log.trace("Found assets [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", assetEntities, tenantId, customerId, pageLink); | |
81 | + return assetEntities; | |
82 | + } | |
83 | + | |
84 | + @Override | |
85 | + public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> assetIds) { | |
86 | + log.debug("Try to find assets by tenantId [{}], customerId [{}] and asset Ids [{}]", tenantId, customerId, assetIds); | |
87 | + Select select = select().from(getColumnFamilyName()); | |
88 | + Select.Where query = select.where(); | |
89 | + query.and(eq(ASSET_TENANT_ID_PROPERTY, tenantId)); | |
90 | + query.and(eq(ASSET_CUSTOMER_ID_PROPERTY, customerId)); | |
91 | + query.and(in(ID_PROPERTY, assetIds)); | |
92 | + return findListByStatementAsync(query); | |
93 | + } | |
94 | + | |
95 | + @Override | |
96 | + public Optional<AssetEntity> findAssetsByTenantIdAndName(UUID tenantId, String assetName) { | |
97 | + Select select = select().from(ASSET_BY_TENANT_AND_NAME_VIEW_NAME); | |
98 | + Select.Where query = select.where(); | |
99 | + query.and(eq(ASSET_TENANT_ID_PROPERTY, tenantId)); | |
100 | + query.and(eq(ASSET_NAME_PROPERTY, assetName)); | |
101 | + return Optional.ofNullable(findOneByStatement(query)); | |
102 | + } | |
103 | + | |
104 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.asset; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.data.EntityType; | |
20 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
21 | +import org.thingsboard.server.dao.relation.RelationsSearchParameters; | |
22 | +import org.thingsboard.server.dao.relation.EntityRelationsQuery; | |
23 | +import org.thingsboard.server.dao.relation.EntityTypeFilter; | |
24 | + | |
25 | +import javax.annotation.Nullable; | |
26 | +import java.util.ArrayList; | |
27 | +import java.util.Collections; | |
28 | +import java.util.List; | |
29 | + | |
30 | +/** | |
31 | + * Created by ashvayka on 03.05.17. | |
32 | + */ | |
33 | +@Data | |
34 | +public class AssetSearchQuery { | |
35 | + | |
36 | + private RelationsSearchParameters parameters; | |
37 | + @Nullable | |
38 | + private String relationType; | |
39 | + @Nullable | |
40 | + private List<String> assetTypes; | |
41 | + | |
42 | + public EntityRelationsQuery toEntitySearchQuery() { | |
43 | + EntityRelationsQuery query = new EntityRelationsQuery(); | |
44 | + query.setParameters(parameters); | |
45 | + query.setFilters( | |
46 | + Collections.singletonList(new EntityTypeFilter(relationType == null ? EntityRelation.CONTAINS_TYPE : relationType, | |
47 | + Collections.singletonList(EntityType.ASSET)))); | |
48 | + return query; | |
49 | + } | |
50 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.asset; | |
17 | + | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
19 | +import org.thingsboard.server.common.data.asset.Asset; | |
20 | +import org.thingsboard.server.common.data.id.AssetId; | |
21 | +import org.thingsboard.server.common.data.id.CustomerId; | |
22 | +import org.thingsboard.server.common.data.id.TenantId; | |
23 | +import org.thingsboard.server.common.data.page.TextPageData; | |
24 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
25 | + | |
26 | +import java.util.List; | |
27 | +import java.util.Optional; | |
28 | + | |
29 | +public interface AssetService { | |
30 | + | |
31 | + Asset findAssetById(AssetId assetId); | |
32 | + | |
33 | + ListenableFuture<Asset> findAssetByIdAsync(AssetId assetId); | |
34 | + | |
35 | + Optional<Asset> findAssetByTenantIdAndName(TenantId tenantId, String name); | |
36 | + | |
37 | + Asset saveAsset(Asset device); | |
38 | + | |
39 | + Asset assignAssetToCustomer(AssetId assetId, CustomerId customerId); | |
40 | + | |
41 | + Asset unassignAssetFromCustomer(AssetId assetId); | |
42 | + | |
43 | + void deleteAsset(AssetId assetId); | |
44 | + | |
45 | + TextPageData<Asset> findAssetsByTenantId(TenantId tenantId, TextPageLink pageLink); | |
46 | + | |
47 | + ListenableFuture<List<Asset>> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List<AssetId> assetIds); | |
48 | + | |
49 | + void deleteAssetsByTenantId(TenantId tenantId); | |
50 | + | |
51 | + TextPageData<Asset> findAssetsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); | |
52 | + | |
53 | + ListenableFuture<List<Asset>> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<AssetId> assetIds); | |
54 | + | |
55 | + void unassignCustomerAssets(TenantId tenantId, CustomerId customerId); | |
56 | + | |
57 | + ListenableFuture<List<Asset>> findAssetsByQuery(AssetSearchQuery query); | |
58 | + | |
59 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.asset; | |
17 | + | |
18 | +import lombok.Data; | |
19 | + | |
20 | +import javax.annotation.Nullable; | |
21 | +import java.util.List; | |
22 | + | |
23 | +/** | |
24 | + * Created by ashvayka on 02.05.17. | |
25 | + */ | |
26 | +@Data | |
27 | +public class AssetTypeFilter { | |
28 | + @Nullable | |
29 | + private String relationType; | |
30 | + @Nullable | |
31 | + private List<String> assetTypes; | |
32 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.asset; | |
17 | + | |
18 | + | |
19 | +import com.google.common.base.Function; | |
20 | +import com.google.common.util.concurrent.AsyncFunction; | |
21 | +import com.google.common.util.concurrent.Futures; | |
22 | +import com.google.common.util.concurrent.ListenableFuture; | |
23 | +import lombok.extern.slf4j.Slf4j; | |
24 | +import org.springframework.beans.factory.annotation.Autowired; | |
25 | +import org.springframework.stereotype.Service; | |
26 | +import org.springframework.util.StringUtils; | |
27 | +import org.thingsboard.server.common.data.EntityType; | |
28 | +import org.thingsboard.server.common.data.asset.Asset; | |
29 | +import org.thingsboard.server.common.data.id.AssetId; | |
30 | +import org.thingsboard.server.common.data.id.CustomerId; | |
31 | +import org.thingsboard.server.common.data.id.EntityId; | |
32 | +import org.thingsboard.server.common.data.id.TenantId; | |
33 | +import org.thingsboard.server.common.data.page.TextPageData; | |
34 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
35 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
36 | +import org.thingsboard.server.dao.customer.CustomerDao; | |
37 | +import org.thingsboard.server.dao.entity.BaseEntityService; | |
38 | +import org.thingsboard.server.dao.exception.DataValidationException; | |
39 | +import org.thingsboard.server.dao.model.AssetEntity; | |
40 | +import org.thingsboard.server.dao.model.CustomerEntity; | |
41 | +import org.thingsboard.server.dao.model.TenantEntity; | |
42 | +import org.thingsboard.server.dao.relation.EntityRelationsQuery; | |
43 | +import org.thingsboard.server.dao.relation.EntitySearchDirection; | |
44 | +import org.thingsboard.server.dao.service.DataValidator; | |
45 | +import org.thingsboard.server.dao.service.PaginatedRemover; | |
46 | +import org.thingsboard.server.dao.tenant.TenantDao; | |
47 | + | |
48 | +import javax.annotation.Nullable; | |
49 | +import java.util.ArrayList; | |
50 | +import java.util.List; | |
51 | +import java.util.Optional; | |
52 | +import java.util.stream.Collectors; | |
53 | + | |
54 | +import static org.thingsboard.server.dao.DaoUtil.*; | |
55 | +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; | |
56 | +import static org.thingsboard.server.dao.service.Validator.*; | |
57 | + | |
58 | +@Service | |
59 | +@Slf4j | |
60 | +public class BaseAssetService extends BaseEntityService implements AssetService { | |
61 | + | |
62 | + @Autowired | |
63 | + private AssetDao assetDao; | |
64 | + | |
65 | + @Autowired | |
66 | + private TenantDao tenantDao; | |
67 | + | |
68 | + @Autowired | |
69 | + private CustomerDao customerDao; | |
70 | + | |
71 | + @Override | |
72 | + public Asset findAssetById(AssetId assetId) { | |
73 | + log.trace("Executing findAssetById [{}]", assetId); | |
74 | + validateId(assetId, "Incorrect assetId " + assetId); | |
75 | + AssetEntity assetEntity = assetDao.findById(assetId.getId()); | |
76 | + return getData(assetEntity); | |
77 | + } | |
78 | + | |
79 | + @Override | |
80 | + public ListenableFuture<Asset> findAssetByIdAsync(AssetId assetId) { | |
81 | + log.trace("Executing findAssetById [{}]", assetId); | |
82 | + validateId(assetId, "Incorrect assetId " + assetId); | |
83 | + ListenableFuture<AssetEntity> assetEntity = assetDao.findByIdAsync(assetId.getId()); | |
84 | + return Futures.transform(assetEntity, (Function<? super AssetEntity, ? extends Asset>) input -> getData(input)); | |
85 | + } | |
86 | + | |
87 | + @Override | |
88 | + public Optional<Asset> findAssetByTenantIdAndName(TenantId tenantId, String name) { | |
89 | + log.trace("Executing findAssetByTenantIdAndName [{}][{}]", tenantId, name); | |
90 | + validateId(tenantId, "Incorrect tenantId " + tenantId); | |
91 | + Optional<AssetEntity> assetEntityOpt = assetDao.findAssetsByTenantIdAndName(tenantId.getId(), name); | |
92 | + if (assetEntityOpt.isPresent()) { | |
93 | + return Optional.of(getData(assetEntityOpt.get())); | |
94 | + } else { | |
95 | + return Optional.empty(); | |
96 | + } | |
97 | + } | |
98 | + | |
99 | + @Override | |
100 | + public Asset saveAsset(Asset asset) { | |
101 | + log.trace("Executing saveAsset [{}]", asset); | |
102 | + assetValidator.validate(asset); | |
103 | + return getData(assetDao.save(asset)); | |
104 | + } | |
105 | + | |
106 | + @Override | |
107 | + public Asset assignAssetToCustomer(AssetId assetId, CustomerId customerId) { | |
108 | + Asset asset = findAssetById(assetId); | |
109 | + asset.setCustomerId(customerId); | |
110 | + return saveAsset(asset); | |
111 | + } | |
112 | + | |
113 | + @Override | |
114 | + public Asset unassignAssetFromCustomer(AssetId assetId) { | |
115 | + Asset asset = findAssetById(assetId); | |
116 | + asset.setCustomerId(null); | |
117 | + return saveAsset(asset); | |
118 | + } | |
119 | + | |
120 | + @Override | |
121 | + public void deleteAsset(AssetId assetId) { | |
122 | + log.trace("Executing deleteAsset [{}]", assetId); | |
123 | + validateId(assetId, "Incorrect assetId " + assetId); | |
124 | + deleteEntityRelations(assetId); | |
125 | + assetDao.removeById(assetId.getId()); | |
126 | + } | |
127 | + | |
128 | + @Override | |
129 | + public TextPageData<Asset> findAssetsByTenantId(TenantId tenantId, TextPageLink pageLink) { | |
130 | + log.trace("Executing findAssetsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); | |
131 | + validateId(tenantId, "Incorrect tenantId " + tenantId); | |
132 | + validatePageLink(pageLink, "Incorrect page link " + pageLink); | |
133 | + List<AssetEntity> assetEntities = assetDao.findAssetsByTenantId(tenantId.getId(), pageLink); | |
134 | + List<Asset> assets = convertDataList(assetEntities); | |
135 | + return new TextPageData<Asset>(assets, pageLink); | |
136 | + } | |
137 | + | |
138 | + @Override | |
139 | + public ListenableFuture<List<Asset>> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List<AssetId> assetIds) { | |
140 | + log.trace("Executing findAssetsByTenantIdAndIdsAsync, tenantId [{}], assetIds [{}]", tenantId, assetIds); | |
141 | + validateId(tenantId, "Incorrect tenantId " + tenantId); | |
142 | + validateIds(assetIds, "Incorrect assetIds " + assetIds); | |
143 | + ListenableFuture<List<AssetEntity>> assetEntities = assetDao.findAssetsByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(assetIds)); | |
144 | + return Futures.transform(assetEntities, (Function<List<AssetEntity>, List<Asset>>) input -> convertDataList(input)); | |
145 | + } | |
146 | + | |
147 | + @Override | |
148 | + public void deleteAssetsByTenantId(TenantId tenantId) { | |
149 | + log.trace("Executing deleteAssetsByTenantId, tenantId [{}]", tenantId); | |
150 | + validateId(tenantId, "Incorrect tenantId " + tenantId); | |
151 | + tenantAssetsRemover.removeEntitites(tenantId); | |
152 | + } | |
153 | + | |
154 | + @Override | |
155 | + public TextPageData<Asset> findAssetsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink) { | |
156 | + log.trace("Executing findAssetsByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); | |
157 | + validateId(tenantId, "Incorrect tenantId " + tenantId); | |
158 | + validateId(customerId, "Incorrect customerId " + customerId); | |
159 | + validatePageLink(pageLink, "Incorrect page link " + pageLink); | |
160 | + List<AssetEntity> assetEntities = assetDao.findAssetsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); | |
161 | + List<Asset> assets = convertDataList(assetEntities); | |
162 | + return new TextPageData<Asset>(assets, pageLink); | |
163 | + } | |
164 | + | |
165 | + @Override | |
166 | + public ListenableFuture<List<Asset>> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<AssetId> assetIds) { | |
167 | + log.trace("Executing findAssetsByTenantIdCustomerIdAndIdsAsync, tenantId [{}], customerId [{}], assetIds [{}]", tenantId, customerId, assetIds); | |
168 | + validateId(tenantId, "Incorrect tenantId " + tenantId); | |
169 | + validateId(customerId, "Incorrect customerId " + customerId); | |
170 | + validateIds(assetIds, "Incorrect assetIds " + assetIds); | |
171 | + ListenableFuture<List<AssetEntity>> assetEntities = assetDao.findAssetsByTenantIdCustomerIdAndIdsAsync(tenantId.getId(), | |
172 | + customerId.getId(), toUUIDs(assetIds)); | |
173 | + return Futures.transform(assetEntities, (Function<List<AssetEntity>, List<Asset>>) input -> convertDataList(input)); | |
174 | + } | |
175 | + | |
176 | + @Override | |
177 | + public void unassignCustomerAssets(TenantId tenantId, CustomerId customerId) { | |
178 | + log.trace("Executing unassignCustomerAssets, tenantId [{}], customerId [{}]", tenantId, customerId); | |
179 | + validateId(tenantId, "Incorrect tenantId " + tenantId); | |
180 | + validateId(customerId, "Incorrect customerId " + customerId); | |
181 | + new CustomerAssetsUnassigner(tenantId).removeEntitites(customerId); | |
182 | + } | |
183 | + | |
184 | + @Override | |
185 | + public ListenableFuture<List<Asset>> findAssetsByQuery(AssetSearchQuery query) { | |
186 | + ListenableFuture<List<EntityRelation>> relations = relationService.findByQuery(query.toEntitySearchQuery()); | |
187 | + ListenableFuture<List<Asset>> assets = Futures.transform(relations, (AsyncFunction<List<EntityRelation>, List<Asset>>) relations1 -> { | |
188 | + EntitySearchDirection direction = query.toEntitySearchQuery().getParameters().getDirection(); | |
189 | + List<ListenableFuture<Asset>> futures = new ArrayList<>(); | |
190 | + for (EntityRelation relation : relations1) { | |
191 | + EntityId entityId = direction == EntitySearchDirection.FROM ? relation.getTo() : relation.getFrom(); | |
192 | + if (entityId.getEntityType() == EntityType.ASSET) { | |
193 | + futures.add(findAssetByIdAsync(new AssetId(entityId.getId()))); | |
194 | + } | |
195 | + } | |
196 | + return Futures.successfulAsList(futures); | |
197 | + }); | |
198 | + | |
199 | + assets = Futures.transform(assets, new Function<List<Asset>, List<Asset>>() { | |
200 | + @Nullable | |
201 | + @Override | |
202 | + public List<Asset> apply(@Nullable List<Asset> assetList) { | |
203 | + return assetList.stream().filter(asset -> query.getAssetTypes().contains(asset.getType())).collect(Collectors.toList()); | |
204 | + } | |
205 | + }); | |
206 | + | |
207 | + return assets; | |
208 | + } | |
209 | + | |
210 | + private DataValidator<Asset> assetValidator = | |
211 | + new DataValidator<Asset>() { | |
212 | + | |
213 | + @Override | |
214 | + protected void validateCreate(Asset asset) { | |
215 | + assetDao.findAssetsByTenantIdAndName(asset.getTenantId().getId(), asset.getName()).ifPresent( | |
216 | + d -> { | |
217 | + throw new DataValidationException("Asset with such name already exists!"); | |
218 | + } | |
219 | + ); | |
220 | + } | |
221 | + | |
222 | + @Override | |
223 | + protected void validateUpdate(Asset asset) { | |
224 | + assetDao.findAssetsByTenantIdAndName(asset.getTenantId().getId(), asset.getName()).ifPresent( | |
225 | + d -> { | |
226 | + if (!d.getId().equals(asset.getUuidId())) { | |
227 | + throw new DataValidationException("Asset with such name already exists!"); | |
228 | + } | |
229 | + } | |
230 | + ); | |
231 | + } | |
232 | + | |
233 | + @Override | |
234 | + protected void validateDataImpl(Asset asset) { | |
235 | + if (StringUtils.isEmpty(asset.getName())) { | |
236 | + throw new DataValidationException("Asset name should be specified!"); | |
237 | + } | |
238 | + if (asset.getTenantId() == null) { | |
239 | + throw new DataValidationException("Asset should be assigned to tenant!"); | |
240 | + } else { | |
241 | + TenantEntity tenant = tenantDao.findById(asset.getTenantId().getId()); | |
242 | + if (tenant == null) { | |
243 | + throw new DataValidationException("Asset is referencing to non-existent tenant!"); | |
244 | + } | |
245 | + } | |
246 | + if (asset.getCustomerId() == null) { | |
247 | + asset.setCustomerId(new CustomerId(NULL_UUID)); | |
248 | + } else if (!asset.getCustomerId().getId().equals(NULL_UUID)) { | |
249 | + CustomerEntity customer = customerDao.findById(asset.getCustomerId().getId()); | |
250 | + if (customer == null) { | |
251 | + throw new DataValidationException("Can't assign asset to non-existent customer!"); | |
252 | + } | |
253 | + if (!customer.getTenantId().equals(asset.getTenantId().getId())) { | |
254 | + throw new DataValidationException("Can't assign asset to customer from different tenant!"); | |
255 | + } | |
256 | + } | |
257 | + } | |
258 | + }; | |
259 | + | |
260 | + private PaginatedRemover<TenantId, AssetEntity> tenantAssetsRemover = | |
261 | + new PaginatedRemover<TenantId, AssetEntity>() { | |
262 | + | |
263 | + @Override | |
264 | + protected List<AssetEntity> findEntities(TenantId id, TextPageLink pageLink) { | |
265 | + return assetDao.findAssetsByTenantId(id.getId(), pageLink); | |
266 | + } | |
267 | + | |
268 | + @Override | |
269 | + protected void removeEntity(AssetEntity entity) { | |
270 | + deleteAsset(new AssetId(entity.getId())); | |
271 | + } | |
272 | + }; | |
273 | + | |
274 | + class CustomerAssetsUnassigner extends PaginatedRemover<CustomerId, AssetEntity> { | |
275 | + | |
276 | + private TenantId tenantId; | |
277 | + | |
278 | + CustomerAssetsUnassigner(TenantId tenantId) { | |
279 | + this.tenantId = tenantId; | |
280 | + } | |
281 | + | |
282 | + @Override | |
283 | + protected List<AssetEntity> findEntities(CustomerId id, TextPageLink pageLink) { | |
284 | + return assetDao.findAssetsByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink); | |
285 | + } | |
286 | + | |
287 | + @Override | |
288 | + protected void removeEntity(AssetEntity entity) { | |
289 | + unassignAssetFromCustomer(new AssetId(entity.getId())); | |
290 | + } | |
291 | + } | |
292 | +} | ... | ... |
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.customer; |
17 | 17 | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
18 | 19 | import org.thingsboard.server.common.data.Customer; |
19 | 20 | import org.thingsboard.server.common.data.id.CustomerId; |
20 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
... | ... | @@ -23,16 +24,18 @@ import org.thingsboard.server.common.data.page.TextPageLink; |
23 | 24 | |
24 | 25 | public interface CustomerService { |
25 | 26 | |
26 | - public Customer findCustomerById(CustomerId customerId); | |
27 | + Customer findCustomerById(CustomerId customerId); | |
28 | + | |
29 | + ListenableFuture<Customer> findCustomerByIdAsync(CustomerId customerId); | |
27 | 30 | |
28 | - public Customer saveCustomer(Customer customer); | |
31 | + Customer saveCustomer(Customer customer); | |
29 | 32 | |
30 | - public void deleteCustomer(CustomerId customerId); | |
33 | + void deleteCustomer(CustomerId customerId); | |
31 | 34 | |
32 | - public Customer findOrCreatePublicCustomer(TenantId tenantId); | |
33 | - | |
34 | - public TextPageData<Customer> findCustomersByTenantId(TenantId tenantId, TextPageLink pageLink); | |
35 | + Customer findOrCreatePublicCustomer(TenantId tenantId); | |
35 | 36 | |
36 | - public void deleteCustomersByTenantId(TenantId tenantId); | |
37 | + TextPageData<Customer> findCustomersByTenantId(TenantId tenantId, TextPageLink pageLink); | |
37 | 38 | |
39 | + void deleteCustomersByTenantId(TenantId tenantId); | |
40 | + | |
38 | 41 | } | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.customer; |
17 | 17 | |
18 | 18 | import static org.thingsboard.server.dao.DaoUtil.convertDataList; |
19 | 19 | import static org.thingsboard.server.dao.DaoUtil.getData; |
20 | +import static org.thingsboard.server.dao.service.Validator.validateId; | |
20 | 21 | |
21 | 22 | import java.io.IOException; |
22 | 23 | import java.util.List; |
... | ... | @@ -24,31 +25,35 @@ import java.util.Optional; |
24 | 25 | |
25 | 26 | import com.fasterxml.jackson.databind.JsonNode; |
26 | 27 | import com.fasterxml.jackson.databind.ObjectMapper; |
28 | +import com.google.common.base.Function; | |
29 | +import com.google.common.util.concurrent.Futures; | |
30 | +import com.google.common.util.concurrent.ListenableFuture; | |
27 | 31 | import lombok.extern.slf4j.Slf4j; |
28 | 32 | import org.apache.commons.lang3.StringUtils; |
29 | 33 | import org.thingsboard.server.common.data.Customer; |
34 | +import org.thingsboard.server.common.data.asset.Asset; | |
30 | 35 | import org.thingsboard.server.common.data.id.CustomerId; |
31 | 36 | import org.thingsboard.server.common.data.id.TenantId; |
32 | 37 | import org.thingsboard.server.common.data.page.TextPageData; |
33 | 38 | import org.thingsboard.server.common.data.page.TextPageLink; |
34 | 39 | import org.thingsboard.server.dao.dashboard.DashboardService; |
35 | 40 | import org.thingsboard.server.dao.device.DeviceService; |
41 | +import org.thingsboard.server.dao.entity.BaseEntityService; | |
36 | 42 | import org.thingsboard.server.dao.exception.DataValidationException; |
37 | 43 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
44 | +import org.thingsboard.server.dao.model.AssetEntity; | |
38 | 45 | import org.thingsboard.server.dao.model.CustomerEntity; |
39 | 46 | import org.thingsboard.server.dao.model.TenantEntity; |
40 | 47 | import org.thingsboard.server.dao.service.DataValidator; |
41 | 48 | import org.thingsboard.server.dao.service.PaginatedRemover; |
42 | 49 | import org.thingsboard.server.dao.tenant.TenantDao; |
43 | 50 | import org.thingsboard.server.dao.user.UserService; |
44 | -import org.slf4j.Logger; | |
45 | -import org.slf4j.LoggerFactory; | |
46 | 51 | import org.springframework.beans.factory.annotation.Autowired; |
47 | 52 | import org.springframework.stereotype.Service; |
48 | 53 | import org.thingsboard.server.dao.service.Validator; |
49 | 54 | @Service |
50 | 55 | @Slf4j |
51 | -public class CustomerServiceImpl implements CustomerService { | |
56 | +public class CustomerServiceImpl extends BaseEntityService implements CustomerService { | |
52 | 57 | |
53 | 58 | private static final String PUBLIC_CUSTOMER_TITLE = "Public"; |
54 | 59 | |
... | ... | @@ -76,6 +81,14 @@ public class CustomerServiceImpl implements CustomerService { |
76 | 81 | } |
77 | 82 | |
78 | 83 | @Override |
84 | + public ListenableFuture<Customer> findCustomerByIdAsync(CustomerId customerId) { | |
85 | + log.trace("Executing findCustomerByIdAsync [{}]", customerId); | |
86 | + validateId(customerId, "Incorrect customerId " + customerId); | |
87 | + ListenableFuture<CustomerEntity> customerEntity = customerDao.findByIdAsync(customerId.getId()); | |
88 | + return Futures.transform(customerEntity, (Function<? super CustomerEntity, ? extends Customer>) input -> getData(input)); | |
89 | + } | |
90 | + | |
91 | + @Override | |
79 | 92 | public Customer saveCustomer(Customer customer) { |
80 | 93 | log.trace("Executing saveCustomer [{}]", customer); |
81 | 94 | customerValidator.validate(customer); |
... | ... | @@ -93,7 +106,8 @@ public class CustomerServiceImpl implements CustomerService { |
93 | 106 | } |
94 | 107 | dashboardService.unassignCustomerDashboards(customer.getTenantId(), customerId); |
95 | 108 | deviceService.unassignCustomerDevices(customer.getTenantId(), customerId); |
96 | - userService.deleteCustomerUsers(customer.getTenantId(), customerId); | |
109 | + userService.deleteCustomerUsers(customer.getTenantId(), customerId); | |
110 | + deleteEntityRelations(customerId); | |
97 | 111 | customerDao.removeById(customerId.getId()); |
98 | 112 | } |
99 | 113 | ... | ... |
... | ... | @@ -26,7 +26,9 @@ import org.thingsboard.server.common.data.page.TextPageLink; |
26 | 26 | public interface DashboardService { |
27 | 27 | |
28 | 28 | public Dashboard findDashboardById(DashboardId dashboardId); |
29 | - | |
29 | + | |
30 | + public DashboardInfo findDashboardInfoById(DashboardId dashboardId); | |
31 | + | |
30 | 32 | public Dashboard saveDashboard(Dashboard dashboard); |
31 | 33 | |
32 | 34 | public Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId); | ... | ... |
... | ... | @@ -30,20 +30,19 @@ import org.thingsboard.server.common.data.id.TenantId; |
30 | 30 | import org.thingsboard.server.common.data.page.TextPageData; |
31 | 31 | import org.thingsboard.server.common.data.page.TextPageLink; |
32 | 32 | import org.thingsboard.server.dao.customer.CustomerDao; |
33 | +import org.thingsboard.server.dao.entity.BaseEntityService; | |
33 | 34 | import org.thingsboard.server.dao.exception.DataValidationException; |
34 | 35 | import org.thingsboard.server.dao.model.*; |
35 | 36 | import org.thingsboard.server.dao.service.DataValidator; |
36 | 37 | import org.thingsboard.server.dao.service.PaginatedRemover; |
37 | 38 | import org.thingsboard.server.dao.tenant.TenantDao; |
38 | -import org.slf4j.Logger; | |
39 | -import org.slf4j.LoggerFactory; | |
40 | 39 | import org.springframework.beans.factory.annotation.Autowired; |
41 | 40 | import org.springframework.stereotype.Service; |
42 | 41 | import org.thingsboard.server.dao.service.Validator; |
43 | 42 | |
44 | 43 | @Service |
45 | 44 | @Slf4j |
46 | -public class DashboardServiceImpl implements DashboardService { | |
45 | +public class DashboardServiceImpl extends BaseEntityService implements DashboardService { | |
47 | 46 | |
48 | 47 | @Autowired |
49 | 48 | private DashboardDao dashboardDao; |
... | ... | @@ -66,6 +65,14 @@ public class DashboardServiceImpl implements DashboardService { |
66 | 65 | } |
67 | 66 | |
68 | 67 | @Override |
68 | + public DashboardInfo findDashboardInfoById(DashboardId dashboardId) { | |
69 | + log.trace("Executing findDashboardInfoById [{}]", dashboardId); | |
70 | + Validator.validateId(dashboardId, "Incorrect dashboardId " + dashboardId); | |
71 | + DashboardInfoEntity dashboardInfoEntity = dashboardInfoDao.findById(dashboardId.getId()); | |
72 | + return getData(dashboardInfoEntity); | |
73 | + } | |
74 | + | |
75 | + @Override | |
69 | 76 | public Dashboard saveDashboard(Dashboard dashboard) { |
70 | 77 | log.trace("Executing saveDashboard [{}]", dashboard); |
71 | 78 | dashboardValidator.validate(dashboard); |
... | ... | @@ -91,6 +98,7 @@ public class DashboardServiceImpl implements DashboardService { |
91 | 98 | public void deleteDashboard(DashboardId dashboardId) { |
92 | 99 | log.trace("Executing deleteDashboard [{}]", dashboardId); |
93 | 100 | Validator.validateId(dashboardId, "Incorrect dashboardId " + dashboardId); |
101 | + deleteEntityRelations(dashboardId); | |
94 | 102 | dashboardDao.removeById(dashboardId.getId()); |
95 | 103 | } |
96 | 104 | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.device; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.data.EntityType; | |
20 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
21 | +import org.thingsboard.server.dao.relation.RelationsSearchParameters; | |
22 | +import org.thingsboard.server.dao.relation.EntityRelationsQuery; | |
23 | +import org.thingsboard.server.dao.relation.EntityTypeFilter; | |
24 | + | |
25 | +import javax.annotation.Nullable; | |
26 | +import java.util.Collections; | |
27 | +import java.util.List; | |
28 | + | |
29 | +@Data | |
30 | +public class DeviceSearchQuery { | |
31 | + | |
32 | + private RelationsSearchParameters parameters; | |
33 | + @Nullable | |
34 | + private String relationType; | |
35 | + @Nullable | |
36 | + private List<String> deviceTypes; | |
37 | + | |
38 | + public EntityRelationsQuery toEntitySearchQuery() { | |
39 | + EntityRelationsQuery query = new EntityRelationsQuery(); | |
40 | + query.setParameters(parameters); | |
41 | + query.setFilters( | |
42 | + Collections.singletonList(new EntityTypeFilter(relationType == null ? EntityRelation.CONTAINS_TYPE : relationType, | |
43 | + Collections.singletonList(EntityType.DEVICE)))); | |
44 | + return query; | |
45 | + } | |
46 | +} | ... | ... |
... | ... | @@ -53,4 +53,7 @@ public interface DeviceService { |
53 | 53 | ListenableFuture<List<Device>> findDevicesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<DeviceId> deviceIds); |
54 | 54 | |
55 | 55 | void unassignCustomerDevices(TenantId tenantId, CustomerId customerId); |
56 | + | |
57 | + ListenableFuture<List<Device>> findDevicesByQuery(DeviceSearchQuery query); | |
58 | + | |
56 | 59 | } | ... | ... |
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | package org.thingsboard.server.dao.device; |
17 | 17 | |
18 | 18 | import com.google.common.base.Function; |
19 | +import com.google.common.util.concurrent.AsyncFunction; | |
19 | 20 | import com.google.common.util.concurrent.Futures; |
20 | 21 | import com.google.common.util.concurrent.ListenableFuture; |
21 | 22 | import lombok.extern.slf4j.Slf4j; |
... | ... | @@ -24,36 +25,40 @@ import org.springframework.beans.factory.annotation.Autowired; |
24 | 25 | import org.springframework.stereotype.Service; |
25 | 26 | import org.springframework.util.StringUtils; |
26 | 27 | import org.thingsboard.server.common.data.Device; |
28 | +import org.thingsboard.server.common.data.EntityType; | |
27 | 29 | import org.thingsboard.server.common.data.id.CustomerId; |
28 | 30 | import org.thingsboard.server.common.data.id.DeviceId; |
31 | +import org.thingsboard.server.common.data.id.EntityId; | |
29 | 32 | import org.thingsboard.server.common.data.id.TenantId; |
30 | 33 | import org.thingsboard.server.common.data.page.TextPageData; |
31 | 34 | import org.thingsboard.server.common.data.page.TextPageLink; |
35 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
32 | 36 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
33 | 37 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
34 | 38 | import org.thingsboard.server.dao.customer.CustomerDao; |
39 | +import org.thingsboard.server.dao.entity.BaseEntityService; | |
35 | 40 | import org.thingsboard.server.dao.exception.DataValidationException; |
36 | 41 | import org.thingsboard.server.dao.model.CustomerEntity; |
37 | 42 | import org.thingsboard.server.dao.model.DeviceEntity; |
38 | 43 | import org.thingsboard.server.dao.model.TenantEntity; |
44 | +import org.thingsboard.server.dao.relation.EntitySearchDirection; | |
39 | 45 | import org.thingsboard.server.dao.service.DataValidator; |
40 | 46 | import org.thingsboard.server.dao.service.PaginatedRemover; |
41 | 47 | import org.thingsboard.server.dao.tenant.TenantDao; |
42 | 48 | |
49 | +import javax.annotation.Nullable; | |
50 | +import java.util.ArrayList; | |
43 | 51 | import java.util.List; |
44 | 52 | import java.util.Optional; |
53 | +import java.util.stream.Collectors; | |
45 | 54 | |
46 | -import static org.thingsboard.server.dao.DaoUtil.convertDataList; | |
47 | -import static org.thingsboard.server.dao.DaoUtil.getData; | |
48 | -import static org.thingsboard.server.dao.DaoUtil.toUUIDs; | |
55 | +import static org.thingsboard.server.dao.DaoUtil.*; | |
49 | 56 | import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; |
50 | -import static org.thingsboard.server.dao.service.Validator.validateId; | |
51 | -import static org.thingsboard.server.dao.service.Validator.validateIds; | |
52 | -import static org.thingsboard.server.dao.service.Validator.validatePageLink; | |
57 | +import static org.thingsboard.server.dao.service.Validator.*; | |
53 | 58 | |
54 | 59 | @Service |
55 | 60 | @Slf4j |
56 | -public class DeviceServiceImpl implements DeviceService { | |
61 | +public class DeviceServiceImpl extends BaseEntityService implements DeviceService { | |
57 | 62 | |
58 | 63 | @Autowired |
59 | 64 | private DeviceDao deviceDao; |
... | ... | @@ -132,6 +137,7 @@ public class DeviceServiceImpl implements DeviceService { |
132 | 137 | if (deviceCredentials != null) { |
133 | 138 | deviceCredentialsService.deleteDeviceCredentials(deviceCredentials); |
134 | 139 | } |
140 | + deleteEntityRelations(deviceId); | |
135 | 141 | deviceDao.removeById(deviceId.getId()); |
136 | 142 | } |
137 | 143 | |
... | ... | @@ -192,6 +198,32 @@ public class DeviceServiceImpl implements DeviceService { |
192 | 198 | new CustomerDevicesUnassigner(tenantId).removeEntitites(customerId); |
193 | 199 | } |
194 | 200 | |
201 | + @Override | |
202 | + public ListenableFuture<List<Device>> findDevicesByQuery(DeviceSearchQuery query) { | |
203 | + ListenableFuture<List<EntityRelation>> relations = relationService.findByQuery(query.toEntitySearchQuery()); | |
204 | + ListenableFuture<List<Device>> devices = Futures.transform(relations, (AsyncFunction<List<EntityRelation>, List<Device>>) relations1 -> { | |
205 | + EntitySearchDirection direction = query.toEntitySearchQuery().getParameters().getDirection(); | |
206 | + List<ListenableFuture<Device>> futures = new ArrayList<>(); | |
207 | + for (EntityRelation relation : relations1) { | |
208 | + EntityId entityId = direction == EntitySearchDirection.FROM ? relation.getTo() : relation.getFrom(); | |
209 | + if (entityId.getEntityType() == EntityType.DEVICE) { | |
210 | + futures.add(findDeviceByIdAsync(new DeviceId(entityId.getId()))); | |
211 | + } | |
212 | + } | |
213 | + return Futures.successfulAsList(futures); | |
214 | + }); | |
215 | + | |
216 | + devices = Futures.transform(devices, new Function<List<Device>, List<Device>>() { | |
217 | + @Nullable | |
218 | + @Override | |
219 | + public List<Device> apply(@Nullable List<Device> deviceList) { | |
220 | + return deviceList.stream().filter(device -> query.getDeviceTypes().contains(device.getType())).collect(Collectors.toList()); | |
221 | + } | |
222 | + }); | |
223 | + | |
224 | + return devices; | |
225 | + } | |
226 | + | |
195 | 227 | private DataValidator<Device> deviceValidator = |
196 | 228 | new DataValidator<Device>() { |
197 | 229 | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.entity; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | +import org.springframework.beans.factory.annotation.Autowired; | |
20 | +import org.thingsboard.server.common.data.id.EntityId; | |
21 | +import org.thingsboard.server.dao.relation.RelationService; | |
22 | + | |
23 | +/** | |
24 | + * Created by ashvayka on 04.05.17. | |
25 | + */ | |
26 | +@Slf4j | |
27 | +public class BaseEntityService { | |
28 | + | |
29 | + @Autowired | |
30 | + protected RelationService relationService; | |
31 | + | |
32 | + protected void deleteEntityRelations(EntityId entityId) { | |
33 | + log.trace("Executing deleteEntityRelations [{}]", entityId); | |
34 | + relationService.deleteEntityRelations(entityId); | |
35 | + } | |
36 | + | |
37 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.model; | |
17 | + | |
18 | +import com.datastax.driver.core.utils.UUIDs; | |
19 | +import com.datastax.driver.mapping.annotations.Column; | |
20 | +import com.datastax.driver.mapping.annotations.PartitionKey; | |
21 | +import com.datastax.driver.mapping.annotations.Table; | |
22 | +import com.datastax.driver.mapping.annotations.Transient; | |
23 | +import com.fasterxml.jackson.databind.JsonNode; | |
24 | +import org.thingsboard.server.common.data.asset.Asset; | |
25 | +import org.thingsboard.server.common.data.id.AssetId; | |
26 | +import org.thingsboard.server.common.data.id.CustomerId; | |
27 | +import org.thingsboard.server.common.data.id.TenantId; | |
28 | +import org.thingsboard.server.dao.model.type.JsonCodec; | |
29 | + | |
30 | +import java.util.UUID; | |
31 | + | |
32 | +import static org.thingsboard.server.dao.model.ModelConstants.*; | |
33 | + | |
34 | +@Table(name = ASSET_COLUMN_FAMILY_NAME) | |
35 | +public final class AssetEntity implements SearchTextEntity<Asset> { | |
36 | + | |
37 | + @Transient | |
38 | + private static final long serialVersionUID = -1265181166886910152L; | |
39 | + | |
40 | + @PartitionKey(value = 0) | |
41 | + @Column(name = ID_PROPERTY) | |
42 | + private UUID id; | |
43 | + | |
44 | + @PartitionKey(value = 1) | |
45 | + @Column(name = ASSET_TENANT_ID_PROPERTY) | |
46 | + private UUID tenantId; | |
47 | + | |
48 | + @PartitionKey(value = 2) | |
49 | + @Column(name = ASSET_CUSTOMER_ID_PROPERTY) | |
50 | + private UUID customerId; | |
51 | + | |
52 | + @Column(name = ASSET_NAME_PROPERTY) | |
53 | + private String name; | |
54 | + | |
55 | + @Column(name = ASSET_TYPE_PROPERTY) | |
56 | + private String type; | |
57 | + | |
58 | + @Column(name = SEARCH_TEXT_PROPERTY) | |
59 | + private String searchText; | |
60 | + | |
61 | + @Column(name = ASSET_ADDITIONAL_INFO_PROPERTY, codec = JsonCodec.class) | |
62 | + private JsonNode additionalInfo; | |
63 | + | |
64 | + public AssetEntity() { | |
65 | + super(); | |
66 | + } | |
67 | + | |
68 | + public AssetEntity(Asset asset) { | |
69 | + if (asset.getId() != null) { | |
70 | + this.id = asset.getId().getId(); | |
71 | + } | |
72 | + if (asset.getTenantId() != null) { | |
73 | + this.tenantId = asset.getTenantId().getId(); | |
74 | + } | |
75 | + if (asset.getCustomerId() != null) { | |
76 | + this.customerId = asset.getCustomerId().getId(); | |
77 | + } | |
78 | + this.name = asset.getName(); | |
79 | + this.type = asset.getType(); | |
80 | + this.additionalInfo = asset.getAdditionalInfo(); | |
81 | + } | |
82 | + | |
83 | + public UUID getId() { | |
84 | + return id; | |
85 | + } | |
86 | + | |
87 | + public void setId(UUID id) { | |
88 | + this.id = id; | |
89 | + } | |
90 | + | |
91 | + public UUID getTenantId() { | |
92 | + return tenantId; | |
93 | + } | |
94 | + | |
95 | + public void setTenantId(UUID tenantId) { | |
96 | + this.tenantId = tenantId; | |
97 | + } | |
98 | + | |
99 | + public UUID getCustomerId() { | |
100 | + return customerId; | |
101 | + } | |
102 | + | |
103 | + public void setCustomerId(UUID customerId) { | |
104 | + this.customerId = customerId; | |
105 | + } | |
106 | + | |
107 | + public String getName() { | |
108 | + return name; | |
109 | + } | |
110 | + | |
111 | + public void setName(String name) { | |
112 | + this.name = name; | |
113 | + } | |
114 | + | |
115 | + public String getType() { | |
116 | + return type; | |
117 | + } | |
118 | + | |
119 | + public void setType(String type) { | |
120 | + this.type = type; | |
121 | + } | |
122 | + | |
123 | + public JsonNode getAdditionalInfo() { | |
124 | + return additionalInfo; | |
125 | + } | |
126 | + | |
127 | + public void setAdditionalInfo(JsonNode additionalInfo) { | |
128 | + this.additionalInfo = additionalInfo; | |
129 | + } | |
130 | + | |
131 | + @Override | |
132 | + public String getSearchTextSource() { | |
133 | + return name; | |
134 | + } | |
135 | + | |
136 | + @Override | |
137 | + public void setSearchText(String searchText) { | |
138 | + this.searchText = searchText; | |
139 | + } | |
140 | + | |
141 | + public String getSearchText() { | |
142 | + return searchText; | |
143 | + } | |
144 | + | |
145 | + @Override | |
146 | + public int hashCode() { | |
147 | + final int prime = 31; | |
148 | + int result = 1; | |
149 | + result = prime * result + ((additionalInfo == null) ? 0 : additionalInfo.hashCode()); | |
150 | + result = prime * result + ((customerId == null) ? 0 : customerId.hashCode()); | |
151 | + result = prime * result + ((id == null) ? 0 : id.hashCode()); | |
152 | + result = prime * result + ((name == null) ? 0 : name.hashCode()); | |
153 | + result = prime * result + ((type == null) ? 0 : type.hashCode()); | |
154 | + result = prime * result + ((tenantId == null) ? 0 : tenantId.hashCode()); | |
155 | + return result; | |
156 | + } | |
157 | + | |
158 | + @Override | |
159 | + public boolean equals(Object obj) { | |
160 | + if (this == obj) | |
161 | + return true; | |
162 | + if (obj == null) | |
163 | + return false; | |
164 | + if (getClass() != obj.getClass()) | |
165 | + return false; | |
166 | + AssetEntity other = (AssetEntity) obj; | |
167 | + if (additionalInfo == null) { | |
168 | + if (other.additionalInfo != null) | |
169 | + return false; | |
170 | + } else if (!additionalInfo.equals(other.additionalInfo)) | |
171 | + return false; | |
172 | + if (customerId == null) { | |
173 | + if (other.customerId != null) | |
174 | + return false; | |
175 | + } else if (!customerId.equals(other.customerId)) | |
176 | + return false; | |
177 | + if (id == null) { | |
178 | + if (other.id != null) | |
179 | + return false; | |
180 | + } else if (!id.equals(other.id)) | |
181 | + return false; | |
182 | + if (name == null) { | |
183 | + if (other.name != null) | |
184 | + return false; | |
185 | + } else if (!name.equals(other.name)) | |
186 | + return false; | |
187 | + if (type == null) { | |
188 | + if (other.type != null) | |
189 | + return false; | |
190 | + } else if (!type.equals(other.type)) | |
191 | + return false; | |
192 | + if (tenantId == null) { | |
193 | + if (other.tenantId != null) | |
194 | + return false; | |
195 | + } else if (!tenantId.equals(other.tenantId)) | |
196 | + return false; | |
197 | + return true; | |
198 | + } | |
199 | + | |
200 | + @Override | |
201 | + public String toString() { | |
202 | + StringBuilder builder = new StringBuilder(); | |
203 | + builder.append("AssetEntity [id="); | |
204 | + builder.append(id); | |
205 | + builder.append(", tenantId="); | |
206 | + builder.append(tenantId); | |
207 | + builder.append(", customerId="); | |
208 | + builder.append(customerId); | |
209 | + builder.append(", name="); | |
210 | + builder.append(name); | |
211 | + builder.append(", type="); | |
212 | + builder.append(type); | |
213 | + builder.append(", additionalInfo="); | |
214 | + builder.append(additionalInfo); | |
215 | + builder.append("]"); | |
216 | + return builder.toString(); | |
217 | + } | |
218 | + | |
219 | + @Override | |
220 | + public Asset toData() { | |
221 | + Asset asset = new Asset(new AssetId(id)); | |
222 | + asset.setCreatedTime(UUIDs.unixTimestamp(id)); | |
223 | + if (tenantId != null) { | |
224 | + asset.setTenantId(new TenantId(tenantId)); | |
225 | + } | |
226 | + if (customerId != null) { | |
227 | + asset.setCustomerId(new CustomerId(customerId)); | |
228 | + } | |
229 | + asset.setName(name); | |
230 | + asset.setType(type); | |
231 | + asset.setAdditionalInfo(additionalInfo); | |
232 | + return asset; | |
233 | + } | |
234 | + | |
235 | +} | |
\ No newline at end of file | ... | ... |
... | ... | @@ -51,7 +51,10 @@ public final class DeviceEntity implements SearchTextEntity<Device> { |
51 | 51 | |
52 | 52 | @Column(name = DEVICE_NAME_PROPERTY) |
53 | 53 | private String name; |
54 | - | |
54 | + | |
55 | + @Column(name = DEVICE_TYPE_PROPERTY) | |
56 | + private String type; | |
57 | + | |
55 | 58 | @Column(name = SEARCH_TEXT_PROPERTY) |
56 | 59 | private String searchText; |
57 | 60 | |
... | ... | @@ -73,6 +76,7 @@ public final class DeviceEntity implements SearchTextEntity<Device> { |
73 | 76 | this.customerId = device.getCustomerId().getId(); |
74 | 77 | } |
75 | 78 | this.name = device.getName(); |
79 | + this.type = device.getType(); | |
76 | 80 | this.additionalInfo = device.getAdditionalInfo(); |
77 | 81 | } |
78 | 82 | |
... | ... | @@ -108,6 +112,14 @@ public final class DeviceEntity implements SearchTextEntity<Device> { |
108 | 112 | this.name = name; |
109 | 113 | } |
110 | 114 | |
115 | + public String getType() { | |
116 | + return type; | |
117 | + } | |
118 | + | |
119 | + public void setType(String type) { | |
120 | + this.type = type; | |
121 | + } | |
122 | + | |
111 | 123 | public JsonNode getAdditionalInfo() { |
112 | 124 | return additionalInfo; |
113 | 125 | } |
... | ... | @@ -138,6 +150,7 @@ public final class DeviceEntity implements SearchTextEntity<Device> { |
138 | 150 | result = prime * result + ((customerId == null) ? 0 : customerId.hashCode()); |
139 | 151 | result = prime * result + ((id == null) ? 0 : id.hashCode()); |
140 | 152 | result = prime * result + ((name == null) ? 0 : name.hashCode()); |
153 | + result = prime * result + ((type == null) ? 0 : type.hashCode()); | |
141 | 154 | result = prime * result + ((tenantId == null) ? 0 : tenantId.hashCode()); |
142 | 155 | return result; |
143 | 156 | } |
... | ... | @@ -171,6 +184,11 @@ public final class DeviceEntity implements SearchTextEntity<Device> { |
171 | 184 | return false; |
172 | 185 | } else if (!name.equals(other.name)) |
173 | 186 | return false; |
187 | + if (type == null) { | |
188 | + if (other.type != null) | |
189 | + return false; | |
190 | + } else if (!type.equals(other.type)) | |
191 | + return false; | |
174 | 192 | if (tenantId == null) { |
175 | 193 | if (other.tenantId != null) |
176 | 194 | return false; |
... | ... | @@ -190,6 +208,8 @@ public final class DeviceEntity implements SearchTextEntity<Device> { |
190 | 208 | builder.append(customerId); |
191 | 209 | builder.append(", name="); |
192 | 210 | builder.append(name); |
211 | + builder.append(", type="); | |
212 | + builder.append(type); | |
193 | 213 | builder.append(", additionalInfo="); |
194 | 214 | builder.append(additionalInfo); |
195 | 215 | builder.append("]"); |
... | ... | @@ -207,6 +227,7 @@ public final class DeviceEntity implements SearchTextEntity<Device> { |
207 | 227 | device.setCustomerId(new CustomerId(customerId)); |
208 | 228 | } |
209 | 229 | device.setName(name); |
230 | + device.setType(type); | |
210 | 231 | device.setAdditionalInfo(additionalInfo); |
211 | 232 | return device; |
212 | 233 | } | ... | ... |
... | ... | @@ -35,7 +35,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.*; |
35 | 35 | */ |
36 | 36 | @Data |
37 | 37 | @NoArgsConstructor |
38 | -@Table(name = DEVICE_COLUMN_FAMILY_NAME) | |
38 | +@Table(name = EVENT_COLUMN_FAMILY_NAME) | |
39 | 39 | public class EventEntity implements BaseEntity<Event> { |
40 | 40 | |
41 | 41 | @Transient |
... | ... | @@ -98,23 +98,7 @@ public class EventEntity implements BaseEntity<Event> { |
98 | 98 | Event event = new Event(new EventId(id)); |
99 | 99 | event.setCreatedTime(UUIDs.unixTimestamp(id)); |
100 | 100 | event.setTenantId(new TenantId(tenantId)); |
101 | - switch (entityType) { | |
102 | - case TENANT: | |
103 | - event.setEntityId(new TenantId(entityId)); | |
104 | - break; | |
105 | - case DEVICE: | |
106 | - event.setEntityId(new DeviceId(entityId)); | |
107 | - break; | |
108 | - case CUSTOMER: | |
109 | - event.setEntityId(new CustomerId(entityId)); | |
110 | - break; | |
111 | - case RULE: | |
112 | - event.setEntityId(new RuleId(entityId)); | |
113 | - break; | |
114 | - case PLUGIN: | |
115 | - event.setEntityId(new PluginId(entityId)); | |
116 | - break; | |
117 | - } | |
101 | + event.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType, entityId)); | |
118 | 102 | event.setBody(body); |
119 | 103 | event.setType(eventType); |
120 | 104 | event.setUid(eventUId); | ... | ... |
... | ... | @@ -120,12 +120,39 @@ public class ModelConstants { |
120 | 120 | public static final String DEVICE_TENANT_ID_PROPERTY = TENTANT_ID_PROPERTY; |
121 | 121 | public static final String DEVICE_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; |
122 | 122 | public static final String DEVICE_NAME_PROPERTY = "name"; |
123 | + public static final String DEVICE_TYPE_PROPERTY = "type"; | |
123 | 124 | public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; |
124 | 125 | |
125 | 126 | public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text"; |
126 | 127 | public static final String DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_and_search_text"; |
127 | 128 | public static final String DEVICE_BY_TENANT_AND_NAME_VIEW_NAME = "device_by_tenant_and_name"; |
128 | 129 | |
130 | + /** | |
131 | + * Cassandra asset constants. | |
132 | + */ | |
133 | + public static final String ASSET_COLUMN_FAMILY_NAME = "asset"; | |
134 | + public static final String ASSET_TENANT_ID_PROPERTY = TENTANT_ID_PROPERTY; | |
135 | + public static final String ASSET_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; | |
136 | + public static final String ASSET_NAME_PROPERTY = "name"; | |
137 | + public static final String ASSET_TYPE_PROPERTY = "type"; | |
138 | + public static final String ASSET_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; | |
139 | + | |
140 | + public static final String ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_and_search_text"; | |
141 | + public static final String ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_customer_and_search_text"; | |
142 | + public static final String ASSET_BY_TENANT_AND_NAME_VIEW_NAME = "asset_by_tenant_and_name"; | |
143 | + | |
144 | + /** | |
145 | + * Cassandra entity relation constants. | |
146 | + */ | |
147 | + public static final String RELATION_COLUMN_FAMILY_NAME = "relation"; | |
148 | + public static final String RELATION_FROM_ID_PROPERTY = "from_id"; | |
149 | + public static final String RELATION_FROM_TYPE_PROPERTY = "from_type"; | |
150 | + public static final String RELATION_TO_ID_PROPERTY = "to_id"; | |
151 | + public static final String RELATION_TO_TYPE_PROPERTY = "to_type"; | |
152 | + public static final String RELATION_TYPE_PROPERTY = "relation_type"; | |
153 | + | |
154 | + public static final String RELATION_REVERSE_VIEW_NAME = "reverse_relation"; | |
155 | + | |
129 | 156 | |
130 | 157 | /** |
131 | 158 | * Cassandra device_credentials constants. | ... | ... |
... | ... | @@ -15,13 +15,14 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.plugin; |
17 | 17 | |
18 | +import com.google.common.util.concurrent.Futures; | |
19 | +import com.google.common.util.concurrent.ListenableFuture; | |
18 | 20 | import lombok.extern.slf4j.Slf4j; |
19 | 21 | import org.apache.commons.lang3.StringUtils; |
20 | -import org.slf4j.Logger; | |
21 | -import org.slf4j.LoggerFactory; | |
22 | 22 | import org.springframework.beans.factory.annotation.Autowired; |
23 | 23 | import org.springframework.stereotype.Service; |
24 | 24 | import org.thingsboard.server.common.data.id.PluginId; |
25 | +import org.thingsboard.server.common.data.id.RuleId; | |
25 | 26 | import org.thingsboard.server.common.data.id.TenantId; |
26 | 27 | import org.thingsboard.server.common.data.page.TextPageData; |
27 | 28 | import org.thingsboard.server.common.data.page.TextPageLink; |
... | ... | @@ -29,7 +30,9 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
29 | 30 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; |
30 | 31 | import org.thingsboard.server.common.data.plugin.ComponentType; |
31 | 32 | import org.thingsboard.server.common.data.plugin.PluginMetaData; |
33 | +import org.thingsboard.server.common.data.rule.RuleMetaData; | |
32 | 34 | import org.thingsboard.server.dao.component.ComponentDescriptorService; |
35 | +import org.thingsboard.server.dao.entity.BaseEntityService; | |
33 | 36 | import org.thingsboard.server.dao.exception.DataValidationException; |
34 | 37 | import org.thingsboard.server.dao.exception.DatabaseException; |
35 | 38 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
... | ... | @@ -48,10 +51,11 @@ import java.util.stream.Collectors; |
48 | 51 | |
49 | 52 | import static org.thingsboard.server.dao.DaoUtil.convertDataList; |
50 | 53 | import static org.thingsboard.server.dao.DaoUtil.getData; |
54 | +import static org.thingsboard.server.dao.service.Validator.validateId; | |
51 | 55 | |
52 | 56 | @Service |
53 | 57 | @Slf4j |
54 | -public class BasePluginService implements PluginService { | |
58 | +public class BasePluginService extends BaseEntityService implements PluginService { | |
55 | 59 | |
56 | 60 | //TODO: move to a better place. |
57 | 61 | public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); |
... | ... | @@ -109,6 +113,13 @@ public class BasePluginService implements PluginService { |
109 | 113 | } |
110 | 114 | |
111 | 115 | @Override |
116 | + public ListenableFuture<PluginMetaData> findPluginByIdAsync(PluginId pluginId) { | |
117 | + validateId(pluginId, "Incorrect plugin id for search plugin request."); | |
118 | + ListenableFuture<PluginMetaDataEntity> pluginEntity = pluginDao.findByIdAsync(pluginId.getId()); | |
119 | + return Futures.transform(pluginEntity, (com.google.common.base.Function<? super PluginMetaDataEntity, ? extends PluginMetaData>) input -> getData(input)); | |
120 | + } | |
121 | + | |
122 | + @Override | |
112 | 123 | public PluginMetaData findPluginByApiToken(String apiToken) { |
113 | 124 | Validator.validateString(apiToken, "Incorrect plugin apiToken for search request."); |
114 | 125 | return getData(pluginDao.findByApiToken(apiToken)); |
... | ... | @@ -205,6 +216,7 @@ public class BasePluginService implements PluginService { |
205 | 216 | @Override |
206 | 217 | public void deletePluginById(PluginId pluginId) { |
207 | 218 | Validator.validateId(pluginId, "Incorrect plugin id for delete request."); |
219 | + deleteEntityRelations(pluginId); | |
208 | 220 | checkRulesAndDelete(pluginId.getId()); |
209 | 221 | } |
210 | 222 | ... | ... |
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.plugin; |
17 | 17 | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
18 | 19 | import org.thingsboard.server.common.data.id.PluginId; |
19 | 20 | import org.thingsboard.server.common.data.id.TenantId; |
20 | 21 | import org.thingsboard.server.common.data.page.TextPageData; |
... | ... | @@ -29,6 +30,8 @@ public interface PluginService { |
29 | 30 | |
30 | 31 | PluginMetaData findPluginById(PluginId pluginId); |
31 | 32 | |
33 | + ListenableFuture<PluginMetaData> findPluginByIdAsync(PluginId pluginId); | |
34 | + | |
32 | 35 | PluginMetaData findPluginByApiToken(String apiToken); |
33 | 36 | |
34 | 37 | TextPageData<PluginMetaData> findSystemPlugins(TextPageLink pageLink); | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.relation; | |
17 | + | |
18 | +import com.datastax.driver.core.*; | |
19 | +import com.fasterxml.jackson.databind.JsonNode; | |
20 | +import com.google.common.base.Function; | |
21 | +import com.google.common.util.concurrent.Futures; | |
22 | +import com.google.common.util.concurrent.ListenableFuture; | |
23 | +import lombok.extern.slf4j.Slf4j; | |
24 | +import org.springframework.stereotype.Component; | |
25 | +import org.thingsboard.server.common.data.id.EntityId; | |
26 | +import org.thingsboard.server.common.data.id.EntityIdFactory; | |
27 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
28 | +import org.thingsboard.server.dao.AbstractAsyncDao; | |
29 | +import org.thingsboard.server.dao.model.ModelConstants; | |
30 | + | |
31 | +import javax.annotation.Nullable; | |
32 | +import javax.annotation.PostConstruct; | |
33 | +import java.util.ArrayList; | |
34 | +import java.util.List; | |
35 | + | |
36 | +/** | |
37 | + * Created by ashvayka on 25.04.17. | |
38 | + */ | |
39 | +@Component | |
40 | +@Slf4j | |
41 | +public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { | |
42 | + | |
43 | + private static final String SELECT_COLUMNS = "SELECT " + | |
44 | + ModelConstants.RELATION_FROM_ID_PROPERTY + "," + | |
45 | + ModelConstants.RELATION_FROM_TYPE_PROPERTY + "," + | |
46 | + ModelConstants.RELATION_TO_ID_PROPERTY + "," + | |
47 | + ModelConstants.RELATION_TO_TYPE_PROPERTY + "," + | |
48 | + ModelConstants.RELATION_TYPE_PROPERTY + "," + | |
49 | + ModelConstants.ADDITIONAL_INFO_PROPERTY; | |
50 | + public static final String FROM = " FROM "; | |
51 | + public static final String WHERE = " WHERE "; | |
52 | + public static final String AND = " AND "; | |
53 | + | |
54 | + private PreparedStatement saveStmt; | |
55 | + private PreparedStatement findAllByFromStmt; | |
56 | + private PreparedStatement findAllByFromAndTypeStmt; | |
57 | + private PreparedStatement findAllByToStmt; | |
58 | + private PreparedStatement findAllByToAndTypeStmt; | |
59 | + private PreparedStatement checkRelationStmt; | |
60 | + private PreparedStatement deleteStmt; | |
61 | + private PreparedStatement deleteAllByEntityStmt; | |
62 | + | |
63 | + @PostConstruct | |
64 | + public void init() { | |
65 | + super.startExecutor(); | |
66 | + } | |
67 | + | |
68 | + @Override | |
69 | + public ListenableFuture<List<EntityRelation>> findAllByFrom(EntityId from) { | |
70 | + BoundStatement stmt = getFindAllByFromStmt().bind().setUUID(0, from.getId()).setString(1, from.getEntityType().name()); | |
71 | + return executeAsyncRead(from, stmt); | |
72 | + } | |
73 | + | |
74 | + @Override | |
75 | + public ListenableFuture<List<EntityRelation>> findAllByFromAndType(EntityId from, String relationType) { | |
76 | + BoundStatement stmt = getFindAllByFromAndTypeStmt().bind() | |
77 | + .setUUID(0, from.getId()) | |
78 | + .setString(1, from.getEntityType().name()) | |
79 | + .setString(2, relationType); | |
80 | + return executeAsyncRead(from, stmt); | |
81 | + } | |
82 | + | |
83 | + @Override | |
84 | + public ListenableFuture<List<EntityRelation>> findAllByTo(EntityId to) { | |
85 | + BoundStatement stmt = getFindAllByToStmt().bind().setUUID(0, to.getId()).setString(1, to.getEntityType().name()); | |
86 | + return executeAsyncRead(to, stmt); | |
87 | + } | |
88 | + | |
89 | + @Override | |
90 | + public ListenableFuture<List<EntityRelation>> findAllByToAndType(EntityId to, String relationType) { | |
91 | + BoundStatement stmt = getFindAllByToAndTypeStmt().bind() | |
92 | + .setUUID(0, to.getId()) | |
93 | + .setString(1, to.getEntityType().name()) | |
94 | + .setString(2, relationType); | |
95 | + return executeAsyncRead(to, stmt); | |
96 | + } | |
97 | + | |
98 | + @Override | |
99 | + public ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType) { | |
100 | + BoundStatement stmt = getCheckRelationStmt().bind() | |
101 | + .setUUID(0, from.getId()) | |
102 | + .setString(1, from.getEntityType().name()) | |
103 | + .setUUID(2, to.getId()) | |
104 | + .setString(3, to.getEntityType().name()) | |
105 | + .setString(4, relationType); | |
106 | + return getFuture(executeAsyncRead(stmt), rs -> rs != null ? rs.one() != null : false); | |
107 | + } | |
108 | + | |
109 | + @Override | |
110 | + public ListenableFuture<Boolean> saveRelation(EntityRelation relation) { | |
111 | + BoundStatement stmt = getSaveStmt().bind() | |
112 | + .setUUID(0, relation.getFrom().getId()) | |
113 | + .setString(1, relation.getFrom().getEntityType().name()) | |
114 | + .setUUID(2, relation.getTo().getId()) | |
115 | + .setString(3, relation.getTo().getEntityType().name()) | |
116 | + .setString(4, relation.getType()) | |
117 | + .set(5, relation.getAdditionalInfo(), JsonNode.class); | |
118 | + ResultSetFuture future = executeAsyncWrite(stmt); | |
119 | + return getBooleanListenableFuture(future); | |
120 | + } | |
121 | + | |
122 | + @Override | |
123 | + public ListenableFuture<Boolean> deleteRelation(EntityRelation relation) { | |
124 | + return deleteRelation(relation.getFrom(), relation.getTo(), relation.getType()); | |
125 | + } | |
126 | + | |
127 | + @Override | |
128 | + public ListenableFuture<Boolean> deleteRelation(EntityId from, EntityId to, String relationType) { | |
129 | + BoundStatement stmt = getDeleteStmt().bind() | |
130 | + .setUUID(0, from.getId()) | |
131 | + .setString(1, from.getEntityType().name()) | |
132 | + .setUUID(2, to.getId()) | |
133 | + .setString(3, to.getEntityType().name()) | |
134 | + .setString(4, relationType); | |
135 | + ResultSetFuture future = executeAsyncWrite(stmt); | |
136 | + return getBooleanListenableFuture(future); | |
137 | + } | |
138 | + | |
139 | + @Override | |
140 | + public ListenableFuture<Boolean> deleteOutboundRelations(EntityId entity) { | |
141 | + BoundStatement stmt = getDeleteAllByEntityStmt().bind() | |
142 | + .setUUID(0, entity.getId()) | |
143 | + .setString(1, entity.getEntityType().name()); | |
144 | + ResultSetFuture future = executeAsyncWrite(stmt); | |
145 | + return getBooleanListenableFuture(future); | |
146 | + } | |
147 | + | |
148 | + private PreparedStatement getSaveStmt() { | |
149 | + if (saveStmt == null) { | |
150 | + saveStmt = getSession().prepare("INSERT INTO " + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " + | |
151 | + "(" + ModelConstants.RELATION_FROM_ID_PROPERTY + | |
152 | + "," + ModelConstants.RELATION_FROM_TYPE_PROPERTY + | |
153 | + "," + ModelConstants.RELATION_TO_ID_PROPERTY + | |
154 | + "," + ModelConstants.RELATION_TO_TYPE_PROPERTY + | |
155 | + "," + ModelConstants.RELATION_TYPE_PROPERTY + | |
156 | + "," + ModelConstants.ADDITIONAL_INFO_PROPERTY + ")" + | |
157 | + " VALUES(?, ?, ?, ?, ?, ?)"); | |
158 | + } | |
159 | + return saveStmt; | |
160 | + } | |
161 | + | |
162 | + private PreparedStatement getDeleteStmt() { | |
163 | + if (deleteStmt == null) { | |
164 | + deleteStmt = getSession().prepare("DELETE FROM " + ModelConstants.RELATION_COLUMN_FAMILY_NAME + | |
165 | + WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ?" + | |
166 | + AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ?" + | |
167 | + AND + ModelConstants.RELATION_TO_ID_PROPERTY + " = ?" + | |
168 | + AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ?" + | |
169 | + AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ?"); | |
170 | + } | |
171 | + return deleteStmt; | |
172 | + } | |
173 | + | |
174 | + private PreparedStatement getDeleteAllByEntityStmt() { | |
175 | + if (deleteAllByEntityStmt == null) { | |
176 | + deleteAllByEntityStmt = getSession().prepare("DELETE FROM " + ModelConstants.RELATION_COLUMN_FAMILY_NAME + | |
177 | + WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ?" + | |
178 | + AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ?"); | |
179 | + } | |
180 | + return deleteAllByEntityStmt; | |
181 | + } | |
182 | + | |
183 | + private PreparedStatement getFindAllByFromStmt() { | |
184 | + if (findAllByFromStmt == null) { | |
185 | + findAllByFromStmt = getSession().prepare(SELECT_COLUMNS + " " + | |
186 | + FROM + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " + | |
187 | + WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ? " + | |
188 | + AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? "); | |
189 | + } | |
190 | + return findAllByFromStmt; | |
191 | + } | |
192 | + | |
193 | + private PreparedStatement getFindAllByFromAndTypeStmt() { | |
194 | + if (findAllByFromAndTypeStmt == null) { | |
195 | + findAllByFromAndTypeStmt = getSession().prepare(SELECT_COLUMNS + " " + | |
196 | + FROM + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " + | |
197 | + WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ? " + | |
198 | + AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? " + | |
199 | + AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? "); | |
200 | + } | |
201 | + return findAllByFromAndTypeStmt; | |
202 | + } | |
203 | + | |
204 | + private PreparedStatement getFindAllByToStmt() { | |
205 | + if (findAllByToStmt == null) { | |
206 | + findAllByToStmt = getSession().prepare(SELECT_COLUMNS + " " + | |
207 | + FROM + ModelConstants.RELATION_REVERSE_VIEW_NAME + " " + | |
208 | + WHERE + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " + | |
209 | + AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? "); | |
210 | + } | |
211 | + return findAllByToStmt; | |
212 | + } | |
213 | + | |
214 | + private PreparedStatement getFindAllByToAndTypeStmt() { | |
215 | + if (findAllByToAndTypeStmt == null) { | |
216 | + findAllByToAndTypeStmt = getSession().prepare(SELECT_COLUMNS + " " + | |
217 | + FROM + ModelConstants.RELATION_REVERSE_VIEW_NAME + " " + | |
218 | + WHERE + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " + | |
219 | + AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? " + | |
220 | + AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? "); | |
221 | + } | |
222 | + return findAllByToAndTypeStmt; | |
223 | + } | |
224 | + | |
225 | + private PreparedStatement getCheckRelationStmt() { | |
226 | + if (checkRelationStmt == null) { | |
227 | + checkRelationStmt = getSession().prepare(SELECT_COLUMNS + " " + | |
228 | + FROM + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " + | |
229 | + WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ? " + | |
230 | + AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? " + | |
231 | + AND + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " + | |
232 | + AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? " + | |
233 | + AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? "); | |
234 | + } | |
235 | + return checkRelationStmt; | |
236 | + } | |
237 | + | |
238 | + private EntityRelation getEntityRelation(Row row) { | |
239 | + EntityRelation relation = new EntityRelation(); | |
240 | + relation.setType(row.getString(ModelConstants.RELATION_TYPE_PROPERTY)); | |
241 | + relation.setAdditionalInfo(row.get(ModelConstants.ADDITIONAL_INFO_PROPERTY, JsonNode.class)); | |
242 | + relation.setFrom(toEntity(row, ModelConstants.RELATION_FROM_ID_PROPERTY, ModelConstants.RELATION_FROM_TYPE_PROPERTY)); | |
243 | + relation.setTo(toEntity(row, ModelConstants.RELATION_TO_ID_PROPERTY, ModelConstants.RELATION_TO_TYPE_PROPERTY)); | |
244 | + return relation; | |
245 | + } | |
246 | + | |
247 | + private EntityId toEntity(Row row, String uuidColumn, String typeColumn) { | |
248 | + return EntityIdFactory.getByTypeAndUuid(row.getString(typeColumn), row.getUUID(uuidColumn)); | |
249 | + } | |
250 | + | |
251 | + private ListenableFuture<List<EntityRelation>> executeAsyncRead(EntityId from, BoundStatement stmt) { | |
252 | + log.debug("Generated query [{}] for entity {}", stmt, from); | |
253 | + return getFuture(executeAsyncRead(stmt), rs -> { | |
254 | + List<Row> rows = rs.all(); | |
255 | + List<EntityRelation> entries = new ArrayList<>(rows.size()); | |
256 | + if (!rows.isEmpty()) { | |
257 | + rows.forEach(row -> { | |
258 | + entries.add(getEntityRelation(row)); | |
259 | + }); | |
260 | + } | |
261 | + return entries; | |
262 | + }); | |
263 | + } | |
264 | + | |
265 | + private ListenableFuture<Boolean> getBooleanListenableFuture(ResultSetFuture rsFuture) { | |
266 | + return getFuture(rsFuture, rs -> rs != null ? rs.wasApplied() : false); | |
267 | + } | |
268 | + | |
269 | + private <T> ListenableFuture<T> getFuture(ResultSetFuture future, java.util.function.Function<ResultSet, T> transformer) { | |
270 | + return Futures.transform(future, new Function<ResultSet, T>() { | |
271 | + @Nullable | |
272 | + @Override | |
273 | + public T apply(@Nullable ResultSet input) { | |
274 | + return transformer.apply(input); | |
275 | + } | |
276 | + }, readResultsProcessingExecutor); | |
277 | + } | |
278 | + | |
279 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.relation; | |
17 | + | |
18 | +import com.google.common.base.Function; | |
19 | +import com.google.common.util.concurrent.AsyncFunction; | |
20 | +import com.google.common.util.concurrent.Futures; | |
21 | +import com.google.common.util.concurrent.ListenableFuture; | |
22 | +import lombok.extern.slf4j.Slf4j; | |
23 | +import org.springframework.beans.factory.annotation.Autowired; | |
24 | +import org.springframework.stereotype.Service; | |
25 | +import org.springframework.util.StringUtils; | |
26 | +import org.thingsboard.server.common.data.id.EntityId; | |
27 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
28 | +import org.thingsboard.server.dao.exception.DataValidationException; | |
29 | + | |
30 | +import javax.annotation.Nullable; | |
31 | +import java.util.*; | |
32 | +import java.util.concurrent.ConcurrentHashMap; | |
33 | + | |
34 | +/** | |
35 | + * Created by ashvayka on 28.04.17. | |
36 | + */ | |
37 | +@Service | |
38 | +@Slf4j | |
39 | +public class BaseRelationService implements RelationService { | |
40 | + | |
41 | + @Autowired | |
42 | + private RelationDao relationDao; | |
43 | + | |
44 | + @Override | |
45 | + public ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType) { | |
46 | + log.trace("Executing checkRelation [{}][{}][{}]", from, to, relationType); | |
47 | + validate(from, to, relationType); | |
48 | + return relationDao.checkRelation(from, to, relationType); | |
49 | + } | |
50 | + | |
51 | + @Override | |
52 | + public ListenableFuture<Boolean> saveRelation(EntityRelation relation) { | |
53 | + log.trace("Executing saveRelation [{}]", relation); | |
54 | + validate(relation); | |
55 | + return relationDao.saveRelation(relation); | |
56 | + } | |
57 | + | |
58 | + @Override | |
59 | + public ListenableFuture<Boolean> deleteRelation(EntityRelation relation) { | |
60 | + log.trace("Executing deleteRelation [{}]", relation); | |
61 | + validate(relation); | |
62 | + return relationDao.deleteRelation(relation); | |
63 | + } | |
64 | + | |
65 | + @Override | |
66 | + public ListenableFuture<Boolean> deleteRelation(EntityId from, EntityId to, String relationType) { | |
67 | + log.trace("Executing deleteRelation [{}][{}][{}]", from, to, relationType); | |
68 | + validate(from, to, relationType); | |
69 | + return relationDao.deleteRelation(from, to, relationType); | |
70 | + } | |
71 | + | |
72 | + @Override | |
73 | + public ListenableFuture<Boolean> deleteEntityRelations(EntityId entity) { | |
74 | + log.trace("Executing deleteEntityRelations [{}]", entity); | |
75 | + validate(entity); | |
76 | + ListenableFuture<List<EntityRelation>> inboundRelations = relationDao.findAllByTo(entity); | |
77 | + ListenableFuture<List<Boolean>> inboundDeletions = Futures.transform(inboundRelations, new AsyncFunction<List<EntityRelation>, List<Boolean>>() { | |
78 | + @Override | |
79 | + public ListenableFuture<List<Boolean>> apply(List<EntityRelation> relations) throws Exception { | |
80 | + List<ListenableFuture<Boolean>> results = new ArrayList<>(); | |
81 | + for (EntityRelation relation : relations) { | |
82 | + results.add(relationDao.deleteRelation(relation)); | |
83 | + } | |
84 | + return Futures.allAsList(results); | |
85 | + } | |
86 | + }); | |
87 | + | |
88 | + ListenableFuture<Boolean> inboundFuture = Futures.transform(inboundDeletions, getListToBooleanFunction()); | |
89 | + | |
90 | + ListenableFuture<Boolean> outboundFuture = relationDao.deleteOutboundRelations(entity); | |
91 | + | |
92 | + return Futures.transform(Futures.allAsList(Arrays.asList(inboundFuture, outboundFuture)), getListToBooleanFunction()); | |
93 | + } | |
94 | + | |
95 | + @Override | |
96 | + public ListenableFuture<List<EntityRelation>> findByFrom(EntityId from) { | |
97 | + log.trace("Executing findByFrom [{}]", from); | |
98 | + validate(from); | |
99 | + return relationDao.findAllByFrom(from); | |
100 | + } | |
101 | + | |
102 | + @Override | |
103 | + public ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType) { | |
104 | + log.trace("Executing findByFromAndType [{}][{}]", from, relationType); | |
105 | + validate(from); | |
106 | + validateType(relationType); | |
107 | + return relationDao.findAllByFromAndType(from, relationType); | |
108 | + } | |
109 | + | |
110 | + @Override | |
111 | + public ListenableFuture<List<EntityRelation>> findByTo(EntityId to) { | |
112 | + log.trace("Executing findByTo [{}]", to); | |
113 | + validate(to); | |
114 | + return relationDao.findAllByTo(to); | |
115 | + } | |
116 | + | |
117 | + @Override | |
118 | + public ListenableFuture<List<EntityRelation>> findByToAndType(EntityId to, String relationType) { | |
119 | + log.trace("Executing findByToAndType [{}][{}]", to, relationType); | |
120 | + validate(to); | |
121 | + validateType(relationType); | |
122 | + return relationDao.findAllByToAndType(to, relationType); | |
123 | + } | |
124 | + | |
125 | + @Override | |
126 | + public ListenableFuture<List<EntityRelation>> findByQuery(EntityRelationsQuery query) { | |
127 | + log.trace("Executing findByQuery [{}][{}]", query); | |
128 | + RelationsSearchParameters params = query.getParameters(); | |
129 | + final List<EntityTypeFilter> filters = query.getFilters(); | |
130 | + if (filters == null || filters.isEmpty()) { | |
131 | + log.warn("Failed to query relations. Filters are not set [{}]", query); | |
132 | + throw new RuntimeException("Filters are not set!"); | |
133 | + } | |
134 | + | |
135 | + int maxLvl = params.getMaxLevel() > 0 ? params.getMaxLevel() : Integer.MAX_VALUE; | |
136 | + | |
137 | + try { | |
138 | + ListenableFuture<Set<EntityRelation>> relationSet = findRelationsRecursively(params.getEntityId(), params.getDirection(), maxLvl, new ConcurrentHashMap<>()); | |
139 | + return Futures.transform(relationSet, (Function<Set<EntityRelation>, List<EntityRelation>>) input -> { | |
140 | + List<EntityRelation> relations = new ArrayList<>(); | |
141 | + for (EntityRelation relation : input) { | |
142 | + for (EntityTypeFilter filter : filters) { | |
143 | + if (match(filter, relation, params.getDirection())) { | |
144 | + relations.add(relation); | |
145 | + break; | |
146 | + } | |
147 | + } | |
148 | + } | |
149 | + return relations; | |
150 | + }); | |
151 | + } catch (Exception e) { | |
152 | + log.warn("Failed to query relations: [{}]", query, e); | |
153 | + throw new RuntimeException(e); | |
154 | + } | |
155 | + } | |
156 | + | |
157 | + protected void validate(EntityRelation relation) { | |
158 | + if (relation == null) { | |
159 | + throw new DataValidationException("Relation type should be specified!"); | |
160 | + } | |
161 | + validate(relation.getFrom(), relation.getTo(), relation.getType()); | |
162 | + } | |
163 | + | |
164 | + protected void validate(EntityId from, EntityId to, String type) { | |
165 | + validateType(type); | |
166 | + if (from == null) { | |
167 | + throw new DataValidationException("Relation should contain from entity!"); | |
168 | + } | |
169 | + if (to == null) { | |
170 | + throw new DataValidationException("Relation should contain to entity!"); | |
171 | + } | |
172 | + } | |
173 | + | |
174 | + private void validateType(String type) { | |
175 | + if (StringUtils.isEmpty(type)) { | |
176 | + throw new DataValidationException("Relation type should be specified!"); | |
177 | + } | |
178 | + } | |
179 | + | |
180 | + protected void validate(EntityId entity) { | |
181 | + if (entity == null) { | |
182 | + throw new DataValidationException("Entity should be specified!"); | |
183 | + } | |
184 | + } | |
185 | + | |
186 | + private Function<List<Boolean>, Boolean> getListToBooleanFunction() { | |
187 | + return new Function<List<Boolean>, Boolean>() { | |
188 | + @Nullable | |
189 | + @Override | |
190 | + public Boolean apply(@Nullable List<Boolean> results) { | |
191 | + for (Boolean result : results) { | |
192 | + if (result == null || !result) { | |
193 | + return false; | |
194 | + } | |
195 | + } | |
196 | + return true; | |
197 | + } | |
198 | + }; | |
199 | + } | |
200 | + | |
201 | + private boolean match(EntityTypeFilter filter, EntityRelation relation, EntitySearchDirection direction) { | |
202 | + if (StringUtils.isEmpty(filter.getRelationType()) || filter.getRelationType().equals(relation.getType())) { | |
203 | + if (filter.getEntityTypes() == null || filter.getEntityTypes().isEmpty()) { | |
204 | + return true; | |
205 | + } else { | |
206 | + EntityId entityId = direction == EntitySearchDirection.FROM ? relation.getTo() : relation.getFrom(); | |
207 | + return filter.getEntityTypes().contains(entityId.getEntityType()); | |
208 | + } | |
209 | + } else { | |
210 | + return false; | |
211 | + } | |
212 | + } | |
213 | + | |
214 | + private ListenableFuture<Set<EntityRelation>> findRelationsRecursively(final EntityId rootId, final EntitySearchDirection direction, int lvl, final ConcurrentHashMap<EntityId, Boolean> uniqueMap) throws Exception { | |
215 | + if (lvl == 0) { | |
216 | + return Futures.immediateFuture(Collections.emptySet()); | |
217 | + } | |
218 | + lvl--; | |
219 | + //TODO: try to remove this blocking operation | |
220 | + Set<EntityRelation> children = new HashSet<>(findRelations(rootId, direction).get()); | |
221 | + Set<EntityId> childrenIds = new HashSet<>(); | |
222 | + for (EntityRelation childRelation : children) { | |
223 | + log.info("Found Relation: {}", childRelation); | |
224 | + EntityId childId; | |
225 | + if (direction == EntitySearchDirection.FROM) { | |
226 | + childId = childRelation.getTo(); | |
227 | + } else { | |
228 | + childId = childRelation.getFrom(); | |
229 | + } | |
230 | + if (uniqueMap.putIfAbsent(childId, Boolean.TRUE) == null) { | |
231 | + log.info("Adding Relation: {}", childId); | |
232 | + if (childrenIds.add(childId)) { | |
233 | + log.info("Added Relation: {}", childId); | |
234 | + } | |
235 | + } | |
236 | + } | |
237 | + List<ListenableFuture<Set<EntityRelation>>> futures = new ArrayList<>(); | |
238 | + for (EntityId entityId : childrenIds) { | |
239 | + futures.add(findRelationsRecursively(entityId, direction, lvl, uniqueMap)); | |
240 | + } | |
241 | + //TODO: try to remove this blocking operation | |
242 | + List<Set<EntityRelation>> relations = Futures.successfulAsList(futures).get(); | |
243 | + relations.forEach(r -> r.forEach(d -> children.add(d))); | |
244 | + return Futures.immediateFuture(children); | |
245 | + } | |
246 | + | |
247 | + private ListenableFuture<List<EntityRelation>> findRelations(final EntityId rootId, final EntitySearchDirection direction) { | |
248 | + ListenableFuture<List<EntityRelation>> relations; | |
249 | + if (direction == EntitySearchDirection.FROM) { | |
250 | + relations = findByFrom(rootId); | |
251 | + } else { | |
252 | + relations = findByTo(rootId); | |
253 | + } | |
254 | + return relations; | |
255 | + } | |
256 | + | |
257 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.relation; | |
17 | + | |
18 | +import lombok.Data; | |
19 | + | |
20 | +import java.util.List; | |
21 | + | |
22 | +/** | |
23 | + * Created by ashvayka on 02.05.17. | |
24 | + */ | |
25 | +@Data | |
26 | +public class EntityRelationsQuery { | |
27 | + | |
28 | + private RelationsSearchParameters parameters; | |
29 | + private List<EntityTypeFilter> filters; | |
30 | + | |
31 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.relation; | |
17 | + | |
18 | +/** | |
19 | + * Created by ashvayka on 02.05.17. | |
20 | + */ | |
21 | +public enum EntitySearchDirection { | |
22 | + | |
23 | + FROM, TO; | |
24 | + | |
25 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.relation; | |
17 | + | |
18 | +import lombok.AllArgsConstructor; | |
19 | +import lombok.Data; | |
20 | +import org.thingsboard.server.common.data.EntityType; | |
21 | + | |
22 | +import javax.annotation.Nullable; | |
23 | +import java.util.List; | |
24 | + | |
25 | +/** | |
26 | + * Created by ashvayka on 02.05.17. | |
27 | + */ | |
28 | +@Data | |
29 | +@AllArgsConstructor | |
30 | +public class EntityTypeFilter { | |
31 | + @Nullable | |
32 | + private String relationType; | |
33 | + @Nullable | |
34 | + private List<EntityType> entityTypes; | |
35 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.relation; | |
17 | + | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
19 | +import org.thingsboard.server.common.data.id.EntityId; | |
20 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
21 | + | |
22 | +import java.util.List; | |
23 | + | |
24 | +/** | |
25 | + * Created by ashvayka on 25.04.17. | |
26 | + */ | |
27 | +public interface RelationDao { | |
28 | + | |
29 | + ListenableFuture<List<EntityRelation>> findAllByFrom(EntityId from); | |
30 | + | |
31 | + ListenableFuture<List<EntityRelation>> findAllByFromAndType(EntityId from, String relationType); | |
32 | + | |
33 | + ListenableFuture<List<EntityRelation>> findAllByTo(EntityId to); | |
34 | + | |
35 | + ListenableFuture<List<EntityRelation>> findAllByToAndType(EntityId to, String relationType); | |
36 | + | |
37 | + ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType); | |
38 | + | |
39 | + ListenableFuture<Boolean> saveRelation(EntityRelation relation); | |
40 | + | |
41 | + ListenableFuture<Boolean> deleteRelation(EntityRelation relation); | |
42 | + | |
43 | + ListenableFuture<Boolean> deleteRelation(EntityId from, EntityId to, String relationType); | |
44 | + | |
45 | + ListenableFuture<Boolean> deleteOutboundRelations(EntityId entity); | |
46 | + | |
47 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.relation; | |
17 | + | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
19 | +import org.thingsboard.server.common.data.id.EntityId; | |
20 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
21 | + | |
22 | +import java.util.List; | |
23 | + | |
24 | +/** | |
25 | + * Created by ashvayka on 27.04.17. | |
26 | + */ | |
27 | +public interface RelationService { | |
28 | + | |
29 | + ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType); | |
30 | + | |
31 | + ListenableFuture<Boolean> saveRelation(EntityRelation relation); | |
32 | + | |
33 | + ListenableFuture<Boolean> deleteRelation(EntityRelation relation); | |
34 | + | |
35 | + ListenableFuture<Boolean> deleteRelation(EntityId from, EntityId to, String relationType); | |
36 | + | |
37 | + ListenableFuture<Boolean> deleteEntityRelations(EntityId entity); | |
38 | + | |
39 | + ListenableFuture<List<EntityRelation>> findByFrom(EntityId from); | |
40 | + | |
41 | + ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType); | |
42 | + | |
43 | + ListenableFuture<List<EntityRelation>> findByTo(EntityId to); | |
44 | + | |
45 | + ListenableFuture<List<EntityRelation>> findByToAndType(EntityId to, String relationType); | |
46 | + | |
47 | + ListenableFuture<List<EntityRelation>> findByQuery(EntityRelationsQuery query); | |
48 | + | |
49 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.relation; | |
17 | + | |
18 | +import lombok.AllArgsConstructor; | |
19 | +import lombok.Data; | |
20 | +import org.thingsboard.server.common.data.EntityType; | |
21 | +import org.thingsboard.server.common.data.id.EntityId; | |
22 | +import org.thingsboard.server.common.data.id.EntityIdFactory; | |
23 | + | |
24 | +import java.util.UUID; | |
25 | + | |
26 | +/** | |
27 | + * Created by ashvayka on 03.05.17. | |
28 | + */ | |
29 | +@Data | |
30 | +@AllArgsConstructor | |
31 | +public class RelationsSearchParameters { | |
32 | + | |
33 | + private UUID rootId; | |
34 | + private EntityType rootType; | |
35 | + private EntitySearchDirection direction; | |
36 | + private int maxLevel = 1; | |
37 | + | |
38 | + public RelationsSearchParameters(EntityId entityId, EntitySearchDirection direction, int maxLevel) { | |
39 | + this.rootId = entityId.getId(); | |
40 | + this.rootType = entityId.getEntityType(); | |
41 | + this.direction = direction; | |
42 | + this.maxLevel = maxLevel; | |
43 | + } | |
44 | + | |
45 | + public EntityId getEntityId() { | |
46 | + return EntityIdFactory.getByTypeAndUuid(rootType, rootId); | |
47 | + } | |
48 | +} | ... | ... |
... | ... | @@ -17,10 +17,13 @@ package org.thingsboard.server.dao.rule; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | 19 | import com.fasterxml.jackson.databind.node.ArrayNode; |
20 | +import com.google.common.util.concurrent.Futures; | |
21 | +import com.google.common.util.concurrent.ListenableFuture; | |
20 | 22 | import lombok.extern.slf4j.Slf4j; |
21 | 23 | import org.apache.commons.lang3.StringUtils; |
22 | 24 | import org.springframework.beans.factory.annotation.Autowired; |
23 | 25 | import org.springframework.stereotype.Service; |
26 | +import org.thingsboard.server.common.data.asset.Asset; | |
24 | 27 | import org.thingsboard.server.common.data.id.RuleId; |
25 | 28 | import org.thingsboard.server.common.data.id.TenantId; |
26 | 29 | import org.thingsboard.server.common.data.page.TextPageData; |
... | ... | @@ -31,9 +34,11 @@ import org.thingsboard.server.common.data.plugin.ComponentType; |
31 | 34 | import org.thingsboard.server.common.data.plugin.PluginMetaData; |
32 | 35 | import org.thingsboard.server.common.data.rule.RuleMetaData; |
33 | 36 | import org.thingsboard.server.dao.component.ComponentDescriptorService; |
37 | +import org.thingsboard.server.dao.entity.BaseEntityService; | |
34 | 38 | import org.thingsboard.server.dao.exception.DataValidationException; |
35 | 39 | import org.thingsboard.server.dao.exception.DatabaseException; |
36 | 40 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
41 | +import org.thingsboard.server.dao.model.AssetEntity; | |
37 | 42 | import org.thingsboard.server.dao.model.RuleMetaDataEntity; |
38 | 43 | import org.thingsboard.server.dao.plugin.PluginService; |
39 | 44 | import org.thingsboard.server.dao.service.DataValidator; |
... | ... | @@ -53,7 +58,7 @@ import static org.thingsboard.server.dao.service.Validator.validatePageLink; |
53 | 58 | |
54 | 59 | @Service |
55 | 60 | @Slf4j |
56 | -public class BaseRuleService implements RuleService { | |
61 | +public class BaseRuleService extends BaseEntityService implements RuleService { | |
57 | 62 | |
58 | 63 | private final TenantId systemTenantId = new TenantId(NULL_UUID); |
59 | 64 | |
... | ... | @@ -167,6 +172,13 @@ public class BaseRuleService implements RuleService { |
167 | 172 | } |
168 | 173 | |
169 | 174 | @Override |
175 | + public ListenableFuture<RuleMetaData> findRuleByIdAsync(RuleId ruleId) { | |
176 | + validateId(ruleId, "Incorrect rule id for search rule request."); | |
177 | + ListenableFuture<RuleMetaDataEntity> ruleEntity = ruleDao.findByIdAsync(ruleId.getId()); | |
178 | + return Futures.transform(ruleEntity, (com.google.common.base.Function<? super RuleMetaDataEntity, ? extends RuleMetaData>) input -> getData(input)); | |
179 | + } | |
180 | + | |
181 | + @Override | |
170 | 182 | public List<RuleMetaData> findPluginRules(String pluginToken) { |
171 | 183 | List<RuleMetaDataEntity> ruleEntities = ruleDao.findRulesByPlugin(pluginToken); |
172 | 184 | return convertDataList(ruleEntities); |
... | ... | @@ -235,6 +247,7 @@ public class BaseRuleService implements RuleService { |
235 | 247 | @Override |
236 | 248 | public void deleteRuleById(RuleId ruleId) { |
237 | 249 | validateId(ruleId, "Incorrect rule id for delete rule request."); |
250 | + deleteEntityRelations(ruleId); | |
238 | 251 | ruleDao.deleteById(ruleId); |
239 | 252 | } |
240 | 253 | ... | ... |
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.rule; |
17 | 17 | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
18 | 19 | import org.thingsboard.server.common.data.id.RuleId; |
19 | 20 | import org.thingsboard.server.common.data.id.TenantId; |
20 | 21 | import org.thingsboard.server.common.data.page.TextPageData; |
... | ... | @@ -29,6 +30,8 @@ public interface RuleService { |
29 | 30 | |
30 | 31 | RuleMetaData findRuleById(RuleId ruleId); |
31 | 32 | |
33 | + ListenableFuture<RuleMetaData> findRuleByIdAsync(RuleId ruleId); | |
34 | + | |
32 | 35 | List<RuleMetaData> findPluginRules(String pluginToken); |
33 | 36 | |
34 | 37 | TextPageData<RuleMetaData> findSystemRules(TextPageLink pageLink); | ... | ... |
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.service; |
17 | 17 | |
18 | +import org.thingsboard.server.common.data.id.EntityId; | |
18 | 19 | import org.thingsboard.server.common.data.id.UUIDBased; |
19 | 20 | import org.thingsboard.server.common.data.page.TextPageLink; |
20 | 21 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
... | ... | @@ -25,6 +26,19 @@ import java.util.UUID; |
25 | 26 | public class Validator { |
26 | 27 | |
27 | 28 | /** |
29 | + * This method validate <code>EntityId</code> entity id. If entity id is invalid than throw | |
30 | + * <code>IncorrectParameterException</code> exception | |
31 | + * | |
32 | + * @param entityId the entityId | |
33 | + * @param errorMessage the error message for exception | |
34 | + */ | |
35 | + public static void validateEntityId(EntityId entityId, String errorMessage) { | |
36 | + if (entityId == null || entityId.getId() == null) { | |
37 | + throw new IncorrectParameterException(errorMessage); | |
38 | + } | |
39 | + } | |
40 | + | |
41 | + /** | |
28 | 42 | * This method validate <code>String</code> string. If string is invalid than throw |
29 | 43 | * <code>IncorrectParameterException</code> exception |
30 | 44 | * | ... | ... |
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.tenant; |
17 | 17 | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
18 | 19 | import org.thingsboard.server.common.data.Tenant; |
19 | 20 | import org.thingsboard.server.common.data.id.TenantId; |
20 | 21 | import org.thingsboard.server.common.data.page.TextPageData; |
... | ... | @@ -22,16 +23,16 @@ import org.thingsboard.server.common.data.page.TextPageLink; |
22 | 23 | |
23 | 24 | public interface TenantService { |
24 | 25 | |
25 | - public Tenant findTenantById(TenantId tenantId); | |
26 | - | |
27 | - public Tenant saveTenant(Tenant tenant); | |
26 | + Tenant findTenantById(TenantId tenantId); | |
27 | + | |
28 | + ListenableFuture<Tenant> findTenantByIdAsync(TenantId customerId); | |
28 | 29 | |
29 | - public void deleteTenant(TenantId tenantId); | |
30 | + Tenant saveTenant(Tenant tenant); | |
30 | 31 | |
31 | - public TextPageData<Tenant> findTenants(TextPageLink pageLink); | |
32 | + void deleteTenant(TenantId tenantId); | |
32 | 33 | |
33 | - //public TextPageData<Tenant> findTenantsByTitle(String title, PageLink pageLink); | |
34 | + TextPageData<Tenant> findTenants(TextPageLink pageLink); | |
34 | 35 | |
35 | - public void deleteTenants(); | |
36 | + void deleteTenants(); | |
36 | 37 | |
37 | 38 | } | ... | ... |
... | ... | @@ -17,11 +17,16 @@ package org.thingsboard.server.dao.tenant; |
17 | 17 | |
18 | 18 | import static org.thingsboard.server.dao.DaoUtil.convertDataList; |
19 | 19 | import static org.thingsboard.server.dao.DaoUtil.getData; |
20 | +import static org.thingsboard.server.dao.service.Validator.validateId; | |
20 | 21 | |
21 | 22 | import java.util.List; |
22 | 23 | |
24 | +import com.google.common.base.Function; | |
25 | +import com.google.common.util.concurrent.Futures; | |
26 | +import com.google.common.util.concurrent.ListenableFuture; | |
23 | 27 | import lombok.extern.slf4j.Slf4j; |
24 | 28 | import org.apache.commons.lang3.StringUtils; |
29 | +import org.thingsboard.server.common.data.Customer; | |
25 | 30 | import org.thingsboard.server.common.data.Tenant; |
26 | 31 | import org.thingsboard.server.common.data.id.TenantId; |
27 | 32 | import org.thingsboard.server.common.data.page.TextPageData; |
... | ... | @@ -29,15 +34,15 @@ import org.thingsboard.server.common.data.page.TextPageLink; |
29 | 34 | import org.thingsboard.server.dao.customer.CustomerService; |
30 | 35 | import org.thingsboard.server.dao.dashboard.DashboardService; |
31 | 36 | import org.thingsboard.server.dao.device.DeviceService; |
37 | +import org.thingsboard.server.dao.entity.BaseEntityService; | |
32 | 38 | import org.thingsboard.server.dao.exception.DataValidationException; |
39 | +import org.thingsboard.server.dao.model.CustomerEntity; | |
33 | 40 | import org.thingsboard.server.dao.model.TenantEntity; |
34 | 41 | import org.thingsboard.server.dao.plugin.PluginService; |
35 | 42 | import org.thingsboard.server.dao.rule.RuleService; |
36 | 43 | import org.thingsboard.server.dao.service.DataValidator; |
37 | 44 | import org.thingsboard.server.dao.service.PaginatedRemover; |
38 | 45 | import org.thingsboard.server.dao.user.UserService; |
39 | -import org.slf4j.Logger; | |
40 | -import org.slf4j.LoggerFactory; | |
41 | 46 | import org.springframework.beans.factory.annotation.Autowired; |
42 | 47 | import org.springframework.stereotype.Service; |
43 | 48 | import org.thingsboard.server.dao.service.Validator; |
... | ... | @@ -45,19 +50,19 @@ import org.thingsboard.server.dao.widget.WidgetsBundleService; |
45 | 50 | |
46 | 51 | @Service |
47 | 52 | @Slf4j |
48 | -public class TenantServiceImpl implements TenantService { | |
49 | - | |
53 | +public class TenantServiceImpl extends BaseEntityService implements TenantService { | |
54 | + | |
50 | 55 | private static final String DEFAULT_TENANT_REGION = "Global"; |
51 | 56 | |
52 | 57 | @Autowired |
53 | 58 | private TenantDao tenantDao; |
54 | - | |
59 | + | |
55 | 60 | @Autowired |
56 | 61 | private UserService userService; |
57 | - | |
62 | + | |
58 | 63 | @Autowired |
59 | 64 | private CustomerService customerService; |
60 | - | |
65 | + | |
61 | 66 | @Autowired |
62 | 67 | private DeviceService deviceService; |
63 | 68 | |
... | ... | @@ -72,7 +77,7 @@ public class TenantServiceImpl implements TenantService { |
72 | 77 | |
73 | 78 | @Autowired |
74 | 79 | private PluginService pluginService; |
75 | - | |
80 | + | |
76 | 81 | @Override |
77 | 82 | public Tenant findTenantById(TenantId tenantId) { |
78 | 83 | log.trace("Executing findTenantById [{}]", tenantId); |
... | ... | @@ -82,6 +87,14 @@ public class TenantServiceImpl implements TenantService { |
82 | 87 | } |
83 | 88 | |
84 | 89 | @Override |
90 | + public ListenableFuture<Tenant> findTenantByIdAsync(TenantId tenantId) { | |
91 | + log.trace("Executing TenantIdAsync [{}]", tenantId); | |
92 | + validateId(tenantId, "Incorrect tenantId " + tenantId); | |
93 | + ListenableFuture<TenantEntity> tenantEntity = tenantDao.findByIdAsync(tenantId.getId()); | |
94 | + return Futures.transform(tenantEntity, (Function<? super TenantEntity, ? extends Tenant>) input -> getData(input)); | |
95 | + } | |
96 | + | |
97 | + @Override | |
85 | 98 | public Tenant saveTenant(Tenant tenant) { |
86 | 99 | log.trace("Executing saveTenant [{}]", tenant); |
87 | 100 | tenant.setRegion(DEFAULT_TENANT_REGION); |
... | ... | @@ -102,6 +115,7 @@ public class TenantServiceImpl implements TenantService { |
102 | 115 | ruleService.deleteRulesByTenantId(tenantId); |
103 | 116 | pluginService.deletePluginsByTenantId(tenantId); |
104 | 117 | tenantDao.removeById(tenantId.getId()); |
118 | + deleteEntityRelations(tenantId); | |
105 | 119 | } |
106 | 120 | |
107 | 121 | @Override |
... | ... | @@ -131,10 +145,10 @@ public class TenantServiceImpl implements TenantService { |
131 | 145 | } |
132 | 146 | } |
133 | 147 | }; |
134 | - | |
148 | + | |
135 | 149 | private PaginatedRemover<String, TenantEntity> tenantsRemover = |
136 | 150 | new PaginatedRemover<String, TenantEntity>() { |
137 | - | |
151 | + | |
138 | 152 | @Override |
139 | 153 | protected List<TenantEntity> findEntities(String region, TextPageLink pageLink) { |
140 | 154 | return tenantDao.findTenantsByRegion(region, pageLink); | ... | ... |
... | ... | @@ -26,6 +26,7 @@ import com.google.common.util.concurrent.ListenableFuture; |
26 | 26 | import lombok.extern.slf4j.Slf4j; |
27 | 27 | import org.springframework.beans.factory.annotation.Value; |
28 | 28 | import org.springframework.stereotype.Component; |
29 | +import org.thingsboard.server.common.data.id.EntityId; | |
29 | 30 | import org.thingsboard.server.common.data.kv.*; |
30 | 31 | import org.thingsboard.server.common.data.kv.DataType; |
31 | 32 | import org.thingsboard.server.dao.AbstractAsyncDao; |
... | ... | @@ -94,8 +95,8 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao |
94 | 95 | } |
95 | 96 | |
96 | 97 | @Override |
97 | - public ListenableFuture<List<TsKvEntry>> findAllAsync(String entityType, UUID entityId, List<TsKvQuery> queries) { | |
98 | - List<ListenableFuture<List<TsKvEntry>>> futures = queries.stream().map(query -> findAllAsync(entityType, entityId, query)).collect(Collectors.toList()); | |
98 | + public ListenableFuture<List<TsKvEntry>> findAllAsync(EntityId entityId, List<TsKvQuery> queries) { | |
99 | + List<ListenableFuture<List<TsKvEntry>>> futures = queries.stream().map(query -> findAllAsync(entityId, query)).collect(Collectors.toList()); | |
99 | 100 | return Futures.transform(Futures.allAsList(futures), new Function<List<List<TsKvEntry>>, List<TsKvEntry>>() { |
100 | 101 | @Nullable |
101 | 102 | @Override |
... | ... | @@ -108,9 +109,9 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao |
108 | 109 | } |
109 | 110 | |
110 | 111 | |
111 | - private ListenableFuture<List<TsKvEntry>> findAllAsync(String entityType, UUID entityId, TsKvQuery query) { | |
112 | + private ListenableFuture<List<TsKvEntry>> findAllAsync(EntityId entityId, TsKvQuery query) { | |
112 | 113 | if (query.getAggregation() == Aggregation.NONE) { |
113 | - return findAllAsyncWithLimit(entityType, entityId, query); | |
114 | + return findAllAsyncWithLimit(entityId, query); | |
114 | 115 | } else { |
115 | 116 | long step = Math.max(query.getInterval(), minAggregationStepMs); |
116 | 117 | long stepTs = query.getStartTs(); |
... | ... | @@ -119,7 +120,7 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao |
119 | 120 | long startTs = stepTs; |
120 | 121 | long endTs = stepTs + step; |
121 | 122 | TsKvQuery subQuery = new BaseTsKvQuery(query.getKey(), startTs, endTs, step, 1, query.getAggregation()); |
122 | - futures.add(findAndAggregateAsync(entityType, entityId, subQuery, toPartitionTs(startTs), toPartitionTs(endTs))); | |
123 | + futures.add(findAndAggregateAsync(entityId, subQuery, toPartitionTs(startTs), toPartitionTs(endTs))); | |
123 | 124 | stepTs = endTs; |
124 | 125 | } |
125 | 126 | ListenableFuture<List<Optional<TsKvEntry>>> future = Futures.allAsList(futures); |
... | ... | @@ -133,11 +134,11 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao |
133 | 134 | } |
134 | 135 | } |
135 | 136 | |
136 | - private ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(String entityType, UUID entityId, TsKvQuery query) { | |
137 | + private ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(EntityId entityId, TsKvQuery query) { | |
137 | 138 | long minPartition = toPartitionTs(query.getStartTs()); |
138 | 139 | long maxPartition = toPartitionTs(query.getEndTs()); |
139 | 140 | |
140 | - ResultSetFuture partitionsFuture = fetchPartitions(entityType, entityId, query.getKey(), minPartition, maxPartition); | |
141 | + ResultSetFuture partitionsFuture = fetchPartitions(entityId, query.getKey(), minPartition, maxPartition); | |
141 | 142 | |
142 | 143 | final SimpleListenableFuture<List<TsKvEntry>> resultFuture = new SimpleListenableFuture<>(); |
143 | 144 | final ListenableFuture<List<Long>> partitionsListFuture = Futures.transform(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor); |
... | ... | @@ -145,13 +146,13 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao |
145 | 146 | Futures.addCallback(partitionsListFuture, new FutureCallback<List<Long>>() { |
146 | 147 | @Override |
147 | 148 | public void onSuccess(@Nullable List<Long> partitions) { |
148 | - TsKvQueryCursor cursor = new TsKvQueryCursor(entityType, entityId, query, partitions); | |
149 | + TsKvQueryCursor cursor = new TsKvQueryCursor(entityId.getEntityType().name(), entityId.getId(), query, partitions); | |
149 | 150 | findAllAsyncSequentiallyWithLimit(cursor, resultFuture); |
150 | 151 | } |
151 | 152 | |
152 | 153 | @Override |
153 | 154 | public void onFailure(Throwable t) { |
154 | - log.error("[{}][{}] Failed to fetch partitions for interval {}-{}", entityType, entityId, minPartition, maxPartition, t); | |
155 | + log.error("[{}][{}] Failed to fetch partitions for interval {}-{}", entityId.getEntityType().name(), entityId.getId(), minPartition, maxPartition, t); | |
155 | 156 | } |
156 | 157 | }, readResultsProcessingExecutor); |
157 | 158 | |
... | ... | @@ -187,19 +188,19 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao |
187 | 188 | } |
188 | 189 | } |
189 | 190 | |
190 | - private ListenableFuture<Optional<TsKvEntry>> findAndAggregateAsync(String entityType, UUID entityId, TsKvQuery query, long minPartition, long maxPartition) { | |
191 | + private ListenableFuture<Optional<TsKvEntry>> findAndAggregateAsync(EntityId entityId, TsKvQuery query, long minPartition, long maxPartition) { | |
191 | 192 | final Aggregation aggregation = query.getAggregation(); |
192 | 193 | final String key = query.getKey(); |
193 | 194 | final long startTs = query.getStartTs(); |
194 | 195 | final long endTs = query.getEndTs(); |
195 | 196 | final long ts = startTs + (endTs - startTs) / 2; |
196 | 197 | |
197 | - ResultSetFuture partitionsFuture = fetchPartitions(entityType, entityId, key, minPartition, maxPartition); | |
198 | + ResultSetFuture partitionsFuture = fetchPartitions(entityId, key, minPartition, maxPartition); | |
198 | 199 | |
199 | 200 | ListenableFuture<List<Long>> partitionsListFuture = Futures.transform(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor); |
200 | 201 | |
201 | 202 | ListenableFuture<List<ResultSet>> aggregationChunks = Futures.transform(partitionsListFuture, |
202 | - getFetchChunksAsyncFunction(entityType, entityId, key, aggregation, startTs, endTs), readResultsProcessingExecutor); | |
203 | + getFetchChunksAsyncFunction(entityId, key, aggregation, startTs, endTs), readResultsProcessingExecutor); | |
203 | 204 | |
204 | 205 | return Futures.transform(aggregationChunks, new AggregatePartitionsFunction(aggregation, key, ts), readResultsProcessingExecutor); |
205 | 206 | } |
... | ... | @@ -209,21 +210,21 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao |
209 | 210 | .map(row -> row.getLong(ModelConstants.PARTITION_COLUMN)).collect(Collectors.toList()); |
210 | 211 | } |
211 | 212 | |
212 | - private AsyncFunction<List<Long>, List<ResultSet>> getFetchChunksAsyncFunction(String entityType, UUID entityId, String key, Aggregation aggregation, long startTs, long endTs) { | |
213 | + private AsyncFunction<List<Long>, List<ResultSet>> getFetchChunksAsyncFunction(EntityId entityId, String key, Aggregation aggregation, long startTs, long endTs) { | |
213 | 214 | return partitions -> { |
214 | 215 | try { |
215 | 216 | PreparedStatement proto = getFetchStmt(aggregation); |
216 | 217 | List<ResultSetFuture> futures = new ArrayList<>(partitions.size()); |
217 | 218 | for (Long partition : partitions) { |
218 | - log.trace("Fetching data for partition [{}] for entityType {} and entityId {}", partition, entityType, entityId); | |
219 | + log.trace("Fetching data for partition [{}] for entityType {} and entityId {}", partition, entityId.getEntityType(), entityId.getId()); | |
219 | 220 | BoundStatement stmt = proto.bind(); |
220 | - stmt.setString(0, entityType); | |
221 | - stmt.setUUID(1, entityId); | |
221 | + stmt.setString(0, entityId.getEntityType().name()); | |
222 | + stmt.setUUID(1, entityId.getId()); | |
222 | 223 | stmt.setString(2, key); |
223 | 224 | stmt.setLong(3, partition); |
224 | 225 | stmt.setLong(4, startTs); |
225 | 226 | stmt.setLong(5, endTs); |
226 | - log.debug("Generated query [{}] for entityType {} and entityId {}", stmt, entityType, entityId); | |
227 | + log.debug("Generated query [{}] for entityType {} and entityId {}", stmt, entityId.getEntityType(), entityId.getId()); | |
227 | 228 | futures.add(executeAsyncRead(stmt)); |
228 | 229 | } |
229 | 230 | return Futures.allAsList(futures); |
... | ... | @@ -235,30 +236,30 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao |
235 | 236 | } |
236 | 237 | |
237 | 238 | @Override |
238 | - public ResultSetFuture findLatest(String entityType, UUID entityId, String key) { | |
239 | + public ResultSetFuture findLatest(EntityId entityId, String key) { | |
239 | 240 | BoundStatement stmt = getFindLatestStmt().bind(); |
240 | - stmt.setString(0, entityType); | |
241 | - stmt.setUUID(1, entityId); | |
241 | + stmt.setString(0, entityId.getEntityType().name()); | |
242 | + stmt.setUUID(1, entityId.getId()); | |
242 | 243 | stmt.setString(2, key); |
243 | - log.debug("Generated query [{}] for entityType {} and entityId {}", stmt, entityType, entityId); | |
244 | + log.debug("Generated query [{}] for entityType {} and entityId {}", stmt, entityId.getEntityType(), entityId.getId()); | |
244 | 245 | return executeAsyncRead(stmt); |
245 | 246 | } |
246 | 247 | |
247 | 248 | @Override |
248 | - public ResultSetFuture findAllLatest(String entityType, UUID entityId) { | |
249 | + public ResultSetFuture findAllLatest(EntityId entityId) { | |
249 | 250 | BoundStatement stmt = getFindAllLatestStmt().bind(); |
250 | - stmt.setString(0, entityType); | |
251 | - stmt.setUUID(1, entityId); | |
252 | - log.debug("Generated query [{}] for entityType {} and entityId {}", stmt, entityType, entityId); | |
251 | + stmt.setString(0, entityId.getEntityType().name()); | |
252 | + stmt.setUUID(1, entityId.getId()); | |
253 | + log.debug("Generated query [{}] for entityType {} and entityId {}", stmt, entityId.getEntityType(), entityId.getId()); | |
253 | 254 | return executeAsyncRead(stmt); |
254 | 255 | } |
255 | 256 | |
256 | 257 | @Override |
257 | - public ResultSetFuture save(String entityType, UUID entityId, long partition, TsKvEntry tsKvEntry) { | |
258 | + public ResultSetFuture save(EntityId entityId, long partition, TsKvEntry tsKvEntry) { | |
258 | 259 | DataType type = tsKvEntry.getDataType(); |
259 | 260 | BoundStatement stmt = getSaveStmt(type).bind() |
260 | - .setString(0, entityType) | |
261 | - .setUUID(1, entityId) | |
261 | + .setString(0, entityId.getEntityType().name()) | |
262 | + .setUUID(1, entityId.getId()) | |
262 | 263 | .setString(2, tsKvEntry.getKey()) |
263 | 264 | .setLong(3, partition) |
264 | 265 | .setLong(4, tsKvEntry.getTs()); |
... | ... | @@ -267,11 +268,11 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao |
267 | 268 | } |
268 | 269 | |
269 | 270 | @Override |
270 | - public ResultSetFuture saveLatest(String entityType, UUID entityId, TsKvEntry tsKvEntry) { | |
271 | + public ResultSetFuture saveLatest(EntityId entityId, TsKvEntry tsKvEntry) { | |
271 | 272 | DataType type = tsKvEntry.getDataType(); |
272 | 273 | BoundStatement stmt = getLatestStmt(type).bind() |
273 | - .setString(0, entityType) | |
274 | - .setUUID(1, entityId) | |
274 | + .setString(0, entityId.getEntityType().name()) | |
275 | + .setUUID(1, entityId.getId()) | |
275 | 276 | .setString(2, tsKvEntry.getKey()) |
276 | 277 | .setLong(3, tsKvEntry.getTs()); |
277 | 278 | addValue(tsKvEntry, stmt, 4); |
... | ... | @@ -279,11 +280,11 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao |
279 | 280 | } |
280 | 281 | |
281 | 282 | @Override |
282 | - public ResultSetFuture savePartition(String entityType, UUID entityId, long partition, String key) { | |
283 | - log.debug("Saving partition {} for the entity [{}-{}] and key {}", partition, entityType, entityId, key); | |
283 | + public ResultSetFuture savePartition(EntityId entityId, long partition, String key) { | |
284 | + log.debug("Saving partition {} for the entity [{}-{}] and key {}", partition, entityId.getEntityType(), entityId.getId(), key); | |
284 | 285 | return executeAsyncWrite(getPartitionInsertStmt().bind() |
285 | - .setString(0, entityType) | |
286 | - .setUUID(1, entityId) | |
286 | + .setString(0, entityId.getEntityType().name()) | |
287 | + .setUUID(1, entityId.getId()) | |
287 | 288 | .setLong(2, partition) |
288 | 289 | .setString(3, key)); |
289 | 290 | } |
... | ... | @@ -339,9 +340,9 @@ public class BaseTimeseriesDao extends AbstractAsyncDao implements TimeseriesDao |
339 | 340 | * Select existing partitions from the table |
340 | 341 | * <code>{@link ModelConstants#TS_KV_PARTITIONS_CF}</code> for the given entity |
341 | 342 | */ |
342 | - private ResultSetFuture fetchPartitions(String entityType, UUID entityId, String key, long minPartition, long maxPartition) { | |
343 | - Select.Where select = QueryBuilder.select(ModelConstants.PARTITION_COLUMN).from(ModelConstants.TS_KV_PARTITIONS_CF).where(eq(ModelConstants.ENTITY_TYPE_COLUMN, entityType)) | |
344 | - .and(eq(ModelConstants.ENTITY_ID_COLUMN, entityId)).and(eq(ModelConstants.KEY_COLUMN, key)); | |
343 | + private ResultSetFuture fetchPartitions(EntityId entityId, String key, long minPartition, long maxPartition) { | |
344 | + Select.Where select = QueryBuilder.select(ModelConstants.PARTITION_COLUMN).from(ModelConstants.TS_KV_PARTITIONS_CF).where(eq(ModelConstants.ENTITY_TYPE_COLUMN, entityId.getEntityType().name())) | |
345 | + .and(eq(ModelConstants.ENTITY_ID_COLUMN, entityId.getId())).and(eq(ModelConstants.KEY_COLUMN, key)); | |
345 | 346 | select.and(QueryBuilder.gte(ModelConstants.PARTITION_COLUMN, minPartition)); |
346 | 347 | select.and(QueryBuilder.lte(ModelConstants.PARTITION_COLUMN, maxPartition)); |
347 | 348 | return executeAsyncRead(select); | ... | ... |